diff --git a/.circleci/config.yml b/.circleci/config.yml index cf69ff68da6..1462891fa7f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2400,6 +2400,11 @@ jobs: environment: DATABASE_URL: "postgresql://e2euser:e2epassword@localhost:5432/litellm_e2e" CI: "true" + # Boot the proxy with an external logout URL so proxyLogoutUrl.spec.ts can + # assert the redirect. Set at job level so both the proxy boot step and the + # Playwright step (whose skip guard reads this) see the same value. Safe for + # the rest of the suite: nothing else performs a logout. + PROXY_LOGOUT_URL: "https://www.example.com" steps: - checkout - setup_google_dns @@ -2476,7 +2481,8 @@ jobs: MOCK_LLM_URL: "http://127.0.0.1:8090/v1" DISABLE_SCHEMA_UPDATE: "true" SERVER_ROOT_PATH: "" - PROXY_LOGOUT_URL: "" + # PROXY_LOGOUT_URL is inherited from the job-level environment so the + # proxy and proxyLogoutUrl.spec.ts agree on the logout target. # LITELLM_LICENSE is forwarded from the project env so premium-gated # UI flows can be exercised. license.spec.ts asserts the resulting # JWT carries premium_user=true; if it ever stops being passed, that diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f9ce9e5dcb8..99f79c0b272 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,9 +10,9 @@ **Please complete all items before asking a LiteLLM maintainer to review your PR** -- [ ] I have Added testing in the [`tests/test_litellm/`](https://github.com/BerriAI/litellm/tree/main/tests/test_litellm) directory, **Adding at least 1 test is a hard requirement** - [see details](https://docs.litellm.ai/docs/extras/contributing_code) +- [ ] I have added meaningful tests - [ ] My PR passes all unit tests on [`make test-unit`](https://docs.litellm.ai/docs/extras/contributing_code) -- [ ] My PR's scope is as isolated as possible, it only solves 1 specific problem +- [ ] My PR's scope is as isolated as possible; it only solves 1 specific problem - [ ] I have requested a Greptile review by commenting `@greptileai` and received a **Confidence Score of at least 4/5** before requesting a maintainer review ## Delays in PR merge? diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e86fca17c7a..babe3b62933 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,3 +53,31 @@ jobs: uses: github/codeql-action/analyze@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 with: category: "/language:${{ matrix.language }}" + output: sarif-results + upload: failure-only + + # py/weak-sensitive-data-hashing (CWE-328) fires on the OCI signing call at + # litellm/llms/oci/common_utils.py, which hashes the HTTP request body to + # produce the x-content-sha256 header required by the OCI HTTP signing spec — + # a content-integrity hash, not a password or secret hash. SHA-256 is mandated + # by Oracle for this header; see + # https://docs.oracle.com/en-us/iaas/Content/API/Concepts/signingrequests.htm + # The `usedforsecurity=False` flag on the hashlib.sha256 call already declares + # non-security intent, but CodeQL's taint flow still re-fires when callers + # further up the stack are modified. The suppression is scoped to this one + # file/rule pair via SARIF post-filtering so every other callsite of + # py/weak-sensitive-data-hashing in the repository continues to be analyzed. + - name: Filter SARIF (OCI sha256) + if: matrix.language == 'python' + uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1 + with: + patterns: | + -litellm/llms/oci/common_utils.py:py/weak-sensitive-data-hashing + input: sarif-results/python.sarif + output: sarif-results/python.sarif + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 + with: + sarif_file: sarif-results + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/create_daily_oss_agent_shin_branch.yml b/.github/workflows/create_daily_oss_agent_shin_branch.yml new file mode 100644 index 00000000000..d6118f3b53c --- /dev/null +++ b/.github/workflows/create_daily_oss_agent_shin_branch.yml @@ -0,0 +1,47 @@ +name: Create Daily oss-agent-shin Branch + +on: + schedule: + - cron: "0 0 * * *" # Runs every day at midnight UTC + workflow_dispatch: # Allow manual trigger + +jobs: + create-oss-agent-shin-branch: + if: github.repository == 'BerriAI/litellm' + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Create daily oss-agent-shin branch + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Configure Git user + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Generate branch name with MM_DD_YYYY format + BRANCH_NAME="litellm_oss_agent_shin_$(date +'%m_%d_%Y')" + echo "Creating branch: $BRANCH_NAME" + + # Fetch all branches + git fetch --all + + # Check if the branch already exists + if git show-ref --verify --quiet refs/remotes/origin/$BRANCH_NAME; then + echo "Branch $BRANCH_NAME already exists. Skipping creation." + else + echo "Creating new branch: $BRANCH_NAME" + # Create the new branch from main + git checkout -b $BRANCH_NAME origin/main + # Push the new branch + git push origin $BRANCH_NAME + echo "Successfully created and pushed branch: $BRANCH_NAME" + fi diff --git a/.github/workflows/test-unit-proxy-endpoints.yml b/.github/workflows/test-unit-proxy-endpoints.yml index 1439b2c07f7..6b34a08a8e0 100644 --- a/.github/workflows/test-unit-proxy-endpoints.yml +++ b/.github/workflows/test-unit-proxy-endpoints.yml @@ -7,6 +7,7 @@ on: - litellm_internal_staging - litellm_oss_branch - "litellm_**" + workflow_dispatch: permissions: contents: read @@ -32,6 +33,7 @@ jobs: tests/test_litellm/proxy/image_endpoints tests/test_litellm/proxy/vector_store_endpoints tests/test_litellm/proxy/agent_endpoints + tests/test_litellm/proxy/a2a tests/test_litellm/proxy/discovery_endpoints tests/test_litellm/proxy/health_endpoints tests/test_litellm/proxy/public_endpoints @@ -42,3 +44,16 @@ jobs: workers: 2 reruns: 2 artifact-name: proxy-endpoints + + # Behavior-pinning tests for litellm/proxy/proxy_server.py. Owns its + # own job (not a path on the proxy-endpoints job above) so its budget + # is independent and its coverage artifact is uploaded separately. + # See: https://www.notion.so/36c43b8acdab81ee845fd5365128a2fc + proxy-server: + uses: ./.github/workflows/_test-unit-base.yml + with: + test-path: tests/test_litellm/proxy/proxy_server + workers: 4 + reruns: 2 + timeout-minutes: 60 + artifact-name: proxy-server diff --git a/.github/workflows/test_server_root_path.yml b/.github/workflows/test_server_root_path.yml index 155445acdf6..57ff746c9c8 100644 --- a/.github/workflows/test_server_root_path.yml +++ b/.github/workflows/test_server_root_path.yml @@ -101,6 +101,31 @@ jobs: docker logs litellm-test exit 1 + - name: Setup Node for Playwright + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "20" + + - name: Install UI deps and Chromium + working-directory: ui/litellm-dashboard + run: | + npm ci + npx playwright install --with-deps chromium + + - name: Run SERVER_ROOT_PATH redirect e2e + working-directory: ui/litellm-dashboard + env: + SERVER_ROOT_PATH: ${{ matrix.root_path }} + run: npx playwright test --config=e2e_tests/serverRootPath.config.ts + + - name: Upload Playwright artifacts on failure + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: playwright-trace-${{ strategy.job-index }} + path: ui/litellm-dashboard/test-results/ + retention-days: 7 + - name: Cleanup if: always() run: | diff --git a/.gitignore b/.gitignore index dff64e3c9e9..572830d35f6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ litellm/tests/config_*.yaml litellm/tests/langfuse.log langfuse.log .langfuse.log +.pin_list.txt +.cov_new.xml litellm/tests/test_custom_logger.py litellm/tests/langfuse.log litellm/tests/dynamo*.log @@ -120,4 +122,5 @@ crash.log crash.*.log # .terraform.lock.hcl is intentionally NOT ignored — it pins provider versions # and should be committed. -.vscode \ No newline at end of file +.vscode +.pin_list.txt diff --git a/AGENTS.md b/AGENTS.md index e99bf79d783..41921fdff4d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,293 +1 @@ -# INSTRUCTIONS FOR LITELLM - -This document provides comprehensive instructions for AI agents working in the LiteLLM repository. - -## OVERVIEW - -LiteLLM is a unified interface for 100+ LLMs that: -- Translates inputs to provider-specific completion, embedding, and image generation endpoints -- Provides consistent OpenAI-format output across all providers -- Includes retry/fallback logic across multiple deployments (Router) -- Offers a proxy server (LLM Gateway) with budgets, rate limits, and authentication -- Supports advanced features like function calling, streaming, caching, and observability - -## REPOSITORY STRUCTURE - -### Core Components -- `litellm/` - Main library code - - `llms/` - Provider-specific implementations (OpenAI, Anthropic, Azure, etc.) - - `proxy/` - Proxy server implementation (LLM Gateway) - - `router_utils/` - Load balancing and fallback logic - - `types/` - Type definitions and schemas - - `integrations/` - Third-party integrations (observability, caching, etc.) - -### Key Directories -- `tests/` - Comprehensive test suites -- `ui/litellm-dashboard/` - Admin dashboard UI -- `enterprise/` - Enterprise-specific features - -Documentation lives in the separate [BerriAI/litellm-docs](https://github.com/BerriAI/litellm-docs) repository and is served at [docs.litellm.ai](https://docs.litellm.ai). - -## DEVELOPMENT GUIDELINES - -### MAKING CODE CHANGES - -1. **Provider Implementations**: When adding/modifying LLM providers: - - Follow existing patterns in `litellm/llms/{provider}/` - - Implement proper transformation classes that inherit from `BaseConfig` - - Support both sync and async operations - - Handle streaming responses appropriately - - Include proper error handling with provider-specific exceptions - -2. **Type Safety**: - - Use proper type hints throughout - - Update type definitions in `litellm/types/` - - Ensure compatibility with both Pydantic v1 and v2 - -3. **Testing**: - - Add tests in appropriate `tests/` subdirectories - - Include both unit tests and integration tests - - Test provider-specific functionality thoroughly - - Consider adding load tests for performance-critical changes - -### MAKING CODE CHANGES FOR THE UI (IGNORE FOR BACKEND) - -1. **Always use `antd` for new UI components — Tremor is DEPRECATED** - - We are migrating off of `@tremor/react`. Do not introduce new `Badge`, `Text`, `Card`, `Grid`, `Title`, or other imports from `@tremor/react` in any new or modified file. - - Use `antd` equivalents: `Tag` for labels, plain ``/`
` with Tailwind classes (or `Typography.Text`) for text, `Card` from `antd`, etc. Note that `antd` has no `"yellow"` Tag color — use `"gold"` for amber/yellow. - - The only exception is the Tremor Table component and its required Tremor Table sub components. - -2. **Use Common Components as much as possible**: - - These are usually defined in the `common_components` directory - - Use these components as much as possible and avoid building new components unless needed - -3. **Testing**: - - The codebase uses **Vitest** and **React Testing Library** - - **Query Priority Order**: Use query methods in this order: `getByRole`, `getByLabelText`, `getByPlaceholderText`, `getByText`, `getByTestId` - - **Always use `screen`** instead of destructuring from `render()` (e.g., use `screen.getByText()` not `getByText`) - - **Wrap user interactions in `act()`**: Always wrap `fireEvent` calls with `act()` to ensure React state updates are properly handled - - **Use `query` methods for absence checks**: Use `queryBy*` methods (not `getBy*`) when expecting an element to NOT be present - - **Test names must start with "should"**: All test names should follow the pattern `it("should ...")` - - **Mock external dependencies**: Check `setupTests.ts` for global mocks and mock child components/networking calls as needed - - **Structure tests properly**: - - First test should verify the component renders successfully - - Subsequent tests should focus on functionality and user interactions - - Use `waitFor` for async operations that aren't already awaited - - **Avoid using `querySelector`**: Prefer React Testing Library queries over direct DOM manipulation - -### IMPORTANT PATTERNS - -1. **Function/Tool Calling**: - - LiteLLM standardizes tool calling across providers - - OpenAI format is the standard, with transformations for other providers - - See `litellm/llms/anthropic/chat/transformation.py` for complex tool handling - -2. **Streaming**: - - All providers should support streaming where possible - - Use consistent chunk formatting across providers - - Handle both sync and async streaming - -3. **Error Handling**: - - Use provider-specific exception classes - - Maintain consistent error formats across providers - - Include proper retry logic and fallback mechanisms - -4. **Configuration**: - - Support both environment variables and programmatic configuration - - Use `BaseConfig` classes for provider configurations - - Allow dynamic parameter passing - -## PROXY SERVER (LLM GATEWAY) - -The proxy server is a critical component that provides: -- Authentication and authorization -- Rate limiting and budget management -- Load balancing across multiple models/deployments -- Observability and logging -- Admin dashboard UI -- Enterprise features - -Key files: -- `litellm/proxy/proxy_server.py` - Main server implementation -- `litellm/proxy/auth/` - Authentication logic -- `litellm/proxy/management_endpoints/` - Admin API endpoints - -**Database (proxy)**: Use Prisma model methods (`prisma_client.db..upsert`, `.find_many`, `.find_unique`, etc.), not raw SQL (`execute_raw`/`query_raw`). See COMMON PITFALLS for details. - -## MCP (MODEL CONTEXT PROTOCOL) SUPPORT - -LiteLLM supports MCP for agent workflows: -- MCP server integration for tool calling -- Transformation between OpenAI and MCP tool formats -- Support for external MCP servers (Zapier, Jira, Linear, etc.) -- See `litellm/experimental_mcp_client/` and `litellm/proxy/_experimental/mcp_server/` - -## RUNNING SCRIPTS - -Use `uv run python script.py` to run Python scripts in the project environment (for non-test files). - -## GITHUB TEMPLATES - -When opening issues or pull requests, follow these templates: - -### Bug Reports (`.github/ISSUE_TEMPLATE/bug_report.yml`) -- Describe what happened vs. expected behavior -- Include relevant log output -- Specify LiteLLM version -- Indicate if you're part of an ML Ops team (helps with prioritization) - -### Feature Requests (`.github/ISSUE_TEMPLATE/feature_request.yml`) -- Clearly describe the feature -- Explain motivation and use case with concrete examples - -### Pull Requests (`.github/pull_request_template.md`) -- Add at least 1 test in `tests/litellm/` -- Ensure `make test-unit` passes - - -## TESTING CONSIDERATIONS - -1. **Provider Tests**: Test against real provider APIs when possible -2. **Proxy Tests**: Include authentication, rate limiting, and routing tests -3. **Performance Tests**: Load testing for high-throughput scenarios -4. **Integration Tests**: End-to-end workflows including tool calling - -## DOCUMENTATION - -- Keep documentation in sync with code changes -- Update provider documentation when adding new providers -- Include code examples for new features -- Update changelog and release notes - -## SECURITY CONSIDERATIONS - -- Handle API keys securely -- Validate all inputs, especially for proxy endpoints -- Consider rate limiting and abuse prevention -- Follow security best practices for authentication - -## ENTERPRISE FEATURES - -- Some features are enterprise-only -- Check `enterprise/` directory for enterprise-specific code -- Maintain compatibility between open-source and enterprise versions - -## COMMON PITFALLS TO AVOID - -1. **Breaking Changes**: LiteLLM has many users - avoid breaking existing APIs -2. **Provider Specifics**: Each provider has unique quirks - handle them properly -3. **Rate Limits**: Respect provider rate limits in tests -4. **Memory Usage**: Be mindful of memory usage in streaming scenarios -5. **Dependencies**: Keep dependencies minimal and well-justified -6. **UI/Backend Contract Mismatch**: When adding a new entity type to the UI, always check whether the backend endpoint accepts a single value or an array. Match the UI control accordingly (single-select vs. multi-select) to avoid silently dropping user selections -7. **Missing Tests for New Entity Types**: When adding a new entity type (e.g., in `EntityUsage`, `UsageViewSelect`), always add corresponding tests in the existing test files and update any icon/component mocks -8. **Raw SQL in proxy DB code**: Do not use `execute_raw` or `query_raw` for proxy database access. Use Prisma model methods (e.g. `prisma_client.db.litellm_tooltable.upsert()`, `.find_many()`, `.find_unique()`) so behavior stays consistent with the schema, the client stays mockable in tests, and you avoid the pitfalls of hand-written SQL (parameter ordering, type casting, schema drift) - -8. **Do not hardcode model-specific flags**: Put model-specific capability flags in `model_prices_and_context_window.json` and read them via `get_model_info` (or existing helpers like `supports_reasoning`). This prevents users from needing to upgrade LiteLLM each time a new model supports a feature. - - **Example of BAD** (hardcoded model checks): - - ```python - @staticmethod - def _is_effort_supported_model(model: str) -> bool: - """Check if the model supports the output_config.effort parameter...""" - model_lower = model.lower() - if AnthropicConfig._is_claude_4_6_model(model): - return True - return any( - v in model_lower for v in ("opus-4-5", "opus_4_5", "opus-4.5", "opus_4.5") - ) - ``` - - **Example of GOOD** (config-driven or helper that reads from config): - - ```python - if ( - "claude-3-7-sonnet" in model - or AnthropicConfig._is_claude_4_6_model(model) - or supports_reasoning( - model=model, - custom_llm_provider=self.custom_llm_provider, - ) - ): - ... - ``` - - Using helpers like `supports_reasoning` (which read from `model_prices_and_context_window.json` / `get_model_info`) allows future model updates to "just work" without code changes. - -9. **Never close HTTP/SDK clients on cache eviction**: Do not add `close()`, `aclose()`, or `create_task(close_fn())` inside `LLMClientCache._remove_key()` or any cache eviction path. Evicted clients may still be held by in-flight requests; closing them causes `RuntimeError: Cannot send a request, as the client has been closed.` in production after the cache TTL (1 hour) expires. Connection cleanup is handled at shutdown by `close_litellm_async_clients()`. See PR #22247 for the full incident history. - -## HELPFUL RESOURCES - -- Main documentation: https://docs.litellm.ai/ (source: [BerriAI/litellm-docs](https://github.com/BerriAI/litellm-docs)) -- Provider-specific docs: https://docs.litellm.ai/docs/providers/ -- Admin UI for testing proxy features - -## WHEN IN DOUBT - -- Follow existing patterns in the codebase -- Check similar provider implementations -- Ensure comprehensive test coverage -- Update documentation appropriately -- Consider backward compatibility impact - -## Cursor Cloud specific instructions - -### Environment - -- uv is installed in `~/.local/bin`; the update script ensures it is on `PATH`. -- Python 3.12, Node 22 are pre-installed. -- The project virtual environment lives under `.venv/`. - -### Running the proxy server - -Create a minimal config file and start the proxy: - -```yaml -# config.yaml -model_list: - - model_name: fake-openai-endpoint - litellm_params: - model: openai/fake-model - api_key: fake-key - api_base: https://fake-api.example.com - -general_settings: - master_key: sk-1234 - -litellm_settings: - drop_params: True - telemetry: False -``` - -```bash -uv run litellm --config config.yaml --port 4000 -``` - -The proxy takes ~15-20 seconds to fully start (it runs Prisma migrations on boot). Wait for `/health` to return before sending requests. Without a PostgreSQL `DATABASE_URL`, the proxy connects to a default Neon dev database embedded in the `litellm-proxy-extras` package. - -### Running tests - -See `CLAUDE.md` and the `Makefile` for standard commands. Key notes: - -- `uv sync --group proxy-dev --extra proxy` installs the Prisma and proxy-side test dependencies used by the standard local workflow. -- The `--timeout` pytest flag is NOT available; don't pass it. -- Unit tests: `uv run pytest tests/test_litellm/ -x -vv -n 4` -- **Before committing, always run `uv run black .` to format your code.** Black formatting is enforced in CI. -- If `uv sync` fails because the lockfile is outdated, run `uv lock` and retry. - -### Lint - -```bash -cd litellm && uv run ruff check . -``` - -Ruff is the primary fast linter. For the full lint suite (including mypy, black, circular imports), run `make lint` per `CLAUDE.md`. - -### UI Dashboard development - -- The UI is at `ui/litellm-dashboard/`. Run `npm run dev` from that directory for the Next.js dev server on port 3000. -- The proxy at port 4000 serves a **pre-built** static UI from `litellm/proxy/_experimental/out/`. After making UI code changes, you must run `npm run build` in the dashboard directory and copy the output: `cp -r ui/litellm-dashboard/out/* litellm/proxy/_experimental/out/` for the proxy to serve the updated UI. -- SVGs used as provider logos (loaded via `` tags) must NOT use `fill="currentColor"` — replace with an explicit color like `#000000` or use the `-color` variant from lobehub icons, since CSS color inheritance does not work inside `` elements. -- Provider logos live in `ui/litellm-dashboard/public/assets/logos/` (source) and `litellm/proxy/_experimental/out/assets/logos/` (pre-built). Both locations must have the file for it to work in dev and proxy-served modes. -- UI Vitest tests: `cd ui/litellm-dashboard && npx vitest run` +Read @CLAUDE.md for coding guidelines diff --git a/CLAUDE.md b/CLAUDE.md index baf23c90148..3477b71a621 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,181 +1,70 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Documentation - -Documentation lives in a separate repository: [BerriAI/litellm-docs](https://github.com/BerriAI/litellm-docs). It is served at [docs.litellm.ai](https://docs.litellm.ai). Do not create or edit documentation files in this repository — open doc PRs against `BerriAI/litellm-docs` instead. - -## Development Commands - -### Installation -- `make install-dev` - Install core development dependencies -- `make install-proxy-dev` - Install proxy development dependencies with full feature set -- `make install-test-deps` - Install the full local test environment and generate the Prisma client - -### Testing -- `make test` - Run all tests -- `make test-unit` - Run unit tests (tests/test_litellm) with 4 parallel workers -- `make test-integration` - Run integration tests (excludes unit tests) -- `pytest tests/` - Direct pytest execution - -### Code Quality -- `make lint` - Run all linting (Ruff, MyPy, Black, circular imports, import safety) -- `make format` - Apply Black code formatting -- `make lint-ruff` - Run Ruff linting only -- `make lint-mypy` - Run MyPy type checking only -- **Before committing, always run `uv run black .` to format your code.** Black formatting is enforced in CI. - -### Single Test Files -- `uv run pytest tests/path/to/test_file.py -v` - Run specific test file -- `uv run pytest tests/path/to/test_file.py::test_function -v` - Run specific test - -### Running Scripts -- `uv run python script.py` - Run Python scripts (use for non-test files) - -### GitHub Issue & PR Templates -When contributing to the project, use the appropriate templates: - -**Bug Reports** (`.github/ISSUE_TEMPLATE/bug_report.yml`): -- Describe what happened vs. what you expected -- Include relevant log output -- Specify your LiteLLM version - -**Feature Requests** (`.github/ISSUE_TEMPLATE/feature_request.yml`): -- Describe the feature clearly -- Explain the motivation and use case - -**Pull Requests** (`.github/pull_request_template.md`): -- Add at least 1 test in `tests/litellm/` -- Ensure `make test-unit` passes - -## Architecture Overview - -LiteLLM is a unified interface for 100+ LLM providers with two main components: - -### Core Library (`litellm/`) -- **Main entry point**: `litellm/main.py` - Contains core completion() function -- **Provider implementations**: `litellm/llms/` - Each provider has its own subdirectory -- **Router system**: `litellm/router.py` + `litellm/router_utils/` - Load balancing and fallback logic -- **Type definitions**: `litellm/types/` - Pydantic models and type hints -- **Integrations**: `litellm/integrations/` - Third-party observability, caching, logging -- **Caching**: `litellm/caching/` - Multiple cache backends (Redis, in-memory, S3, etc.) - -### Proxy Server (`litellm/proxy/`) -- **Main server**: `proxy_server.py` - FastAPI application -- **Authentication**: `auth/` - API key management, JWT, OAuth2 -- **Database**: `db/` - Prisma ORM with PostgreSQL/SQLite support -- **Management endpoints**: `management_endpoints/` - Admin APIs for keys, teams, models -- **Pass-through endpoints**: `pass_through_endpoints/` - Provider-specific API forwarding -- **Guardrails**: `guardrails/` - Safety and content filtering hooks -- **UI Dashboard**: Served from `_experimental/out/` (Next.js build) - -## Key Patterns - -### Provider Implementation -- Providers inherit from base classes in `litellm/llms/base.py` -- Each provider has transformation functions for input/output formatting -- Support both sync and async operations -- Handle streaming responses and function calling - -### Error Handling -- Provider-specific exceptions mapped to OpenAI-compatible errors -- Fallback logic handled by Router system -- Comprehensive logging through `litellm/_logging.py` - -### Configuration -- YAML config files for proxy server (see `proxy/example_config_yaml/`) -- Environment variables for API keys and settings -- Database schema managed via Prisma (`proxy/schema.prisma`) - -## Development Notes - -### Code Style -- Uses Black formatter, Ruff linter, MyPy type checker -- Pydantic v2 for data validation -- Async/await patterns throughout -- Type hints required for all public APIs -- **Avoid imports within methods** — place all imports at the top of the file (module-level). Inline imports inside functions/methods make dependencies harder to trace and hurt readability. The only exception is avoiding circular imports where absolutely necessary. -- **Use dict spread for immutable copies** — prefer `{**original, "key": new_value}` over `dict(obj)` + mutation. The spread produces the final dict in one step and makes intent clear. -- **Guard at resolution time** — when resolving an optional value through a fallback chain (`a or b or ""`), raise immediately if the resolved result being empty is an error. Don't pass empty strings or sentinel values downstream for the callee to deal with. -- **Extract complex comprehensions to named helpers** — a set/dict comprehension that calls into the DB or manager (e.g. "which of these server IDs are OAuth2?") belongs in a named helper function, not inline in the caller. -- **FastAPI parameter declarations** — mark required query/form params with `= Query(...)` / `= Form(...)` explicitly when other params in the same handler are optional. Mixing `str` (required) with `Optional[str] = None` in the same signature causes silent 422s when the required param is missing. - -### Testing Strategy -- Unit tests in `tests/test_litellm/` -- Integration tests for each provider in `tests/llm_translation/` -- Proxy tests in `tests/proxy_unit_tests/` -- Load tests in `tests/load_tests/` -- **Always add tests when adding new entity types or features** — if the existing test file covers other entity types, add corresponding tests for the new one -- **Keep monkeypatch stubs in sync with real signatures** — when a function gains a new optional parameter, update every `fake_*` / `stub_*` in tests that patch it to also accept that kwarg (even as `**kwargs`). Stale stubs fail with `unexpected keyword argument` and mask real bugs. -- **Test all branches of name→ID resolution** — when adding server/resource lookup that resolves names to UUIDs, test: (1) name resolves and UUID is allowed, (2) name resolves but UUID is not allowed, (3) name does not resolve at all. The silent-fallback path is where access-control bugs hide. - -### UI / Backend Consistency -- When wiring a new UI entity type to an existing backend endpoint, verify the backend API contract (single value vs. array, required vs. optional params) and ensure the UI controls match — e.g., use a single-select dropdown when the backend accepts a single value, not a multi-select - -### UI Component Library -- **Always use `antd` for new UI components** — we are migrating off of `@tremor/react`. Do not introduce new `Badge`, `Text`, `Card`, `Grid`, `Title`, or other imports from `@tremor/react` in any new or modified file. Use `antd` equivalents: `Tag` for labels, `Typography.Text` / `Typography.Title` / `Typography.Paragraph` for textual content (avoid plain text-only ``, `

`, `` when Typography fits), and `Card` from `antd`. Note that `antd` has no `"yellow"` Tag color — use `"gold"` for amber/yellow. - -### MCP OAuth / OpenAPI Transport Mapping -- **`available_on_public_internet: false` with `delegate_auth_to_upstream: true` (oauth2, interactive — not `client_credentials`)** — LiteLLM still allows the anonymous upstream PKCE path (no proxy API key for `/authorize` and matching MCP routes). The internal-only flag mainly affects other surfaces (e.g. IP-based discovery). Rely on the upstream IdP and network policy; the dashboard shows a warning when both are set, and the proxy logs a warning when the server is loaded from config or the database. -- `TRANSPORT.OPENAPI` is a UI-only concept. The backend only accepts `"http"`, `"sse"`, or `"stdio"`. Always map it to `"http"` before any API call (including pre-OAuth temp-session calls). -- FastAPI validation errors return `detail` as an array of `{loc, msg, type}` objects. Error extractors must handle: array (map `.msg`), string, nested `{error: string}`, and fallback. -- When an MCP server already has `authorization_url` stored, skip OAuth discovery (`_discovery_metadata`) — the server URL for OpenAPI MCPs is the spec file, not the API base, and fetching it causes timeouts. -- `client_id` should be optional in the `/authorize` endpoint — if the server has a stored `client_id` in credentials, use that. Never require callers to re-supply it. - -### MCP Credential Storage -- OAuth credentials and BYOK credentials share the `litellm_mcpusercredentials` table, distinguished by a `"type"` field in the JSON payload (`"oauth2"` vs plain string). -- When deleting OAuth credentials, check type before deleting to avoid accidentally deleting a BYOK credential for the same `(user_id, server_id)` pair. -- Always pass the raw `expires_at` timestamp to the client — never set it to `None` for expired credentials. Let the frontend compute the "Expired" display state from the timestamp. -- Use `RecordNotFoundError` (not bare `except Exception`) when catching "already deleted" in credential delete endpoints. - -### Browser Storage Safety (UI) -- Never write LiteLLM access tokens or API keys to `localStorage` — use `sessionStorage` only. `localStorage` survives browser close and is readable by any injected script (XSS). -- Shared utility functions (e.g. `extractErrorMessage`) belong in `src/utils/` — never define them inline in hooks or duplicate them across files. - -### Database Migrations -- Prisma handles schema migrations -- Migration files auto-generated with `prisma migrate dev` -- Always test migrations against both PostgreSQL and SQLite - -### Proxy database access -- **Do not write raw SQL** for proxy DB operations. Use Prisma model methods instead of `execute_raw` / `query_raw`. -- Use the generated client: `prisma_client.db.` (e.g. `litellm_tooltable`, `litellm_usertable`) with `.upsert()`, `.find_many()`, `.find_unique()`, `.update()`, `.update_many()` as appropriate. This avoids schema/client drift, keeps code testable with simple mocks, and matches patterns used in spend logs and other proxy code. -- **No N+1 queries.** Never query the DB inside a loop. Batch-fetch with `{"in": ids}` and distribute in-memory. -- **Batch writes.** Use `create_many`/`update_many`/`delete_many` instead of individual calls (these return counts only; `update_many`/`delete_many` no-op silently on missing rows). When multiple separate writes target the same table (e.g. in `batch_()`), order by primary key to avoid deadlocks. -- **Push work to the DB.** Filter, sort, group, and aggregate in SQL, not Python. Verify Prisma generates the expected SQL — e.g. prefer `group_by` over `find_many(distinct=...)` which does client-side processing. -- **Bound large result sets.** Prisma materializes full results in memory. For results over ~10 MB, paginate with `take`/`skip` or `cursor`/`take`, always with an explicit `order`. Prefer cursor-based pagination (`skip` is O(n)). Don't paginate naturally small result sets. -- **Limit fetched columns on wide tables.** Use `select` to fetch only needed fields — returns a partial object, so downstream code must not access unselected fields. -- **Check index coverage.** For new or modified queries, check `schema.prisma` for a supporting index. Prefer extending an existing index (e.g. `@@index([a])` → `@@index([a, b])`) over adding a new one, unless it's a `@@unique`. Only add indexes for large/frequent queries. -- **Keep schema files in sync.** Apply schema changes to all `schema.prisma` copies (`schema.prisma`, `litellm/proxy/`, `litellm-proxy-extras/`) with a migration under `litellm-proxy-extras/litellm_proxy_extras/migrations/`. - -### Setup Wizard (`litellm/setup_wizard.py`) -- The wizard is implemented as a single `SetupWizard` class with `@staticmethod` methods — keep it that way. No module-level functions except `run_setup_wizard()` (the public entrypoint) and pure helpers (color, ANSI). -- Use `litellm.utils.check_valid_key(model, api_key)` for credential validation — never roll a custom completion call. -- Do not hardcode provider env-key names or model lists that already exist in the codebase. Add a `test_model` field to each provider entry to drive `check_valid_key`; set it to `None` for providers that can't be validated with a single API key (Azure, Bedrock, Ollama). - -### Enterprise Features -- Enterprise-specific code in `enterprise/` directory -- Optional features enabled via environment variables -- Separate licensing and authentication for enterprise features - -### CI Supply-Chain Safety -- **Never pipe a remote script into a shell** (`curl ... | bash`, `wget ... | sh`). Download the artifact to a file, verify its SHA-256 checksum, then install. -- **Pin every external tool to a specific version** with a full URL (not `latest` or `stable`). Unversioned downloads silently change under you. -- **Verify checksums for all downloaded binaries.** Use the provider's official `.sha256` / `.sha256sum` sidecar file when available; otherwise compute and hardcode the digest. -- **Prefer reusable CircleCI commands** (`commands:` section) so a tool is installed and verified in exactly one place, then referenced everywhere with `- install_` or `- wait_for_service`. -- **Don't add tools just because they were there before.** Audit whether an external dependency is still needed. If it can be replaced with a shell one-liner or a tool already in the image, remove it. -- These rules apply to every download in CI: binaries, install scripts, language version managers, package repos. No exceptions. - -### HTTP Client Cache Safety -- **Never close HTTP/SDK clients on cache eviction.** `LLMClientCache._remove_key()` must not call `close()`/`aclose()` on evicted clients — they may still be used by in-flight requests. Doing so causes `RuntimeError: Cannot send a request, as the client has been closed.` after the 1-hour TTL expires. Cleanup happens at shutdown via `close_litellm_async_clients()`. - -### Troubleshooting: DB schema out of sync after proxy restart -`litellm-proxy-extras` runs `prisma migrate deploy` on startup using **its own** bundled migration files, which may lag behind schema changes in the current worktree. Symptoms: `Unknown column`, `Invalid prisma invocation`, or missing data on new fields. - -**Diagnose:** Run `\d "TableName"` in psql and compare against `schema.prisma` — missing columns confirm the issue. - -**Fix options:** -1. **Create a Prisma migration** (permanent) — run `prisma migrate dev --name ` in the worktree. The generated file will be picked up by `prisma migrate deploy` on next startup. -2. **Apply manually for local dev** — `psql -d litellm -c "ALTER TABLE ... ADD COLUMN IF NOT EXISTS ..."` after each proxy start. Fine for dev, not for production. -3. **Update litellm-proxy-extras** — if the package is installed from PyPI, its migration directory must include the new file. Either update the package or run the migration manually until the next release ships it. +Do not write comments unless they are absolutely necessary to explain some very complex business logic. Please clean up if there are comments that are not absolutely necessary. Do not remove comments that are unrelated to the addition of the code of this PR + +Explanation: code comments are, in a way, a violation of DRY code. You must update logic in two locations to change the code and "hard to change" is literally the definition of tech debt. We should instead aim to write code that is intuitive to the reader, while being both easy to maintain and high performance + +Don't assume that the existing code is correct or the right way of doing things / good coding patterns. In fact, there are a lot of bad coding practices, overly complex code, code smells, etc. If something doesn't look right, speak up. Feel free to break existing patterns or question weird existing code to make new code high quality, as in: +- correct +- secure +- performant +- readable +- easy to maintain/change +- modern +In that order of importance + +When adding new features, add meaningful tests. Don't add tests that don't check anything substantial and is there just to make the code coverage pass. Yes, code coverage is important, but I'd rather have no signal whether the code is working than tests that don't fail when code is broken. The goal is to have tests that would fail before the feature was added/if the code was mutated in a way that breaks the feature and succeed only when the feature is fully working. I should run mutation testing and see > 90% kill rate + +Same thing for bug fixes. The tests should make it so that this specific bug can never happen again without failing tests (i.e., regression) + +When creating PRs, don't set base to `main`. `litellm_internal_staging` serves that purpose + +Always use @.github/pull_request_template.md as a guide for your PR body + +Never use `pytest` commands or the like as "Screenshots / Proof of Fix". We prefer curl'ing a live proxy instance running on localhost:4000 (I like to run it with `python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml --detailed_debug --reload --use_v2_migration_resolver 2>&1 | tee litellm.log`) and showing both the command run and the output. Also, it should hit real LLM provider APIs, not mocks, and cost real $$$ because that is the most realistic test. The proof of fix should be exactly what the end user / customer would see / do. The run logs in PR #27703 is a prime example of how to do it (not a huge fan of using a python test script that future me and the team will have no visibility into; I prefer just curl commands or a short list of bash commands (e.g., using `for`)). If it's a UI thing, just tell me which URLs to go to (e.g., http://localhost:4000/ui/?page=logs), where to click, what fields to fill out, etc. along with the other commands to run in an ordered list, and I'll do it myself and post the screenshots after you make the PR + +If you ever make public-facing PR descriptions, comments, issues, commit messages, etc., always follow these guidelines to sound less AI-y: +- don't use emojis +- don't use "—". Instead, reach for ";", ".", etc. +- don't use the pattern "It's not X, it's Y", "You're not X, you're Y", etc. +- don't use bulleted or numbered lists unless it would be nonsensical not to. Instead, prefer prose + +Don't hesitate to use values in .env to get needed API keys and other secrets, as long as you never add them to conversation history, commit them, or include them in GitHub issues / PRs + +Run tests, format your code, and lint your code before each commit + +Ask to commit and push your work when you're done (or if you're confident that your code is good and works, just do it) + +When you must use real LLM models to, for example, write e2e tests, write a QA runbook, etc., make sure to use the latest models (doesn't have to be smartest, can also be a modern small, fast one. No strong preference for smart vs fast here, just use something modern) as of the year and month of the current date. Do a web search as necessary to figure that out + +If you're an internal contributor, when creating a new PR, the typical flow is to branch off litellm_internal_staging and create a branch prefixed with litellm_. Do not create a branch prefixed with claude/ and generally do not have / in your branch names + +Do not add `Co-Authored-By: Claude` or any Claude attribution to commit messages. Never use a `claude/` prefix or put a `/` in a branch name. Do not add "Generated with Claude Code" (or any similar attribution) to PR descriptions. Do not create a new PR/branch off the existing PR to fix/add something that is related and could've just been committed directly to the existing PR's branch + +When working on a PR, keep the PR description in sync with new commits being made + +Monkeypatching attributes of a class to do testing is an anti-pattern. Prefer dependency-injecting things into classes. That way, at unit test time, you can pass a mocked dependency in + +Do not put names of customers or customer company names in code, PRs, and issues. The codebase is public + +CI supply-chain safety: Never pipe a remote script into a shell (`curl ... | bash`, `wget ... | sh`); download the artifact to a file, verify its SHA-256 checksum, then install. Pin every external tool to a specific version with a full URL (not `latest` or `stable`). Verify checksums for all downloaded binaries, using the provider's official `.sha256` / `.sha256sum` sidecar when available. These rules apply to every download in CI + +## Think Before Coding + +**Don't assume. Don't hide confusion. Surface tradeoffs.** + +Before implementing: +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them. Don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +## Simplicity First + +**Minimum code that solves the problem. Nothing speculative.** + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. diff --git a/GEMINI.md b/GEMINI.md index 9e950d89b33..41921fdff4d 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -1,108 +1 @@ -# GEMINI.md - -This file provides guidance to Gemini when working with code in this repository. - -## Development Commands - -### Installation -- `make install-dev` - Install core development dependencies -- `make install-proxy-dev` - Install proxy development dependencies with full feature set -- `make install-test-deps` - Install all test dependencies - -### Testing -- `make test` - Run all tests -- `make test-unit` - Run unit tests (tests/test_litellm) with 4 parallel workers -- `make test-integration` - Run integration tests (excludes unit tests) -- `pytest tests/` - Direct pytest execution - -### Code Quality -- `make lint` - Run all linting (Ruff, MyPy, Black, circular imports, import safety) -- `make format` - Apply Black code formatting -- `make lint-ruff` - Run Ruff linting only -- `make lint-mypy` - Run MyPy type checking only - -### Single Test Files -- `uv run pytest tests/path/to/test_file.py -v` - Run specific test file -- `uv run pytest tests/path/to/test_file.py::test_function -v` - Run specific test - -### Running Scripts -- `uv run python script.py` - Run Python scripts (use for non-test files) - -### GitHub Issue & PR Templates -When contributing to the project, use the appropriate templates: - -**Bug Reports** (`.github/ISSUE_TEMPLATE/bug_report.yml`): -- Describe what happened vs. what you expected -- Include relevant log output -- Specify your LiteLLM version - -**Feature Requests** (`.github/ISSUE_TEMPLATE/feature_request.yml`): -- Describe the feature clearly -- Explain the motivation and use case - -**Pull Requests** (`.github/pull_request_template.md`): -- Add at least 1 test in `tests/litellm/` -- Ensure `make test-unit` passes - -## Architecture Overview - -LiteLLM is a unified interface for 100+ LLM providers with two main components: - -### Core Library (`litellm/`) -- **Main entry point**: `litellm/main.py` - Contains core completion() function -- **Provider implementations**: `litellm/llms/` - Each provider has its own subdirectory -- **Router system**: `litellm/router.py` + `litellm/router_utils/` - Load balancing and fallback logic -- **Type definitions**: `litellm/types/` - Pydantic models and type hints -- **Integrations**: `litellm/integrations/` - Third-party observability, caching, logging -- **Caching**: `litellm/caching/` - Multiple cache backends (Redis, in-memory, S3, etc.) - -### Proxy Server (`litellm/proxy/`) -- **Main server**: `proxy_server.py` - FastAPI application -- **Authentication**: `auth/` - API key management, JWT, OAuth2 -- **Database**: `db/` - Prisma ORM with PostgreSQL/SQLite support -- **Management endpoints**: `management_endpoints/` - Admin APIs for keys, teams, models -- **Pass-through endpoints**: `pass_through_endpoints/` - Provider-specific API forwarding -- **Guardrails**: `guardrails/` - Safety and content filtering hooks -- **UI Dashboard**: Served from `_experimental/out/` (Next.js build) - -## Key Patterns - -### Provider Implementation -- Providers inherit from base classes in `litellm/llms/base.py` -- Each provider has transformation functions for input/output formatting -- Support both sync and async operations -- Handle streaming responses and function calling - -### Error Handling -- Provider-specific exceptions mapped to OpenAI-compatible errors -- Fallback logic handled by Router system -- Comprehensive logging through `litellm/_logging.py` - -### Configuration -- YAML config files for proxy server (see `proxy/example_config_yaml/`) -- Environment variables for API keys and settings -- Database schema managed via Prisma (`proxy/schema.prisma`) - -## Development Notes - -### Code Style -- Uses Black formatter, Ruff linter, MyPy type checker -- Pydantic v2 for data validation -- Async/await patterns throughout -- Type hints required for all public APIs - -### Testing Strategy -- Unit tests in `tests/test_litellm/` -- Integration tests for each provider in `tests/llm_translation/` -- Proxy tests in `tests/proxy_unit_tests/` -- Load tests in `tests/load_tests/` - -### Database Migrations -- Prisma handles schema migrations -- Migration files auto-generated with `prisma migrate dev` -- Always test migrations against both PostgreSQL and SQLite - -### Enterprise Features -- Enterprise-specific code in `enterprise/` directory -- Optional features enabled via environment variables -- Separate licensing and authentication for enterprise features +Read @CLAUDE.md for coding guidelines diff --git a/backend/Dockerfile b/backend/Dockerfile index c08014fc0ef..2cfdde8a517 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -12,17 +12,27 @@ USER root COPY --from=uvbin /uv /uvx /usr/local/bin/ -RUN apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile +# nodejs/npm so `prisma generate` uses Wolfi's Node via PRISMA_USE_GLOBAL_NODE +# instead of nodeenv downloading one whose dynamic deps may not be in Wolfi +# (e.g. Node 26.2.0 needs libatomic). Retry for transient apk.cgr.dev flakes. +RUN for i in 1 2 3; do \ + apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile nodejs npm && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done # UV_COMPILE_BYTECODE=1 precompiles .pyc at install time → faster cold start. # UV_LINK_MODE=copy avoids hardlink warnings when uv installs from a # BuildKit cache mount (different filesystem). # UV_PYTHON_DOWNLOADS=0 force uv to use the apk-installed CPython instead of # silently pulling a managed interpreter. +# PRISMA_USE_GLOBAL_NODE explicit (matches default) so an env override can't +# silently re-enable nodeenv's Node download. ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ UV_COMPILE_BYTECODE=1 \ UV_PYTHON_DOWNLOADS=0 \ + PRISMA_USE_GLOBAL_NODE=true \ PATH="/app/.venv/bin:${PATH}" # Stage 1 — install dependencies only. @@ -58,7 +68,11 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root -RUN apk add --no-cache bash openssl tzdata python3 libsndfile libatomic +RUN for i in 1 2 3; do \ + apk add --no-cache bash openssl tzdata python3 libsndfile libatomic && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done # wolfi-base ships an unprivileged `nonroot` account (UID/GID 65532) with # /home/nonroot. We run the backend as that user diff --git a/cookbook/gollem_go_agent_framework/go.mod b/cookbook/gollem_go_agent_framework/go.mod index 89d9033aa22..a8dc9365d7f 100644 --- a/cookbook/gollem_go_agent_framework/go.mod +++ b/cookbook/gollem_go_agent_framework/go.mod @@ -1,5 +1,5 @@ module github.com/BerriAI/litellm/cookbook/gollem_go_agent_framework -go 1.25.1 +go 1.26.3 require github.com/fugue-labs/gollem v0.1.0 diff --git a/deploy/charts/litellm-helm/Chart.yaml b/deploy/charts/litellm-helm/Chart.yaml index 0f6db331e50..0aef2442bfe 100644 --- a/deploy/charts/litellm-helm/Chart.yaml +++ b/deploy/charts/litellm-helm/Chart.yaml @@ -24,7 +24,7 @@ version: 1.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: v1.80.12 +appVersion: v1.85.1 annotations: org.opencontainers.image.source: "https://github.com/BerriAI/litellm" diff --git a/deploy/charts/litellm-helm/templates/deployment.yaml b/deploy/charts/litellm-helm/templates/deployment.yaml index 25f69080878..b9cd1be06ec 100644 --- a/deploy/charts/litellm-helm/templates/deployment.yaml +++ b/deploy/charts/litellm-helm/templates/deployment.yaml @@ -30,7 +30,7 @@ spec: checksum/config: {{ include (print $.Template.BasePath "/configmap-litellm.yaml") . | sha256sum }} {{- end }} {{- with .Values.podAnnotations }} - {{- toYaml . | nindent 8 }} + {{- tpl (toYaml .) $ | nindent 8 }} {{- end }} labels: {{- include "litellm.labels" . | nindent 8 }} @@ -53,7 +53,7 @@ spec: - name: {{ include "litellm.name" . }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (printf "main-%s" .Chart.AppVersion) }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: - name: HOST diff --git a/deploy/charts/litellm-helm/templates/migrations-job.yaml b/deploy/charts/litellm-helm/templates/migrations-job.yaml index c3f32fe32f3..5ec7f5b7f3e 100644 --- a/deploy/charts/litellm-helm/templates/migrations-job.yaml +++ b/deploy/charts/litellm-helm/templates/migrations-job.yaml @@ -41,7 +41,7 @@ spec: {{- end }} containers: - name: prisma-migrations - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (printf "main-%s" .Chart.AppVersion) }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} diff --git a/deploy/charts/litellm-helm/tests/deployment_tests.yaml b/deploy/charts/litellm-helm/tests/deployment_tests.yaml index df6d1345644..f3d62651d8f 100644 --- a/deploy/charts/litellm-helm/tests/deployment_tests.yaml +++ b/deploy/charts/litellm-helm/tests/deployment_tests.yaml @@ -377,3 +377,28 @@ tests: content: name: sidecar-tpl image: "ghcr.io/berriai/litellm-database:test" + - it: should support tpl in podAnnotations + template: deployment.yaml + set: + image: + repository: ghcr.io/berriai/litellm-database + tag: test + # Mirrors the real-world scenario this feature unblocks: + # user disables the built-in ConfigMap (and its built-in checksum/config + # annotation) and re-implements checksum/config themselves via tpl. + proxyConfigMap: + create: false + podAnnotations: + checksum/config: "{{ .Values.image.tag }}" + example.com/some-key: "{{ .Values.image.repository }}" + example.com/literal: "plain-string-value" + asserts: + - equal: + path: spec.template.metadata.annotations["checksum/config"] + value: "test" + - equal: + path: spec.template.metadata.annotations["example.com/some-key"] + value: "ghcr.io/berriai/litellm-database" + - equal: + path: spec.template.metadata.annotations["example.com/literal"] + value: "plain-string-value" diff --git a/deploy/charts/litellm-helm/values.yaml b/deploy/charts/litellm-helm/values.yaml index 81558ed5b29..a9cdf28f0e7 100644 --- a/deploy/charts/litellm-helm/values.yaml +++ b/deploy/charts/litellm-helm/values.yaml @@ -10,7 +10,7 @@ image: repository: ghcr.io/berriai/litellm-database pullPolicy: Always # Overrides the image tag whose default is the chart appVersion. - # tag: "main-latest" + # tag: "latest" tag: "" imagePullSecrets: [] diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 2729babb6d6..8717e5b3fcd 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -55,22 +55,10 @@ COPY . . # Set non-root flag for build time consistency ENV LITELLM_NON_ROOT=true -# Stage the pre-built Admin UI from the checked-in Next.js static export. -# _experimental/out/ is regenerated as part of the release runbook. -# Restructure extensionless routes (foo.html -> foo/index.html) to match the layout -# proxy_server.py expects, and drop a readiness marker. RUN mkdir -p /var/lib/litellm/ui /var/lib/litellm/assets && \ cp -r /app/litellm/proxy/_experimental/out/. /var/lib/litellm/ui/ && \ cp /app/litellm/proxy/logo.jpg /var/lib/litellm/assets/logo.jpg && \ - ( cd /var/lib/litellm/ui && \ - for html_file in *.html; do \ - if [ "$html_file" != "index.html" ] && [ -f "$html_file" ]; then \ - folder_name="${html_file%.html}" && \ - mkdir -p "$folder_name" && \ - mv "$html_file" "$folder_name/index.html"; \ - fi; \ - done && \ - touch .litellm_ui_ready ) + touch /var/lib/litellm/ui/.litellm_ui_ready RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \ if [ "$PROXY_EXTRAS_SOURCE" = "published" ]; then \ diff --git a/enterprise/litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py b/enterprise/litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py index 7593e66aa47..3fad5601f52 100644 --- a/enterprise/litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py +++ b/enterprise/litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py @@ -19,12 +19,26 @@ class ResendEmailLogger(BaseEmailLogger): + """ + Send emails using Resend's API. + + Required env vars: + - RESEND_API_KEY + + Optional env vars: + - RESEND_FROM_EMAIL: Override the default sender address. Must be on a + domain verified in your Resend account. When unset, falls back to the + `from_email` argument passed by the caller (which defaults to + `notifications@alerts.litellm.ai` and only works on LiteLLM Cloud). + """ + def __init__(self, internal_usage_cache=None, **kwargs): super().__init__(internal_usage_cache=internal_usage_cache, **kwargs) self.async_httpx_client = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback ) self.resend_api_key = os.getenv("RESEND_API_KEY") + self.resend_from_email = os.getenv("RESEND_FROM_EMAIL") async def send_email( self, @@ -33,13 +47,14 @@ async def send_email( subject: str, html_body: str, ): + sender_email = self.resend_from_email or from_email verbose_logger.debug( - f"Sending email from {from_email} to {to_email} with subject {subject}" + f"Sending email from {sender_email} to {to_email} with subject {subject}" ) response = await self.async_httpx_client.post( url=RESEND_API_ENDPOINT, json={ - "from": from_email, + "from": sender_email, "to": to_email, "subject": subject, "html": html_body, diff --git a/enterprise/litellm_enterprise/proxy/hooks/managed_files.py b/enterprise/litellm_enterprise/proxy/hooks/managed_files.py index 5ed49070347..ae5905f9cdf 100644 --- a/enterprise/litellm_enterprise/proxy/hooks/managed_files.py +++ b/enterprise/litellm_enterprise/proxy/hooks/managed_files.py @@ -658,7 +658,7 @@ def get_file_ids_from_messages(self, messages: List[AllMessageValues]) -> List[s if isinstance(content, str): continue for c in content: - if c["type"] == "file": + if c.get("type") == "file": file_object = cast(ChatCompletionFileObject, c) file_object_file_field = file_object["file"] file_id = file_object_file_field.get("file_id") diff --git a/enterprise/pyproject.toml b/enterprise/pyproject.toml index 9f37b52d94c..d0432448433 100644 --- a/enterprise/pyproject.toml +++ b/enterprise/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "litellm-enterprise" -version = "0.1.41" +version = "0.1.42" description = "Package for LiteLLM Enterprise features" readme = "README.md" requires-python = ">=3.9" @@ -26,7 +26,7 @@ required-version = ">=0.10.9" module-root = "" [tool.commitizen] -version = "0.1.41" +version = "0.1.42" version_files = [ "pyproject.toml:^version", "../pyproject.toml:litellm-enterprise==", diff --git a/gateway/Dockerfile b/gateway/Dockerfile index a2ca3d3f83f..19c8a10fdfe 100644 --- a/gateway/Dockerfile +++ b/gateway/Dockerfile @@ -12,17 +12,27 @@ USER root COPY --from=uvbin /uv /uvx /usr/local/bin/ -RUN apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile +# nodejs/npm so `prisma generate` uses Wolfi's Node via PRISMA_USE_GLOBAL_NODE +# instead of nodeenv downloading one whose dynamic deps may not be in Wolfi +# (e.g. Node 26.2.0 needs libatomic). Retry for transient apk.cgr.dev flakes. +RUN for i in 1 2 3; do \ + apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile nodejs npm && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done # UV_COMPILE_BYTECODE=1 precompiles .pyc at install time → faster cold start. # UV_LINK_MODE=copy avoids hardlink warnings when uv installs from a # BuildKit cache mount (different filesystem). # UV_PYTHON_DOWNLOADS=0 force uv to use the apk-installed CPython instead of # silently pulling a managed interpreter. +# PRISMA_USE_GLOBAL_NODE explicit (matches default) so an env override can't +# silently re-enable nodeenv's Node download. ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ UV_COMPILE_BYTECODE=1 \ UV_PYTHON_DOWNLOADS=0 \ + PRISMA_USE_GLOBAL_NODE=true \ PATH="/app/.venv/bin:${PATH}" # Stage 1 — install dependencies only. @@ -58,7 +68,11 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root -RUN apk add --no-cache bash openssl tzdata python3 libsndfile libatomic +RUN for i in 1 2 3; do \ + apk add --no-cache bash openssl tzdata python3 libsndfile libatomic && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done # wolfi-base ships an unprivileged `nonroot` account (UID/GID 65532) with # /home/nonroot. We run the proxy as that user. diff --git a/helm/litellm/templates/_helpers.tpl b/helm/litellm/templates/_helpers.tpl index e2faf42b766..4319907883e 100644 --- a/helm/litellm/templates/_helpers.tpl +++ b/helm/litellm/templates/_helpers.tpl @@ -56,16 +56,34 @@ app.kubernetes.io/component: ui {{- end -}} {{/* -Shared ServiceAccount name used by all three component Deployments. When -`serviceAccount.create` is true and `serviceAccount.name` is empty, default -to the chart fullname. When `create` is false, fall back to the provided -name or the namespace's `default` SA. +Per-component ServiceAccount name helpers. + +Each component (gateway, backend, ui) has its own SA config under +.Values.serviceAccounts.. When `create` is true and `name` is +empty the chart defaults to "-litellm-". When `create` +is false the chart uses the provided name, or the namespace `default` SA. */}} -{{- define "litellm.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} -{{ default (include "litellm.fullname" .) .Values.serviceAccount.name }} +{{- define "litellm.gateway.serviceAccountName" -}} +{{- if .Values.serviceAccounts.gateway.create -}} +{{ default (include "litellm.gateway.fullname" .) .Values.serviceAccounts.gateway.name }} +{{- else -}} +{{ default "default" .Values.serviceAccounts.gateway.name }} +{{- end -}} +{{- end -}} + +{{- define "litellm.backend.serviceAccountName" -}} +{{- if .Values.serviceAccounts.backend.create -}} +{{ default (include "litellm.backend.fullname" .) .Values.serviceAccounts.backend.name }} +{{- else -}} +{{ default "default" .Values.serviceAccounts.backend.name }} +{{- end -}} +{{- end -}} + +{{- define "litellm.ui.serviceAccountName" -}} +{{- if .Values.serviceAccounts.ui.create -}} +{{ default (include "litellm.ui.fullname" .) .Values.serviceAccounts.ui.name }} {{- else -}} -{{ default "default" .Values.serviceAccount.name }} +{{ default "default" .Values.serviceAccounts.ui.name }} {{- end -}} {{- end -}} diff --git a/helm/litellm/templates/backend/deployment.yaml b/helm/litellm/templates/backend/deployment.yaml index e761409f8c4..3b59c58c8bf 100644 --- a/helm/litellm/templates/backend/deployment.yaml +++ b/helm/litellm/templates/backend/deployment.yaml @@ -19,7 +19,8 @@ spec: labels: {{- include "litellm.backend.selectorLabels" . | nindent 8 }} spec: - serviceAccountName: {{ include "litellm.serviceAccountName" . }} + serviceAccountName: {{ include "litellm.backend.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.serviceAccounts.backend.automount }} {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} diff --git a/helm/litellm/templates/gateway/deployment.yaml b/helm/litellm/templates/gateway/deployment.yaml index 935d432342e..05ea4052159 100644 --- a/helm/litellm/templates/gateway/deployment.yaml +++ b/helm/litellm/templates/gateway/deployment.yaml @@ -22,7 +22,8 @@ spec: labels: {{- include "litellm.gateway.selectorLabels" . | nindent 8 }} spec: - serviceAccountName: {{ include "litellm.serviceAccountName" . }} + serviceAccountName: {{ include "litellm.gateway.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.serviceAccounts.gateway.automount }} {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} diff --git a/helm/litellm/templates/migrations-job.yaml b/helm/litellm/templates/migrations-job.yaml index f3dc2ae0236..92671388546 100644 --- a/helm/litellm/templates/migrations-job.yaml +++ b/helm/litellm/templates/migrations-job.yaml @@ -28,7 +28,7 @@ spec: app.kubernetes.io/component: migrations spec: restartPolicy: Never - serviceAccountName: {{ include "litellm.serviceAccountName" . }} + serviceAccountName: {{ include "litellm.backend.serviceAccountName" . }} {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} diff --git a/helm/litellm/templates/serviceaccount.yaml b/helm/litellm/templates/serviceaccount.yaml index 3c998448ae5..a2fc52f47c0 100644 --- a/helm/litellm/templates/serviceaccount.yaml +++ b/helm/litellm/templates/serviceaccount.yaml @@ -1,13 +1,51 @@ -{{- if .Values.serviceAccount.create -}} +{{- $prev := false -}} +{{- if .Values.serviceAccounts.gateway.create -}} +{{- $prev = true }} apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "litellm.serviceAccountName" . }} + name: {{ include "litellm.gateway.serviceAccountName" . }} labels: {{- include "litellm.commonLabels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + app.kubernetes.io/component: gateway + {{- with .Values.serviceAccounts.gateway.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} -automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +automountServiceAccountToken: {{ .Values.serviceAccounts.gateway.automount }} +{{- end }} +{{- if .Values.serviceAccounts.backend.create }} +{{- if $prev }} +--- +{{- end }} +{{- $prev = true }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "litellm.backend.serviceAccountName" . }} + labels: + {{- include "litellm.commonLabels" . | nindent 4 }} + app.kubernetes.io/component: backend + {{- with .Values.serviceAccounts.backend.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccounts.backend.automount }} +{{- end }} +{{- if .Values.serviceAccounts.ui.create }} +{{- if $prev }} +--- +{{- end }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "litellm.ui.serviceAccountName" . }} + labels: + {{- include "litellm.commonLabels" . | nindent 4 }} + app.kubernetes.io/component: ui + {{- with .Values.serviceAccounts.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccounts.ui.automount }} {{- end }} diff --git a/helm/litellm/templates/ui/deployment.yaml b/helm/litellm/templates/ui/deployment.yaml index 549bf61a0dd..b40b44cca53 100644 --- a/helm/litellm/templates/ui/deployment.yaml +++ b/helm/litellm/templates/ui/deployment.yaml @@ -19,7 +19,8 @@ spec: labels: {{- include "litellm.ui.selectorLabels" . | nindent 8 }} spec: - serviceAccountName: {{ include "litellm.serviceAccountName" . }} + serviceAccountName: {{ include "litellm.ui.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.serviceAccounts.ui.automount }} {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} diff --git a/helm/litellm/values.yaml b/helm/litellm/values.yaml index 92477616a9a..934661643bd 100644 --- a/helm/litellm/values.yaml +++ b/helm/litellm/values.yaml @@ -14,16 +14,33 @@ ingress: host: "" # optional; if set, becomes the rule's host tls: [] -# Shared ServiceAccount used by all three component Deployments. Set -# `create: true` to have the chart provision it (e.g. when wiring an EKS -# Pod Identity association by SA name). Set `name` to use an existing SA -# (chart-created or out-of-band). When both are empty / false, pods run -# with the namespace's `default` SA. -serviceAccount: - create: false - automount: true - annotations: {} - name: "" +# Per-component ServiceAccounts for gateway, backend, and ui. +# +# Each section mirrors the old shared serviceAccount shape. Set `create: +# true` to have the chart provision the SA (useful for EKS Pod Identity / +# GKE Workload Identity annotations). Set `name` to bind an existing SA. +# When both are unset the component pod runs with the namespace `default` SA. +# +# The UI SA deliberately defaults to `automount: false` — the static nginx +# container does not need the K8s API and should not carry a projected +# ServiceAccount token that a compromised container could use to call the +# cloud-provider metadata service or the K8s API. +serviceAccounts: + gateway: + create: false + automount: true + annotations: {} + name: "" + backend: + create: false + automount: true + annotations: {} + name: "" + ui: + create: false + automount: false + annotations: {} + name: "" # Pre-install / pre-upgrade Helm hook that runs `prisma migrate deploy` # against the writer database, creating the LiteLLM schema (tables that diff --git a/litellm/__init__.py b/litellm/__init__.py index 3365abe3256..56d516536e8 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -225,6 +225,11 @@ route_all_chat_openai_to_responses: bool = ( os.getenv("LITELLM_ROUTE_ALL_CHAT_OPENAI_TO_RESPONSES", "false").lower() == "true" ) # When True, routes all OpenAI /chat/completions requests through the Responses API bridge +# When True, Gemini/Vertex Live setup is deferred until client `session.update`. +# Default False preserves historical behavior (auto-send setup on connect). +gemini_live_defer_setup: bool = ( + os.getenv("LITELLM_GEMINI_LIVE_DEFER_SETUP", "false").lower() == "true" +) use_legacy_interactions_schema: bool = ( os.getenv("LITELLM_USE_LEGACY_INTERACTIONS_SCHEMA", "false").lower() == "true" ) # When True, sends Api-Revision: 2026-05-07 to Google so responses use the legacy `outputs` @@ -1877,6 +1882,9 @@ def set_global_gitlab_config(config: Dict[str, Any]) -> None: from .llms.azure.completion.transformation import ( AzureOpenAITextConfig as AzureOpenAITextConfig, ) + from .llms.azure.audio_transcription.transformation import ( + AzureSpeechAudioTranscriptionConfig as AzureSpeechAudioTranscriptionConfig, + ) from .llms.hosted_vllm.chat.transformation import ( HostedVLLMChatConfig as HostedVLLMChatConfig, ) diff --git a/litellm/_lazy_imports_registry.py b/litellm/_lazy_imports_registry.py index e3656b340fa..17eb6609292 100644 --- a/litellm/_lazy_imports_registry.py +++ b/litellm/_lazy_imports_registry.py @@ -273,6 +273,7 @@ "AzureOpenAIConfig", "AzureOpenAIGPT5Config", "AzureOpenAITextConfig", + "AzureSpeechAudioTranscriptionConfig", "HostedVLLMChatConfig", "HostedVLLMEmbeddingConfig", # Alias for backwards compatibility @@ -1054,6 +1055,10 @@ ".llms.azure.completion.transformation", "AzureOpenAITextConfig", ), + "AzureSpeechAudioTranscriptionConfig": ( + ".llms.azure.audio_transcription.transformation", + "AzureSpeechAudioTranscriptionConfig", + ), "HostedVLLMChatConfig": ( ".llms.hosted_vllm.chat.transformation", "HostedVLLMChatConfig", diff --git a/litellm/_service_logger.py b/litellm/_service_logger.py index 1a3be203fec..5531c418799 100644 --- a/litellm/_service_logger.py +++ b/litellm/_service_logger.py @@ -24,6 +24,22 @@ UserAPIKeyAuth = Any +def _get_otel_v2_class() -> Optional[type]: + """Return the ``OpenTelemetryV2`` class, or ``None`` if the OTel SDK is absent. + + Imported lazily: ``litellm.integrations.otel.logger`` imports the OpenTelemetry + SDK at module scope, so importing it eagerly would break installs without the + SDK. The V2 logger only exists when ``LITELLM_OTEL_V2`` is enabled (which + requires the SDK), so a failed import simply means "no V2 logger in play". + """ + try: + from litellm.integrations.otel.logger import OpenTelemetryV2 + + return OpenTelemetryV2 + except Exception: + return None + + class ServiceLogging(CustomLogger): """ Separate class used for monitoring health of litellm-adjacent services (redis/postgres). @@ -38,6 +54,37 @@ def __init__(self, mock_testing: bool = False) -> None: if "prometheus_system" in litellm.service_callback: self.prometheusServicesLogger = PrometheusServicesLogger() + def _resolve_otel_service_logger(self, callback: Any) -> Optional[Any]: + """Resolve the OTel logger (legacy or V2) to emit a service span on. + + Returns the logger instance whose ``async_service_*_hook`` should fire for + this ``callback``, or ``None`` when ``callback`` is not an OTel callback. + + The V2 ``OpenTelemetryV2`` logger is a plain ``CustomLogger`` and is NOT a + subclass of the legacy ``OpenTelemetry``, so the legacy ``isinstance`` + check alone misses it — which is why redis/postgres service spans never + showed up under ``LITELLM_OTEL_V2``. Match both the legacy and V2 types, + whether the callback is the logger instance itself or the ``"otel"`` string + (which routes to the proxy's registered ``open_telemetry_logger``). + """ + otel_v2_cls = _get_otel_v2_class() + + def _is_otel_logger(obj: Any) -> bool: + if isinstance(obj, OpenTelemetry): + return True + return otel_v2_cls is not None and isinstance(obj, otel_v2_cls) + + if _is_otel_logger(callback): + return callback + if callback == "otel": + from litellm.proxy.proxy_server import open_telemetry_logger + + if open_telemetry_logger is not None and _is_otel_logger( + open_telemetry_logger + ): + return open_telemetry_logger + return None + def service_success_hook( self, service: ServiceTypes, @@ -129,6 +176,13 @@ async def async_service_success_hook( event_metadata=event_metadata, ) + # OTel loggers already fired this event. ``service_callback`` can hold more + # than one reference that resolves to the *same* logger — the ``"otel"`` + # string AND the registered instance both map to ``open_telemetry_logger`` + # (the V2 logger self-registers its instance even when the string is + # present, unlike V1). Without this guard each such reference emits its own + # span, so a single DB call shows up as duplicate ``postgres ...`` spans. + emitted_otel_logger_ids: set = set() for callback in litellm.service_callback: if callback == "prometheus_system": await self.init_prometheus_services_logger_if_none() @@ -144,19 +198,18 @@ async def async_service_success_hook( end_time=end_time, event_metadata=event_metadata, ) - elif callback == "otel" or isinstance(callback, OpenTelemetry): - _otel_logger_to_use: Optional[OpenTelemetry] = None - if isinstance(callback, OpenTelemetry): - _otel_logger_to_use = callback - else: - from litellm.proxy.proxy_server import open_telemetry_logger - - if open_telemetry_logger is not None and isinstance( - open_telemetry_logger, OpenTelemetry - ): - _otel_logger_to_use = open_telemetry_logger - - if _otel_logger_to_use is not None and parent_otel_span is not None: + else: + _otel_logger_to_use = self._resolve_otel_service_logger(callback) + # No ``parent_otel_span is not None`` gate: a background service + # call (no request on the stack) has no parent, and dropping it + # here is what hid those calls from traces entirely. The OTel + # logger decides what to do with a missing parent — legacy V1 + # no-ops, V2 emits a root span (and skips metrics-only pings). + if ( + _otel_logger_to_use is not None + and id(_otel_logger_to_use) not in emitted_otel_logger_ids + ): + emitted_otel_logger_ids.add(id(_otel_logger_to_use)) await _otel_logger_to_use.async_service_success_hook( payload=payload, parent_otel_span=parent_otel_span, @@ -238,6 +291,9 @@ async def async_service_failure_hook( event_metadata=event_metadata, ) + # Dedupe OTel loggers per event — see ``async_service_success_hook`` for why + # the same logger can be referenced twice in ``service_callback``. + emitted_otel_logger_ids: set = set() for callback in litellm.service_callback: if callback == "prometheus_system": await self.init_prometheus_services_logger_if_none() @@ -255,22 +311,19 @@ async def async_service_failure_hook( end_time=end_time, event_metadata=event_metadata, ) - elif callback == "otel" or isinstance(callback, OpenTelemetry): - _otel_logger_to_use: Optional[OpenTelemetry] = None - if isinstance(callback, OpenTelemetry): - _otel_logger_to_use = callback - else: - from litellm.proxy.proxy_server import open_telemetry_logger - - if open_telemetry_logger is not None and isinstance( - open_telemetry_logger, OpenTelemetry - ): - _otel_logger_to_use = open_telemetry_logger + else: + _otel_logger_to_use = self._resolve_otel_service_logger(callback) if not isinstance(error, str): error = str(error) - if _otel_logger_to_use is not None and parent_otel_span is not None: + # See the success hook: no parent gate, so background failures + # are traced too. V1 no-ops without a parent; V2 emits a root. + if ( + _otel_logger_to_use is not None + and id(_otel_logger_to_use) not in emitted_otel_logger_ids + ): + emitted_otel_logger_ids.add(id(_otel_logger_to_use)) await _otel_logger_to_use.async_service_failure_hook( payload=payload, error=error, diff --git a/litellm/a2a_protocol/litellm_completion_bridge/handler.py b/litellm/a2a_protocol/litellm_completion_bridge/handler.py index 4e66fe4ba67..67ffcf4f8f7 100644 --- a/litellm/a2a_protocol/litellm_completion_bridge/handler.py +++ b/litellm/a2a_protocol/litellm_completion_bridge/handler.py @@ -107,6 +107,14 @@ async def handle_non_streaming( if k not in ("model", "custom_llm_provider") and k not in _AGENT_ONLY_PARAMS } completion_params.update(litellm_params_to_add) + # Apply forward metadata AFTER the litellm_params merge so the helper + # sees any agent-owner-configured ``extra_body.metadata`` and can keep + # those keys authoritative over the client-supplied A2A metadata. + A2ACompletionBridgeTransformation.apply_forward_metadata_to_completion_params( + completion_params=completion_params, + a2a_message=message, + params=params, + ) # Call litellm.acompletion response = await litellm.acompletion(**completion_params) @@ -214,6 +222,14 @@ async def handle_streaming( if k not in ("model", "custom_llm_provider") and k not in _AGENT_ONLY_PARAMS } completion_params.update(litellm_params_to_add) + # Apply forward metadata AFTER the litellm_params merge so the helper + # sees any agent-owner-configured ``extra_body.metadata`` and can keep + # those keys authoritative over the client-supplied A2A metadata. + A2ACompletionBridgeTransformation.apply_forward_metadata_to_completion_params( + completion_params=completion_params, + a2a_message=message, + params=params, + ) # 1. Emit initial task event (kind: "task", status: "submitted") task_event = A2ACompletionBridgeTransformation.create_task_event(ctx) diff --git a/litellm/a2a_protocol/litellm_completion_bridge/transformation.py b/litellm/a2a_protocol/litellm_completion_bridge/transformation.py index 8a03569f689..06c0a8fc82f 100644 --- a/litellm/a2a_protocol/litellm_completion_bridge/transformation.py +++ b/litellm/a2a_protocol/litellm_completion_bridge/transformation.py @@ -45,10 +45,80 @@ class A2ACompletionBridgeTransformation: Static methods for transforming between A2A and OpenAI message formats. """ + @staticmethod + def _extract_text_from_a2a_parts(parts: List[Dict[str, Any]]) -> str: + """Extract text from A2A parts (with or without explicit ``kind``).""" + content_parts: List[str] = [] + for part in parts: + if not isinstance(part, dict): + continue + kind = part.get("kind") + text = part.get("text") + if text is None: + continue + if kind in (None, "", "text"): + content_parts.append(str(text)) + return "\n".join(content_parts) + + @staticmethod + def get_forward_metadata( + a2a_message: Dict[str, Any], + params: Optional[Dict[str, Any]] = None, + ) -> Optional[Dict[str, Any]]: + """ + Merge A2A metadata from MessageSendParams and the message for downstream providers. + + Forwarded once on the LangGraph run payload (``metadata``), not duplicated on + each input message — see ``apply_forward_metadata_to_completion_params``. + """ + merged: Dict[str, Any] = {} + if params and isinstance(params.get("metadata"), dict): + merged.update(params["metadata"]) + message_metadata = a2a_message.get("metadata") + if isinstance(message_metadata, dict): + merged.update(message_metadata) + return merged or None + + @staticmethod + def apply_forward_metadata_to_completion_params( + completion_params: Dict[str, Any], + a2a_message: Dict[str, Any], + params: Optional[Dict[str, Any]] = None, + ) -> None: + """ + Attach A2A metadata to completion kwargs for provider bridges (e.g. LangGraph). + + Uses ``extra_body`` so we do not collide with LiteLLM's spend-log ``metadata`` kwarg. + """ + forward_metadata = A2ACompletionBridgeTransformation.get_forward_metadata( + a2a_message=a2a_message, + params=params, + ) + if not forward_metadata: + return + + extra_body = completion_params.get("extra_body") + if not isinstance(extra_body, dict): + extra_body = {} + # Layer client-supplied A2A metadata under any agent-owner-configured + # ``extra_body.metadata`` so the configured keys remain authoritative + # and an A2A caller cannot overwrite server-set run metadata. + existing_metadata = extra_body.get("metadata") + existing_dict: Dict[str, Any] = ( + existing_metadata if isinstance(existing_metadata, dict) else {} + ) + merged_metadata: Dict[str, Any] = {**forward_metadata, **existing_dict} + extra_body = {**extra_body, "metadata": merged_metadata} + completion_params["extra_body"] = extra_body + + verbose_logger.debug( + f"A2A -> completion forward metadata keys={list(forward_metadata.keys())}" + ) + @staticmethod def a2a_message_to_openai_messages( a2a_message: Dict[str, Any], - ) -> List[Dict[str, str]]: + ) -> List[Dict[str, Any]]: """ Transform an A2A message to OpenAI message format. @@ -70,21 +140,20 @@ def a2a_message_to_openai_messages( elif role == "system": openai_role = "system" - # Extract text content from parts - content_parts = [] - for part in parts: - kind = part.get("kind", "") - if kind == "text": - text = part.get("text", "") - content_parts.append(text) + if not isinstance(parts, list): + parts = [] + + content = A2ACompletionBridgeTransformation._extract_text_from_a2a_parts(parts) - content = "\n".join(content_parts) if content_parts else "" + # Do not attach A2A message.metadata here — the completion bridge forwards it + # once at run level via extra_body.metadata (LangGraph POST /runs/wait shape). + openai_message: Dict[str, Any] = {"role": openai_role, "content": content} verbose_logger.debug( f"A2A -> OpenAI transform: role={role} -> {openai_role}, content_length={len(content)}" ) - return [{"role": openai_role, "content": content}] + return [openai_message] @staticmethod def openai_response_to_a2a_response( @@ -110,6 +179,7 @@ def openai_response_to_a2a_response( # Build A2A message a2a_message = { + "kind": "message", "role": "agent", "parts": [{"kind": "text", "text": content}], "messageId": uuid4().hex, @@ -119,9 +189,7 @@ def openai_response_to_a2a_response( a2a_response = { "jsonrpc": "2.0", "id": request_id, - "result": { - "message": a2a_message, - }, + "result": a2a_message, } verbose_logger.debug(f"OpenAI -> A2A transform: content_length={len(content)}") @@ -235,50 +303,3 @@ def create_artifact_update_event( "taskId": ctx.task_id, }, } - - @staticmethod - def openai_chunk_to_a2a_chunk( - chunk: Any, - request_id: Optional[str] = None, - is_final: bool = False, - ) -> Optional[Dict[str, Any]]: - """ - Transform a LiteLLM streaming chunk to A2A streaming format. - - NOTE: This method is deprecated for streaming. Use the event-based - methods (create_task_event, create_status_update_event, - create_artifact_update_event) instead for proper A2A streaming. - - Args: - chunk: LiteLLM ModelResponse chunk - request_id: Original A2A request ID - is_final: Whether this is the final chunk - - Returns: - A2A streaming chunk dict or None if no content - """ - # Extract delta content - content = "" - if chunk is not None and hasattr(chunk, "choices") and chunk.choices: - choice = chunk.choices[0] - if hasattr(choice, "delta") and choice.delta: - content = choice.delta.content or "" - - if not content and not is_final: - return None - - # Build A2A streaming chunk (legacy format) - a2a_chunk = { - "jsonrpc": "2.0", - "id": request_id, - "result": { - "message": { - "role": "agent", - "parts": [{"kind": "text", "text": content}], - "messageId": uuid4().hex, - }, - "final": is_final, - }, - } - - return a2a_chunk diff --git a/litellm/a2a_protocol/providers/litellm_completion/README.md b/litellm/a2a_protocol/providers/litellm_completion/README.md deleted file mode 100644 index a809e9bf55e..00000000000 --- a/litellm/a2a_protocol/providers/litellm_completion/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# A2A to LiteLLM Completion Bridge - -Routes A2A protocol requests through `litellm.acompletion`, enabling any LiteLLM-supported provider to be invoked via A2A. - -## Flow - -``` -A2A Request → Transform → litellm.acompletion → Transform → A2A Response -``` - -## SDK Usage - -Use the existing `asend_message` and `asend_message_streaming` functions with `litellm_params`: - -```python -from litellm.a2a_protocol import asend_message, asend_message_streaming -from a2a.types import SendMessageRequest, SendStreamingMessageRequest, MessageSendParams -from uuid import uuid4 - -# Non-streaming -request = SendMessageRequest( - id=str(uuid4()), - params=MessageSendParams( - message={"role": "user", "parts": [{"kind": "text", "text": "Hello!"}], "messageId": uuid4().hex} - ) -) -response = await asend_message( - request=request, - api_base="http://localhost:2024", - litellm_params={"custom_llm_provider": "langgraph", "model": "agent"}, -) - -# Streaming -stream_request = SendStreamingMessageRequest( - id=str(uuid4()), - params=MessageSendParams( - message={"role": "user", "parts": [{"kind": "text", "text": "Hello!"}], "messageId": uuid4().hex} - ) -) -async for chunk in asend_message_streaming( - request=stream_request, - api_base="http://localhost:2024", - litellm_params={"custom_llm_provider": "langgraph", "model": "agent"}, -): - print(chunk) -``` - -## Proxy Usage - -Configure an agent with `custom_llm_provider` in `litellm_params`: - -```yaml -agents: - - agent_name: my-langgraph-agent - agent_card_params: - name: "LangGraph Agent" - url: "http://localhost:2024" # Used as api_base - litellm_params: - custom_llm_provider: langgraph - model: agent -``` - -When an A2A request hits `/a2a/{agent_id}/message/send`, the bridge: - -1. Detects `custom_llm_provider` in agent's `litellm_params` -2. Transforms A2A message → OpenAI messages -3. Calls `litellm.acompletion(model="langgraph/agent", api_base="http://localhost:2024")` -4. Transforms response → A2A format - -## Classes - -- `A2ACompletionBridgeTransformation` - Static methods for message format conversion -- `A2ACompletionBridgeHandler` - Static methods for handling requests (streaming/non-streaming) - diff --git a/litellm/a2a_protocol/providers/litellm_completion/__init__.py b/litellm/a2a_protocol/providers/litellm_completion/__init__.py deleted file mode 100644 index fc2fc17f54f..00000000000 --- a/litellm/a2a_protocol/providers/litellm_completion/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -LiteLLM Completion bridge provider for A2A protocol. - -Routes A2A requests through litellm.acompletion based on custom_llm_provider. -""" diff --git a/litellm/a2a_protocol/providers/litellm_completion/handler.py b/litellm/a2a_protocol/providers/litellm_completion/handler.py deleted file mode 100644 index 730f8f6b36f..00000000000 --- a/litellm/a2a_protocol/providers/litellm_completion/handler.py +++ /dev/null @@ -1,301 +0,0 @@ -""" -Handler for A2A to LiteLLM completion bridge. - -Routes A2A requests through litellm.acompletion based on custom_llm_provider. - -A2A Streaming Events (in order): -1. Task event (kind: "task") - Initial task creation with status "submitted" -2. Status update (kind: "status-update") - Status change to "working" -3. Artifact update (kind: "artifact-update") - Content/artifact delivery -4. Status update (kind: "status-update") - Final status "completed" with final=true -""" - -from typing import Any, AsyncIterator, Dict, Optional - -import litellm -from litellm._logging import verbose_logger -from litellm.a2a_protocol.litellm_completion_bridge.pydantic_ai_transformation import ( - PydanticAITransformation, -) -from litellm.a2a_protocol.litellm_completion_bridge.transformation import ( - A2ACompletionBridgeTransformation, - A2AStreamingContext, -) - - -class A2ACompletionBridgeHandler: - """ - Static methods for handling A2A requests via LiteLLM completion. - """ - - @staticmethod - async def handle_non_streaming( - request_id: str, - params: Dict[str, Any], - litellm_params: Dict[str, Any], - api_base: Optional[str] = None, - ) -> Dict[str, Any]: - """ - Handle non-streaming A2A request via litellm.acompletion. - - Args: - request_id: A2A JSON-RPC request ID - params: A2A MessageSendParams containing the message - litellm_params: Agent's litellm_params (custom_llm_provider, model, etc.) - api_base: API base URL from agent_card_params - - Returns: - A2A SendMessageResponse dict - """ - # Check if this is a Pydantic AI agent request - custom_llm_provider = litellm_params.get("custom_llm_provider") - if custom_llm_provider == "pydantic_ai_agents": - if api_base is None: - raise ValueError("api_base is required for Pydantic AI agents") - - verbose_logger.info( - f"Pydantic AI: Routing to Pydantic AI agent at {api_base}" - ) - - # Send request directly to Pydantic AI agent - response_data = await PydanticAITransformation.send_non_streaming_request( - api_base=api_base, - request_id=request_id, - params=params, - ) - - return response_data - - # Extract message from params - message = params.get("message", {}) - - # Transform A2A message to OpenAI format - openai_messages = ( - A2ACompletionBridgeTransformation.a2a_message_to_openai_messages(message) - ) - - # Get completion params - custom_llm_provider = litellm_params.get("custom_llm_provider") - model = litellm_params.get("model", "agent") - - # Build full model string if provider specified - # Skip prepending if model already starts with the provider prefix - if custom_llm_provider and not model.startswith(f"{custom_llm_provider}/"): - full_model = f"{custom_llm_provider}/{model}" - else: - full_model = model - - verbose_logger.info( - f"A2A completion bridge: model={full_model}, api_base={api_base}" - ) - - # Build completion params dict - completion_params = { - "model": full_model, - "messages": openai_messages, - "api_base": api_base, - "stream": False, - } - # Add litellm_params (contains api_key, client_id, client_secret, tenant_id, etc.) - litellm_params_to_add = { - k: v - for k, v in litellm_params.items() - if k not in ("model", "custom_llm_provider") - } - completion_params.update(litellm_params_to_add) - - # Call litellm.acompletion - response = await litellm.acompletion(**completion_params) - - # Transform response to A2A format - a2a_response = ( - A2ACompletionBridgeTransformation.openai_response_to_a2a_response( - response=response, - request_id=request_id, - ) - ) - - verbose_logger.info(f"A2A completion bridge completed: request_id={request_id}") - - return a2a_response - - @staticmethod - async def handle_streaming( - request_id: str, - params: Dict[str, Any], - litellm_params: Dict[str, Any], - api_base: Optional[str] = None, - ) -> AsyncIterator[Dict[str, Any]]: - """ - Handle streaming A2A request via litellm.acompletion with stream=True. - - Emits proper A2A streaming events: - 1. Task event (kind: "task") - Initial task with status "submitted" - 2. Status update (kind: "status-update") - Status "working" - 3. Artifact update (kind: "artifact-update") - Content delivery - 4. Status update (kind: "status-update") - Final "completed" status - - Args: - request_id: A2A JSON-RPC request ID - params: A2A MessageSendParams containing the message - litellm_params: Agent's litellm_params (custom_llm_provider, model, etc.) - api_base: API base URL from agent_card_params - - Yields: - A2A streaming response events - """ - # Check if this is a Pydantic AI agent request - custom_llm_provider = litellm_params.get("custom_llm_provider") - if custom_llm_provider == "pydantic_ai_agents": - if api_base is None: - raise ValueError("api_base is required for Pydantic AI agents") - - verbose_logger.info( - f"Pydantic AI: Faking streaming for Pydantic AI agent at {api_base}" - ) - - # Get non-streaming response first - response_data = await PydanticAITransformation.send_non_streaming_request( - api_base=api_base, - request_id=request_id, - params=params, - ) - - # Convert to fake streaming - async for chunk in PydanticAITransformation.fake_streaming_from_response( - response_data=response_data, - request_id=request_id, - ): - yield chunk - - return - - # Extract message from params - message = params.get("message", {}) - - # Create streaming context - ctx = A2AStreamingContext( - request_id=request_id, - input_message=message, - ) - - # Transform A2A message to OpenAI format - openai_messages = ( - A2ACompletionBridgeTransformation.a2a_message_to_openai_messages(message) - ) - - # Get completion params - custom_llm_provider = litellm_params.get("custom_llm_provider") - model = litellm_params.get("model", "agent") - - # Build full model string if provider specified - # Skip prepending if model already starts with the provider prefix - if custom_llm_provider and not model.startswith(f"{custom_llm_provider}/"): - full_model = f"{custom_llm_provider}/{model}" - else: - full_model = model - - verbose_logger.info( - f"A2A completion bridge streaming: model={full_model}, api_base={api_base}" - ) - - # Build completion params dict - completion_params = { - "model": full_model, - "messages": openai_messages, - "api_base": api_base, - "stream": True, - } - # Add litellm_params (contains api_key, client_id, client_secret, tenant_id, etc.) - litellm_params_to_add = { - k: v - for k, v in litellm_params.items() - if k not in ("model", "custom_llm_provider") - } - completion_params.update(litellm_params_to_add) - - # 1. Emit initial task event (kind: "task", status: "submitted") - task_event = A2ACompletionBridgeTransformation.create_task_event(ctx) - yield task_event - - # 2. Emit status update (kind: "status-update", status: "working") - working_event = A2ACompletionBridgeTransformation.create_status_update_event( - ctx=ctx, - state="working", - final=False, - message_text="Processing request...", - ) - yield working_event - - # Call litellm.acompletion with streaming - response = await litellm.acompletion(**completion_params) - - # 3. Accumulate content and emit artifact update - accumulated_text = "" - chunk_count = 0 - async for chunk in response: # type: ignore[union-attr] - chunk_count += 1 - - # Extract delta content - content = "" - if chunk is not None and hasattr(chunk, "choices") and chunk.choices: - choice = chunk.choices[0] - if hasattr(choice, "delta") and choice.delta: - content = choice.delta.content or "" - - if content: - accumulated_text += content - - # Emit artifact update with accumulated content - if accumulated_text: - artifact_event = ( - A2ACompletionBridgeTransformation.create_artifact_update_event( - ctx=ctx, - text=accumulated_text, - ) - ) - yield artifact_event - - # 4. Emit final status update (kind: "status-update", status: "completed", final: true) - completed_event = A2ACompletionBridgeTransformation.create_status_update_event( - ctx=ctx, - state="completed", - final=True, - ) - yield completed_event - - verbose_logger.info( - f"A2A completion bridge streaming completed: request_id={request_id}, chunks={chunk_count}" - ) - - -# Convenience functions that delegate to the class methods -async def handle_a2a_completion( - request_id: str, - params: Dict[str, Any], - litellm_params: Dict[str, Any], - api_base: Optional[str] = None, -) -> Dict[str, Any]: - """Convenience function for non-streaming A2A completion.""" - return await A2ACompletionBridgeHandler.handle_non_streaming( - request_id=request_id, - params=params, - litellm_params=litellm_params, - api_base=api_base, - ) - - -async def handle_a2a_completion_streaming( - request_id: str, - params: Dict[str, Any], - litellm_params: Dict[str, Any], - api_base: Optional[str] = None, -) -> AsyncIterator[Dict[str, Any]]: - """Convenience function for streaming A2A completion.""" - async for chunk in A2ACompletionBridgeHandler.handle_streaming( - request_id=request_id, - params=params, - litellm_params=litellm_params, - api_base=api_base, - ): - yield chunk diff --git a/litellm/a2a_protocol/providers/litellm_completion/transformation.py b/litellm/a2a_protocol/providers/litellm_completion/transformation.py deleted file mode 100644 index 8a03569f689..00000000000 --- a/litellm/a2a_protocol/providers/litellm_completion/transformation.py +++ /dev/null @@ -1,284 +0,0 @@ -""" -Transformation utilities for A2A <-> OpenAI message format conversion. - -A2A Message Format: -{ - "role": "user", - "parts": [{"kind": "text", "text": "Hello!"}], - "messageId": "abc123" -} - -OpenAI Message Format: -{"role": "user", "content": "Hello!"} - -A2A Streaming Events: -- Task event (kind: "task") - Initial task creation with status "submitted" -- Status update (kind: "status-update") - Status changes (working, completed) -- Artifact update (kind: "artifact-update") - Content/artifact delivery -""" - -from datetime import datetime, timezone -from typing import Any, Dict, List, Optional -from uuid import uuid4 - -from litellm._logging import verbose_logger - - -class A2AStreamingContext: - """ - Context holder for A2A streaming state. - Tracks task_id, context_id, and message accumulation. - """ - - def __init__(self, request_id: str, input_message: Dict[str, Any]): - self.request_id = request_id - self.task_id = str(uuid4()) - self.context_id = str(uuid4()) - self.input_message = input_message - self.accumulated_text = "" - self.has_emitted_task = False - self.has_emitted_working = False - - -class A2ACompletionBridgeTransformation: - """ - Static methods for transforming between A2A and OpenAI message formats. - """ - - @staticmethod - def a2a_message_to_openai_messages( - a2a_message: Dict[str, Any], - ) -> List[Dict[str, str]]: - """ - Transform an A2A message to OpenAI message format. - - Args: - a2a_message: A2A message with role, parts, and messageId - - Returns: - List of OpenAI-format messages - """ - role = a2a_message.get("role", "user") - parts = a2a_message.get("parts", []) - - # Map A2A roles to OpenAI roles - openai_role = role - if role == "user": - openai_role = "user" - elif role == "assistant": - openai_role = "assistant" - elif role == "system": - openai_role = "system" - - # Extract text content from parts - content_parts = [] - for part in parts: - kind = part.get("kind", "") - if kind == "text": - text = part.get("text", "") - content_parts.append(text) - - content = "\n".join(content_parts) if content_parts else "" - - verbose_logger.debug( - f"A2A -> OpenAI transform: role={role} -> {openai_role}, content_length={len(content)}" - ) - - return [{"role": openai_role, "content": content}] - - @staticmethod - def openai_response_to_a2a_response( - response: Any, - request_id: Optional[str] = None, - ) -> Dict[str, Any]: - """ - Transform a LiteLLM ModelResponse to A2A SendMessageResponse format. - - Args: - response: LiteLLM ModelResponse object - request_id: Original A2A request ID - - Returns: - A2A SendMessageResponse dict - """ - # Extract content from response - content = "" - if hasattr(response, "choices") and response.choices: - choice = response.choices[0] - if hasattr(choice, "message") and choice.message: - content = choice.message.content or "" - - # Build A2A message - a2a_message = { - "role": "agent", - "parts": [{"kind": "text", "text": content}], - "messageId": uuid4().hex, - } - - # Build A2A response - a2a_response = { - "jsonrpc": "2.0", - "id": request_id, - "result": { - "message": a2a_message, - }, - } - - verbose_logger.debug(f"OpenAI -> A2A transform: content_length={len(content)}") - - return a2a_response - - @staticmethod - def _get_timestamp() -> str: - """Get current timestamp in ISO format with timezone.""" - return datetime.now(timezone.utc).isoformat() - - @staticmethod - def create_task_event( - ctx: A2AStreamingContext, - ) -> Dict[str, Any]: - """ - Create the initial task event with status 'submitted'. - - This is the first event emitted in an A2A streaming response. - """ - return { - "id": ctx.request_id, - "jsonrpc": "2.0", - "result": { - "contextId": ctx.context_id, - "history": [ - { - "contextId": ctx.context_id, - "kind": "message", - "messageId": ctx.input_message.get("messageId", uuid4().hex), - "parts": ctx.input_message.get("parts", []), - "role": ctx.input_message.get("role", "user"), - "taskId": ctx.task_id, - } - ], - "id": ctx.task_id, - "kind": "task", - "status": { - "state": "submitted", - }, - }, - } - - @staticmethod - def create_status_update_event( - ctx: A2AStreamingContext, - state: str, - final: bool = False, - message_text: Optional[str] = None, - ) -> Dict[str, Any]: - """ - Create a status update event. - - Args: - ctx: Streaming context - state: Status state ('working', 'completed') - final: Whether this is the final event - message_text: Optional message text for 'working' status - """ - status: Dict[str, Any] = { - "state": state, - "timestamp": A2ACompletionBridgeTransformation._get_timestamp(), - } - - # Add message for 'working' status - if state == "working" and message_text: - status["message"] = { - "contextId": ctx.context_id, - "kind": "message", - "messageId": str(uuid4()), - "parts": [{"kind": "text", "text": message_text}], - "role": "agent", - "taskId": ctx.task_id, - } - - return { - "id": ctx.request_id, - "jsonrpc": "2.0", - "result": { - "contextId": ctx.context_id, - "final": final, - "kind": "status-update", - "status": status, - "taskId": ctx.task_id, - }, - } - - @staticmethod - def create_artifact_update_event( - ctx: A2AStreamingContext, - text: str, - ) -> Dict[str, Any]: - """ - Create an artifact update event with content. - - Args: - ctx: Streaming context - text: The text content for the artifact - """ - return { - "id": ctx.request_id, - "jsonrpc": "2.0", - "result": { - "artifact": { - "artifactId": str(uuid4()), - "name": "response", - "parts": [{"kind": "text", "text": text}], - }, - "contextId": ctx.context_id, - "kind": "artifact-update", - "taskId": ctx.task_id, - }, - } - - @staticmethod - def openai_chunk_to_a2a_chunk( - chunk: Any, - request_id: Optional[str] = None, - is_final: bool = False, - ) -> Optional[Dict[str, Any]]: - """ - Transform a LiteLLM streaming chunk to A2A streaming format. - - NOTE: This method is deprecated for streaming. Use the event-based - methods (create_task_event, create_status_update_event, - create_artifact_update_event) instead for proper A2A streaming. - - Args: - chunk: LiteLLM ModelResponse chunk - request_id: Original A2A request ID - is_final: Whether this is the final chunk - - Returns: - A2A streaming chunk dict or None if no content - """ - # Extract delta content - content = "" - if chunk is not None and hasattr(chunk, "choices") and chunk.choices: - choice = chunk.choices[0] - if hasattr(choice, "delta") and choice.delta: - content = choice.delta.content or "" - - if not content and not is_final: - return None - - # Build A2A streaming chunk (legacy format) - a2a_chunk = { - "jsonrpc": "2.0", - "id": request_id, - "result": { - "message": { - "role": "agent", - "parts": [{"kind": "text", "text": content}], - "messageId": uuid4().hex, - }, - "final": is_final, - }, - } - - return a2a_chunk diff --git a/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py b/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py index e73b17ac3c0..bf68a01d98c 100644 --- a/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py +++ b/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py @@ -289,16 +289,16 @@ def _transform_to_a2a_response( Transform Pydantic AI task response to standard A2A non-streaming format. Pydantic AI returns a task with history/artifacts, but the standard A2A - non-streaming format expects: + non-streaming format expects ``result`` to be the Message directly + (``kind="message"``), per the A2A spec / ``SendMessageResponse``: { "jsonrpc": "2.0", "id": "...", "result": { - "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "..."}], - "messageId": "..." - } + "kind": "message", + "role": "agent", + "parts": [{"kind": "text", "text": "..."}], + "messageId": "..." } } @@ -316,6 +316,7 @@ def _transform_to_a2a_response( # Build standard A2A message a2a_message = { + "kind": "message", "role": "agent", "parts": parts if parts else [{"kind": "text", "text": full_text}], "messageId": message_id, @@ -325,9 +326,7 @@ def _transform_to_a2a_response( return { "jsonrpc": "2.0", "id": request_id, - "result": { - "message": a2a_message, - }, + "result": a2a_message, } @staticmethod diff --git a/litellm/a2a_protocol/utils.py b/litellm/a2a_protocol/utils.py index 1cdbde97755..0dbd1eefc63 100644 --- a/litellm/a2a_protocol/utils.py +++ b/litellm/a2a_protocol/utils.py @@ -60,6 +60,12 @@ def extract_text_from_response(response_dict: Dict[str, Any]) -> str: if not isinstance(result, dict): return "" + # Direct message format (A2A spec): detect by explicit kind tag only. + # The "parts" heuristic is too broad and would match any future result + # type that happens to include a "parts" field. + if result.get("kind") == "message": + return A2ARequestUtils.extract_text_from_message(result) + message = result.get("message", {}) return A2ARequestUtils.extract_text_from_message(message) diff --git a/litellm/anthropic_interface/messages/__init__.py b/litellm/anthropic_interface/messages/__init__.py index 0996d62c866..f71279b226d 100644 --- a/litellm/anthropic_interface/messages/__init__.py +++ b/litellm/anthropic_interface/messages/__init__.py @@ -10,7 +10,7 @@ """ -from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union +from typing import Any, AsyncIterator, Coroutine, Dict, Iterator, List, Optional, Union from litellm.llms.anthropic.experimental_pass_through.messages.handler import ( anthropic_messages as _async_anthropic_messages, @@ -100,8 +100,11 @@ def create( **kwargs, ) -> Union[ AnthropicMessagesResponse, + Iterator[bytes], AsyncIterator[Any], - Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], + Coroutine[ + Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any], Iterator[bytes]] + ], ]: """ Async wrapper for Anthropic's messages API diff --git a/litellm/constants.py b/litellm/constants.py index fb765c0226c..ae98b37d6e6 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1147,6 +1147,7 @@ "openai.gpt-oss-120b-1:0", "anthropic.claude-haiku-4-5-20251001-v1:0", "anthropic.claude-sonnet-4-5-20250929-v1:0", + "anthropic.claude-opus-4-8", "anthropic.claude-opus-4-7", "anthropic.claude-opus-4-6-v1:0", "anthropic.claude-opus-4-6-v1", @@ -1408,6 +1409,13 @@ # Prometheus metrics, audit trails, or any other downstream consumer. LITELLM_PROXY_MASTER_KEY_ALIAS = "litellm_proxy_master_key" +# Marker placed in ``model_call_details`` on a synthetic ``Logging`` object that +# records a proxy-gate error (auth/rate-limit rejection) for a request that never +# reached an upstream provider. Tracing callbacks key off it to avoid fabricating +# an LLM-call span for a call that did not happen. See +# ``ProxyLogging._handle_logging_proxy_only_error``. +LITELLM_LOGGING_NO_UPSTREAM_LLM_CALL = "litellm_no_upstream_llm_call" + # Key Rotation Constants LITELLM_KEY_ROTATION_ENABLED = os.getenv("LITELLM_KEY_ROTATION_ENABLED", "false") LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDS = int( diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index 98e00cf5788..9a4b158b622 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -24,6 +24,7 @@ from litellm.litellm_core_utils.llm_cost_calc.utils import ( CostCalculatorUtils, _generic_cost_per_character, + _get_regional_uplift_multiplier, _get_service_tier_cost_key, _parse_prompt_tokens_details, calculate_cost_component, @@ -132,6 +133,8 @@ { CallTypes.create_video.value, CallTypes.acreate_video.value, + CallTypes.video_edit.value, + CallTypes.avideo_edit.value, CallTypes.video_remix.value, CallTypes.avideo_remix.value, } @@ -312,6 +315,10 @@ def cost_per_token( # noqa: PLR0915 audio_transcription_file_duration: float = 0.0, # for audio transcription calls - the file time in seconds ### SERVICE TIER ### service_tier: Optional[str] = None, # for OpenAI service tier pricing + ### DATA RESIDENCY ### + data_residency: Optional[ + str + ] = None, # for OpenAI regional-processing uplift (e.g. "eu", "us") response: Optional[Any] = None, ### REQUEST MODEL ### request_model: Optional[str] = None, # original request model for router detection @@ -412,9 +419,36 @@ def cost_per_token( # noqa: PLR0915 prompt_tokens_cost_usd_dollar: float = 0 completion_tokens_cost_usd_dollar: float = 0 model_cost_ref = litellm.model_cost + # Only callers that explicitly pass `custom_llm_provider` get the + # dedup/prefix-join treatment. When provider is omitted, preserve legacy + # behavior: `model_with_provider` stays equal to the raw `model` string + # (provider is detected below for downstream use only). + caller_supplied_provider = custom_llm_provider is not None + + # `model` is normally a string, but callers that mock the transport can pass + # non-string objects. Only run the string-based dedup/prefix-join when it is + # actually a string — e.g. a MagicMock's `.startswith()` is always truthy and + # its slices return new mocks, which would spin the dedup loop forever. + model_is_str = isinstance(model, str) + + # Router/proxy deployments may repeat the provider segment (e.g. model_name + # "openai/openai/gpt-5.5"). Strip duplicated `{provider}/` chains before joining. + if caller_supplied_provider and model_is_str: + _dup_prefix = f"{custom_llm_provider}/" + while model.startswith(_dup_prefix): + _remainder = model[len(_dup_prefix) :] + if _remainder.startswith(_dup_prefix): + model = _remainder + else: + break + model_with_provider = model - if custom_llm_provider is not None: - model_with_provider = custom_llm_provider + "/" + model + if caller_supplied_provider: + _prov_prefix = f"{custom_llm_provider}/" + if model_is_str and model.startswith(_prov_prefix): + model_with_provider = model + else: + model_with_provider = f"{custom_llm_provider}/{model}" if region_name is not None: model_with_provider_and_region = ( f"{custom_llm_provider}/{region_name}/{model}" @@ -425,6 +459,9 @@ def cost_per_token( # noqa: PLR0915 model_with_provider = model_with_provider_and_region else: _, custom_llm_provider, _, _ = litellm.get_llm_provider(model=model) + + assert custom_llm_provider is not None # caller-supplied or get_llm_provider + model_without_prefix = model model_parts = model.split("/", 1) if len(model_parts) > 1: @@ -493,6 +530,7 @@ def cost_per_token( # noqa: PLR0915 usage=usage_block, custom_llm_provider=custom_llm_provider, service_tier=service_tier, + data_residency=data_residency, ) return prompt_cost, completion_cost @@ -521,7 +559,10 @@ def cost_per_token( # noqa: PLR0915 or call_type == CallTypes.retrieve_batch ): return batch_cost_calculator( - usage=usage_block, model=model, custom_llm_provider=custom_llm_provider + usage=usage_block, + model=model, + custom_llm_provider=custom_llm_provider, + data_residency=data_residency, ) elif call_type == "atranscription" or call_type == "transcription": if _transcription_usage_has_token_details(usage_block): @@ -529,6 +570,7 @@ def cost_per_token( # noqa: PLR0915 model=model_without_prefix, usage=usage_block, service_tier=service_tier, + data_residency=data_residency, ) return openai_cost_per_second( @@ -579,7 +621,10 @@ def cost_per_token( # noqa: PLR0915 ) elif custom_llm_provider == "openai": return openai_cost_per_token( - model=model, usage=usage_block, service_tier=service_tier + model=model, + usage=usage_block, + service_tier=service_tier, + data_residency=data_residency, ) elif custom_llm_provider == "databricks": return databricks_cost_per_token(model=model, usage=usage_block) @@ -631,6 +676,7 @@ def cost_per_token( # noqa: PLR0915 usage=usage_block, custom_llm_provider=custom_llm_provider, service_tier=service_tier, + data_residency=data_residency, ) if ( @@ -1117,6 +1163,10 @@ def completion_cost( # noqa: PLR0915 litellm_logging_obj: Optional[LitellmLoggingObject] = None, ### SERVICE TIER ### service_tier: Optional[str] = None, # for OpenAI service tier pricing + ### DATA RESIDENCY ### + data_residency: Optional[ + str + ] = None, # for OpenAI regional-processing uplift (e.g. "eu", "us") ) -> float: """ Calculate the cost of a given completion call fot GPT-3.5-turbo, llama2, any litellm supported llm. @@ -1516,6 +1566,7 @@ def completion_cost( # noqa: PLR0915 combined_usage_object=cost_per_token_usage_object, custom_llm_provider=custom_llm_provider, litellm_model_name=model, + data_residency=data_residency, ) elif call_type == _MCP_CALL_TYPE: from litellm.proxy._experimental.mcp_server.cost_calculator import ( @@ -1600,6 +1651,7 @@ def completion_cost( # noqa: PLR0915 audio_transcription_file_duration=audio_transcription_file_duration, rerank_billed_units=rerank_billed_units, service_tier=service_tier, + data_residency=data_residency, response=completion_response, request_model=request_model_for_cost, ) @@ -1811,6 +1863,10 @@ def response_cost_calculator( litellm_logging_obj: Optional[LitellmLoggingObject] = None, ### SERVICE TIER ### service_tier: Optional[str] = None, # for OpenAI service tier pricing + ### DATA RESIDENCY ### + data_residency: Optional[ + str + ] = None, # for OpenAI regional-processing uplift (e.g. "eu", "us") ) -> float: """ Returns @@ -1844,6 +1900,7 @@ def response_cost_calculator( router_model_id=router_model_id, litellm_logging_obj=litellm_logging_obj, service_tier=service_tier, + data_residency=data_residency, ) return response_cost except Exception as e: @@ -2202,6 +2259,7 @@ def batch_cost_calculator( model: str, custom_llm_provider: Optional[str] = None, model_info: Optional[ModelInfo] = None, + data_residency: Optional[str] = None, ) -> Tuple[float, float]: """ Calculate the cost of a batch job. @@ -2286,6 +2344,11 @@ def batch_cost_calculator( usage.completion_tokens * (output_cost_per_token) / 2 ) # batch cost is usually half of the regular token cost + uplift = _get_regional_uplift_multiplier(model_info, data_residency) + if uplift != 1.0: + total_prompt_cost *= uplift + total_completion_cost *= uplift + return total_prompt_cost, total_completion_cost @@ -2431,6 +2494,7 @@ def handle_realtime_stream_cost_calculation( combined_usage_object: Usage, custom_llm_provider: str, litellm_model_name: str, + data_residency: Optional[str] = None, ) -> float: """ Handles the cost calculation for realtime stream responses. @@ -2461,6 +2525,7 @@ def handle_realtime_stream_cost_calculation( model=model_name, usage=combined_usage_object, custom_llm_provider=custom_llm_provider, + data_residency=data_residency, ) except Exception: continue diff --git a/litellm/integrations/arize/arize_phoenix.py b/litellm/integrations/arize/arize_phoenix.py index b8cd04836c3..d48dba8e7bb 100644 --- a/litellm/integrations/arize/arize_phoenix.py +++ b/litellm/integrations/arize/arize_phoenix.py @@ -1,5 +1,7 @@ import os -from typing import TYPE_CHECKING, Any, Optional, Union +import threading +from collections import OrderedDict +from typing import TYPE_CHECKING, Any, Optional, Tuple, Union from litellm._logging import verbose_logger from litellm.integrations.arize import _utils @@ -8,8 +10,10 @@ if TYPE_CHECKING: from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.sdk.trace.export import SpanProcessor from opentelemetry.trace import Span as _Span from opentelemetry.trace import SpanKind + from opentelemetry.trace import Tracer from litellm.integrations.opentelemetry import OpenTelemetry as _OpenTelemetry from litellm.integrations.opentelemetry import ( @@ -21,20 +25,27 @@ OpenTelemetryConfig = _OpenTelemetryConfig Span = Union[_Span, Any] OpenTelemetry = _OpenTelemetry + LITELLM_TRACER_NAME: str else: Protocol = Any OpenTelemetryConfig = Any Span = Any + Tracer = Any TracerProvider = Any SpanKind = Any - # Import OpenTelemetry at runtime + SpanProcessor = Any try: - from litellm.integrations.opentelemetry import OpenTelemetry + from litellm.integrations.opentelemetry import ( + LITELLM_TRACER_NAME, + OpenTelemetry, + ) except ImportError: + LITELLM_TRACER_NAME = "litellm" OpenTelemetry = None # type: ignore ARIZE_HOSTED_PHOENIX_ENDPOINT = "https://otlp.arize.com/v1/traces" +_MAX_PROJECT_PROVIDERS = 64 class ArizePhoenixLogger(OpenTelemetry): # type: ignore @@ -48,37 +59,142 @@ class ArizePhoenixLogger(OpenTelemetry): # type: ignore def _init_tracing(self, tracer_provider): """ - Override to always create a *private* TracerProvider for Arize Phoenix. + Override to create per-project TracerProviders (LRU-cached) for Arize Phoenix. The base ``OpenTelemetry._init_tracing`` falls back to the global TracerProvider when one already exists. That causes whichever integration initialises second to silently reuse the first one's exporter, so spans only reach one destination. - - By creating our own provider we guarantee Arize Phoenix always gets - its own exporter pipeline, regardless of initialisation order. """ - from opentelemetry.sdk.trace import TracerProvider from opentelemetry.trace import SpanKind if tracer_provider is not None: - # Explicitly supplied (e.g. in tests) — honour it. - self.tracer = tracer_provider.get_tracer("litellm") + self._use_injected_tracer_provider = True + self._shared_span_processor = None + self.tracer = tracer_provider.get_tracer(LITELLM_TRACER_NAME) self.span_kind = SpanKind return - # Always create a dedicated provider — never touch the global one. - provider = TracerProvider(resource=self._get_litellm_resource(self.config)) - provider.add_span_processor(self._get_span_processor()) - self.tracer = provider.get_tracer("litellm") + self._use_injected_tracer_provider = False + self._project_providers: OrderedDict[str, TracerProvider] = OrderedDict() + self._project_providers_lock = threading.Lock() + self._shared_span_processor = self._get_span_processor() self.span_kind = SpanKind + + default_project = self._resolve_project_name({}) + self.tracer = self._get_tracer_for(default_project) verbose_logger.debug( - "ArizePhoenixLogger: Created dedicated TracerProvider " - "(endpoint=%s, exporter=%s)", + "ArizePhoenixLogger: Initialized per-project TracerProvider cache " + "(default_project=%s, endpoint=%s, exporter=%s)", + default_project, self.config.endpoint, self.config.exporter, ) + def flush_tracer_providers(self) -> None: + """ + Flush all cached per-project providers and the shared span processor. + + Call on graceful proxy shutdown. Do not call on LRU eviction — in-flight + spans may still reference evicted providers. + """ + if getattr(self, "_use_injected_tracer_provider", False): + return + + shared_processor = getattr(self, "_shared_span_processor", None) + if shared_processor is not None: + try: + shared_processor.force_flush() + except Exception as e: + verbose_logger.debug( + "ArizePhoenixLogger: shared span processor force_flush failed: %s", + e, + ) + + with getattr(self, "_project_providers_lock", threading.Lock()): + providers = list(getattr(self, "_project_providers", {}).values()) + + for provider in providers: + try: + provider.force_flush() + except Exception as e: + verbose_logger.debug( + "ArizePhoenixLogger: TracerProvider force_flush failed: %s", e + ) + + def _get_litellm_resource_for_project(self, project_name: str): + """ + Build an OTEL Resource with project routing attrs that win over env detector. + + Phoenix uses ``openinference.project.name``; Arize AX uses ``model_id`` and + ``service.name``. Project attrs are merged last so OTEL_RESOURCE_ATTRIBUTES + from init does not pin every provider to one project. + """ + from opentelemetry.sdk.resources import OTELResourceDetector, Resource + + project_attributes: dict[str, str] = { + "openinference.project.name": project_name, + "model_id": project_name, + "service.name": project_name, + } + deployment_environment = getattr(self.config, "deployment_environment", None) + if deployment_environment is not None: + project_attributes["deployment.environment"] = deployment_environment + + env_resource = OTELResourceDetector().detect() + project_resource = Resource.create(project_attributes) # type: ignore[arg-type] + return env_resource.merge(project_resource) + + def _build_tracer_provider_for_project(self, project_name: str) -> TracerProvider: + """Create a TracerProvider for *project_name* (caller holds no cache lock).""" + from opentelemetry.sdk.trace import TracerProvider + + provider = TracerProvider( + resource=self._get_litellm_resource_for_project(project_name) + ) + provider.add_span_processor(self._shared_span_processor) + return provider + + def _get_tracer_for(self, project_name: str) -> Tracer: + """Return a tracer for *project_name*, creating/caching a provider on miss.""" + if getattr(self, "_use_injected_tracer_provider", False): + return self.tracer + + with self._project_providers_lock: + if project_name in self._project_providers: + self._project_providers.move_to_end(project_name) + return self._project_providers[project_name].get_tracer( + LITELLM_TRACER_NAME + ) + + # OTELResourceDetector().detect() is synchronous; build outside the lock so + # concurrent requests for other projects are not blocked on cache misses. + new_provider = self._build_tracer_provider_for_project(project_name) + + with self._project_providers_lock: + if project_name in self._project_providers: + self._project_providers.move_to_end(project_name) + return self._project_providers[project_name].get_tracer( + LITELLM_TRACER_NAME + ) + + if len(self._project_providers) >= _MAX_PROJECT_PROVIDERS: + self._project_providers.popitem(last=False) + + self._project_providers[project_name] = new_provider + return new_provider.get_tracer(LITELLM_TRACER_NAME) + + def _resolve_tracer_for_kwargs(self, kwargs: dict) -> Tuple[str, Tracer]: + """Resolve project name once and return the matching tracer.""" + project_name = self._resolve_project_name(kwargs) + return project_name, self._get_tracer_for(project_name) + + def get_tracer_to_use_for_request(self, kwargs: dict) -> Tracer: + """Route guardrail/raw-request spans to the same per-project tracer as the request.""" + if getattr(self, "_use_injected_tracer_provider", False): + return self.tracer + return self._resolve_tracer_for_kwargs(kwargs)[1] + def _init_otel_logger_on_litellm_proxy(self): """ Override: Arize Phoenix should NOT overwrite the proxy's @@ -93,56 +209,109 @@ def set_attributes(self, span: Span, kwargs, response_obj: Optional[Any]): @staticmethod def set_arize_phoenix_attributes(span: Span, kwargs, response_obj): - from litellm.integrations.opentelemetry_utils.base_otel_llm_obs_attributes import ( - safe_set_attribute, - ) - _utils.set_attributes(span, kwargs, response_obj, ArizeOTELAttributes) + return - # Dynamic project name: check metadata first, then fall back to env var config - dynamic_project_name = ArizePhoenixLogger._get_dynamic_project_name(kwargs) - if dynamic_project_name: - safe_set_attribute(span, "openinference.project.name", dynamic_project_name) - else: - # Fall back to static config from env var - config = ArizePhoenixLogger.get_arize_phoenix_config() - if config.project_name: - safe_set_attribute( - span, "openinference.project.name", config.project_name - ) + @staticmethod + def _normalize_project_name(name: Optional[str]) -> Optional[str]: + if name is None: + return None + normalized = str(name).strip() + return normalized if normalized else None - return + @staticmethod + def _iter_metadata_dicts_from_kwargs(kwargs: dict): + """Yield request metadata dicts; standard_logging_object before litellm_params.""" + for key in ("standard_logging_object", "litellm_params"): + found_key = kwargs.get(key) + if not isinstance(found_key, dict): + continue + metadata = found_key.get("metadata") + if isinstance(metadata, dict): + yield metadata @staticmethod - def _get_dynamic_project_name(kwargs) -> Optional[str]: + def _is_proxy_request(kwargs: dict) -> bool: + """True when the call is routed through the LiteLLM proxy. + + Proxy mode is determined solely by the server-set ``proxy_server_request`` + field in ``litellm_params``. Checking request metadata for + ``user_api_key_auth_metadata`` is intentionally avoided: that field is + user-supplied and would let an authenticated caller fake proxy-mode + detection to route their telemetry into arbitrary Arize/Phoenix projects. """ - Retrieve dynamic Phoenix project name from request metadata. + litellm_params = kwargs.get("litellm_params") + return isinstance(litellm_params, dict) and bool( + litellm_params.get("proxy_server_request") + ) - Users can set `metadata.phoenix_project_name` in their request to route - traces to different Phoenix projects dynamically. + @staticmethod + def _project_from_metadata_dict( + metadata: dict, metadata_key: str, *, proxy_mode: bool + ) -> Optional[str]: """ - standard_logging_payload = kwargs.get("standard_logging_object") - if isinstance(standard_logging_payload, dict): - metadata = standard_logging_payload.get("metadata") - if isinstance(metadata, dict): - project_name = metadata.get("phoenix_project_name") - if project_name: - return str(project_name) + Read a Phoenix project field from proxy/SDK metadata. - # Also check litellm_params.metadata for SDK usage - litellm_params = kwargs.get("litellm_params") - if isinstance(litellm_params, dict): - metadata = litellm_params.get("metadata") or {} - else: - metadata = {} - if isinstance(metadata, dict): - project_name = metadata.get("phoenix_project_name") - if project_name: - return str(project_name) + On the proxy, only ``user_api_key_auth_metadata`` (team/key config) may + select the project. SDK callers may still set project fields directly on + ``metadata``. + """ + auth_metadata = metadata.get("user_api_key_auth_metadata") + if isinstance(auth_metadata, dict): + project = ArizePhoenixLogger._normalize_project_name( + auth_metadata.get(metadata_key) + ) + if project: + return project + if not proxy_mode: + return ArizePhoenixLogger._normalize_project_name( + metadata.get(metadata_key) + ) return None - def _get_phoenix_context(self, kwargs): + @staticmethod + def _metadata_project_from_kwargs(kwargs: dict, metadata_key: str) -> Optional[str]: + proxy_mode = ArizePhoenixLogger._is_proxy_request(kwargs) + for metadata in ArizePhoenixLogger._iter_metadata_dicts_from_kwargs(kwargs): + project = ArizePhoenixLogger._project_from_metadata_dict( + metadata, metadata_key, proxy_mode=proxy_mode + ) + if project: + return project + return None + + @staticmethod + def _resolve_project_name(kwargs: dict) -> str: + """ + Resolve the target Phoenix/Arize project for this request. + + Proxy priority: ``user_api_key_auth_metadata.phoenix_project_name_override``, + ``user_api_key_auth_metadata.phoenix_project_name``, env, then ``default``. + SDK priority: request metadata fields, then env, then ``default``. + """ + override = ArizePhoenixLogger._metadata_project_from_kwargs( + kwargs, "phoenix_project_name_override" + ) + if override: + return override + + phoenix_name = ArizePhoenixLogger._metadata_project_from_kwargs( + kwargs, "phoenix_project_name" + ) + if phoenix_name: + return phoenix_name + + env_name = ArizePhoenixLogger._normalize_project_name( + os.environ.get("PHOENIX_PROJECT_NAME") + or os.environ.get("ARIZE_PROJECT_NAME") + ) + if env_name: + return env_name + + return "default" + + def _get_phoenix_context(self, kwargs, tracer: Optional[Tracer] = None): """ Build a trace context for Phoenix's dedicated TracerProvider. @@ -159,11 +328,13 @@ def _get_phoenix_context(self, kwargs): """ from opentelemetry import trace + if tracer is None: + tracer = self._resolve_tracer_for_kwargs(kwargs)[1] + litellm_params = kwargs.get("litellm_params", {}) or {} proxy_server_request = litellm_params.get("proxy_server_request", {}) or {} headers = proxy_server_request.get("headers", {}) or {} - # Propagate distributed trace context if the caller sent a traceparent traceparent_ctx = ( self.get_traceparent_from_header(headers=headers) if headers.get("traceparent") @@ -173,10 +344,8 @@ def _get_phoenix_context(self, kwargs): is_proxy_mode = bool(proxy_server_request) if is_proxy_mode: - # Create a parent span on Phoenix's own tracer so both parent - # and child are exported to Phoenix. start_time_val = kwargs.get("start_time", kwargs.get("api_call_start_time")) - parent_span = self.tracer.start_span( + parent_span = tracer.start_span( name="litellm_proxy_request", start_time=( self._to_ns(start_time_val) if start_time_val is not None else None @@ -187,100 +356,77 @@ def _get_phoenix_context(self, kwargs): ctx = trace.set_span_in_context(parent_span) return ctx, parent_span - # SDK mode — no parent span needed return traceparent_ctx, None def _handle_success(self, kwargs, response_obj, start_time, end_time): - """ - Override to always create spans on ArizePhoenixLogger's dedicated TracerProvider. - - The base class's ``_get_span_context`` would find the parent span created by - the ``otel`` callback on the *global* TracerProvider. That span is invisible - in Phoenix (different exporter pipeline), so we ignore it and build our own - hierarchy via ``_get_phoenix_context``. - """ - from opentelemetry.trace import Status, StatusCode - - verbose_logger.debug( - "ArizePhoenixLogger: Logging kwargs: %s, OTEL config settings=%s", - kwargs, - self.config, + self._handle_phoenix_trace( + kwargs, response_obj, start_time, end_time, success=True ) - ctx, parent_span = self._get_phoenix_context(kwargs) - - # Create litellm_request span (child of our parent when in proxy mode) - span = self.tracer.start_span( - name=self._get_span_name(kwargs), - start_time=self._to_ns(start_time), - context=ctx, + def _handle_failure(self, kwargs, response_obj, start_time, end_time): + self._handle_phoenix_trace( + kwargs, response_obj, start_time, end_time, success=False ) - span.set_status(Status(StatusCode.OK)) - self.set_attributes(span, kwargs, response_obj) - # Raw-request sub-span (if enabled) — must be created before - # ending the parent span so the hierarchy is valid. - self._maybe_log_raw_request(kwargs, response_obj, start_time, end_time, span) - span.end(end_time=self._to_ns(end_time)) - - # Guardrail span - self._create_guardrail_span(kwargs=kwargs, context=ctx) - - # Annotate and close our proxy parent span - if parent_span is not None: - parent_span.set_status(Status(StatusCode.OK)) - self.set_attributes(parent_span, kwargs, response_obj) - parent_span.end(end_time=self._to_ns(end_time)) - - # Metrics & cost recording - self._record_metrics(kwargs, response_obj, start_time, end_time) - - # Semantic logs - if self.config.enable_events: - self._emit_semantic_logs(kwargs, response_obj, span) - - def _handle_failure(self, kwargs, response_obj, start_time, end_time): - """ - Override to always create failure spans on ArizePhoenixLogger's dedicated - TracerProvider. Mirrors ``_handle_success`` but sets ERROR status. - """ + def _handle_phoenix_trace( + self, + kwargs, + response_obj, + start_time, + end_time, + *, + success: bool, + ): from opentelemetry.trace import Status, StatusCode verbose_logger.debug( - "ArizePhoenixLogger: Failure - Logging kwargs: %s, OTEL config settings=%s", + "ArizePhoenixLogger: %s - kwargs: %s, OTEL config settings=%s", + "success" if success else "failure", kwargs, self.config, ) - ctx, parent_span = self._get_phoenix_context(kwargs) + _project_name, tracer = self._resolve_tracer_for_kwargs(kwargs) + ctx, parent_span = self._get_phoenix_context(kwargs, tracer=tracer) - # Create litellm_request span (child of our parent when in proxy mode) - span = self.tracer.start_span( + status = Status(StatusCode.OK if success else StatusCode.ERROR) + + span = tracer.start_span( name=self._get_span_name(kwargs), start_time=self._to_ns(start_time), context=ctx, ) - span.set_status(Status(StatusCode.ERROR)) + span.set_status(status) self.set_attributes(span, kwargs, response_obj) - self._record_exception_on_span(span=span, kwargs=kwargs) + if not success: + self._record_exception_on_span(span=span, kwargs=kwargs) + + if success: + self._maybe_log_raw_request( + kwargs, response_obj, start_time, end_time, span + ) span.end(end_time=self._to_ns(end_time)) - # Guardrail span self._create_guardrail_span(kwargs=kwargs, context=ctx) - # Annotate and close our proxy parent span if parent_span is not None: - parent_span.set_status(Status(StatusCode.ERROR)) + parent_span.set_status(status) self.set_attributes(parent_span, kwargs, response_obj) - self._record_exception_on_span(span=parent_span, kwargs=kwargs) + if not success: + self._record_exception_on_span(span=parent_span, kwargs=kwargs) parent_span.end(end_time=self._to_ns(end_time)) + if success: + self._record_metrics(kwargs, response_obj, start_time, end_time) + + if self.config.enable_events: + self._emit_semantic_logs(kwargs, response_obj, span) + @staticmethod def get_arize_phoenix_config() -> ArizePhoenixConfig: """ Retrieves the Arize Phoenix configuration based on environment variables. Returns: - ArizePhoenixConfig: A Pydantic model containing Arize Phoenix configuration. """ api_key = os.environ.get("PHOENIX_API_KEY", None) @@ -295,18 +441,15 @@ def get_arize_phoenix_config() -> ArizePhoenixConfig: protocol: Protocol = "otlp_http" if collector_endpoint: - # Parse the endpoint to determine protocol if collector_endpoint.startswith("grpc://") or ( ":4317" in collector_endpoint and "/v1/traces" not in collector_endpoint ): endpoint = collector_endpoint protocol = "otlp_grpc" else: - # Phoenix Cloud endpoints (app.phoenix.arize.com) include the space in the URL if "app.phoenix.arize.com" in collector_endpoint: endpoint = collector_endpoint protocol = "otlp_http" - # For other HTTP endpoints, ensure they have the correct path elif "/v1/traces" not in collector_endpoint: if collector_endpoint.endswith("/v1"): endpoint = collector_endpoint + "/traces" @@ -318,7 +461,6 @@ def get_arize_phoenix_config() -> ArizePhoenixConfig: endpoint = collector_endpoint protocol = "otlp_http" else: - # If no endpoint specified, self hosted phoenix endpoint = "http://localhost:6006/v1/traces" protocol = "otlp_http" verbose_logger.debug( @@ -329,12 +471,11 @@ def get_arize_phoenix_config() -> ArizePhoenixConfig: if api_key is not None: otlp_auth_headers = f"Authorization=Bearer {api_key}" elif "app.phoenix.arize.com" in endpoint: - # Phoenix Cloud requires an API key raise ValueError( "PHOENIX_API_KEY must be set when using Phoenix Cloud (app.phoenix.arize.com)." ) - project_name = os.environ.get("PHOENIX_PROJECT_NAME", "default") + project_name = os.environ.get("PHOENIX_PROJECT_NAME") or "default" return ArizePhoenixConfig( otlp_auth_headers=otlp_auth_headers, @@ -343,8 +484,6 @@ def get_arize_phoenix_config() -> ArizePhoenixConfig: project_name=project_name, ) - ## cannot suppress additional proxy server spans, removed previous methods. - async def async_health_check(self): config = self.get_arize_phoenix_config() diff --git a/litellm/integrations/datadog/datadog_cost_management.py b/litellm/integrations/datadog/datadog_cost_management.py index a961d4f9244..0f954eb1ce0 100644 --- a/litellm/integrations/datadog/datadog_cost_management.py +++ b/litellm/integrations/datadog/datadog_cost_management.py @@ -2,10 +2,17 @@ import os import time from datetime import datetime -from typing import Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple, cast from litellm._logging import verbose_logger from litellm.integrations.custom_batch_logger import CustomBatchLogger +from litellm.integrations.datadog.datadog_handler import ( + get_datadog_env, + get_datadog_hostname, + get_datadog_pod_name, + get_datadog_service, +) +from litellm.litellm_core_utils.safe_json_dumps import safe_dumps from litellm.llms.custom_httpx.http_handler import ( get_async_httpx_client, httpxSpecialProvider, @@ -15,9 +22,30 @@ ) from litellm.types.utils import StandardLoggingPayload +# Reserved tag keys whose values come from trusted sources (infra env, LiteLLM +# core payload fields, or proxy-controlled auth metadata). User-supplied +# request_tags / metadata cannot overwrite these, even when the key is +# allowlisted via cost_tag_keys, because that would let an authenticated caller +# spoof cost attribution (e.g. request_tags=["team:victim-team"]). +_RESERVED_TAG_KEYS: frozenset = frozenset( + { + "env", + "service", + "host", + "pod_name", + "provider", + "model", + "model_id", + "team", + "user", + "model_group", + } +) + class DatadogCostManagementLogger(CustomBatchLogger): - def __init__(self, **kwargs): + def __init__(self, cost_tag_keys: Optional[List[str]] = None, **kwargs): + self.cost_tag_keys: List[str] = list(cost_tag_keys) if cost_tag_keys else [] self.dd_api_key = os.getenv("DD_API_KEY") self.dd_app_key = os.getenv("DD_APP_KEY") self.dd_site = os.getenv("DD_SITE", "datadoghq.com") @@ -68,20 +96,21 @@ async def async_send_batch(self): if not self.log_queue: return - try: - # Aggregate costs from the batch - aggregated_entries = self._aggregate_costs(self.log_queue) + batch_to_send = self.log_queue[:] + self.log_queue = [] + try: + aggregated_entries = self._aggregate_costs(batch_to_send) if not aggregated_entries: + verbose_logger.debug( + "Datadog Cost Management: batch produced no aggregable entries; " + "dropping %d log(s) from queue.", + len(batch_to_send), + ) return - - # Send to Datadog await self._upload_to_datadog(aggregated_entries) - - # Clear queue only on success (or if we decide to drop on failure) - # CustomBatchLogger clears queue in flush_queue, so we just process here - except Exception as e: + self.log_queue = batch_to_send + self.log_queue verbose_logger.exception( f"Datadog Cost Management: Error in async_send_batch: {str(e)}" ) @@ -151,45 +180,81 @@ def _aggregate_costs( return list(aggregator.values()) def _extract_tags(self, log: StandardLoggingPayload) -> Dict[str, str]: - from litellm.integrations.datadog.datadog_handler import ( - get_datadog_env, - get_datadog_hostname, - get_datadog_pod_name, - get_datadog_service, - ) - - tags = { + tags: Dict[str, str] = { "env": get_datadog_env(), "service": get_datadog_service(), "host": get_datadog_hostname(), "pod_name": get_datadog_pod_name(), } - # Add metadata as tags - metadata = log.get("metadata", {}) - if metadata: - # Add user info - # Add user info - if metadata.get("user_api_key_alias"): - tags["user"] = str(metadata["user_api_key_alias"]) - - # Add Team Tag - team_tag = ( - metadata.get("user_api_key_team_alias") - or metadata.get("team_alias") # type: ignore - or metadata.get("user_api_key_team_id") - or metadata.get("team_id") # type: ignore - ) - - if team_tag: - tags["team"] = str(team_tag) - # model_group is not in StandardLoggingMetadata TypedDict, so we need to access it via dict.get() - model_group = metadata.get("model_group") # type: ignore[misc] - if model_group: - tags["model_group"] = str(model_group) + # Always-on canonical FOCUS dimensions from top-level payload fields. + # Non-sensitive and required for Datadog Custom Costs per-model attribution. + self._add_tag(tags, "provider", log.get("custom_llm_provider")) + self._add_tag(tags, "model", log.get("model")) + self._add_tag(tags, "model_id", log.get("model_id")) + + # cast because StandardLoggingMetadata is a TypedDict; we iterate it + # as a generic mapping below. + metadata: Dict[str, Any] = cast(Dict[str, Any], log.get("metadata") or {}) + + # Backwards-compat: team/user/model_group preserved regardless of allowlist. + if metadata.get("user_api_key_alias"): + tags["user"] = str(metadata["user_api_key_alias"]) + team_tag = ( + metadata.get("user_api_key_team_alias") + or metadata.get("team_alias") + or metadata.get("user_api_key_team_id") + or metadata.get("team_id") + ) + if team_tag: + tags["team"] = str(team_tag) + if metadata.get("model_group"): + tags["model_group"] = str(metadata["model_group"]) + + # Allowlist-gated: request_tags (split on `:`) and arbitrary metadata.*. + # Reserved keys are hard-blocked here regardless of allowlist membership — + # see _RESERVED_TAG_KEYS for the rationale. + if self.cost_tag_keys: + allow = set(self.cost_tag_keys) + for rt in log.get("request_tags") or []: + if not isinstance(rt, str) or ":" not in rt: + continue + k, _, v = rt.partition(":") + if k in allow and v: + self._set_custom_tag(tags, k, v) + for k, v in metadata.items(): + if k in allow and v is not None and not isinstance(v, (dict, list)): + self._set_custom_tag(tags, k, str(v)) + for nested_key in ("spend_logs_metadata", "requester_metadata"): + nested = metadata.get(nested_key) + if isinstance(nested, dict): + for k, v in nested.items(): + if ( + k in allow + and v is not None + and not isinstance(v, (dict, list)) + ): + self._set_custom_tag(tags, k, str(v)) return tags + @staticmethod + def _set_custom_tag(tags: Dict[str, str], key: str, value: str) -> None: + if key in _RESERVED_TAG_KEYS: + verbose_logger.debug( + "Datadog Cost Management: dropping user-supplied tag %r=%r — " + "key is reserved for trusted cost attribution.", + key, + value, + ) + return + tags[key] = value + + @staticmethod + def _add_tag(tags: Dict[str, str], key: str, value: Any) -> None: + if value: + tags[key] = str(value) + async def _upload_to_datadog(self, payload: List[Dict]): if not self.dd_api_key or not self.dd_app_key: return @@ -201,8 +266,6 @@ async def _upload_to_datadog(self, payload: List[Dict]): } # The API endpoint expects a list of objects directly in the body (file content behavior) - from litellm.litellm_core_utils.safe_json_dumps import safe_dumps - data_json = safe_dumps(payload) response = await self.async_client.put( diff --git a/litellm/integrations/datadog/datadog_metrics.py b/litellm/integrations/datadog/datadog_metrics.py index fcf40701e28..d7847027d7e 100644 --- a/litellm/integrations/datadog/datadog_metrics.py +++ b/litellm/integrations/datadog/datadog_metrics.py @@ -144,7 +144,26 @@ def _add_metrics_from_log( } self.log_queue.append(series_llm_latency) - # 3. Request Count / Status Code + # 3. LiteLLM Overhead Latency Metric (total - llm_api time) + hidden_params = log.get("hidden_params", {}) or {} + litellm_overhead_time_ms = hidden_params.get("litellm_overhead_time_ms") + if litellm_overhead_time_ms is not None: + overhead_tags = self._extract_tags(log) # no status_code on latency metric + series_overhead: DatadogMetricSeries = { + "metric": "litellm.overhead.latency", + "type": 3, # gauge + "points": [ + { + "timestamp": timestamp, + "value": litellm_overhead_time_ms + / 1000, # convert ms → seconds + } + ], + "tags": overhead_tags, + } + self.log_queue.append(series_overhead) + + # 4. Request Count / Status Code series_count: DatadogMetricSeries = { "metric": "litellm.llm_api.request_count", "type": 1, # count diff --git a/litellm/integrations/galileo.py b/litellm/integrations/galileo.py index e99d5f23a4c..a598124f612 100644 --- a/litellm/integrations/galileo.py +++ b/litellm/integrations/galileo.py @@ -1,18 +1,29 @@ +import json import os -from typing import Any, Dict, List, Optional +import re +from typing import Any, Dict, List, Optional, Tuple, cast from pydantic import BaseModel, Field import litellm from litellm._logging import verbose_logger from litellm.integrations.custom_logger import CustomLogger +from litellm.litellm_core_utils.prompt_templates.common_utils import ( + convert_content_list_to_str, + get_content_from_model_response, +) from litellm.llms.custom_httpx.http_handler import ( get_async_httpx_client, httpxSpecialProvider, ) +from litellm.types.llms.openai import AllMessageValues + +GALILEO_CLOUD_API_BASE_URL = "https://api.galileo.ai" +# Cap the in-memory buffer so persistent flush failures (e.g. Galileo +# unavailable, invalid credentials) cannot leak memory unboundedly. +GALILEO_MAX_IN_MEMORY_RECORDS = 1000 -# from here: https://docs.rungalileo.io/galileo/gen-ai-studio-products/galileo-observe/how-to/logging-data-via-restful-apis#structuring-your-records class LLMResponse(BaseModel): latency_ms: int status_code: int @@ -37,65 +48,190 @@ class GalileoObserve(CustomLogger): def __init__(self) -> None: self.in_memory_records: List[dict] = [] self.batch_size = 1 - self.base_url = os.getenv("GALILEO_BASE_URL", None) - self.project_id = os.getenv("GALILEO_PROJECT_ID", None) + self.api_key = os.getenv("GALILEO_API_KEY") + self.project_id = os.getenv("GALILEO_PROJECT_ID") + self.log_stream_id = os.getenv("GALILEO_LOG_STREAM_ID") + self.username = os.getenv("GALILEO_USERNAME") + self.password = os.getenv("GALILEO_PASSWORD") + self.base_url = self._normalize_base_url(os.getenv("GALILEO_BASE_URL")) + if self.api_key and not self.base_url: + self.base_url = GALILEO_CLOUD_API_BASE_URL + self.use_v2_api = bool(self.api_key) self.headers: Optional[Dict[str, str]] = None self.async_httpx_handler = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback ) - pass - def set_galileo_headers(self): - # following https://docs.rungalileo.io/galileo/gen-ai-studio-products/galileo-observe/how-to/logging-data-via-restful-apis#logging-your-records + @staticmethod + def _normalize_base_url(base_url: Optional[str]) -> Optional[str]: + if base_url: + return base_url.rstrip("/") + return None - headers = { - "accept": "application/json", - "Content-Type": "application/x-www-form-urlencoded", - } - galileo_login_response = litellm.module_level_client.post( + def _is_configured(self) -> bool: + if not self.project_id or not self.base_url: + return False + if self.use_v2_api: + return bool(self.api_key) + return bool(self.username and self.password) + + async def async_set_galileo_headers(self) -> None: + galileo_login_response = await self.async_httpx_handler.post( url=f"{self.base_url}/login", - headers=headers, + headers={ + "accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, data={ - "username": os.getenv("GALILEO_USERNAME"), - "password": os.getenv("GALILEO_PASSWORD"), + "username": self.username, + "password": self.password, }, ) - + galileo_login_response.raise_for_status() access_token = galileo_login_response.json()["access_token"] - self.headers = { "accept": "application/json", "Content-Type": "application/json", "Authorization": f"Bearer {access_token}", } - def get_output_str_from_response(self, response_obj, kwargs): - output = None - if response_obj is not None and ( - kwargs.get("call_type", None) == "embedding" - or isinstance(response_obj, litellm.EmbeddingResponse) - ): - output = None - elif response_obj is not None and isinstance( - response_obj, litellm.ModelResponse - ): - output = response_obj["choices"][0]["message"].json() - elif response_obj is not None and isinstance( - response_obj, litellm.TextCompletionResponse - ): - output = response_obj.choices[0].text - elif response_obj is not None and isinstance( - response_obj, litellm.ImageResponse - ): - output = response_obj["data"] + async def _ensure_headers(self) -> bool: + if self.headers is not None: + return True + + if self.use_v2_api: + if not self.api_key: + return False + self.headers = { + "accept": "application/json", + "Content-Type": "application/json", + "Galileo-API-Key": self.api_key, + } + return True + + if not (self.username and self.password and self.base_url): + return False + + try: + await self.async_set_galileo_headers() + return True + except Exception as e: + verbose_logger.debug("Galileo Logger: failed to authenticate: %s", e) + return False + + @staticmethod + def _galileo_input_messages( + messages: Optional[List[Any]], input_text: str + ) -> List[Dict[str, str]]: + if not messages: + return [{"role": "user", "content": input_text}] + + galileo_messages: List[Dict[str, str]] = [] + for message in messages: + if not isinstance(message, dict): + continue + role = message.get("role") + if not role: + continue + galileo_messages.append( + { + "role": str(role), + "content": convert_content_list_to_str( + message=cast(AllMessageValues, message) + ), + } + ) + + if galileo_messages: + return galileo_messages + return [{"role": "user", "content": input_text}] + + @staticmethod + def _record_to_v2_span(record: Dict[str, Any]) -> Dict[str, Any]: + created_at = record.get("created_at", "") + if created_at and not re.search(r"(Z|[+-]\d{2}:?\d{2})$", created_at): + created_at = f"{created_at}Z" + + span: Dict[str, Any] = { + "type": "llm", + "name": record.get("node_type", "litellm"), + "created_at": created_at, + "input": GalileoObserve._galileo_input_messages( + record.get("messages"), record.get("input_text", "") + ), + "output": { + "role": "assistant", + "content": record.get("output_text", ""), + }, + "status_code": record.get("status_code", 200), + "model": record.get("model"), + "metrics": { + "duration_ns": int(record.get("latency_ms", 0)) * 1_000_000, + "num_input_tokens": record.get("num_input_tokens"), + "num_output_tokens": record.get("num_output_tokens"), + }, + } + if record.get("tags"): + span["tags"] = record["tags"] + return span + + def _get_ingest_request(self) -> Optional[Tuple[str, Dict[str, Any]]]: + if not self.base_url or not self.project_id: + return None + + # Snapshot the records to be sent into a new list so concurrent appends + # during the network round-trip (across the await points in + # flush_in_memory_records) aren't silently dropped when we later clear + # the in-memory buffer. + records = list(self.in_memory_records) + + if self.use_v2_api: + payload: Dict[str, Any] = { + "spans": [self._record_to_v2_span(record) for record in records], + "reliable": False, + } + if self.log_stream_id: + payload["log_stream_id"] = self.log_stream_id + return ( + f"{self.base_url}/v2/projects/{self.project_id}/spans", + payload, + ) + + return ( + f"{self.base_url}/projects/{self.project_id}/observe/ingest", + {"records": records}, + ) - return output + def get_output_str_from_response( + self, response_obj: Any, kwargs: Dict[str, Any] + ) -> Optional[str]: + if response_obj is None: + return None + if kwargs.get("call_type", None) == "embedding" or isinstance( + response_obj, litellm.EmbeddingResponse + ): + return None + if isinstance(response_obj, litellm.TextCompletionResponse): + return response_obj.choices[0].text + if isinstance(response_obj, litellm.ImageResponse): + return json.dumps(response_obj["data"], default=str) + if isinstance(response_obj, (litellm.ModelResponse, dict)): + return get_content_from_model_response(response_obj) + return None async def async_log_success_event( self, kwargs: Any, response_obj: Any, start_time: Any, end_time: Any ): verbose_logger.debug("On Async Success") + if not self._is_configured(): + verbose_logger.debug( + "Galileo Logger: skipping flush — set GALILEO_PROJECT_ID and " + "either GALILEO_API_KEY (hosted) or GALILEO_USERNAME/GALILEO_PASSWORD " + "(enterprise Observe)." + ) + return + _latency_ms = int((end_time - start_time).total_seconds() * 1000) _call_type = kwargs.get("call_type", "litellm") input_text = litellm.utils.get_formatted_prompt( @@ -125,26 +261,69 @@ async def async_log_success_event( ), # timestamp str constructed in "%Y-%m-%dT%H:%M:%S" format ) - # dump to dict request_dict = request_record.model_dump() + messages = kwargs.get("messages") + if messages: + request_dict["messages"] = messages self.in_memory_records.append(request_dict) + # Bound the buffer so persistent flush failures cannot grow it + # without limit. Drop the oldest records once we exceed the cap. + if len(self.in_memory_records) > GALILEO_MAX_IN_MEMORY_RECORDS: + dropped = len(self.in_memory_records) - GALILEO_MAX_IN_MEMORY_RECORDS + self.in_memory_records = self.in_memory_records[ + -GALILEO_MAX_IN_MEMORY_RECORDS: + ] + verbose_logger.warning( + "Galileo Logger: in-memory buffer exceeded %s records; " + "dropped %s oldest record(s). Check Galileo connectivity/credentials.", + GALILEO_MAX_IN_MEMORY_RECORDS, + dropped, + ) + if len(self.in_memory_records) >= self.batch_size: await self.flush_in_memory_records() async def flush_in_memory_records(self): - verbose_logger.debug("flushing in memory records") - response = await self.async_httpx_handler.post( - url=f"{self.base_url}/projects/{self.project_id}/observe/ingest", - headers=self.headers, - json={"records": self.in_memory_records}, - ) + if not self.in_memory_records: + return + + # Capture the number of records that will be sent BEFORE any await so + # that concurrent appends made by other asyncio tasks during the + # network round-trip aren't silently dropped on the success-clear. + records_in_payload = len(self.in_memory_records) + + ingest_request = self._get_ingest_request() + if ingest_request is None: + verbose_logger.debug( + "Galileo Logger: missing GALILEO_BASE_URL or GALILEO_PROJECT_ID" + ) + return + + if not await self._ensure_headers(): + verbose_logger.debug("Galileo Logger: could not set request headers") + return + + url, payload = ingest_request + verbose_logger.debug("flushing in memory records to %s", url) + + try: + response = await self.async_httpx_handler.post( + url=url, + headers=self.headers, + json=payload, + ) + except Exception as e: + verbose_logger.debug( + "Galileo Logger: failed to flush in memory records: %s", e + ) + return - if response.status_code == 200: + if response.is_success: verbose_logger.debug( - "Galileo Logger:successfully flushed in memory records" + "Galileo Logger: successfully flushed in memory records" ) - self.in_memory_records = [] + del self.in_memory_records[:records_in_payload] else: verbose_logger.debug("Galileo Logger: failed to flush in memory records") verbose_logger.debug( @@ -152,6 +331,13 @@ async def flush_in_memory_records(self): response.text, response.status_code, ) + # Legacy enterprise auth caches a bearer token obtained from + # /login. If the request was rejected for auth reasons, drop the + # cached headers so the next flush re-authenticates instead of + # silently failing forever on a stale token. The v2 API key path + # uses a long-lived static key, so leave its headers in place. + if not self.use_v2_api and response.status_code in (401, 403): + self.headers = None async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): verbose_logger.debug("On Async Failure") diff --git a/litellm/integrations/opentelemetry.py b/litellm/integrations/opentelemetry.py index 6c8510380a8..814da344f03 100644 --- a/litellm/integrations/opentelemetry.py +++ b/litellm/integrations/opentelemetry.py @@ -64,6 +64,9 @@ HTTP_ROUTE_ATTRIBUTE = "http.route" URL_PATH_ATTRIBUTE = "url.path" PREPROCESSING_DURATION_MS_ATTRIBUTE = "litellm.preprocessing.duration_ms" +TEAM_METADATA_ATTRIBUTE = "litellm.team.metadata" +MODEL_GROUP_ATTRIBUTE = "litellm.model_group" +PROVIDER_MODEL_ATTRIBUTE = "litellm.provider.model" # Remove the hardcoded LITELLM_RESOURCE dictionary - we'll create it properly later RAW_REQUEST_SPAN_NAME = "raw_gen_ai_request" LITELLM_REQUEST_SPAN_NAME = "litellm_request" @@ -702,6 +705,14 @@ async def async_post_call_failure_hook( }, ) + # _record_exception_on_span only stamps when error_code is set; + # bare TypeError etc. has none, and the span is about to be ended. + error_code = ( + error_information.get("error_code") if error_information else None + ) + if not error_code: + self.set_response_status_code_attribute(parent_otel_span, 500) + # Pre-request latency (request_data carries the propagated # metadata on the failure path; omitted if it failed before handoff). self.set_preprocessing_duration_attribute(parent_otel_span, request_data) @@ -798,11 +809,6 @@ async def async_post_call_success_hook( # Pre-request latency on the SERVER span (success path). self.set_preprocessing_duration_attribute(parent_span, kwargs) - # http.response.status_code on the SERVER span (success path). - # A successful proxy response is HTTP 200; the failure path sets - # this from the error code in _record_exception_on_span. - self.set_response_status_code_attribute(parent_span, 200) - # 3. Guardrail span self._create_guardrail_span(kwargs=kwargs, context=ctx) @@ -985,7 +991,15 @@ def _end_proxy_span_from_kwargs(self, kwargs: dict, end_time) -> None: and hasattr(proxy_span, "is_recording") and proxy_span.is_recording() ): - proxy_span.end(end_time=self._to_ns(end_time)) + self._close_proxy_span_ok(proxy_span, end_time) + + def _close_proxy_span_ok(self, span: Span, end_time) -> None: + """Stamp http.response.status_code=200 + status=OK, then end the span.""" + from opentelemetry.trace import Status, StatusCode + + self.set_response_status_code_attribute(span, 200) + span.set_status(Status(StatusCode.OK)) + span.end(end_time=self._to_ns(end_time)) def _handle_success(self, kwargs, response_obj, start_time, end_time): """Create the litellm_request span then close the proxy span.""" @@ -1071,8 +1085,10 @@ def _handle_success(self, kwargs, response_obj, start_time, end_time): parent_span is not None and hasattr(parent_span, "name") and parent_span.name == LITELLM_PROXY_REQUEST_SPAN_NAME + and hasattr(parent_span, "is_recording") + and parent_span.is_recording() ): - parent_span.end(end_time=self._to_ns(end_time)) + self._close_proxy_span_ok(parent_span, end_time) # Stamp team attributes onto the SERVER (root) span before it is # closed, so the trace root carries them like every child span. @@ -1200,6 +1216,68 @@ def _set_team_attributes_on_proxy_span_from_kwargs(self, kwargs: dict) -> None: ): self._set_team_attributes_from_kwargs(proxy_span, kwargs) + def _set_inference_identity_attributes( + self, + span: Span, + standard_logging_payload: StandardLoggingPayload, + litellm_params: dict, + ) -> None: + """Stamp request-identity attributes onto an inference span so every + LLM-call span is filterable by the route it came in on, the team's + metadata, and both the user-facing (model_group alias) and the + dispatched (provider) model names. Empty/absent values are skipped. + """ + metadata = standard_logging_payload.get("metadata") or {} + + http_route = metadata.get("user_api_key_request_route") + if http_route: + self.safe_set_attribute( + span=span, key=HTTP_ROUTE_ATTRIBUTE, value=http_route + ) + + # ``user_api_key_team_metadata`` is dropped from the standard logging + # payload metadata, so read it from the raw request metadata in kwargs. + # ``metadata`` and ``litellm_metadata`` are alternate names for the same + # full metadata dict (the name varies by endpoint), so first-truthy wins. + raw_metadata = ( + litellm_params.get("metadata") + or litellm_params.get("litellm_metadata") + or {} + ) + team_metadata = self._team_metadata_json( + raw_metadata.get("user_api_key_team_metadata") + ) + if team_metadata: + self.safe_set_attribute( + span=span, key=TEAM_METADATA_ATTRIBUTE, value=team_metadata + ) + + model_group = standard_logging_payload.get("model_group") + if model_group: + self.safe_set_attribute( + span=span, key=MODEL_GROUP_ATTRIBUTE, value=model_group + ) + + hidden_params = standard_logging_payload.get("hidden_params") or {} + provider_model = hidden_params.get( + "litellm_model_name" + ) or standard_logging_payload.get("model") + if provider_model: + self.safe_set_attribute( + span=span, key=PROVIDER_MODEL_ATTRIBUTE, value=provider_model + ) + + @staticmethod + def _team_metadata_json(value: Any) -> Optional[str]: + """JSON-serialize a team's metadata dict for a single span attribute. + + Returns ``None`` for a missing, non-dict, or empty mapping so the + empty case is dropped rather than stamping a useless ``"{}"``. + """ + if not isinstance(value, dict) or not value: + return None + return safe_dumps(value) + def _record_metrics(self, kwargs, response_obj, start_time, end_time): duration_s = (end_time - start_time).total_seconds() params = kwargs.get("litellm_params") or {} @@ -2010,6 +2088,12 @@ def set_attributes( # noqa: PLR0915 key="hidden_params", value=safe_dumps(hidden_params), ) + + self._set_inference_identity_attributes( + span=span, + standard_logging_payload=standard_logging_payload, + litellm_params=litellm_params, + ) # Cost breakdown tracking cost_breakdown: Optional[CostBreakdown] = standard_logging_payload.get( "cost_breakdown" @@ -3041,6 +3125,11 @@ async def async_management_endpoint_success_hook( management_endpoint_span.set_status(Status(StatusCode.OK)) management_endpoint_span.end(end_time=_end_time_ns) + # The management wrapper has no other hook that closes the SERVER span. + self.set_response_status_code_attribute(parent_otel_span, 200) + parent_otel_span.set_status(Status(StatusCode.OK)) + parent_otel_span.end(end_time=_end_time_ns) + async def async_management_endpoint_failure_hook( self, logging_payload: ManagementEndpointLoggingPayload, @@ -3091,6 +3180,24 @@ async def async_management_endpoint_failure_hook( management_endpoint_span.set_status(Status(StatusCode.ERROR)) management_endpoint_span.end(end_time=_end_time_ns) + # The management wrapper has no other hook that closes the SERVER span. + from litellm.litellm_core_utils.litellm_logging import ( + StandardLoggingPayloadSetup, + ) + + error_information = StandardLoggingPayloadSetup.get_error_information( + original_exception=_exception, + ) + parent_otel_span.set_status(Status(StatusCode.ERROR)) + self._record_exception_on_span( + span=parent_otel_span, + kwargs={ + "exception": _exception, + "standard_logging_object": {"error_information": error_information}, + }, + ) + parent_otel_span.end(end_time=_end_time_ns) + def create_litellm_proxy_request_started_span( self, start_time: datetime, diff --git a/litellm/integrations/otel/README.md b/litellm/integrations/otel/README.md new file mode 100644 index 00000000000..99b3ecea162 --- /dev/null +++ b/litellm/integrations/otel/README.md @@ -0,0 +1,258 @@ +# OpenTelemetry instrumentation + +This package produces OpenTelemetry traces for LiteLLM. It is enabled by the +`LITELLM_OTEL_V2` environment variable (`is_otel_v2_enabled()` in +[`config.py`](./model/config.py)); when unset, nothing in this package runs. + +## What gets traced + +A traced proxy request produces one trace with two kinds of spans: + +``` +SERVER span "POST /v1/chat/completions" ← FastAPI instrumentation +├── INTERNAL span "auth /v1/chat/completions" ← auth phase ┐ +│ ├── CLIENT span "postgres get_key_object" ← datastore call │ +│ └── CLIENT span "postgres get_team_membership" │ +├── INTERNAL span "execute_guardrail …" ← guardrail │ this package +├── CLIENT span "chat gpt-4o" ← LLM call │ +└── CLIENT span "batch_write_to_db …" ← spend write ┘ +``` + +The gen-ai spans are siblings under the server span. In particular the guardrail +span is a sibling of the LLM call, not a child of it: pre/during/post-call +guardrail hooks are part of the request lifecycle (a pre-call guardrail runs +before the LLM call even starts), so they belong directly under the server span, +alongside the LLM call. + +Request-level spans (LLM call, guardrail) parent to the server span via an +**explicit anchor** — `context.set_request_root_span` captures the server span +once at request entry, and `resolve_request_span_context` reads it — rather than +to whatever span is momentarily active. Ambient-only parenting was wrong at two +boundaries: inside the live `auth` phase span the active span is `auth` (so the +span would nest under auth), and a pass-through request closes its span from a +detached `asyncio.create_task` where the server span is no longer active (so the +span orphaned into its own trace). The anchor — a contextvar inherited by those +child tasks — gives a stable parent in both cases. DB/service spans keep ambient +parenting so an auth DB lookup still nests under `auth`. + +**Which service calls become spans (`spans.span_role_for_service`).** LiteLLM's +service-logging layer instruments many internal functions, but only some are +traceable units of work: + +- **`DB_CALL` (CLIENT)** — outbound datastore calls (redis, postgres, + `batch_write_to_db`), carrying `db.system.name` / `db.operation.name` semconv. +- **`SERVICE` (INTERNAL)** — genuine internal work worth a span (background + budget/reset jobs, pod-lock manager). +- **metrics-only (no span)** — `self` (the `track_llm_api_timing` wrapper, which + duplicates the LLM-call span), `router` (duplicates the request), and + `proxy_pre_call` (a guardrail's real span is `execute_guardrail …`). These + still feed Prometheus/Datadog through their own hooks; they just never enter + the trace. `auth` is also excluded here because it gets a **live phase span** + instead (see below). + +Spans are named `"{service} {call_type}"` (e.g. `"redis set"`) so repeated calls +to one service stay distinguishable. Like every other span they parent to the +**ambient** context, falling back to the threaded `litellm_parent_otel_span` only +when ambient has no live span; a background job with neither starts its own root +trace. Caller-supplied `event_metadata` is **sanitized** before it reaches a span +(primitives only, no live objects, no secrets/headers, bounded) — see +`payloads.sanitize_event_metadata`. + +**Live phase spans.** `auth` is wrapped in a real, active span +(`logger.phase_span`) for the duration of authentication, so the DB lookups it +triggers nest **under** it instead of flattening onto the server span. Identity +Baggage (team/key/user) is seeded once the key resolves, so every post-auth span +inherits it; auth-internal DB lookups that run before the key is known stay +unlabeled, which is correct. + +**Status.** On success a span's status is left `UNSET` (the semconv default, +matching the FastAPI server span); only a genuine error sets `ERROR`. + +- **Server spans** (one per HTTP route) are created by the + `opentelemetry-instrumentation-fastapi` package. It stamps `http.*` attributes + and extracts inbound `traceparent` headers. This package does **not** create + or modify server spans — request routes never touch spans. +- **Gen-AI spans** (LLM calls, guardrails, internal service calls) are created + by this package from LiteLLM's logging callbacks. Request-level spans parent to + the server span via the captured anchor; DB/service spans parent to the active + span (ambient) so they nest under the request phase that triggered them. + +Both kinds share a single `TracerProvider`, so they belong to the same trace +and export through the same configured exporters. FastAPI middleware can only be +added before the app starts serving, so the app is instrumented at +import time **without** a provider — it binds to the OTel global +`ProxyTracerProvider`. Once config (and the callbacks) is loaded, the proxy +publishes the chosen logger's `TracerProvider` as the global via +`trace.set_tracer_provider(...)`, and the server spans delegate to it. When a +preset callback (`arize`, `langfuse_otel`, …) is configured, its provider +becomes the global, so server spans export to that backend too. + +## How a request flows + +1. **App creation** (`proxy_server` import): when the gate is on, + `mount.instrument_fastapi_app(app)` calls `FastAPIInstrumentor.instrument_app` + with no provider (the middleware stack is frozen once the app serves, so this + can't wait for startup). It binds to the OTel global `ProxyTracerProvider`. Noisy + non-LLM routes are excluded by default (`mount._DEFAULT_EXCLUDED_ROUTES`): health + checks (`/health*`), the Prometheus scrape (`/metrics`), and static UI/docs assets + (`/litellm-asset-prefix`, `/_next`, `/ui`, `/swagger`, `/docs`, `/redoc`, + `/openapi.json`, favicons, `/.well-known`) — so load-balancer polling, metric + scrapes, and asset fetches don't flood traces. Entries are substring-matched, so + `/metrics` also drops the `/model/metrics` admin-analytics spans. Set + `OTEL_PYTHON_FASTAPI_EXCLUDED_URLS` to override the whole set (e.g. `""` to trace + everything, or your own comma-separated path list). +2. **Startup** (`proxy_server.proxy_startup_event`): after the config (and + callbacks) is loaded, the already-registered preset `OpenTelemetryV2` logger + is reused — or a generic one reading `OTEL_*` envs is built when no preset is + configured — and its `TracerProvider` is published as the OTel global with + `trace.set_tracer_provider(...)`. The proxy tracer then delegates to it, so + server spans and gen-ai spans share one provider and the same trace. +3. **Request**: the FastAPI instrumentation starts the server span and makes it + the active context for the request task. The proxy's first call into the V2 + logger (`create_litellm_proxy_request_started_span`, at the auth boundary) + **captures it as the request anchor** (`set_request_root_span`), so every later + request-level span has a stable explicit parent regardless of what is active + when it emits. +4. **LLM call span (born at the boundary)**: `OpenTelemetryV2.log_pre_api_call` + runs synchronously in the request task, just before the upstream call, and + **opens** the LLM-call span there, parented to the anchored server span + (`resolve_request_span_context`). The open span is held in a bounded cache keyed + by `litellm_call_id` (a primitive the callback kwargs carry at both `pre_call` + and close), so no live `Span` ever travels through a `litellm_params` metadata + dict. For the boundary hook to fire at all, the logger is registered into + `litellm.input_callback` — the list `Logging.pre_call` iterates. The async + success/failure callback later + **closes** it: it builds an `LLMCallSpanData` from the typed + `standard_logging_object` (token usage and cost are computed only by then), + stamps the attributes, sets status, and ends the span. The sync callback is a + no-op (closing is async-only). When `pre_call` runs off the request task — a + sync-only provider driven through a thread pool, where contextvars (and so the + anchor) don't follow — no parent is visible there, so creation is **deferred** + to the async callback, whose worker context was copied from the request task at + enqueue and so still carries the anchor. **Pass-through** endpoints call + `logging_obj.pre_call` in the request task too, then close from a detached + `asyncio.create_task`; the anchor (not the by-then-inactive server span) keeps + their LLM-call span in the request's trace. `pre_call` is litellm's generic + "log the attempt" hook, so it also fires for synthetic proxy-gate error logs + (auth/rate-limit rejections); those carry `LITELLM_LOGGING_NO_UPSTREAM_LLM_CALL` + and are skipped, so a request rejected before reaching a provider never produces + a phantom CLIENT span. +5. **Guardrails / services**: the post-call and service hooks emit guardrail and + service spans the same way — typed data → engine → span. Service spans + (Redis/Postgres) are dispatched by `litellm/_service_logger.py`, which + recognizes the V2 `OpenTelemetryV2` logger (a plain `CustomLogger`, not a + subclass of the legacy `OpenTelemetry`). It hands every service call to the + logger — including calls with no parent span — and the V2 adapter decides the + role (`DB_CALL` vs `SERVICE`), the parent (ambient → threaded → root), and + whether the call is a traceable operation or a metrics-only ping. Guardrail + span data is built from the typed, provider-agnostic + `StandardLoggingGuardrailInformation` — no single provider's field shape is + assumed. +6. **Export**: each span ends and is handed to the provider's span processors, + which export to the configured backends (OTLP, console, in-memory, …). + +## Components + +### Sources of truth (`model/`, no OpenTelemetry import) + +These define the shape of a span without depending on the OTel SDK, so they can +be imported anywhere. They live in [`model/`](./model) and form a closed set — +nothing here imports outside it: + +- [`semconv.py`](./model/semconv.py) — attribute-key constants (`gen_ai.*`, `http.*`, + `litellm.*`), the GenAI operation/provider enums, and the functions that map + LiteLLM provider/call-type strings onto convention values. +- [`spans.py`](./model/spans.py) — the span registry: every span role, its OTel span + kind, its place in the hierarchy, and its name builder. +- [`payloads.py`](./model/payloads.py) — frozen dataclasses (`LLMCallSpanData`, + `GuardrailSpanData`, `ServiceSpanData`, …) built from heterogeneous logging + payloads via `from_*` classmethods. +- [`config.py`](./model/config.py) — `OpenTelemetryV2Config`, a pydantic-settings + model that reads `OTEL_*` / `LITELLM_OTEL_*` env vars, plus the feature gate. + `capture_span_content` gates whether prompt/response bodies may be written as + span attributes; it defaults **off** (`no_content`). The Baggage allowlists are + configurable, not hard-coded: set `LITELLM_OTEL_BAGGAGE_PROMOTED_KEYS` / + `LITELLM_OTEL_BAGGAGE_METADATA_KEYS` (comma-separated) as env vars, or + `baggage_promoted_keys` / `baggage_metadata_keys` (YAML lists) under + `callback_settings.otel` in `config.yaml` — the latter reach the config through + the logger's constructor kwargs. +- [`baggage.py`](./model/baggage.py) — the single definition of which request-identity + values are promoted into Baggage (so child spans inherit them) and under which + attribute keys. +- [`utils.py`](./model/utils.py) — value coercion, JSON serialization, and + extractor-table application, shared across the package. + +### Engine + +- [`emitter.py`](./emitter.py) — `SpanEmitter.emit(role, data)`: dedupe → start + the span → run the mapper chain to stamp attributes → set status → end. It + owns no attribute keys. The dedupe set (which coalesces the sync+async firing + of one request) is a bounded LRU so it can't grow without limit. +- [`mappers/`](./mappers) — each mapper turns typed span data into a flat + `{attribute key: value}` dict. They compose: listing several mapper names in + the config layers multiple attribute vocabularies onto the same span. + - `genai` — the canonical OpenTelemetry GenAI vocabulary, always present. + - `legacy` — an additional vocabulary using the older semconv-ai / Traceloop + attribute key names, for backends that read those. + - `openinference`, `langfuse`, `weave`, `langtrace` — vendor vocabularies. + - `resolve_mappers(names)` turns config names into mapper instances. + +### Plumbing (`plumbing/`) + +The OTel-SDK wiring. Everything here imports only `model/` and each other; it +lives in [`plumbing/`](./plumbing): + +- [`providers.py`](./plumbing/providers.py) — builds the `TracerProvider`, its exporters + (from `ExporterSpec`s), and the span processor that copies allowlisted Baggage + entries onto every span. `register_exporter_factory(kind, factory)` lets a + preset contribute a custom exporter `kind` (e.g. one that fetches an auth + token lazily) without coupling this module to any vendor. +- [`context.py`](./plumbing/context.py) — trace-context and Baggage read/write helpers. +- [`routing.py`](./plumbing/routing.py) — `TenantTracerCache`: when a request carries + team/key-scoped vendor credentials, route its spans through a credential-keyed + `TracerProvider` so one logger serves many tenants. The cache is a bounded LRU + that flushes + shuts down evicted providers, since the key derives from + request-supplied credentials and must not grow (or leak threads) without limit. +- [`metrics.py`](./plumbing/metrics.py) — GenAI client metric instruments. + +### Adapter + +- [`logger.py`](./logger.py) — `OpenTelemetryV2`, a `CustomLogger` that + translates LiteLLM's logging callbacks into typed span data and hands them to + the engine. The LLM-call span is opened at the `log_pre_api_call` boundary + (parented to the live server span via ambient context) and closed at the async + success/failure callback; the open span is held in a bounded cache keyed by + `litellm_call_id`, never threaded through a metadata dict. The logger registers + itself into `litellm.input_callback` so `Logging.pre_call` fires the boundary + hook. +- [`mount.py`](./mount.py) — `instrument_fastapi_app(app)`, the single call site + that attaches `opentelemetry-instrumentation-fastapi` for SERVER spans. It owns + the health-check exclusion default (`OTEL_PYTHON_FASTAPI_EXCLUDED_URLS`) and the + passthrough span-naming hook (`PASSTHROUGH_PREFIXES`) so `proxy_server` carries + no OTel detail. A safe no-op when the gate is off or the instrumentation package + is absent; must be called at app-creation time (the middleware stack freezes + once the app serves). + +### Presets + +- [`presets/`](./presets) — each preset reads one integration's env vars and + returns an `OpenTelemetryV2Config` (exporter destination + mapper vocabularies + + resource attributes). `PRESET_BY_CALLBACK` maps a callback name (`"arize"`, + `"langfuse_otel"`, …) to its preset. Integrations that support team/key-scoped + credentials also provide a per-request OTLP header builder + (`DYNAMIC_HEADERS_BY_CALLBACK`). Presets do **no** network I/O at build time: + AgentOps, for example, mints its JWT lazily inside a custom exporter on the + first export (in the `BatchSpanProcessor` worker thread), never on the event + loop. + +## Extending + +- **A new attribute vocabulary for a backend**: add a mapper in `mappers/` + (a class with a `map(data) -> AttributeMap` method, typically built from + `key -> extractor` tables) and register it in `mappers/__init__._MAPPER_BY_NAME`. +- **A new integration**: add a preset in `presets/` that returns an + `OpenTelemetryV2Config`, and register it in `presets/__init__.PRESET_BY_CALLBACK`. + If it supports dynamic credentials, add a header builder to + `DYNAMIC_HEADERS_BY_CALLBACK`. +- **A new span kind**: add a role to `spans.py` (registry entry + name builder), + a payload dataclass in `payloads.py`, and a branch in the relevant mapper(s). diff --git a/litellm/integrations/otel/__init__.py b/litellm/integrations/otel/__init__.py new file mode 100644 index 00000000000..42a84a85fbd --- /dev/null +++ b/litellm/integrations/otel/__init__.py @@ -0,0 +1,102 @@ +"""Typed, semconv-aligned OpenTelemetry instrumentation for LiteLLM. + +The three sources of truth — attribute keys (:mod:`semconv`), the span and +hierarchy registry (:mod:`spans`), and the typed span-data inputs +(:mod:`payloads`) — plus :mod:`config` are exported here and are free of any +``opentelemetry`` import. The engine layer (``emitter``, ``providers``, +``context``, ``metrics``) and the ``CustomLogger`` adapter (``logger``) are +reached via their submodule paths so that importing this package never +requires the OTel SDK. + +The ``LITELLM_OTEL_V2`` env var gates whether the factory in +``litellm_core_utils.litellm_logging`` constructs the ``OpenTelemetryV2`` +class (from :mod:`logger`). +""" + +from litellm.integrations.otel.model.config import ( + OTEL_V2_ENV, + OpenTelemetryV2Config, + is_otel_v2_enabled, +) +from litellm.integrations.otel.model.baggage import ( + BAGGAGE_PROMOTED_KEYS, + DEFAULT_BAGGAGE_METADATA_KEYS, + promoted_baggage, +) +from litellm.integrations.otel.model.metadata import ( + RequestContext, + RequestIdentity, +) +from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + LLMRequestParams, + LLMUsage, + ProxyRequestSpanData, + ServerInfo, + ServiceSpanData, + SpanError, +) +from litellm.integrations.otel.model.semconv import ( + DB, + Error, + GenAI, + GenAIOperation, + GenAIProvider, + HTTP, + LiteLLM, + Metric, + Server, + resolve_operation, + resolve_provider, +) +from litellm.integrations.otel.model.spans import ( + SPAN_REGISTRY, + LiteLLMSpanKind, + SpanRole, + SpanSpec, + db_system, + span_role_for_service, + validate_registry, +) + +__all__ = [ + # config + "OTEL_V2_ENV", + "OpenTelemetryV2Config", + "is_otel_v2_enabled", + # semconv + "BAGGAGE_PROMOTED_KEYS", + "DB", + "DEFAULT_BAGGAGE_METADATA_KEYS", + "Error", + "GenAI", + "GenAIOperation", + "GenAIProvider", + "HTTP", + "LiteLLM", + "Metric", + "Server", + "resolve_operation", + "resolve_provider", + # spans + "SPAN_REGISTRY", + "LiteLLMSpanKind", + "SpanRole", + "SpanSpec", + "db_system", + "span_role_for_service", + "validate_registry", + # payloads + "GuardrailSpanData", + "LLMCallSpanData", + "LLMRequestParams", + "LLMUsage", + "ProxyRequestSpanData", + "RequestContext", + "RequestIdentity", + "ServerInfo", + "ServiceSpanData", + "SpanError", + "promoted_baggage", +] diff --git a/litellm/integrations/otel/emitter.py b/litellm/integrations/otel/emitter.py new file mode 100644 index 00000000000..cae6514efdf --- /dev/null +++ b/litellm/integrations/otel/emitter.py @@ -0,0 +1,175 @@ +"""The span engine: dedup, start, run the mapper chain, set status, end.""" + +from collections import OrderedDict +from typing import Callable, Sequence + +from opentelemetry.context import Context +from opentelemetry.trace import Span, Tracer +from opentelemetry.trace.status import Status, StatusCode + +from litellm.integrations.otel.model.config import OpenTelemetryV2Config +from litellm.integrations.otel.mappers import resolve_mappers +from litellm.integrations.otel.mappers.base import AttributeMapper, SpanData +from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + ServiceSpanData, +) +from litellm.integrations.otel.plumbing.providers import to_otel_span_kind +from litellm.integrations.otel.model.semconv import Error +from litellm.integrations.otel.model.spans import ( + SPAN_REGISTRY, + SpanRole, + guardrail_span_name, + llm_call_span_name, + service_span_name, +) + +# Roles emit() knows how to name and emit. PROXY_REQUEST and the management +# routes are SERVER spans owned by the mounted FastAPI instrumentor, so they +# have no builder here. +_NAME_BUILDERS: dict[SpanRole, Callable[..., str]] = { + SpanRole.LLM_CALL: llm_call_span_name, + SpanRole.GUARDRAIL: guardrail_span_name, + # DB_CALL and SERVICE are both built from ServiceSpanData; they differ only in + # span kind (CLIENT vs INTERNAL) and attribute vocabulary, not in naming. + SpanRole.DB_CALL: service_span_name, + SpanRole.SERVICE: service_span_name, +} + +# Cap on the dedup cache. It only needs to coalesce the sync+async firing window +# of a single in-flight request, so a bounded LRU keeps memory flat on a +# long-running proxy while still covering every concurrently-open call. +_DEDUP_CACHE_MAX = 10_000 + + +class SpanEmitter: + def __init__( + self, + tracer: Tracer, + config: OpenTelemetryV2Config, + mappers: Sequence[AttributeMapper] | None = None, + ) -> None: + self._tracer = tracer + self._config = config + # The mapper chain is the sole source of span attributes. When not + # passed in, resolve it from the config so there's one source of truth. + self._mappers: list[AttributeMapper] = ( + list(mappers) + if mappers is not None + else resolve_mappers(config.mapper_names) + ) + # Bounded LRU (ordered by insertion / most-recent touch). Storing keys + # only — the value is unused — so it behaves like a capped set. + self._emitted: "OrderedDict[tuple[str, SpanRole], None]" = OrderedDict() + + # -- low-level helpers --------------------------------------------------- # + + def start_span( + self, + role: SpanRole, + name: str, + parent_context: Context | None = None, + start_time_ns: int | None = None, + *, + tracer: Tracer | None = None, + ) -> Span: + """Start a span for ``role`` without dedup or attribute mapping. + + For callers that own and manage their own span lifecycle. ``tracer`` + overrides the bound tracer for this span only, used for per-request + multi-tenant credential routing. + """ + return (tracer or self._tracer).start_span( + name, + context=parent_context, + kind=to_otel_span_kind(SPAN_REGISTRY[role].kind), + start_time=start_time_ns, + ) + + def _seen(self, dedup_key: str | None, role: SpanRole) -> bool: + """Return True once a ``(dedup_key, role)`` pair has been emitted. + + Guards against emitting the same span twice when a streaming call + fires both a sync and an async logging callback. + """ + if not dedup_key: + return False + marker = (dedup_key, role) + if marker in self._emitted: + self._emitted.move_to_end(marker) + return True + self._emitted[marker] = None + if len(self._emitted) > _DEDUP_CACHE_MAX: + self._emitted.popitem(last=False) # evict least-recently-used + return False + + # -- the engine ---------------------------------------------------------- # + + def emit( + self, + role: SpanRole, + data: SpanData, + parent_context: Context | None = None, + *, + start_time_ns: int | None = None, + end_time_ns: int | None = None, + tracer: Tracer | None = None, + ) -> Span | None: + """Emit one complete span: dedup, start, map attributes, status, end. + + Return the span, or ``None`` if it was deduplicated away. ``tracer`` + overrides the bound tracer for this span, used for per-request routing. + """ + # Only LLM-call spans carry a dedup key; LLM-call and service spans + # carry an ``error`` field. ``isinstance`` narrows the type for mypy and + # keeps the engine free of duck-typed attribute reads. + dedup_key = data.identity.call_id if isinstance(data, LLMCallSpanData) else None + if self._seen(dedup_key, role): + return None + span = self.start_span( + role, + _NAME_BUILDERS[role](data), + parent_context=parent_context, + start_time_ns=start_time_ns, + tracer=tracer, + ) + self.finish_span(role, span, data, end_time_ns=end_time_ns) + return span + + def finish_span( + self, + role: SpanRole, + span: Span, + data: SpanData, + *, + end_time_ns: int | None = None, + ) -> None: + """Stamp attributes + status on an already-started ``span`` and end it. + + The counterpart to :meth:`start_span` for callers that own a span's + lifecycle — the LLM-call span is opened at the request's ``pre_call`` + boundary (so it parents to the live server span via real ambient context, + never a span threaded through a metadata dict) and closed here once the + typed payload is available. The span name is (re)built from the now-known + data, since the boundary opener only has a provisional name. + """ + span.update_name(_NAME_BUILDERS[role](data)) + for mapper in self._mappers: + for key, value in mapper.map(data).items(): + span.set_attribute(key, value) + error = ( + data.error + if isinstance(data, (LLMCallSpanData, ServiceSpanData, GuardrailSpanData)) + else None + ) + if error and (error.error_type or error.message): + span.set_attribute(Error.TYPE, error.error_type or "error") + span.set_status( + Status(StatusCode.ERROR, error.message or error.error_type or "error") + ) + # On success leave the status UNSET (the semconv default) rather than + # forcing OK — that matches the FastAPI server span and avoids implying a + # span-level health signal litellm doesn't actually evaluate. Only a + # genuine error sets a status. + span.end(end_time=end_time_ns) diff --git a/litellm/integrations/otel/logger.py b/litellm/integrations/otel/logger.py new file mode 100644 index 00000000000..007b41df0a3 --- /dev/null +++ b/litellm/integrations/otel/logger.py @@ -0,0 +1,495 @@ +"""``CustomLogger`` adapter on the OpenTelemetry span engine.""" + +from collections import OrderedDict +from contextlib import contextmanager +from datetime import datetime +from typing import TYPE_CHECKING, Any, Iterator, Mapping, cast + +from opentelemetry.context import attach, get_current +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.trace import Span, Tracer, get_current_span, use_span + +import litellm +from litellm.integrations.custom_logger import CustomLogger +from litellm.integrations.otel.model.baggage import promoted_baggage +from litellm.integrations.otel.model.config import OpenTelemetryV2Config +from litellm.integrations.otel.plumbing.context import ( + is_recordable_span, + resolve_parent_context, + resolve_request_span_context, + set_request_baggage, + set_request_root_span, +) +from litellm.integrations.otel.emitter import SpanEmitter +from litellm.integrations.otel.mappers import resolve_mappers +from litellm.integrations.otel.model.metadata import ( + LLMCallEvent, + RequestIdentity, + guardrail_entries_from_request_data, + model_from_request_data, +) +from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + ServiceSpanData, + SpanError, +) +from litellm.integrations.otel.plumbing.providers import ( + build_tracer_provider, + get_tracer, +) +from litellm.integrations.otel.plumbing.routing import TenantTracerCache +from litellm.integrations.otel.model.spans import SpanRole, span_role_for_service +from litellm.integrations.otel.model.utils import to_ns + +if TYPE_CHECKING: + from litellm.types.utils import StandardLoggingGuardrailInformation + +LITELLM_TRACER_NAME = "litellm" + +# Any callback whose class belongs to one of these modules is "the OTel +# callback" for proxy-global-registration purposes. +_OTEL_MODULES = ( + "litellm.integrations.otel", + "litellm.integrations.opentelemetry", +) + + +# Cap on the open-call carrier map. A span opened at ``pre_call`` that never +# reaches a success/failure callback (e.g. a stream that only fires stream +# events) would otherwise linger; bounding the map evicts the oldest so memory +# stays flat on a long-running proxy while covering every concurrent in-flight +# call. +_OPEN_CALLS_MAX = 10_000 + + +class _LLMCallSpan: + """The state carried from the ``pre_call`` boundary to span close. + + ``span`` is the live span when it could be opened at the boundary (the server + span was ambient), or ``None`` when creation was deferred because no ambient + parent was visible — in which case the async callback creates it against its + own (worker-copied) ambient context using ``start_time_ns``. The presence of + a carrier for a call at all is the proof that ``pre_call`` ran, i.e. that an + upstream call was actually attempted. + """ + + __slots__ = ("span", "start_time_ns") + + def __init__(self, span: "Span | None", start_time_ns: int | None) -> None: + self.span = span + self.start_time_ns = start_time_ns + + +class OpenTelemetryV2(CustomLogger): + """The ``CustomLogger`` for OpenTelemetry.""" + + def __init__( + self, + config: OpenTelemetryV2Config | None = None, + callback_name: str | None = None, + tracer_provider: TracerProvider | None = None, + logger_provider: Any | None = None, # reserved for OTel logs + meter_provider: Any | None = None, # reserved for metrics + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + self.config: OpenTelemetryV2Config = config or OpenTelemetryV2Config(**kwargs) + self.callback_name = callback_name + self._tracer_provider: TracerProvider = ( + tracer_provider + if tracer_provider is not None + else build_tracer_provider(self.config) + ) + self.tracer: Tracer = get_tracer(self._tracer_provider, LITELLM_TRACER_NAME) + self._emitter = SpanEmitter( + self.tracer, self.config, mappers=resolve_mappers(self.config.mapper_names) + ) + self._tenant_tracers = TenantTracerCache( + self.config, callback_name, LITELLM_TRACER_NAME + ) + self._open_llm_calls: "OrderedDict[str, _LLMCallSpan]" = OrderedDict() + self._init_otel_logger_on_litellm_proxy() + + # ====================================================================== # + # Proxy global registration + # ====================================================================== # + + def _register_in_callback_list(self, callbacks: list) -> None: + already_otel = any( + cb.__class__.__module__.startswith(_OTEL_MODULES) + for cb in callbacks + if hasattr(cb, "__class__") + ) + if not already_otel: + callbacks.append(self) + + def _init_otel_logger_on_litellm_proxy(self) -> None: + try: + from litellm.proxy import proxy_server + except Exception: + return + try: + self._register_in_callback_list(litellm.service_callback) + self._register_in_callback_list(litellm.input_callback) + self._register_in_callback_list(litellm._async_success_callback) + self._register_in_callback_list(litellm._async_failure_callback) + except Exception: + pass + if getattr(proxy_server, "open_telemetry_logger", None) is None: + setattr(proxy_server, "open_telemetry_logger", self) + + # ====================================================================== # + # LLM-call callbacks — the span is opened at the ``pre_call`` boundary and + # closed here. See ``log_pre_api_call``. + # ====================================================================== # + + def log_pre_api_call(self, model, messages, kwargs): + """Open the LLM-call span at the call boundary. + + Runs synchronously inside the request task, before the upstream call — + the one place where the live server span is genuinely the ambient OTel + context — so the span parents to it natively, with no span threaded + through a metadata dict. The open span is stashed on the per-request + ``LiteLLMLoggingObj`` (a typed object) and closed in the async callback. + + When no recordable parent is visible (``pre_call`` was driven from a thread + pool for a sync-only provider, where contextvars — and so the anchor — + don't follow), creation is deferred: only the start time is recorded, and + the async callback — whose worker context was copied from the request task + and so still carries the anchor — creates the span then. + + Synthetic proxy-gate error logs (auth/rate-limit rejections) also fire this + hook but never made an upstream call; they are tagged and skipped so no + phantom LLM-call span is produced. + """ + call = LLMCallEvent.from_dict(kwargs) + if call.is_no_upstream_call: + return + call_id = call.call_id + if call_id is None: + return + # Idempotent: a retried call may re-enter ``pre_call`` with the same + # call id; keep the first span so its start time is the true one. + if call_id in self._open_llm_calls: + return + start_time_ns = to_ns(datetime.now()) + span: Span | None = None + # Parent to the request's anchored root span (stable across the request), + # falling back to ambient on the SDK path. Open the span live only when + # that resolves to a recordable parent; otherwise defer to the close + # callback (the thread-pool case, where the anchor isn't visible here). + parent_context = resolve_request_span_context() + if is_recordable_span(get_current_span(parent_context)): + span = self._emitter.start_span( + SpanRole.LLM_CALL, + call.provisional_span_name, + parent_context=parent_context, + start_time_ns=start_time_ns, + tracer=self._tenant_tracers.tracer_for( + self.tracer, call.dynamic_params + ), + ) + self._open_llm_calls[call_id] = _LLMCallSpan( + span=span, start_time_ns=start_time_ns + ) + # Evict the oldest open call if the map is over budget. A call that opens + # but never closes (a stream that only fires stream events) would linger + # otherwise; the evicted span is simply dropped (never exported). + if len(self._open_llm_calls) > _OPEN_CALLS_MAX: + self._open_llm_calls.popitem(last=False) + + async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): + self._close_llm_call(kwargs, start_time, end_time) + + async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): + self._close_llm_call(kwargs, start_time, end_time) + + def _close_llm_call( + self, + kwargs: Mapping[str, Any], + start_time: datetime | float | None, + end_time: datetime | float | None, + ) -> Span | None: + """Finish the LLM-call span opened at ``pre_call`` (or create it deferred). + + No carrier for this call id means ``pre_call`` never ran — the request was + rejected at the gate or blocked by a pre-call guardrail before any upstream + call — so there is nothing to record and no phantom span. + """ + call = LLMCallEvent.from_dict(kwargs) + call_id = call.call_id + # ``pop`` is the dedup: this method runs from both the success and failure + # paths, and whichever fires first removes the carrier and closes the span. + carrier = self._open_llm_calls.pop(call_id, None) if call_id else None + if carrier is None: + return None + payload = call.payload + if payload is None: + if carrier.span is not None: + # Opened at the boundary but the payload never materialized — end + # it (named provisionally) so it isn't leaked as an open span. + carrier.span.end(end_time=to_ns(end_time)) + return None + data = LLMCallSpanData.from_standard_logging_payload( + payload, capture_content=self.config.capture_span_content + ) + end_time_ns = to_ns(end_time) + if carrier.span is not None: + # Born at the boundary: stamp attributes from the typed payload, set + # status, and end it. Its parent (the server span) was captured at + # creation from real ambient context. + self._emitter.finish_span( + SpanRole.LLM_CALL, carrier.span, data, end_time_ns=end_time_ns + ) + return carrier.span + # Deferred: ``pre_call`` saw no recordable parent, so create the span now. + # The worker copied the request task's context, which carries the anchored + # root span — parent to it (ambient fallback on the SDK path). Seed identity + # Baggage so the span — and the SDK path, which has none — is labeled + # consistently. + parent_ctx = resolve_request_span_context() + bag = promoted_baggage( + data.identity, + data.request_model, + promoted_keys=tuple(self.config.baggage_promoted_keys), + metadata_keys=tuple(self.config.baggage_metadata_keys), + ) + if bag: + parent_ctx = set_request_baggage(bag, context=parent_ctx) + return self._emitter.emit( + SpanRole.LLM_CALL, + data, + parent_context=parent_ctx, + start_time_ns=carrier.start_time_ns, + end_time_ns=end_time_ns, + tracer=self._tenant_tracers.tracer_for(self.tracer, call.dynamic_params), + ) + + # ====================================================================== # + # Service hooks + # ====================================================================== # + + async def async_service_success_hook( + self, + payload: Any, + parent_otel_span: Span | None = None, + start_time: datetime | float | None = None, + end_time: datetime | float | None = None, + event_metadata: dict | None = None, + ) -> None: + self._emit_service( + payload, + parent_otel_span=parent_otel_span, + start_time=start_time, + end_time=end_time, + event_metadata=event_metadata, + error_override=None, + ) + + async def async_service_failure_hook( + self, + payload: Any, + error: str | None = "", + parent_otel_span: Span | None = None, + start_time: datetime | float | None = None, + end_time: datetime | float | None = None, + event_metadata: dict | None = None, + ) -> None: + self._emit_service( + payload, + parent_otel_span=parent_otel_span, + start_time=start_time, + end_time=end_time, + event_metadata=event_metadata, + error_override=error or "error", + ) + + def _emit_service( + self, + payload: Any, + *, + parent_otel_span: Span | None, + start_time: datetime | float | None, + end_time: datetime | float | None, + event_metadata: dict | None, + error_override: str | None, + ) -> Span | None: + data = ServiceSpanData.from_payload(payload, event_metadata=event_metadata) + # Decide whether this service call is a span at all, and of what kind. + # ``None`` means metrics-only (framework instrumentation that duplicates a + # gen-AI span — ``self``/``router``/``proxy_pre_call`` — or ``auth``, which + # gets a live phase span instead). Those still feed Prometheus/Datadog via + # their own hooks; they just never enter the trace. + role = span_role_for_service(data.service_name) + if role is None: + return None + # A metrics-only ping with neither timing nor a parent (in-memory queue + # gauges) is not a traceable operation; a span for it would be a + # zero-duration root with no context, so skip it. Real background work + # (budget/reset jobs, spend flush) passes start/end times and still emits + # as a root; anything with a parent emits regardless. + if ( + error_override is None + and start_time is None + and end_time is None + and parent_otel_span is None + ): + return None + if error_override is not None and data.error is None: + data = ServiceSpanData( + service_name=data.service_name, + call_type=data.call_type, + error=SpanError(message=error_override), + event_metadata=data.event_metadata, + ) + # Parent like every other span: ambient context first (so identity Baggage + # rides along and the call nests under whatever request phase is active — + # e.g. a DB lookup under the live ``auth`` span), falling back to the + # server span the proxy threaded as ``parent_otel_span``. A background + # service call has neither, so it starts its own root trace. + parent_context = resolve_parent_context(threaded=parent_otel_span) + return self._emitter.emit( + role, + data, + parent_context=parent_context, + start_time_ns=to_ns(start_time), + end_time_ns=to_ns(end_time), + ) + + # ====================================================================== # + # async_post_call_* hooks — emit guardrail spans. The server span's status + # / errors are the FastAPI instrumentor's job, so we don't touch it here. + # ====================================================================== # + + def seed_request_identity(self, user_api_key_dict: Any, model: Any = None) -> None: + """Attach request-identity Baggage to the current context + server span. + + Seeding identity into Baggage makes **every** span emitted afterwards for + this request — LLM call, guardrail, DB call — inherit it via + ``LiteLLMBaggageSpanProcessor``. Called once at the auth boundary (as soon + as the key resolves) so post-auth spans are labeled consistently; the + Baggage rides the request task's contextvar from there on. Auth-internal + DB lookups that run before the key is known stay unlabeled — identity + isn't determined yet, which is correct. + """ + try: + identity = RequestIdentity.from_user_api_key_auth(user_api_key_dict) + bag = promoted_baggage( + identity, + model, + promoted_keys=tuple(self.config.baggage_promoted_keys), + metadata_keys=tuple(self.config.baggage_metadata_keys), + ) + if bag: + # Attach (no detach): the contextvar is scoped to this request's + # asyncio task and is reclaimed when the task ends. + attach(set_request_baggage(bag, context=get_current())) + # The server span was started by the instrumentor before this ran, + # so the Baggage processor (which only fires at span start) won't + # backfill it — stamp identity on it directly. + server_span = get_current_span() + if is_recordable_span(server_span): + # Re-capture the anchor here too: this runs post-auth with the + # server span active and covers entrypoints that bypass + # ``create_litellm_proxy_request_started_span`` (e.g. the SDK + # path's ``async_pre_call_hook``). Idempotent. + set_request_root_span(server_span) + for key, value in bag.items(): + server_span.set_attribute(key, value) + except Exception: + pass + + @contextmanager + def start_phase_span(self, name: str) -> "Iterator[Span]": + span = self._emitter.start_span(SpanRole.SERVICE, name) + with use_span(span, end_on_exit=True): + yield span + + async def async_pre_call_hook( + self, + user_api_key_dict: Any, + cache: Any, + data: dict, + call_type: Any, + ) -> dict: + self.seed_request_identity( + user_api_key_dict, + model=model_from_request_data(data), + ) + return data + + async def async_post_call_success_hook( + self, + data: Mapping[str, Any], + user_api_key_dict: Any, + response: Any, + ) -> Any: + self._emit_guardrail_spans(data) + return response + + async def async_post_call_failure_hook( + self, + request_data: Mapping[str, Any], + original_exception: BaseException | None, + user_api_key_dict: Any, + traceback_str: str | None = None, + ) -> None: + self._emit_guardrail_spans(request_data) + + def _emit_guardrail_spans(self, request_data: Mapping[str, Any]) -> None: + # A guardrail is a sibling of the LLM call under the request's root span, + # so parent it to the explicit anchor — not the active span, which on the + # failure path can be the live ``auth`` phase span (post-call failure hooks + # run from inside it on an auth rejection). Emit with the guardrail's actual + # execution window so a pre_call guardrail is placed before the LLM call + # rather than at post-call emission time. + guardrails = guardrail_entries_from_request_data(request_data) + if not guardrails: + return + parent_ctx = resolve_request_span_context() + for entry in guardrails: + data = GuardrailSpanData.from_logging_entry( + cast("StandardLoggingGuardrailInformation", entry) + ) + self._emitter.emit( + SpanRole.GUARDRAIL, + data, + parent_context=parent_ctx, + start_time_ns=to_ns(data.start_time), + end_time_ns=to_ns(data.end_time), + ) + + def create_litellm_proxy_request_started_span( + self, start_time: datetime, headers: Mapping[str, str] | None + ) -> Span | None: + span = get_current_span() + if not is_recordable_span(span): + return None + set_request_root_span(span) + return span + + +def _registered_v2_logger() -> "OpenTelemetryV2 | None": + try: + from litellm.proxy import proxy_server + except Exception: + return None + logger = getattr(proxy_server, "open_telemetry_logger", None) + return logger if isinstance(logger, OpenTelemetryV2) else None + + +def seed_request_identity(user_api_key_dict: Any, model: Any = None) -> None: + logger = _registered_v2_logger() + if logger is not None: + logger.seed_request_identity(user_api_key_dict, model=model) + + +@contextmanager +def phase_span(name: str) -> "Iterator[Span | None]": + logger = _registered_v2_logger() + if logger is None: + yield None + return + with logger.start_phase_span(name) as span: + yield span diff --git a/litellm/integrations/otel/mappers/__init__.py b/litellm/integrations/otel/mappers/__init__.py new file mode 100644 index 00000000000..012e63f1bee --- /dev/null +++ b/litellm/integrations/otel/mappers/__init__.py @@ -0,0 +1,58 @@ +"""Attribute mappers: pure ``LLMCallSpanData -> {attribute key: value}`` functions. + +Composition over inheritance: vocabularies layer onto the same span. Listing +``["genai", "openinference"]`` in ``config.mapper_names`` makes every span +carry both the canonical ``gen_ai.*`` keys and the OpenInference (Arize + +Phoenix) keys. Add ``"langfuse"`` and it works for all three backends at once. +""" + +from typing import Callable, Iterable + +from litellm.integrations.otel.mappers.base import ( + AttributeMap, + AttributeMapper, + AttrValue, +) +from litellm.integrations.otel.mappers.genai import GenAIMapper +from litellm.integrations.otel.mappers.langfuse import LangfuseMapper +from litellm.integrations.otel.mappers.langtrace import LangtraceMapper +from litellm.integrations.otel.mappers.legacy import LegacyMapper +from litellm.integrations.otel.mappers.openinference import OpenInferenceMapper +from litellm.integrations.otel.mappers.weave import WeaveMapper + +# Registry keyed by ``config.mapper_names`` entries. +_MAPPER_BY_NAME: dict[str, Callable[[], AttributeMapper]] = { + "genai": GenAIMapper, + "legacy": LegacyMapper, + "openinference": OpenInferenceMapper, + "langfuse": LangfuseMapper, + "weave": WeaveMapper, + "langtrace": LangtraceMapper, +} + + +def resolve_mappers(names: Iterable[str]) -> list[AttributeMapper]: + """Resolve mapper names to instances. Unknown names raise ``ValueError``.""" + out: list[AttributeMapper] = [] + for name in names: + factory = _MAPPER_BY_NAME.get(name) + if factory is None: + raise ValueError( + f"unknown mapper name {name!r}; known: " f"{sorted(_MAPPER_BY_NAME)}" + ) + out.append(factory()) + return out + + +__all__ = [ + "AttributeMap", + "AttributeMapper", + "AttrValue", + "GenAIMapper", + "LangfuseMapper", + "LangtraceMapper", + "LegacyMapper", + "OpenInferenceMapper", + "WeaveMapper", + "resolve_mappers", +] diff --git a/litellm/integrations/otel/mappers/base.py b/litellm/integrations/otel/mappers/base.py new file mode 100644 index 00000000000..e8fb5af9797 --- /dev/null +++ b/litellm/integrations/otel/mappers/base.py @@ -0,0 +1,36 @@ +"""Mapper protocol and attribute value types.""" + +from typing import Sequence + +from typing_extensions import Protocol, runtime_checkable + +from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + ServiceSpanData, +) + +AttrScalar = str | bool | int | float +# Mirrors ``opentelemetry.util.types.AttributeValue`` (homogeneous sequences) +# without importing the SDK, so mappers stay OTel-free. +AttrValue = ( + AttrScalar | Sequence[str] | Sequence[bool] | Sequence[int] | Sequence[float] +) +AttributeMap = dict[str, AttrValue] + +# The closed set of span-data types the engine routes through the mapper chain. +# Server spans (PROXY_REQUEST + management routes) belong to the mounted FastAPI +# instrumentor, not the mapper chain. +SpanData = LLMCallSpanData | GuardrailSpanData | ServiceSpanData + + +@runtime_checkable +class AttributeMapper(Protocol): + """Maps a typed span input to a flat dict of OTel span attributes. + + One method per mapper, dispatched internally on the ``data`` type. The + engine calls this uniformly for every span kind — mappers that don't speak + a given type return ``{}``. This is why the engine contains no attribute keys. + """ + + def map(self, data: SpanData) -> AttributeMap: ... diff --git a/litellm/integrations/otel/mappers/genai.py b/litellm/integrations/otel/mappers/genai.py new file mode 100644 index 00000000000..57fa51ea1fb --- /dev/null +++ b/litellm/integrations/otel/mappers/genai.py @@ -0,0 +1,137 @@ +"""Canonical OpenTelemetry GenAI semantic-convention mapper (always active). + +Owns the attribute schema for every span kind the engine emits — LLM call, +guardrail, and service — so the engine itself never references attribute keys. + +Each span kind declares its schema as a flat ``attribute key -> extractor`` +table: one lambda per mapping operation, applied against the typed span data. +""" + +from typing import Callable + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import collect, drop_none +from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + ServiceSpanData, + ToolDefinition, +) +from litellm.integrations.otel.model.semconv import DB, Error, GenAI, LiteLLM, Server +from litellm.integrations.otel.model.spans import db_system + + +class GenAIMapper: + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + GenAI.OPERATION_NAME: lambda d: d.operation.value, + GenAI.PROVIDER_NAME: lambda d: d.provider or None, + GenAI.REQUEST_MODEL: lambda d: d.request_model or None, + GenAI.REQUEST_TEMPERATURE: lambda d: d.request_params.temperature, + GenAI.REQUEST_TOP_P: lambda d: d.request_params.top_p, + GenAI.REQUEST_TOP_K: lambda d: d.request_params.top_k, + GenAI.REQUEST_MAX_TOKENS: lambda d: d.request_params.max_tokens, + GenAI.REQUEST_FREQUENCY_PENALTY: lambda d: d.request_params.frequency_penalty, + GenAI.REQUEST_PRESENCE_PENALTY: lambda d: d.request_params.presence_penalty, + GenAI.REQUEST_STOP_SEQUENCES: lambda d: ( + list(d.request_params.stop_sequences) + if d.request_params.stop_sequences + else None + ), + GenAI.REQUEST_SEED: lambda d: d.request_params.seed, + GenAI.RESPONSE_MODEL: lambda d: d.response_model, + GenAI.RESPONSE_ID: lambda d: d.response_id, + GenAI.RESPONSE_FINISH_REASONS: lambda d: ( + list(d.finish_reasons) if d.finish_reasons else None + ), + GenAI.USAGE_INPUT_TOKENS: lambda d: d.usage.input_tokens, + GenAI.USAGE_OUTPUT_TOKENS: lambda d: d.usage.output_tokens, + Error.TYPE: lambda d: d.error.error_type if d.error else None, + Server.ADDRESS: lambda d: d.server.address if d.server else None, + Server.PORT: lambda d: d.server.port if d.server else None, + LiteLLM.CALL_ID: lambda d: d.identity.call_id or None, + # The provider/underlying model is only known once routing has picked a + # deployment, so it can't ride identity Baggage (seeded at auth, before + # routing) onto the boundary-born LLM span — stamp it directly here. + LiteLLM.PROVIDER_MODEL: lambda d: d.identity.provider_model or None, + f"{LiteLLM.COST_PREFIX}total": lambda d: d.response_cost, + LiteLLM.REQUEST_STREAMING: lambda d: d.is_streaming, + } + + _TOOL_ATTRS: dict[str, Callable[[ToolDefinition], AttrValue | None]] = { + "name": lambda t: t.name, + "description": lambda t: t.description or None, + "parameters": lambda t: t.parameters_json or None, + } + + _GUARDRAIL_ATTRS: dict[str, Callable[[GuardrailSpanData], AttrValue | None]] = { + LiteLLM.GUARDRAIL_NAME: lambda d: d.guardrail_name, + LiteLLM.GUARDRAIL_MODE: lambda d: d.mode, + LiteLLM.GUARDRAIL_STATUS: lambda d: d.status, + LiteLLM.GUARDRAIL_PROVIDER: lambda d: d.provider, + LiteLLM.GUARDRAIL_ACTION: lambda d: d.action, + LiteLLM.GUARDRAIL_RESPONSE: lambda d: d.response_json, + LiteLLM.GUARDRAIL_VIOLATION_CATEGORIES: lambda d: ( + list(d.violation_categories) if d.violation_categories else None + ), + LiteLLM.GUARDRAIL_CONFIDENCE_SCORE: lambda d: d.confidence_score, + LiteLLM.GUARDRAIL_RISK_SCORE: lambda d: d.risk_score, + LiteLLM.GUARDRAIL_MASKED_ENTITY_COUNT: lambda d: d.masked_entity_count, + LiteLLM.GUARDRAIL_DURATION: lambda d: d.duration, + LiteLLM.GUARDRAIL_ID: lambda d: d.guardrail_id, + LiteLLM.GUARDRAIL_POLICY_TEMPLATE: lambda d: d.policy_template, + LiteLLM.GUARDRAIL_DETECTION_METHOD: lambda d: d.detection_method, + } + + _SERVICE_ATTRS: dict[str, Callable[[ServiceSpanData], AttrValue | None]] = { + LiteLLM.SERVICE_NAME: lambda d: d.service_name, + LiteLLM.SERVICE_CALL_TYPE: lambda d: d.call_type, + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case GuardrailSpanData(): + return self._guardrail(data) + case ServiceSpanData(): + return self._service(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + attrs = collect(cls._LLM_CALL_ATTRS, data) + attrs.update( + drop_none( + { + f"gen_ai.tool.{idx}.{suffix}": extract(tool) + for idx, tool in enumerate(data.tools) + for suffix, extract in cls._TOOL_ATTRS.items() + } + ) + ) + return attrs + + @classmethod + def _guardrail(cls, data: GuardrailSpanData) -> AttributeMap: + return collect(cls._GUARDRAIL_ATTRS, data) + + @classmethod + def _service(cls, data: ServiceSpanData) -> AttributeMap: + attrs = collect(cls._SERVICE_ATTRS, data) + # An outbound datastore call (DB_CALL / CLIENT span) also carries db.* + # semconv. Internal services (router, budget jobs, …) have no db.system, + # so they get only the litellm.service.* keys above. + system = db_system(data.service_name) + if system is not None: + attrs[DB.SYSTEM_NAME] = system + if data.call_type: + attrs[DB.OPERATION_NAME] = data.call_type + attrs.update( + { + f"{LiteLLM.METADATA_PREFIX}{key}": value + for key, value in data.event_metadata.items() + } + ) + return attrs diff --git a/litellm/integrations/otel/mappers/langfuse.py b/litellm/integrations/otel/mappers/langfuse.py new file mode 100644 index 00000000000..14c9fd01d05 --- /dev/null +++ b/litellm/integrations/otel/mappers/langfuse.py @@ -0,0 +1,84 @@ +"""Langfuse OTLP attribute mapper. + +Langfuse ingests OTLP spans and reads from its own vendor namespace +(``langfuse.observation.*``, ``langfuse.trace.*``). Compose this mapper after +``GenAIMapper`` to send canonical + Langfuse-flavored spans simultaneously. + +Every attribute is declared as a ``key -> extractor`` table entry (one callable +per mapping operation): ``_LLM_CALL_ATTRS`` for scalars and ``_BLOB_ATTRS`` for +the JSON-serialized payloads. ``_llm_call`` just applies both tables. +""" + +import json +from typing import Callable + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import ( + collect, + json_if, + output_messages, + serialize_messages, +) +from litellm.integrations.otel.model.payloads import ( + LLMCallSpanData, + LLMRequestParams, + LLMUsage, +) + + +class LangfuseMapper: + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "langfuse.observation.type": lambda d: "generation", + "langfuse.observation.model.name": lambda d: d.request_model or None, + "langfuse.observation.metadata.provider": lambda d: d.provider or None, + "langfuse.observation.id": lambda d: d.identity.call_id or None, + "langfuse.trace.metadata.team_id": lambda d: d.identity.team_id or None, + "langfuse.trace.metadata.team_alias": lambda d: d.identity.team_alias or None, + } + + # Sub-tables folded into their respective JSON blobs. + _MODEL_PARAMS: dict[str, Callable[[LLMRequestParams], AttrValue | None]] = { + "temperature": lambda rp: rp.temperature, + "top_p": lambda rp: rp.top_p, + "max_tokens": lambda rp: rp.max_tokens, + "frequency_penalty": lambda rp: rp.frequency_penalty, + "presence_penalty": lambda rp: rp.presence_penalty, + "seed": lambda rp: rp.seed, + } + _USAGE_FIELDS: dict[str, Callable[[LLMUsage], AttrValue | None]] = { + "input": lambda u: u.input_tokens, + "output": lambda u: u.output_tokens, + "total": lambda u: u.total_tokens, + } + + # JSON-payload attributes: each builder returns the serialized blob or None. + _BLOB_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "langfuse.observation.model.parameters": lambda d: json_if( + collect(LangfuseMapper._MODEL_PARAMS, d.request_params) + ), + "langfuse.observation.input": lambda d: serialize_messages(d.messages_in), + "langfuse.observation.output": lambda d: serialize_messages(output_messages(d)), + "langfuse.observation.usage_details": lambda d: json_if( + collect(LangfuseMapper._USAGE_FIELDS, d.usage) + ), + "langfuse.observation.cost_details": lambda d: ( + json.dumps({"total": d.response_cost}) + if d.response_cost is not None + else None + ), + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + return { + **collect(cls._LLM_CALL_ATTRS, data), + **collect(cls._BLOB_ATTRS, data), + } diff --git a/litellm/integrations/otel/mappers/langtrace.py b/litellm/integrations/otel/mappers/langtrace.py new file mode 100644 index 00000000000..7c0f30e57dd --- /dev/null +++ b/litellm/integrations/otel/mappers/langtrace.py @@ -0,0 +1,64 @@ +"""Langtrace attribute mapper. + +Produces Langtrace's attribute vocabulary so a span can be ingested by a +Langtrace backend. Compose it alongside other mappers like any other +vocabulary. + +Scalar attributes are declared as a flat ``key -> extractor`` table (one lambda +per mapping operation); the prompt/completion blobs are serialized as a tail. +""" + +from typing import Callable + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import ( + collect, + json_or_none, + output_messages, +) +from litellm.integrations.otel.model.payloads import LLMCallSpanData + + +class LangtraceMapper: + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "gen_ai.operation.name": lambda d: "chat", + "langtrace.service.name": lambda d: d.provider or None, + "llm.model": lambda d: d.request_model or None, + "gen_ai.response.model": lambda d: d.response_model or None, + "gen_ai.response_id": lambda d: d.response_id or None, + "gen_ai.system_fingerprint": lambda d: d.system_fingerprint or None, + "llm.temperature": lambda d: d.request_params.temperature, + "llm.top_p": lambda d: d.request_params.top_p, + "llm.top_k": lambda d: d.request_params.top_k, + "llm.max_tokens": lambda d: d.request_params.max_tokens, + "llm.frequency_penalty": lambda d: d.request_params.frequency_penalty, + "llm.presence_penalty": lambda d: d.request_params.presence_penalty, + "llm.stream": lambda d: d.is_streaming, + "llm.token.counts.prompt": lambda d: d.usage.input_tokens, + "llm.token.counts.completion": lambda d: d.usage.output_tokens, + "llm.token.counts.total": lambda d: d.usage.total_tokens, + } + + _BLOB_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "llm.prompts": lambda d: ( + json_or_none(list(d.messages_in)) if d.messages_in else None + ), + "llm.completions": lambda d: ( + json_or_none(output_messages(d)) if d.choices_out else None + ), + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + return { + **collect(cls._LLM_CALL_ATTRS, data), + **collect(cls._BLOB_ATTRS, data), + } diff --git a/litellm/integrations/otel/mappers/legacy.py b/litellm/integrations/otel/mappers/legacy.py new file mode 100644 index 00000000000..20ffe8b0dd8 --- /dev/null +++ b/litellm/integrations/otel/mappers/legacy.py @@ -0,0 +1,97 @@ +"""Mapper for the older semantic-convention attribute vocabulary. + +Emits attributes under the semconv-ai / Traceloop key names (e.g. +``gen_ai.system``, ``gen_ai.usage.prompt_tokens``, ``llm.is_streaming``) plus a +few bare, unprefixed service keys (``service``, ``call_type``, ``error``), for +backends that consume those names. + +Like ``GenAIMapper``, each span kind declares its schema as a flat +``attribute key -> extractor`` table: one lambda per mapping operation. +""" + +from typing import Callable, Final + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import collect, drop_none +from litellm.integrations.otel.model.payloads import ( + LLMCallSpanData, + ServiceSpanData, + ToolDefinition, +) + +# Attribute keys in the semconv-ai / Traceloop vocabulary. +_LEGACY_SYSTEM: Final = "gen_ai.system" +_LEGACY_PROMPT_TOKENS: Final = "gen_ai.usage.prompt_tokens" +_LEGACY_COMPLETION_TOKENS: Final = "gen_ai.usage.completion_tokens" +_LEGACY_TOTAL_TOKENS: Final = "gen_ai.usage.total_tokens" +_LEGACY_IS_STREAMING: Final = "llm.is_streaming" +_LEGACY_TOP_K: Final = "llm.top_k" +_LEGACY_FREQUENCY_PENALTY: Final = "llm.frequency_penalty" +_LEGACY_PRESENCE_PENALTY: Final = "llm.presence_penalty" +_LEGACY_STOP_SEQUENCES: Final = "llm.chat.stop_sequences" +_LEGACY_SERVICE: Final = "service" +_LEGACY_CALL_TYPE: Final = "call_type" +_LEGACY_ERROR: Final = "error" + + +class LegacyMapper: + """Emits LLM-call and service attributes under the older key names.""" + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + _LEGACY_SYSTEM: lambda d: d.provider or None, + _LEGACY_PROMPT_TOKENS: lambda d: d.usage.input_tokens, + _LEGACY_COMPLETION_TOKENS: lambda d: d.usage.output_tokens, + _LEGACY_TOTAL_TOKENS: lambda d: d.usage.total_tokens, + _LEGACY_IS_STREAMING: lambda d: d.is_streaming, + _LEGACY_TOP_K: lambda d: d.request_params.top_k, + _LEGACY_FREQUENCY_PENALTY: lambda d: d.request_params.frequency_penalty, + _LEGACY_PRESENCE_PENALTY: lambda d: d.request_params.presence_penalty, + _LEGACY_STOP_SEQUENCES: lambda d: ( + list(d.request_params.stop_sequences) + if d.request_params.stop_sequences + else None + ), + } + + _TOOL_ATTRS: dict[str, Callable[[ToolDefinition], AttrValue | None]] = { + "name": lambda t: t.name, + "description": lambda t: t.description or None, + "parameters": lambda t: t.parameters_json or None, + } + + _SERVICE_ATTRS: dict[str, Callable[[ServiceSpanData], AttrValue | None]] = { + _LEGACY_SERVICE: lambda d: d.service_name, + _LEGACY_CALL_TYPE: lambda d: d.call_type, + _LEGACY_ERROR: lambda d: ( + d.error.message if d.error is not None and d.error.message else None + ), + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case ServiceSpanData(): + return self._service(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + attrs = collect(cls._LLM_CALL_ATTRS, data) + attrs.update( + drop_none( + { + f"llm.request.functions.{idx}.{suffix}": extract(tool) + for idx, tool in enumerate(data.tools) + for suffix, extract in cls._TOOL_ATTRS.items() + } + ) + ) + return attrs + + @classmethod + def _service(cls, data: ServiceSpanData) -> AttributeMap: + attrs = collect(cls._SERVICE_ATTRS, data) + attrs.update(dict(data.event_metadata)) + return attrs diff --git a/litellm/integrations/otel/mappers/openinference.py b/litellm/integrations/otel/mappers/openinference.py new file mode 100644 index 00000000000..d8195cbe03d --- /dev/null +++ b/litellm/integrations/otel/mappers/openinference.py @@ -0,0 +1,128 @@ +"""OpenInference attribute mapper (Arize + Arize-Phoenix shared vocabulary). + +Spec: https://github.com/Arize-ai/openinference/tree/main/spec — the standard +both Arize and Phoenix consume. Composing this mapper after ``GenAIMapper`` +gives the same span both vocabularies, so a single trace lights up Arize + +Phoenix + any other OpenInference-aware backend simultaneously. +""" + +import json +from typing import Callable, Sequence + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import ( + collect, + drop_none, + json_if, + message_content, + output_messages, +) +from litellm.integrations.otel.model.payloads import ( + LLMCallSpanData, + LLMRequestParams, + ToolDefinition, +) + + +class OpenInferenceMapper: + """Emits OpenInference attributes for LLM_CALL spans. + + Key families (per the OpenInference spec): + - ``openinference.span.kind`` — discriminator (``"LLM"`` here) + - ``llm.model_name`` / ``llm.provider`` / ``llm.invocation_parameters`` + - ``llm.input_messages.{i}.message.role`` / ``...content`` + - ``llm.output_messages.{i}.message.role`` / ``...content`` + - ``llm.token_count.prompt`` / ``...completion`` / ``...total`` + - ``input.value`` / ``output.value`` — JSON-serialized request / response + """ + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "openinference.span.kind": lambda d: "LLM", + "llm.model_name": lambda d: d.request_model or None, + "llm.provider": lambda d: d.provider or None, + "llm.token_count.prompt": lambda d: d.usage.input_tokens, + "llm.token_count.completion": lambda d: d.usage.output_tokens, + "llm.token_count.total": lambda d: d.usage.total_tokens, + } + + # Folded into the ``llm.invocation_parameters`` JSON blob. + _INVOCATION_PARAMS: dict[str, Callable[[LLMRequestParams], AttrValue | None]] = { + "temperature": lambda rp: rp.temperature, + "top_p": lambda rp: rp.top_p, + "top_k": lambda rp: rp.top_k, + "max_tokens": lambda rp: rp.max_tokens, + "frequency_penalty": lambda rp: rp.frequency_penalty, + "presence_penalty": lambda rp: rp.presence_penalty, + "seed": lambda rp: rp.seed, + } + + # Per-tool extractors, keyed by the ``llm.tools.{idx}.*`` suffix. + _TOOL_ATTRS: dict[str, Callable[[ToolDefinition], AttrValue | None]] = { + "tool.name": lambda t: t.name, + "tool.description": lambda t: t.description or None, + "tool.json_schema": lambda t: t.parameters_json or None, + } + + # JSON-payload attributes: each builder returns the serialized blob or None. + _BLOB_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + "llm.invocation_parameters": lambda d: json_if( + collect(OpenInferenceMapper._INVOCATION_PARAMS, d.request_params) + ), + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + return { + **collect(cls._LLM_CALL_ATTRS, data), + **collect(cls._BLOB_ATTRS, data), + **cls._messages("llm.input_messages", "input.value", data.messages_in), + **cls._messages( + "llm.output_messages", "output.value", output_messages(data) + ), + **cls._tools(data), + } + + @staticmethod + def _messages( + prefix: str, value_key: str, messages: Sequence[object] + ) -> AttributeMap: + """Per-message ``{prefix}.{idx}.message.*`` keys + the ``value_key`` blob.""" + parsed = [ + (m.get("role") if isinstance(m, dict) else None, message_content(m)) + for m in messages + ] + attrs = drop_none( + { + key: value + for idx, (role, content) in enumerate(parsed) + for key, value in ( + ( + f"{prefix}.{idx}.message.role", + role if isinstance(role, str) else None, + ), + (f"{prefix}.{idx}.message.content", content), + ) + } + ) + if parsed: + attrs[value_key] = json.dumps( + [{"role": role, "content": content} for role, content in parsed] + ) + return attrs + + @classmethod + def _tools(cls, data: LLMCallSpanData) -> AttributeMap: + return drop_none( + { + f"llm.tools.{idx}.{suffix}": extract(tool) + for idx, tool in enumerate(data.tools) + for suffix, extract in cls._TOOL_ATTRS.items() + } + ) diff --git a/litellm/integrations/otel/mappers/utils.py b/litellm/integrations/otel/mappers/utils.py new file mode 100644 index 00000000000..6228fc8bbe7 --- /dev/null +++ b/litellm/integrations/otel/mappers/utils.py @@ -0,0 +1,76 @@ +"""Shared helpers for the attribute mappers. + +Small, mapper-agnostic utilities — JSON serialization, message extraction, and +extractor-table application — pulled out of the individual mapper modules so +they live in one place. +""" + +import json +from typing import Callable, Mapping, Sequence + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue +from litellm.integrations.otel.model.payloads import LLMCallSpanData + + +def drop_none(values: Mapping[str, AttrValue | None]) -> AttributeMap: + """Return ``values`` with ``None``-valued entries removed.""" + return {k: v for k, v in values.items() if v is not None} + + +def collect(table: Mapping[str, Callable], source: object) -> AttributeMap: + """Apply an extractor table to ``source``, dropping ``None`` results.""" + return drop_none({key: extract(source) for key, extract in table.items()}) + + +def json_if(payload: Mapping[str, object]) -> str | None: + """JSON-serialize ``payload`` only when it's non-empty; else ``None``.""" + return json.dumps(payload) if payload else None + + +def json_or_none(value: object) -> str | None: + """JSON-serialize ``value`` (falling back to ``str``); ``None`` on failure.""" + try: + return json.dumps(value, default=str) + except Exception: + return None + + +def stringify_message(message: object) -> str | None: + """JSON-serialize a chat message dict; ``None`` if not a dict or on failure.""" + if not isinstance(message, dict): + return None + try: + return json.dumps(message, default=str) + except Exception: + return None + + +def serialize_messages(messages: Sequence[object]) -> str | None: + """Round-trip a sequence of message dicts through ``stringify_message``.""" + serialized = [ + json.loads(s) for s in (stringify_message(m) for m in messages) if s is not None + ] + return json.dumps(serialized) if serialized else None + + +def message_content(message: object) -> str | None: + """Extract the textual ``content`` from a chat message dict.""" + if not isinstance(message, dict): + return None + content = message.get("content") + if isinstance(content, str): + return content + if isinstance(content, list): + # multimodal: concatenate text parts only + parts = [ + part.get("text", "") + for part in content + if isinstance(part, dict) and part.get("type") == "text" + ] + return "".join(p for p in parts if isinstance(p, str)) or None + return None + + +def output_messages(data: LLMCallSpanData) -> list: + """The ``message`` payload of each response choice.""" + return [c.get("message") for c in data.choices_out if isinstance(c, dict)] diff --git a/litellm/integrations/otel/mappers/weave.py b/litellm/integrations/otel/mappers/weave.py new file mode 100644 index 00000000000..54b07299271 --- /dev/null +++ b/litellm/integrations/otel/mappers/weave.py @@ -0,0 +1,48 @@ +"""Weave (W&B) attribute mapper. + +Weave consumes OpenInference + a small set of Weave-specific keys (display +name, thread id, output value). This mapper layers the latter on top of +OpenInference's vocabulary — compose ``["genai", "openinference", "weave"]`` +to feed a Weave backend. +""" + +from typing import Callable + +from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData +from litellm.integrations.otel.mappers.utils import collect, json_or_none +from litellm.integrations.otel.model.payloads import LLMCallSpanData + + +class WeaveMapper: + """Maps ``LLMCallSpanData`` to Weave's vendor attributes.""" + + _LLM_CALL_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + # ``display_name`` has the form ``"{operation} {model}"``. The span + # name already covers that, but Weave reads this attribute too. + "weave.display_name": lambda d: ( + f"{d.operation.value} {d.request_model}" if d.request_model else None + ), + "weave.call_id": lambda d: d.identity.call_id or None, + } + + # JSON-payload attributes: each builder returns the serialized blob or None. + _BLOB_ATTRS: dict[str, Callable[[LLMCallSpanData], AttrValue | None]] = { + # Weave treats the response choices as the "output" payload. + "weave.output": lambda d: ( + json_or_none(list(d.choices_out)) if d.choices_out else None + ), + } + + def map(self, data: SpanData) -> AttributeMap: + match data: + case LLMCallSpanData(): + return self._llm_call(data) + case _: + return {} + + @classmethod + def _llm_call(cls, data: LLMCallSpanData) -> AttributeMap: + return { + **collect(cls._LLM_CALL_ATTRS, data), + **collect(cls._BLOB_ATTRS, data), + } diff --git a/litellm/integrations/otel/model/__init__.py b/litellm/integrations/otel/model/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/litellm/integrations/otel/model/baggage.py b/litellm/integrations/otel/model/baggage.py new file mode 100644 index 00000000000..67dd64e3914 --- /dev/null +++ b/litellm/integrations/otel/model/baggage.py @@ -0,0 +1,76 @@ +"""Baggage promotion: request-identity values carried across child spans. + +A bounded set of identity values is written into OpenTelemetry Baggage on the +LLM-call span so that child spans (guardrail, service) inherit them. +``providers.LiteLLMBaggageSpanProcessor`` reads Baggage at span start and stamps +the allowlisted keys onto every span. + +This module is the single place baggage is defined: ``_PROMOTABLE`` maps each +promotable attribute key to how its value is read, and the two ``*_KEYS`` +defaults select what is promoted unless the config overrides them. +""" + +from collections.abc import Callable +from typing import Final + +from litellm.integrations.otel.model.metadata import RequestIdentity +from litellm.integrations.otel.model.semconv import GenAI, LiteLLM + +# Attribute key -> value extractor over (identity, request_model). The single +# definition of what may be promoted and under which key. +_PROMOTABLE: Final[dict[str, Callable[[RequestIdentity, str | None], str | None]]] = { + LiteLLM.TEAM_ID: lambda identity, model: identity.team_id, + LiteLLM.TEAM_ALIAS: lambda identity, model: identity.team_alias, + LiteLLM.TEAM_METADATA: lambda identity, model: identity.team_metadata, + LiteLLM.KEY_HASH: lambda identity, model: identity.key_hash, + LiteLLM.END_USER: lambda identity, model: identity.end_user, + GenAI.REQUEST_MODEL: lambda identity, model: model, + LiteLLM.PROVIDER_MODEL: lambda identity, model: identity.provider_model, +} + +# Keys promoted by default (a subset of ``_PROMOTABLE``). ``END_USER`` is +# promotable but off by default — it identifies an individual user, so stamping +# it onto every span is opt-in via ``config.baggage_promoted_keys``. +BAGGAGE_PROMOTED_KEYS: Final[tuple[str, ...]] = ( + LiteLLM.TEAM_ID, + LiteLLM.TEAM_ALIAS, + LiteLLM.TEAM_METADATA, + LiteLLM.KEY_HASH, + GenAI.REQUEST_MODEL, + LiteLLM.PROVIDER_MODEL, +) + +# Metadata sub-keys eligible for promotion under the ``litellm.metadata.*`` +# namespace. The full metadata blob is never promoted; only this allowlist is. +DEFAULT_BAGGAGE_METADATA_KEYS: Final[tuple[str, ...]] = ( + "user_api_key_org_id", + "user_api_key_user_id", + "user_api_key_alias", + "user_api_key_end_user_id", + "requester_ip_address", +) + + +def promoted_baggage( + identity: RequestIdentity, + request_model: str | None, + promoted_keys: tuple[str, ...], + metadata_keys: tuple[str, ...] = DEFAULT_BAGGAGE_METADATA_KEYS, +) -> dict[str, str]: + """Identity values to write into Baggage, filtered to ``promoted_keys``. + + ``promoted_keys`` selects from ``_PROMOTABLE``; ``metadata_keys`` selects + sub-keys of ``identity.metadata`` to promote under ``litellm.metadata.*``. + Empty values are dropped. + """ + out: dict[str, str] = {} + for key, extract in _PROMOTABLE.items(): + if key in promoted_keys: + value = extract(identity, request_model) + if value: + out[key] = value + for meta_key in metadata_keys: + value = identity.metadata.get(meta_key) + if value: + out[f"{LiteLLM.METADATA_PREFIX}{meta_key}"] = value + return out diff --git a/litellm/integrations/otel/model/config.py b/litellm/integrations/otel/model/config.py new file mode 100644 index 00000000000..f78e1515ea1 --- /dev/null +++ b/litellm/integrations/otel/model/config.py @@ -0,0 +1,236 @@ +"""Typed configuration for the OpenTelemetry instrumentation.""" + +from typing import Any, List + +from pydantic import AliasChoices, BaseModel, Field, field_validator, model_validator +from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict +from typing_extensions import Annotated + +from litellm.integrations.otel.model.baggage import ( + BAGGAGE_PROMOTED_KEYS, + DEFAULT_BAGGAGE_METADATA_KEYS, +) + +#: Master feature-flag env var. The logger is inert until this is truthy. +OTEL_V2_ENV = "LITELLM_OTEL_V2" + + +class CaptureMessageContent(str): + NO_CONTENT = "no_content" + SPAN_ONLY = "span_only" + EVENT_ONLY = "event_only" + SPAN_AND_EVENT = "span_and_event" + + +class _OTelV2Flag(BaseSettings): + model_config = SettingsConfigDict(extra="ignore") + + enabled: bool = Field(default=False, validation_alias=AliasChoices(OTEL_V2_ENV)) + + +def is_otel_v2_enabled() -> bool: + return _OTelV2Flag().enabled + + +class ExporterSpec(BaseModel): + """One span-export destination. + + The shared ``TracerProvider`` attaches one ``SpanProcessor`` per spec, so + listing several specs sends every span to all of them at once (e.g. Arize + + Phoenix + your own Honeycomb). + """ + + model_config = {"extra": "forbid"} + + kind: str = Field( + default="console", + description="console | in_memory | otlp_http | otlp_grpc | ", + ) + endpoint: str | None = None + headers: str | None = None + options: dict[str, str] | None = Field( + default=None, + description=( + "Factory-specific configuration for a custom exporter ``kind`` " + "registered via ``providers.register_exporter_factory`` (e.g. an " + "API key a lazy-auth exporter fetches a token with). Ignored by the " + "built-in console/in_memory/otlp exporters." + ), + ) + use_simple_processor: bool | None = Field( + default=None, + description=( + "Force SimpleSpanProcessor regardless of exporter kind. Default: " + "auto (Simple for console/in_memory, Batch otherwise)." + ), + ) + + +class OpenTelemetryV2Config(BaseSettings): + model_config = SettingsConfigDict(populate_by_name=True, extra="ignore") + + # ----- single-destination shorthand, read from standard OTEL_* envs ----- # + exporter: str = Field( + default="console", + validation_alias=AliasChoices("OTEL_EXPORTER", "OTEL_EXPORTER_OTLP_PROTOCOL"), + description=( + "Exporter kind for the single-destination shorthand. The model " + "validator folds this (with ``endpoint`` / ``headers``) into a " + "one-entry ``exporters`` list when ``exporters`` is empty; set " + "``exporters`` directly for multiple destinations." + ), + ) + endpoint: str | None = Field( + default=None, + validation_alias=AliasChoices("OTEL_ENDPOINT", "OTEL_EXPORTER_OTLP_ENDPOINT"), + ) + headers: str | None = Field( + default=None, + validation_alias=AliasChoices("OTEL_HEADERS", "OTEL_EXPORTER_OTLP_HEADERS"), + ) + service_name: str = Field( + default="litellm", validation_alias=AliasChoices("OTEL_SERVICE_NAME") + ) + deployment_environment: str | None = Field( + default=None, validation_alias=AliasChoices("OTEL_ENVIRONMENT_NAME") + ) + + enable_metrics: bool = Field( + default=False, + validation_alias=AliasChoices("LITELLM_OTEL_INTEGRATION_ENABLE_METRICS"), + ) + enable_events: bool = Field( + default=False, + validation_alias=AliasChoices("LITELLM_OTEL_INTEGRATION_ENABLE_EVENTS"), + ) + capture_message_content: str = Field( + default=CaptureMessageContent.NO_CONTENT, + validation_alias=AliasChoices( + "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT" + ), + ) + legacy_compat: bool = Field( + default=True, validation_alias=AliasChoices("LITELLM_OTEL_LEGACY_COMPAT") + ) + + # ----- explicit multi-destination / vocabulary configuration ------------ # + + exporters: list[ExporterSpec] = Field( + default_factory=list, + description=( + "One destination per spec. The shared TracerProvider attaches a " + "SpanProcessor per entry. When empty, the model validator folds " + "the ``exporter`` / ``endpoint`` / ``headers`` shorthand into a " + "single spec so there is always at least one destination." + ), + ) + + mapper_names: Annotated[List[str], NoDecode] = Field( + default_factory=lambda: ["genai"], + description=( + "Ordered attribute vocabularies to emit. ``genai`` is the " + "canonical OTel GenAI vocabulary and is always placed first. " + "Vendor names: ``openinference`` (Arize + Phoenix), ``langfuse``, " + "``weave``, ``langtrace``." + ), + ) + + resource_attributes: dict[str, str] = Field( + default_factory=dict, + description=( + "Extra Resource attributes beyond ``service.name`` and " + "``deployment.environment`` (e.g. integration-specific markers)." + ), + ) + + baggage_promoted_keys: Annotated[List[str], NoDecode] = Field( + default_factory=lambda: list(BAGGAGE_PROMOTED_KEYS), + validation_alias=AliasChoices( + "baggage_promoted_keys", "LITELLM_OTEL_BAGGAGE_PROMOTED_KEYS" + ), + description=( + "Identity attribute keys written into Baggage and stamped on every " + "child span (e.g. ``litellm.team.id``). Configure via the " + "``LITELLM_OTEL_BAGGAGE_PROMOTED_KEYS`` env var (comma-separated) or " + "``callback_settings.otel.baggage_promoted_keys`` in config.yaml (a " + "YAML list)." + ), + ) + baggage_metadata_keys: Annotated[List[str], NoDecode] = Field( + default_factory=lambda: list(DEFAULT_BAGGAGE_METADATA_KEYS), + validation_alias=AliasChoices( + "baggage_metadata_keys", "LITELLM_OTEL_BAGGAGE_METADATA_KEYS" + ), + description=( + "Metadata sub-keys promoted under the ``litellm.metadata.*`` " + "namespace. Configure via the ``LITELLM_OTEL_BAGGAGE_METADATA_KEYS`` " + "env var (comma-separated) or " + "``callback_settings.otel.baggage_metadata_keys`` in config.yaml." + ), + ) + + @field_validator( + "baggage_promoted_keys", + "baggage_metadata_keys", + "mapper_names", + mode="before", + ) + @classmethod + def _split_csv(cls, value: Any) -> Any: + """Accept a comma-separated string for list fields. + + Env vars are strings, but these fields are lists. Pydantic-settings would + otherwise require JSON for a list env var; splitting on commas here lets + an operator write ``LITELLM_OTEL_BAGGAGE_PROMOTED_KEYS=litellm.team.id,litellm.api_key.hash``. + YAML lists (from ``callback_settings.otel.*``) and real lists pass through + unchanged. + """ + if isinstance(value, str): + return [item.strip() for item in value.split(",") if item.strip()] + return value + + @model_validator(mode="after") + def _normalize(self) -> "OpenTelemetryV2Config": + # An endpoint with the default exporter kind implies OTLP/HTTP. + if self.endpoint and self.exporter == "console": + self.exporter = "otlp_http" + # When no explicit destinations are given, fold the single-destination + # shorthand into one spec so the provider always has a destination. + if not self.exporters: + self.exporters = [ + ExporterSpec( + kind=self.exporter, + endpoint=self.endpoint, + headers=self.headers, + ) + ] + # Ensure ``genai`` is always present and first. + names = list(self.mapper_names) + if "genai" in names: + names = ["genai"] + [n for n in names if n != "genai"] + else: + names = ["genai"] + names + # When enabled, also emit attribute keys under their semconv-ai / + # Traceloop names via the ``legacy`` mapper. Append it at the tail so + # the canonical ``genai`` keys win on any conflict. + if self.legacy_compat and "legacy" not in names: + names.append("legacy") + self.mapper_names = names + return self + + @property + def capture_span_content(self) -> bool: + """Whether prompt/response content may be stamped as span attributes. + + Defaults off (``no_content``): an operator must opt in before message + bodies leave the process, so a user request can never force its prompt + or completion into the configured backend while capture is disabled. + """ + return self.capture_message_content in ( + CaptureMessageContent.SPAN_ONLY, + CaptureMessageContent.SPAN_AND_EVENT, + ) + + @classmethod + def from_env(cls) -> "OpenTelemetryV2Config": + return cls() diff --git a/litellm/integrations/otel/model/metadata.py b/litellm/integrations/otel/model/metadata.py new file mode 100644 index 00000000000..f0ea0a608c6 --- /dev/null +++ b/litellm/integrations/otel/model/metadata.py @@ -0,0 +1,315 @@ +"""The single translation layer between a request's metadata and the spans. + +Every relevant field litellm exposes about a request — the user-facing model, +the model actually dispatched to the provider, the deployment, and the caller's +identity (team, key, end-user) — is parsed **once**, here, out of the +``StandardLoggingPayload`` (or a ``UserAPIKeyAuth`` at the auth boundary). Span +data, baggage promotion, and the mappers then read these typed fields instead of +each digging into the raw ``metadata`` / ``hidden_params`` dicts. + +Two models live here because a request's identity is known *before* its model +resolution is: + +* :class:`RequestIdentity` — team / key / end-user, seeded into Baggage at the + auth boundary (``from_user_api_key_auth``), before routing has picked a + deployment. ``provider_model`` is therefore absent from that early seed and is + only filled in from the payload once the call closes. +* :class:`RequestContext` — the full picture available at close: the resolved + request vs. provider model split, plus the response model, model group, model + id, and api base, wrapping the :class:`RequestIdentity`. + +The request-vs-provider model split is the subtle part. On the proxy a caller +asks for a *model group* (e.g. ``gpt-4o``) that routes to a concrete deployment +(e.g. ``azure/my-deployment``); the two are distinct and both worth recording. +``StandardLoggingPayload`` exposes them as: + +* ``model_group`` — the user-facing name the caller requested. +* ``model`` — already reconstructed (see ``reconstruct_model_name``) to the name + litellm dispatched to the provider (the deployment, provider-prefixed). +* ``hidden_params.litellm_model_name`` — a secondary source for the dispatched + model (populated only on some call paths, e.g. files). + +So ``gen_ai.request.model`` is the *group* (falling back to the call model on the +SDK path, which has no group), and ``litellm.provider.model`` is the *dispatched* +model. They coincide on the SDK path, which is correct. +""" + +from __future__ import annotations + +import json +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Mapping, cast + +from litellm.constants import LITELLM_LOGGING_NO_UPSTREAM_LLM_CALL +from litellm.integrations.otel.model.semconv import resolve_operation +from litellm.integrations.otel.model.utils import as_str + +if TYPE_CHECKING: + from litellm.types.utils import StandardLoggingPayload + + +@dataclass(frozen=True) +class RequestIdentity: + call_id: str | None = None + team_id: str | None = None + team_alias: str | None = None + # The team's free-form metadata dict, JSON-serialized (empty/missing -> None). + team_metadata: str | None = None + key_hash: str | None = None + end_user: str | None = None + # The model litellm dispatched to the provider. Only known once the call + # completes (routing has picked a deployment), so it's absent from the + # auth-time seed and filled only from the payload. + provider_model: str | None = None + metadata: Mapping[str, str] = field(default_factory=dict) + + @classmethod + def from_payload(cls, payload: "StandardLoggingPayload") -> "RequestIdentity": + """Parse caller identity out of a closed request's payload metadata. + + ``provider_model`` is resolved here too (see :func:`resolve_provider_model`) + so the identity carried into Baggage labels every span with the dispatched + model, not just the user-facing one. + """ + raw_meta = cast(Mapping[str, object], payload.get("metadata") or {}) + metadata = { + key: str(value) + for key, value in raw_meta.items() + if isinstance(value, (str, bool, int, float)) + } + return cls( + call_id=as_str(payload.get("litellm_call_id")) or as_str(payload.get("id")), + # StandardLoggingMetadata's canonical key is ``user_api_key_team_id``; + # the bare ``team_id`` is a legacy alias and is often empty, so prefer + # the canonical key and fall back to the alias. + team_id=as_str(raw_meta.get("user_api_key_team_id")) + or as_str(raw_meta.get("team_id")), + team_alias=as_str(raw_meta.get("user_api_key_team_alias")) + or as_str(raw_meta.get("team_alias")), + team_metadata=_team_metadata_json( + raw_meta.get("user_api_key_team_metadata") + ), + key_hash=as_str(raw_meta.get("user_api_key_hash")), + end_user=as_str(payload.get("end_user")) + or as_str(raw_meta.get("user_api_key_end_user_id")), + provider_model=resolve_provider_model(payload), + metadata=metadata, + ) + + @classmethod + def from_user_api_key_auth(cls, auth: object) -> "RequestIdentity": + """Identity from a ``UserAPIKeyAuth`` (duck-typed to keep this module + free of a proxy import). + + Used in the pre-call hook to seed Baggage early — before any LLM, + guardrail, or service span is created — so the whole request's spans + inherit identity, not just the LLM-call span. Metadata sub-keys use the + ``user_api_key_*`` names that ``baggage.DEFAULT_BAGGAGE_METADATA_KEYS`` + promotes. + """ + get = lambda name: getattr(auth, name, None) # noqa: E731 + metadata = { + meta_key: str(value) + for meta_key, attr in ( + ("user_api_key_user_id", "user_id"), + ("user_api_key_org_id", "org_id"), + ("user_api_key_alias", "key_alias"), + ("user_api_key_end_user_id", "end_user_id"), + ) + if (value := get(attr)) + } + return cls( + team_id=as_str(get("team_id")), + team_alias=as_str(get("team_alias")), + team_metadata=_team_metadata_json(get("team_metadata")), + key_hash=as_str(get("api_key")), + end_user=as_str(get("end_user_id")), + # ``provider_model`` is unknown at the auth boundary — routing hasn't + # picked a deployment yet — so it's only populated from the payload. + metadata=metadata, + ) + + +@dataclass(frozen=True) +class RequestContext: + """The fully-resolved view of a closed request, parsed once from the payload. + + ``request_model`` is the user-facing requested model and ``provider_model`` + (on :attr:`identity`) is the model litellm dispatched to the provider; the two + differ on the proxy (group vs. deployment) and coincide on the SDK path. + """ + + request_model: str + response_model: str | None + model_group: str | None + model_id: str | None + api_base: str | None + identity: RequestIdentity + + @property + def provider_model(self) -> str | None: + """The dispatched-model name, carried on the identity for Baggage.""" + return self.identity.provider_model + + @classmethod + def from_standard_logging_payload( + cls, payload: "StandardLoggingPayload" + ) -> "RequestContext": + raw_meta = cast(Mapping[str, object], payload.get("metadata") or {}) + hidden = cast(Mapping[str, object], payload.get("hidden_params") or {}) + raw_response = payload.get("response") + response = cast( + Mapping[str, object], raw_response if isinstance(raw_response, dict) else {} + ) + model_group = as_str(payload.get("model_group")) or as_str( + raw_meta.get("model_group") + ) + return cls( + # The user asked for the group; fall back to the call model on the SDK + # path, which has no group. Empty string (never None) so the span name + # builder and the mapper see a plain string. + request_model=model_group or as_str(payload.get("model")) or "", + response_model=as_str(response.get("model")), + model_group=model_group, + model_id=as_str(payload.get("model_id")) + or _model_info_id(raw_meta.get("model_info")), + api_base=as_str(payload.get("api_base")) or as_str(hidden.get("api_base")), + identity=RequestIdentity.from_payload(payload), + ) + + +# --- live-callback kwargs parsing ------------------------------------------- # +# +# The model and helpers below parse the *live* callback ``kwargs`` god object (and +# the raw pre/post-call ``data`` dicts) — the untyped request state that reaches a +# ``CustomLogger`` before, or instead of, a ``StandardLoggingPayload``. They live +# here, with the payload/auth parsers, so every read out of a request's raw dicts +# is in one place rather than scattered across the ``CustomLogger``. + + +@dataclass(frozen=True) +class LLMCallEvent: + """The typed view of the live callback ``kwargs`` (``model_call_details``). + + litellm hands every callback an untyped ``kwargs`` god object. The fields the + OTel logger needs out of it are parsed **once**, here, so the ``CustomLogger`` + reads typed attributes instead of digging into the dict at each boundary. + """ + + # The ``litellm_call_id`` correlating ``pre_call`` with the close callback. + # Present in ``model_call_details`` at ``pre_call`` and in both the kwargs and + # the ``standard_logging_object`` at success/failure, so it's a stable key for + # the open-call carrier — no back-reference to the logging object required (the + # object isn't reachable from the callback kwargs at ``pre_call`` time). + call_id: str | None + # The ``StandardLoggingPayload`` carried on a success/failure callback; ``None`` + # at ``pre_call``, or when the call closed before any payload materialized (so + # there is nothing to stamp on the span). + payload: "StandardLoggingPayload | None" + # The ``standard_callback_dynamic_params`` routing the call to a per-tenant + # tracer (its own exporter/endpoint), or ``None`` when the call isn't scoped. + dynamic_params: Any + # True for synthetic proxy-gate logs (auth / rate-limit rejections): they fire + # the ``pre_call`` hook but never made an upstream call, so they get no span. + is_no_upstream_call: bool + # A best-effort ``"{operation} {model}"`` name known at ``pre_call`` time. The + # span is renamed from the typed payload at close (``finish_span``); this only + # needs to be reasonable for a span that never gets closed (a leak). + provisional_span_name: str + + @classmethod + def from_dict(cls, kwargs: Mapping[str, Any]) -> "LLMCallEvent": + raw_payload = kwargs.get("standard_logging_object") + payload = cast("StandardLoggingPayload", raw_payload) if raw_payload else None + operation = resolve_operation(as_str(kwargs.get("call_type"))) + model = as_str(kwargs.get("model")) or "" + return cls( + call_id=_call_id(payload, kwargs), + payload=payload, + dynamic_params=kwargs.get("standard_callback_dynamic_params"), + is_no_upstream_call=bool(kwargs.get(LITELLM_LOGGING_NO_UPSTREAM_LLM_CALL)), + provisional_span_name=f"{operation.value} {model}".strip(), + ) + + +def _call_id( + payload: "StandardLoggingPayload | None", kwargs: Mapping[str, Any] +) -> str | None: + """The call id from the payload (when closed) or the bare kwargs (at pre_call).""" + if payload is not None: + call_id = as_str(payload.get("litellm_call_id")) or as_str(payload.get("id")) + if call_id: + return call_id + return as_str(kwargs.get("litellm_call_id")) + + +def model_from_request_data(data: object) -> str | None: + """The user-facing ``model`` from a pre-call ``data`` dict (``None`` if absent). + + Read at the auth boundary to label early Baggage before routing has resolved + a deployment; ``data`` is duck-typed since it arrives untyped from the proxy. + """ + if isinstance(data, Mapping): + return as_str(data.get("model")) + return None + + +def guardrail_entries_from_request_data( + request_data: Mapping[str, Any], +) -> list[dict]: + """The guardrail-information dicts buried in ``metadata`` of a post-call dict. + + ``standard_logging_guardrail_information`` is stored as either a single dict + or a list of them; normalize to a list of dicts (dropping non-dict noise) so + the caller just iterates. Empty list when none are present. + """ + metadata = request_data.get("metadata") + if not isinstance(metadata, Mapping): + return [] + info = metadata.get("standard_logging_guardrail_information") + if isinstance(info, Mapping): + return [cast(dict, info)] + if isinstance(info, list): + return [entry for entry in info if isinstance(entry, dict)] + return [] + + +def resolve_provider_model(payload: "StandardLoggingPayload") -> str | None: + """The model litellm dispatched to the provider, from the payload. + + Prefers the explicit ``hidden_params.litellm_model_name`` (set on call paths + that know it, e.g. files), then the top-level ``model`` — which + ``reconstruct_model_name`` has already resolved to the deployment's + provider-prefixed name. Returns ``None`` only when neither is present. + """ + raw_meta = cast(Mapping[str, object], payload.get("metadata") or {}) + hidden = cast(Mapping[str, object], payload.get("hidden_params") or {}) + return ( + # ``deployment`` survives only on paths that don't strip it from metadata; + # harmless (and most precise) to prefer it when present. + as_str(raw_meta.get("deployment")) + or as_str(hidden.get("litellm_model_name")) + or as_str(payload.get("model")) + ) + + +def _model_info_id(model_info: object) -> str | None: + """The deployment id from a ``metadata.model_info`` sub-dict, if present.""" + if isinstance(model_info, Mapping): + return as_str(model_info.get("id")) + return None + + +def _team_metadata_json(value: object) -> str | None: + """JSON-serialize a team's metadata dict for a single Baggage value. + + Returns ``None`` for a missing, non-dict, or empty mapping so the empty case + is dropped rather than promoting a useless ``"{}"``. Keys are sorted for a + stable, diff-friendly serialization. + """ + if not isinstance(value, Mapping) or not value: + return None + try: + return json.dumps(value, default=str, sort_keys=True) + except Exception: + return None diff --git a/litellm/integrations/otel/model/payloads.py b/litellm/integrations/otel/model/payloads.py new file mode 100644 index 00000000000..65b50d0fc12 --- /dev/null +++ b/litellm/integrations/otel/model/payloads.py @@ -0,0 +1,468 @@ +"""Typed span-data inputs: frozen dataclasses the engine and mappers consume.""" + +from __future__ import annotations + +import json +from dataclasses import dataclass, field +from enum import Enum +from typing import TYPE_CHECKING, ClassVar, Mapping, cast +from urllib.parse import urlsplit + +from litellm.integrations.otel.model.metadata import ( + RequestContext, + RequestIdentity, +) +from litellm.integrations.otel.model.semconv import ( + GenAIOperation, + resolve_operation, + resolve_provider, +) +from litellm.integrations.otel.model.utils import ( + as_bool, + as_float, + as_int, + as_str, + as_str_tuple, +) + +# ``RequestIdentity`` and the request-metadata translation now live in +# :mod:`metadata`; re-exported here so existing ``model.payloads`` imports keep +# resolving it. +__all__ = [ + "RequestContext", + "RequestIdentity", + "GuardrailSpanData", + "LLMCallSpanData", + "LLMRequestParams", + "LLMUsage", + "ProxyRequestSpanData", + "ServerInfo", + "ServiceSpanData", + "SpanError", + "ToolDefinition", +] + +if TYPE_CHECKING: + from litellm.types.services import ServiceLoggerPayload + from litellm.types.utils import ( + StandardLoggingGuardrailInformation, + StandardLoggingPayload, + ) + + +# --- typed sub-structures ---------------------------------------------------- # + + +@dataclass(frozen=True) +class LLMRequestParams: + temperature: float | None = None + top_p: float | None = None + top_k: int | None = None + max_tokens: int | None = None + frequency_penalty: float | None = None + presence_penalty: float | None = None + stop_sequences: tuple[str, ...] | None = None + seed: int | None = None + + @classmethod + def from_model_parameters(cls, params: Mapping[str, object]) -> "LLMRequestParams": + max_tokens = as_int(params.get("max_tokens")) + if max_tokens is None: + max_tokens = as_int(params.get("max_completion_tokens")) + return cls( + temperature=as_float(params.get("temperature")), + top_p=as_float(params.get("top_p")), + top_k=as_int(params.get("top_k")), + max_tokens=max_tokens, + frequency_penalty=as_float(params.get("frequency_penalty")), + presence_penalty=as_float(params.get("presence_penalty")), + stop_sequences=as_str_tuple(params.get("stop")), + seed=as_int(params.get("seed")), + ) + + +@dataclass(frozen=True) +class LLMUsage: + input_tokens: int | None = None + output_tokens: int | None = None + total_tokens: int | None = None + + +@dataclass(frozen=True) +class SpanError: + error_type: str | None = None + message: str | None = None + + +@dataclass(frozen=True) +class ServerInfo: + address: str | None = None + port: int | None = None + + @classmethod + def from_api_base(cls, api_base: str | None) -> ServerInfo | None: + if not api_base: + return None + parsed = urlsplit(api_base if "://" in api_base else f"//{api_base}") + if not parsed.hostname: + return None + return cls(address=parsed.hostname, port=parsed.port) + + +@dataclass(frozen=True) +class GuardrailSpanData: + guardrail_name: str + mode: str | None = None + status: str | None = None + masked_entity_count: int | None = None + provider: str | None = None + action: str | None = None + # The guardrail verdict / provider response (e.g. the moderation result), + # JSON-serialized. This is the detail that belongs on the guardrail span. + response_json: str | None = None + violation_categories: tuple[str, ...] = () + confidence_score: float | None = None + risk_score: float | None = None + duration: float | None = None + # Actual execution window (epoch seconds) from the logging entry, so the span + # is placed when the guardrail really ran — a pre_call guardrail before the + # LLM call — rather than at post-call emission time. + start_time: float | None = None + end_time: float | None = None + # Provider-agnostic configuration/detection metadata (see + # ``StandardLoggingGuardrailInformation``). Present for any guardrail that + # populates them, not just one provider's shape. + guardrail_id: str | None = None + policy_template: str | None = None + detection_method: str | None = None + # Set when the guardrail intervened/blocked or failed, so the emitter marks + # the span ERROR — a blocking guardrail is an error outcome for that span. + error: SpanError | None = None + + # Guardrail statuses that mean the guardrail did not pass the request through. + _ERROR_STATUSES: ClassVar[frozenset[str]] = frozenset( + {"guardrail_intervened", "guardrail_failed_to_respond"} + ) + + @classmethod + def from_logging_entry( + cls, entry: "StandardLoggingGuardrailInformation" + ) -> "GuardrailSpanData": + """Build from one ``standard_logging_guardrail_information`` entry. + + Reads the canonical, provider-agnostic ``StandardLoggingGuardrailInformation`` + keys only — no guessing at a single provider's field names. Values that are + typed as enums or lists (e.g. ``guardrail_mode``) are normalized to a + stable string rather than assumed to already be plain strings. + """ + get = cast(Mapping[str, object], entry).get + status = as_str(get("guardrail_status")) + response = get("guardrail_response") + error = ( + SpanError(error_type=status, message=as_str(get("guardrail_action"))) + if status in cls._ERROR_STATUSES + else None + ) + return cls( + guardrail_name=as_str(get("guardrail_name")) or "guardrail", + mode=_guardrail_mode_str(get("guardrail_mode")), + status=status, + masked_entity_count=_total_masked_entities(get("masked_entity_count")), + provider=as_str(get("guardrail_provider")), + action=as_str(get("guardrail_action")), + response_json=_json_or_none(response) if response is not None else None, + violation_categories=as_str_tuple(get("violation_categories")) or (), + confidence_score=as_float(get("confidence_score")), + risk_score=as_float(get("risk_score")), + duration=as_float(get("duration")), + start_time=as_float(get("start_time")), + end_time=as_float(get("end_time")), + guardrail_id=as_str(get("guardrail_id")), + policy_template=as_str(get("policy_template")), + detection_method=as_str(get("detection_method")), + error=error, + ) + + +@dataclass(frozen=True) +class ServiceSpanData: + service_name: str + call_type: str | None = None + error: SpanError | None = None + # Caller-supplied attributes to stamp on the service span, passed through + # from ``async_service_*_hook(event_metadata=...)``. The mapper owns how + # these are namespaced: the canonical vocabulary uses ``litellm.metadata.*`` + # keys, the semconv-ai / Traceloop vocabulary uses the bare key names. + event_metadata: Mapping[str, str] = field(default_factory=dict) + + @classmethod + def from_payload( + cls, + payload: "ServiceLoggerPayload", + event_metadata: Mapping[str, object] | None = None, + ) -> "ServiceSpanData": + # ``payload.service`` is a ``ServiceTypes(str, Enum)`` and ``error`` is + # ``Optional[str]`` on the Pydantic model — no defensive reads needed. + # ``event_metadata`` is sanitized: the legacy service decorators pass raw + # call-site data (live objects, full request metadata, response headers), + # none of which belongs on a span. + return cls( + service_name=payload.service.value, + call_type=payload.call_type, + error=SpanError(message=payload.error) if payload.error else None, + event_metadata=sanitize_event_metadata(event_metadata), + ) + + +@dataclass(frozen=True) +class ProxyRequestSpanData: + http_method: str + route: str + url_path: str | None = None + status_code: int | None = None + identity: RequestIdentity | None = None + + +# --- the primary LLM-call model ---------------------------------------------- # + + +@dataclass(frozen=True) +class ToolDefinition: + """A single function/tool declared on a chat-completion request.""" + + name: str + description: str | None = None + parameters_json: str | None = ( + None # JSON-serialized schema (str so it's an AttrValue) + ) + + +@dataclass(frozen=True) +class LLMCallSpanData: + operation: GenAIOperation + provider: str + request_model: str + response_model: str | None + response_id: str | None + request_params: LLMRequestParams + usage: LLMUsage + finish_reasons: tuple[str, ...] + error: SpanError | None + response_cost: float | None + server: ServerInfo | None + identity: RequestIdentity + is_streaming: bool | None = None + tools: tuple[ToolDefinition, ...] = () + # Raw messages and response, needed by vendor mappers (OpenInference, + # Langfuse, Weave) that stamp message-level attributes. ``messages_in`` is + # the request payload; ``choices_out`` mirrors ``response.choices`` from + # the StandardLoggingPayload. Both are tuples of immutable mappings so the + # dataclass stays hashable and frozen. + messages_in: tuple[Mapping[str, object], ...] = () + choices_out: tuple[Mapping[str, object], ...] = () + system_fingerprint: str | None = None + + @classmethod + def from_standard_logging_payload( + cls, payload: "StandardLoggingPayload", capture_content: bool = False + ) -> "LLMCallSpanData": + params = cast(Mapping[str, object], payload.get("model_parameters") or {}) + # The single parse of the request's metadata — the request-vs-provider + # model split, the response model, api base, and identity all come from + # here rather than being re-derived from the raw payload dicts. + context = RequestContext.from_standard_logging_payload(payload) + # Normalize ``response`` to a dict once so the content/id reads below are a + # plain ``.get`` — no repeated ``isinstance`` guards. + raw_response = payload.get("response") + response = cast( + Mapping[str, object], raw_response if isinstance(raw_response, dict) else {} + ) + choices_out = _dicts(response.get("choices")) + # ``finish_reasons`` is metadata, not content, so derive it from + # ``choices_out`` before gating. The raw message/choice bodies are only + # retained when content capture is enabled (see ``capture_span_content``); + # otherwise the content-bearing mappers receive empty sequences and emit + # no prompt/response text. + finish_reasons = _finish_reasons(choices_out) + return cls( + operation=resolve_operation(as_str(payload.get("call_type"))), + provider=resolve_provider(as_str(payload.get("custom_llm_provider"))), + request_model=context.request_model, + response_model=context.response_model, + response_id=as_str(response.get("id")), + request_params=LLMRequestParams.from_model_parameters(params), + usage=LLMUsage( + input_tokens=as_int(payload.get("prompt_tokens")), + output_tokens=as_int(payload.get("completion_tokens")), + total_tokens=as_int(payload.get("total_tokens")), + ), + finish_reasons=finish_reasons, + error=_parse_error(payload), + response_cost=as_float(payload.get("response_cost")), + server=ServerInfo.from_api_base(context.api_base), + identity=context.identity, + is_streaming=as_bool(payload.get("stream")), + tools=_extract_tools(params), + messages_in=_dicts(payload.get("messages")) if capture_content else (), + choices_out=choices_out if capture_content else (), + system_fingerprint=as_str(response.get("system_fingerprint")), + ) + + +# --- service event_metadata sanitization ------------------------------------ # + +# Substrings (case-insensitive) of keys that must never reach a span: secrets, +# tokens, and raw request/response dumps the legacy service decorators pass. +_SENSITIVE_METADATA_SUBSTRINGS: tuple[str, ...] = ( + "api_key", + "token", + "secret", + "password", + "cookie", + "authorization", + "header", + "hidden_params", +) +# Keys that carry raw call-site internals — live objects, full kwargs/args. The +# operation name is already the span's ``call_type``, so ``function_name`` is +# redundant. +_DROP_METADATA_KEYS: frozenset = frozenset( + {"function_kwargs", "function_args", "function_name"} +) +_MAX_METADATA_VALUE_LEN = 1024 +_MAX_METADATA_ITEMS = 32 + + +def sanitize_event_metadata( + event_metadata: Mapping[str, object] | None, +) -> dict[str, str]: + """Reduce caller-supplied ``event_metadata`` to span-safe string attributes. + + Keeps only primitive values (str/int/float/bool) under non-sensitive keys — + never ``repr()``-ing objects, dicts, or lists, never stamping secrets/headers, + and bounding the count and per-value length. This is the single chokepoint: + both the GenAI and legacy mappers read the cleaned result. + """ + if not event_metadata: + return {} + clean: dict[str, str] = {} + for key, value in event_metadata.items(): + if len(clean) >= _MAX_METADATA_ITEMS: + break + if not isinstance(key, str) or key in _DROP_METADATA_KEYS: + continue + lowered = key.lower() + if any(token in lowered for token in _SENSITIVE_METADATA_SUBSTRINGS): + continue + # ``bool`` is a subclass of ``int``, so it's covered. Non-primitive values + # (objects, dicts, lists) are dropped rather than stringified. + if isinstance(value, (str, int, float)): + clean[key] = str(value)[:_MAX_METADATA_VALUE_LEN] + return clean + + +def _json_or_none(value: object) -> str | None: + """JSON-serialize ``value`` (already-string values pass through). ``None`` on failure.""" + if isinstance(value, str): + return value + try: + return json.dumps(value, default=str) + except Exception: + return None + + +def _guardrail_mode_str(value: object) -> str | None: + """Normalize ``guardrail_mode`` to a stable string. + + ``guardrail_mode`` is typed as a ``GuardrailEventHooks`` enum, a list of them, + or a ``GuardrailMode`` — not a plain string. Emit the enum *value* (e.g. + ``"pre_call"``) rather than ``str(enum)`` (``"GuardrailEventHooks.pre_call"``), + and join a list of modes so a guardrail that runs at multiple hooks is + represented faithfully. + """ + if value is None: + return None + if isinstance(value, (list, tuple)): + parts: list[str] = [] + for item in value: + if item is None: + continue + part = as_str(item.value) if isinstance(item, Enum) else as_str(item) + if part: + parts.append(part) + return ",".join(parts) or None + if isinstance(value, Enum): + return as_str(value.value) + return as_str(value) + + +def _total_masked_entities(value: object) -> int | None: + """``masked_entity_count`` is a ``{entity_type: count}`` map — sum to a total.""" + if isinstance(value, Mapping): + total = sum(v for v in value.values() if isinstance(v, int)) + return total or None + return as_int(value) + + +def _dicts(value: object) -> tuple[Mapping[str, object], ...]: + """The dict items of ``value`` (when it's a list), as a tuple. Else empty.""" + if not isinstance(value, list): + return () + return tuple(item for item in value if isinstance(item, dict)) + + +def _finish_reasons(choices: tuple[Mapping[str, object], ...]) -> tuple[str, ...]: + """Non-empty ``finish_reason`` of each response choice.""" + return tuple(r for c in choices if (r := as_str(c.get("finish_reason")))) + + +def _parse_error(payload: "StandardLoggingPayload") -> SpanError | None: + """A ``SpanError`` for a failed request, or ``None`` on success.""" + if payload.get("status") != "failure": + return None + info = cast(Mapping[str, object], payload.get("error_information") or {}) + return SpanError( + error_type=as_str(info.get("error_class")) or as_str(info.get("error_code")), + message=as_str(info.get("error_message")) or as_str(payload.get("error_str")), + ) + + +def _tool_from_entry(entry: object) -> ToolDefinition | None: + """One ``tools``/``functions`` entry → ``ToolDefinition``, or ``None`` if unusable.""" + if not isinstance(entry, dict): + return None + fn = entry.get("function") if "function" in entry else entry + if not isinstance(fn, dict): + return None + name = as_str(fn.get("name")) + if not name: + return None + params = fn.get("parameters") + parameters_json: str | None = None + if params is not None: + try: + parameters_json = json.dumps(params, default=str) + except Exception: + parameters_json = None + return ToolDefinition( + name=name, + description=as_str(fn.get("description")), + parameters_json=parameters_json, + ) + + +def _extract_tools( + model_parameters: Mapping[str, object], +) -> tuple[ToolDefinition, ...]: + """Pull declared tools from request params (OpenAI / Anthropic shape). + + Accepts the chat-completion ``tools=[{"type":"function", "function": + {...}}, ...]`` shape, and falls back to the ``functions=[...]`` shape. + Returns an empty tuple when neither is present. + """ + raw_tools = model_parameters.get("tools") + if not isinstance(raw_tools, list): + raw_tools = model_parameters.get("functions") # ``functions`` shape + if not isinstance(raw_tools, list): + return () + return tuple(t for entry in raw_tools if (t := _tool_from_entry(entry)) is not None) diff --git a/litellm/integrations/otel/model/semconv.py b/litellm/integrations/otel/model/semconv.py new file mode 100644 index 00000000000..1c6c30eda0d --- /dev/null +++ b/litellm/integrations/otel/model/semconv.py @@ -0,0 +1,201 @@ +""" +Keys follow the OpenTelemetry GenAI semantic conventions (experimental). Anything +without a semconv equivalent lives under the ``litellm.*`` vendor namespace. +""" + +from enum import Enum +from typing import Final + + +class GenAIOperation(str, Enum): + """Values for ``gen_ai.operation.name``.""" + + CHAT = "chat" + TEXT_COMPLETION = "text_completion" + EMBEDDINGS = "embeddings" + GENERATE_CONTENT = "generate_content" + CREATE_AGENT = "create_agent" # reserved for future agent spans + INVOKE_AGENT = "invoke_agent" # reserved for future agent spans + EXECUTE_TOOL = "execute_tool" # reserved for future tool spans + + +class GenAIProvider(str, Enum): + """Common values for the ``gen_ai.provider.name`` attribute.""" + + OPENAI = "openai" + ANTHROPIC = "anthropic" + AWS_BEDROCK = "aws.bedrock" + AZURE_AI_OPENAI = "azure.ai.openai" + AZURE_AI_INFERENCE = "azure.ai.inference" + GCP_GEMINI = "gcp.gemini" + GCP_VERTEX_AI = "gcp.vertex_ai" + COHERE = "cohere" + MISTRAL_AI = "mistral_ai" + DEEPSEEK = "deepseek" + GROQ = "groq" + PERPLEXITY = "perplexity" + X_AI = "x_ai" + IBM_WATSONX_AI = "ibm.watsonx.ai" + + +class GenAI: + """Canonical OTel GenAI span-attribute keys.""" + + # request + OPERATION_NAME: Final = "gen_ai.operation.name" + PROVIDER_NAME: Final = "gen_ai.provider.name" + REQUEST_MODEL: Final = "gen_ai.request.model" + REQUEST_TEMPERATURE: Final = "gen_ai.request.temperature" + REQUEST_TOP_P: Final = "gen_ai.request.top_p" + REQUEST_TOP_K: Final = "gen_ai.request.top_k" + REQUEST_MAX_TOKENS: Final = "gen_ai.request.max_tokens" + REQUEST_FREQUENCY_PENALTY: Final = "gen_ai.request.frequency_penalty" + REQUEST_PRESENCE_PENALTY: Final = "gen_ai.request.presence_penalty" + REQUEST_STOP_SEQUENCES: Final = "gen_ai.request.stop_sequences" + REQUEST_SEED: Final = "gen_ai.request.seed" + REQUEST_CHOICE_COUNT: Final = "gen_ai.request.choice.count" + REQUEST_ENCODING_FORMATS: Final = "gen_ai.request.encoding_formats" + # response + RESPONSE_ID: Final = "gen_ai.response.id" + RESPONSE_MODEL: Final = "gen_ai.response.model" + RESPONSE_FINISH_REASONS: Final = "gen_ai.response.finish_reasons" + # usage + USAGE_INPUT_TOKENS: Final = "gen_ai.usage.input_tokens" + USAGE_OUTPUT_TOKENS: Final = "gen_ai.usage.output_tokens" + # content (opt-in, gated by capture mode) + INPUT_MESSAGES: Final = "gen_ai.input.messages" + OUTPUT_MESSAGES: Final = "gen_ai.output.messages" + SYSTEM_INSTRUCTIONS: Final = "gen_ai.system_instructions" + OUTPUT_TYPE: Final = "gen_ai.output.type" + CONVERSATION_ID: Final = "gen_ai.conversation.id" + # agent / tool (reserved) + AGENT_ID: Final = "gen_ai.agent.id" + AGENT_NAME: Final = "gen_ai.agent.name" + TOOL_NAME: Final = "gen_ai.tool.name" + TOOL_CALL_ID: Final = "gen_ai.tool.call.id" + + +class Error: + TYPE: Final = "error.type" + + +class Server: + ADDRESS: Final = "server.address" + PORT: Final = "server.port" + + +class DB: + """Database / cache client-span keys (OTel ``db.*`` semconv). + + Stamped on ``DB_CALL`` spans (redis / postgres), which are CLIENT spans for + outbound datastore calls — not on the INTERNAL ``SERVICE`` spans. + """ + + SYSTEM_NAME: Final = "db.system.name" + OPERATION_NAME: Final = "db.operation.name" + + +class HTTP: + """HTTP server-span keys. Belong on the SERVER span only (never promoted).""" + + REQUEST_METHOD: Final = "http.request.method" + ROUTE: Final = "http.route" + RESPONSE_STATUS_CODE: Final = "http.response.status_code" + URL_PATH: Final = "url.path" + + +class LiteLLM: + """Vendor-extension keys (no semconv equivalent). Always ``litellm.*``.""" + + CALL_ID: Final = "litellm.call_id" + COST_PREFIX: Final = "litellm.cost." + METADATA_PREFIX: Final = "litellm.metadata." + TEAM_ID: Final = "litellm.team.id" + TEAM_ALIAS: Final = "litellm.team.alias" + # The team's free-form metadata dict, JSON-serialized into a single value. + TEAM_METADATA: Final = "litellm.team.metadata" + KEY_HASH: Final = "litellm.api_key.hash" + END_USER: Final = "litellm.end_user.id" + # The model string litellm actually sent to the provider (the deployment's + # ``litellm_params.model``), distinct from the user-facing ``gen_ai.request.model``. + PROVIDER_MODEL: Final = "litellm.provider.model" + REQUEST_STREAMING: Final = "litellm.request.streaming" + GUARDRAIL_NAME: Final = "litellm.guardrail.name" + GUARDRAIL_MODE: Final = "litellm.guardrail.mode" + GUARDRAIL_STATUS: Final = "litellm.guardrail.status" + GUARDRAIL_PROVIDER: Final = "litellm.guardrail.provider" + GUARDRAIL_ACTION: Final = "litellm.guardrail.action" + GUARDRAIL_RESPONSE: Final = "litellm.guardrail.response" + GUARDRAIL_VIOLATION_CATEGORIES: Final = "litellm.guardrail.violation_categories" + GUARDRAIL_CONFIDENCE_SCORE: Final = "litellm.guardrail.confidence_score" + GUARDRAIL_RISK_SCORE: Final = "litellm.guardrail.risk_score" + GUARDRAIL_MASKED_ENTITY_COUNT: Final = "litellm.guardrail.masked_entity_count" + GUARDRAIL_DURATION: Final = "litellm.guardrail.duration" + GUARDRAIL_ID: Final = "litellm.guardrail.id" + GUARDRAIL_POLICY_TEMPLATE: Final = "litellm.guardrail.policy_template" + GUARDRAIL_DETECTION_METHOD: Final = "litellm.guardrail.detection_method" + SERVICE_NAME: Final = "litellm.service.name" + SERVICE_CALL_TYPE: Final = "litellm.service.call_type" + PREPROCESSING_MS: Final = "litellm.preprocessing.duration_ms" + + +class Metric: + """GenAI metric instrument names.""" + + TOKEN_USAGE: Final = "gen_ai.client.token.usage" + OPERATION_DURATION: Final = "gen_ai.client.operation.duration" + + +# litellm ``custom_llm_provider`` -> ``gen_ai.provider.name`` value. +_PROVIDER_BY_LITELLM: dict[str, GenAIProvider] = { + "openai": GenAIProvider.OPENAI, + "text-completion-openai": GenAIProvider.OPENAI, + "azure": GenAIProvider.AZURE_AI_OPENAI, + "azure_ai": GenAIProvider.AZURE_AI_INFERENCE, + "anthropic": GenAIProvider.ANTHROPIC, + "bedrock": GenAIProvider.AWS_BEDROCK, + "bedrock_converse": GenAIProvider.AWS_BEDROCK, + "vertex_ai": GenAIProvider.GCP_VERTEX_AI, + "vertex_ai_beta": GenAIProvider.GCP_VERTEX_AI, + "gemini": GenAIProvider.GCP_GEMINI, + "cohere": GenAIProvider.COHERE, + "cohere_chat": GenAIProvider.COHERE, + "mistral": GenAIProvider.MISTRAL_AI, + "deepseek": GenAIProvider.DEEPSEEK, + "groq": GenAIProvider.GROQ, + "perplexity": GenAIProvider.PERPLEXITY, + "xai": GenAIProvider.X_AI, + "watsonx": GenAIProvider.IBM_WATSONX_AI, +} + +# litellm ``call_type`` -> ``gen_ai.operation.name``. +_OPERATION_BY_CALL_TYPE: dict[str, GenAIOperation] = { + "completion": GenAIOperation.CHAT, + "acompletion": GenAIOperation.CHAT, + "completion_with_retries": GenAIOperation.CHAT, + "text_completion": GenAIOperation.TEXT_COMPLETION, + "atext_completion": GenAIOperation.TEXT_COMPLETION, + "embedding": GenAIOperation.EMBEDDINGS, + "aembedding": GenAIOperation.EMBEDDINGS, + "responses": GenAIOperation.CHAT, + "aresponses": GenAIOperation.CHAT, +} + + +def resolve_provider(custom_llm_provider: str | None) -> str: + """Map a litellm provider string to a ``gen_ai.provider.name`` value. + + Unknown providers pass through verbatim — the convention explicitly allows + provider-specific values, so an unmapped name is still valid. + """ + if not custom_llm_provider: + return "" + mapped = _PROVIDER_BY_LITELLM.get(custom_llm_provider.lower()) + return mapped.value if mapped is not None else custom_llm_provider + + +def resolve_operation(call_type: str | None) -> GenAIOperation: + """Map a litellm ``call_type`` to a ``gen_ai.operation.name`` value.""" + if not call_type: + return GenAIOperation.CHAT + return _OPERATION_BY_CALL_TYPE.get(call_type.lower(), GenAIOperation.CHAT) diff --git a/litellm/integrations/otel/model/spans.py b/litellm/integrations/otel/model/spans.py new file mode 100644 index 00000000000..e4876f4ee58 --- /dev/null +++ b/litellm/integrations/otel/model/spans.py @@ -0,0 +1,203 @@ +""" +This module declares every span the instrumentation can emit and the hierarchy. + +Span-name patterns live here as typed builder functions. + +Canonical hierarchy:: + + PROXY_REQUEST (SERVER, root) # owned by the FastAPI instrumentor + ├── SERVICE (INTERNAL) # auth phase span (live; see logger.phase_span) + │ └── DB_CALL (CLIENT) # its key/user/team lookups nest here + ├── GUARDRAIL (INTERNAL) # request-lifecycle hook, sibling of LLM_CALL + ├── LLM_CALL (CLIENT) + └── DB_CALL (CLIENT) # e.g. the spend-log write + +Guardrails parent to PROXY_REQUEST, not LLM_CALL: pre/during/post-call guardrail +hooks are orchestrated by the request lifecycle (a pre-call guardrail runs +before the LLM call even starts), so a guardrail is a sibling of the LLM call, +not a child of it. The emitter parents every span to the ambient OTel context +(the active server span), which matches this. + +Not every service call becomes a span — :func:`span_role_for_service` decides: + +- ``DB_CALL`` (CLIENT) — outbound datastores (redis, postgres, + ``batch_write_to_db``), carrying ``db.*`` semconv. +- ``SERVICE`` (INTERNAL) — genuine internal work worth a span (background + budget/reset jobs, pod-lock manager). +- ``None`` (metrics-only) — framework instrumentation that duplicates a gen-AI + span (``self`` = the ``track_llm_api_timing`` wrapper, ``router``, + ``proxy_pre_call``) or ``auth`` (which gets a live phase span instead). These + still feed Prometheus/Datadog; they just never enter the trace. + +``DB_CALL`` and ``SERVICE`` are built from the same ``ServiceSpanData``; only the +role (hence span kind and attribute vocabulary) differs. A service call can fire +outside any request (a background job), in which case it parents to no server +span and starts its own root trace rather than being dropped. + +Management/admin endpoints are ordinary FastAPI routes — their SERVER spans are +owned by the instrumentor too, so they don't appear as a role here. +""" + +from dataclasses import dataclass +from enum import Enum +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from litellm.integrations.otel.model.payloads import ( + GuardrailSpanData, + LLMCallSpanData, + ProxyRequestSpanData, + ServiceSpanData, + ) + + +class SpanRole(str, Enum): + PROXY_REQUEST = "proxy_request" + LLM_CALL = "llm_call" + GUARDRAIL = "guardrail" + DB_CALL = "db_call" + SERVICE = "service" + + +class LiteLLMSpanKind(str, Enum): + SERVER = "server" + CLIENT = "client" + INTERNAL = "internal" + PRODUCER = "producer" + CONSUMER = "consumer" + + +@dataclass(frozen=True) +class SpanSpec: + role: SpanRole + kind: LiteLLMSpanKind + parent: SpanRole | None + + +SPAN_REGISTRY: dict[SpanRole, SpanSpec] = { + SpanRole.PROXY_REQUEST: SpanSpec( + SpanRole.PROXY_REQUEST, LiteLLMSpanKind.SERVER, parent=None + ), + SpanRole.LLM_CALL: SpanSpec( + SpanRole.LLM_CALL, LiteLLMSpanKind.CLIENT, parent=SpanRole.PROXY_REQUEST + ), + SpanRole.GUARDRAIL: SpanSpec( + SpanRole.GUARDRAIL, LiteLLMSpanKind.INTERNAL, parent=SpanRole.PROXY_REQUEST + ), + SpanRole.DB_CALL: SpanSpec( + SpanRole.DB_CALL, LiteLLMSpanKind.CLIENT, parent=SpanRole.PROXY_REQUEST + ), + SpanRole.SERVICE: SpanSpec( + SpanRole.SERVICE, LiteLLMSpanKind.INTERNAL, parent=SpanRole.PROXY_REQUEST + ), +} + + +# ``ServiceTypes`` value -> ``db.system.name``. These are outbound datastore +# calls and become CLIENT ``DB_CALL`` spans; ``redis_``-prefixed names cover the +# redis-backed spend queues. Any service not mapped here is litellm-internal work +# and stays an INTERNAL ``SERVICE`` span. This table is the single source of +# datastore knowledge — both the role classifier and the mapper read it. +_DB_SYSTEM_BY_SERVICE: dict[str, str] = { + "redis": "redis", + "postgres": "postgresql", + "batch_write_to_db": "postgresql", +} + + +def db_system(service_name: str) -> str | None: + """The ``db.system.name`` for a datastore service, else ``None``. + + ``None`` means the service is not an outbound datastore call. Redis-backed + spend queues (``redis_*``) map to ``redis``. + """ + if service_name in _DB_SYSTEM_BY_SERVICE: + return _DB_SYSTEM_BY_SERVICE[service_name] + if service_name.startswith("redis_"): + return "redis" + return None + + +# ``ServiceTypes`` values that are NOT emitted as spans — they are framework +# instrumentation that either duplicates a gen-AI span or has a better home as a +# Prometheus/Datadog metric. They still flow to those metric backends via their +# own hooks; the v2 logger just does not put them in the trace: +# +# - ``self`` — ``track_llm_api_timing`` wraps the LLM call; the +# ``chat {model}`` CLIENT span already represents it. +# - ``router`` — wraps the whole request; duplicates the server span. +# - ``proxy_pre_call`` — per-callback pre-call timing; a guardrail's real span +# is ``execute_guardrail {name}``. +# - ``auth`` — emitted instead as a live phase span (see +# ``logger.phase_span``) so its DB lookups nest under it, +# not as a flat post-hoc service span. +_METRICS_ONLY_SERVICES: frozenset[str] = frozenset( + {"self", "router", "proxy_pre_call", "auth"} +) + + +def span_role_for_service(service_name: str) -> SpanRole | None: + """The span role for a service call, or ``None`` when it must not be a span. + + ``DB_CALL`` for outbound datastores, ``SERVICE`` for genuine internal work + worth a span (background jobs), and ``None`` for framework instrumentation + that duplicates a gen-AI span or belongs in metrics only + (see ``_METRICS_ONLY_SERVICES``). + """ + if service_name in _METRICS_ONLY_SERVICES: + return None + return SpanRole.DB_CALL if db_system(service_name) is not None else SpanRole.SERVICE + + +# --- span name builders (the naming convention, per role) ------------------- # + + +# The name the FastAPI instrumentor gives the root server span. V2 never creates +# this span (the instrumentor owns it), but it anchors request-level spans to it +# and tests assert against it by name, so the literal lives here with the rest of +# the span vocabulary rather than being duplicated at each call site. +LITELLM_PROXY_REQUEST_SPAN_NAME = "Received Proxy Server Request" + + +def llm_call_span_name(data: "LLMCallSpanData") -> str: + """``"{operation} {model}"`` e.g. ``"chat gpt-4o"`` (GenAI semconv).""" + model = data.request_model or "" + return f"{data.operation.value} {model}".strip() + + +def proxy_request_span_name(data: "ProxyRequestSpanData") -> str: + """``"{method} {route}"`` (HTTP semconv).""" + return f"{data.http_method} {data.route}".strip() + + +def guardrail_span_name(data: "GuardrailSpanData") -> str: + return f"execute_guardrail {data.guardrail_name}".strip() + + +def service_span_name(data: "ServiceSpanData") -> str: + """``"{service} {call_type}"`` e.g. ``"redis set"`` — service name alone when + no call type is known, so identically-named calls stay distinguishable.""" + return f"{data.service_name} {data.call_type or ''}".strip() + + +def root_roles() -> list[SpanRole]: + """Roles that start a new trace (no in-process parent).""" + return [role for role, spec in SPAN_REGISTRY.items() if spec.parent is None] + + +def child_roles(parent: SpanRole) -> list[SpanRole]: + return [role for role, spec in SPAN_REGISTRY.items() if spec.parent == parent] + + +def validate_registry( + registry: dict[SpanRole, SpanSpec] | None = None, +) -> None: + reg = registry if registry is not None else SPAN_REGISTRY + for role, spec in reg.items(): + if spec.role is not role: + raise ValueError(f"SPAN_REGISTRY[{role}] has mismatched role {spec.role}") + if spec.parent is not None and spec.parent not in reg: + raise ValueError(f"span role {role} declares unknown parent {spec.parent}") + missing = [role for role in SpanRole if role not in reg] + if missing: + raise ValueError(f"SPAN_REGISTRY is missing roles: {missing}") diff --git a/litellm/integrations/otel/model/utils.py b/litellm/integrations/otel/model/utils.py new file mode 100644 index 00000000000..f37afc97879 --- /dev/null +++ b/litellm/integrations/otel/model/utils.py @@ -0,0 +1,103 @@ +"""Shared, OpenTelemetry-free helpers for the otel integration. + +Generic value coercion (for reading heterogeneous logging-payload dicts), time +conversion, and header parsing — pulled out of the individual modules so they +live in one place. Deliberately free of any ``opentelemetry`` import so the +OTel-free sources of truth (payloads, semconv, spans, config) can use it too. +""" + +from datetime import datetime + + +def as_str(value: object) -> str | None: + if value is None: + return None + if isinstance(value, str): + return value + return str(value) + + +def as_int(value: object) -> int | None: + if isinstance(value, bool): + return int(value) + if isinstance(value, int): + return value + if isinstance(value, float): + return int(value) + if isinstance(value, str): + try: + return int(value) + except ValueError: + return None + return None + + +def as_float(value: object) -> float | None: + if isinstance(value, bool): + return float(value) + if isinstance(value, (int, float)): + return float(value) + if isinstance(value, str): + try: + return float(value) + except ValueError: + return None + return None + + +def as_bool(value: object) -> bool | None: + if value is None: + return None + if isinstance(value, bool): + return value + return bool(value) + + +def as_str_tuple(value: object) -> tuple[str, ...] | None: + if value is None: + return None + if isinstance(value, str): + return (value,) + if isinstance(value, (list, tuple)): + return tuple(str(v) for v in value) + return None + + +def to_ns(value: datetime | float | int | None) -> int | None: + """Coerce a datetime / epoch value to integer nanoseconds.""" + if value is None: + return None + if isinstance(value, datetime): + return int(value.timestamp() * 1e9) + if isinstance(value, (int, float)) and not isinstance(value, bool): + return int(float(value) * 1e9) + return None + + +def to_seconds(value: datetime | float | int | str | None) -> float | None: + """Coerce a datetime / epoch / formatted-string value to epoch seconds.""" + if value is None: + return None + if isinstance(value, datetime): + return value.timestamp() + if isinstance(value, (int, float)) and not isinstance(value, bool): + return float(value) + if isinstance(value, str): + for fmt in ("%Y-%m-%d %H:%M:%S.%f", "%Y-%m-%d %H:%M:%S"): + try: + return datetime.strptime(value, fmt).timestamp() + except ValueError: + continue + return None + + +def parse_headers(raw: str | None) -> dict[str, str]: + """Parse an OTLP ``"k=v,k=v"`` header string into a dict.""" + headers: dict[str, str] = {} + if not raw: + return headers + for pair in raw.split(","): + if "=" in pair: + key, _, value = pair.partition("=") + headers[key.strip()] = value.strip() + return headers diff --git a/litellm/integrations/otel/mount.py b/litellm/integrations/otel/mount.py new file mode 100644 index 00000000000..ebcf4aa35af --- /dev/null +++ b/litellm/integrations/otel/mount.py @@ -0,0 +1,130 @@ +"""FastAPI server-span instrumentation — the proxy mounts this at app creation. + +``opentelemetry-instrumentation-fastapi`` creates the SERVER span for each HTTP +route and extracts inbound ``traceparent`` headers. This module owns the one call +site that attaches it to the proxy app, plus the passthrough span-naming hook, so +``proxy_server`` stays free of OTel details. + +The ``FastAPIInstrumentor`` import is kept lazy (inside :func:`instrument_fastapi_app`, +after the gate check) so importing this module never requires the optional +``opentelemetry-instrumentation-fastapi`` package and pulls in nothing OTel-related +when the feature gate is off. +""" + +import os +from typing import Any + +from litellm._logging import verbose_logger +from litellm.integrations.otel.model.config import is_otel_v2_enabled + +# Routes excluded from server-span tracing by default: high-frequency pollers and +# static UI/docs assets, none of which are LLM traffic. Entries are substring-matched +# against the request path (unanchored, so they survive a ``server_root_path`` prefix +# and each entry also covers everything beneath it — e.g. ``/health`` covers +# ``/health/readiness``). Operators override the whole set via the standard +# ``OTEL_PYTHON_FASTAPI_EXCLUDED_URLS`` env var (set "" to trace everything). +_DEFAULT_EXCLUDED_ROUTES = ( + "/health", # load-balancer liveness/readiness polling + "/metrics", # Prometheus scrape (also drops the /model/metrics admin analytics) + "/litellm-asset-prefix", # hashed UI asset bundles + "/_next", # Next.js static JS/CSS chunks (root-level mount) + "/ui", # admin UI single-page app + "/swagger", # static Swagger UI assets + "/docs", # FastAPI Swagger docs page + "/redoc", # FastAPI ReDoc docs page + "/openapi.json", # OpenAPI schema + "favicon", # /favicon.ico + /get_favicon + "/.well-known", # UI config discovery +) +_DEFAULT_EXCLUDED_URLS = ",".join(_DEFAULT_EXCLUDED_ROUTES) + +# Passthrough routes are catch-alls (e.g. "/openai/{endpoint:path}"), so the +# default OTel server-span name "{method} {route}" collapses every upstream +# endpoint into "POST /openai/{endpoint:path}". The hook below renames those spans +# to the real request path so each endpoint is distinguishable. Non-catch-all +# routes keep their low-cardinality template name. +PASSTHROUGH_PREFIXES = frozenset( + { + "openai", + "openai_passthrough", + "anthropic", + "azure", + "azure_ai", + "bedrock", + "cohere", + "cursor", + "gemini", + "mistral", + "vllm", + "vertex_ai", + "vertex-ai", + "assemblyai", + "eu.assemblyai", + "milvus", + } +) + + +def _passthrough_span_name_hook(span: Any, scope: dict) -> None: + """FastAPI ``server_request_hook``: give passthrough server spans a useful name. + + The instrumentation matches the route at span creation, so both the span name + and ``http.route`` are set to the catch-all template (``/openai/{endpoint:path}``) + before this hook runs. Rewrite both to the real request path so each upstream + endpoint is distinguishable. (The ASGI ``http receive``/``http send`` sub-spans + can't be renamed from here — their name is captured at creation — so they are + dropped via ``exclude_spans`` at instrumentation time.) + """ + try: + if span is None or not span.is_recording(): + return + path = scope.get("path") or "" + method = scope.get("method") or "" + first_segment = path.lstrip("/").split("/", 1)[0] + if first_segment in PASSTHROUGH_PREFIXES: + span.update_name(f"{method} {path}".strip()) + span.set_attribute("http.route", path) + except Exception: + pass + + +def instrument_fastapi_app(app: Any) -> None: + """Attach OTel server-span instrumentation to the proxy FastAPI app. + + Safe no-op when the V2 gate is off or ``opentelemetry-instrumentation-fastapi`` + is unavailable. This MUST be called at app-creation time — once the lifespan + runs, the middleware stack is frozen and ``instrument_app`` raises "Cannot add + middleware after an application has started". + + No ``TracerProvider`` is passed, so the instrumentation binds to the OTel global + ``ProxyTracerProvider``; the proxy publishes the real provider as the global + after config load (see ``proxy_startup_event``), and the proxy delegates to it. + That way server spans and gen-ai spans share one provider and the same trace. + """ + try: + if not is_otel_v2_enabled(): + return + + # Lazy: only the V2-enabled path needs the optional + # ``opentelemetry-instrumentation-fastapi`` package, which is not part of the + # base ``litellm[proxy]`` install. Importing it at module top would make + # ``proxy_server``'s unconditional ``import`` of this module crash when the + # package is absent, even with the gate off. + from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor + + excluded_urls = ( + os.environ.get("OTEL_PYTHON_FASTAPI_EXCLUDED_URLS") + if "OTEL_PYTHON_FASTAPI_EXCLUDED_URLS" in os.environ + else _DEFAULT_EXCLUDED_URLS + ) + FastAPIInstrumentor.instrument_app( + app, + excluded_urls=excluded_urls, + server_request_hook=_passthrough_span_name_hook, + # Drop the ASGI "http receive"/"http send" lifecycle sub-spans: they + # are low-value noise and (for passthrough) carry the catch-all route + # template in their name, which can't be rewritten from a hook. + exclude_spans=["receive", "send"], + ) + except Exception as e: + verbose_logger.debug("Skipping OTel V2 FastAPI instrumentation: %s", e) diff --git a/litellm/integrations/otel/plumbing/__init__.py b/litellm/integrations/otel/plumbing/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/litellm/integrations/otel/plumbing/context.py b/litellm/integrations/otel/plumbing/context.py new file mode 100644 index 00000000000..64790da814b --- /dev/null +++ b/litellm/integrations/otel/plumbing/context.py @@ -0,0 +1,127 @@ +"""Trace-context + Baggage helpers.""" + +from contextvars import ContextVar +from typing import Mapping + +from opentelemetry import baggage +from opentelemetry.context import Context, get_current +from opentelemetry.trace import Span, get_current_span, set_span_in_context +from opentelemetry.trace.propagation.tracecontext import ( + TraceContextTextMapPropagator, +) + +_PROPAGATOR = TraceContextTextMapPropagator() + +# The request's root span — the FastAPI-owned SERVER span — captured ONCE when the +# proxy first resolves it, so request-level spans (the LLM call, guardrails) can +# parent to it EXPLICITLY instead of to whatever span happens to be active at the +# instant they are emitted. Ambient-only parenting (``get_current_span()``) is +# wrong at two boundaries: +# * inside the ``auth`` phase span the active span is the auth span, so an LLM / +# guardrail span emitted there would nest under auth instead of being its +# sibling; and +# * in a detached success task (pass-through logs success from a fire-and-forget +# ``asyncio.create_task``) the server span may not be active at all, orphaning +# the span into a brand-new trace. +# A ``ContextVar`` (not a request attribute) so it rides the request task's context +# and is inherited by ``asyncio.create_task`` children — i.e. the async logging +# callbacks that close the span. It is never reset: the contextvar dies with the +# request task, so there is nothing to leak. +_request_root_span: "ContextVar[Span | None]" = ContextVar( + "litellm_otel_request_root_span", default=None +) + + +def set_request_root_span(span: Span) -> None: + """Anchor the request's root (server) span for explicit child parenting. + + No-ops for a non-recordable span so a bad capture can never replace a good one + with a phantom parent. Idempotent — the proxy captures the same server span at + more than one entry point. + """ + if is_recordable_span(span): + _request_root_span.set(span) + + +def request_root_span() -> "Span | None": + """The anchored request root span, or ``None`` outside a proxy request.""" + span = _request_root_span.get() + return span if is_recordable_span(span) else None + + +def set_request_baggage( + values: Mapping[str, str], context: Context | None = None +) -> Context: + """Return a context with ``values`` written into Baggage.""" + ctx = context + for key, value in values.items(): + ctx = baggage.set_baggage(key, value, context=ctx) + return ctx if ctx is not None else (context or get_current()) + + +def get_baggage_attributes(context: Context | None = None) -> dict[str, str]: + """All Baggage entries on ``context`` as strings.""" + return {key: str(value) for key, value in baggage.get_all(context).items()} + + +def context_from_span(span: Span, context: Context | None = None) -> Context: + """A context with ``span`` as the active span (for explicit parenting).""" + return set_span_in_context(span, context=context) + + +def resolve_parent_context(threaded: Span | None = None) -> Context: + """The context a child span should parent under. + + Ambient-first: parent to the active OTel context (the server span, restored + by the logging worker or active in the request task), falling back to a span + passed explicitly (``threaded``) only when the ambient context has no + recordable span — e.g. a background service call with no request on the + stack. When neither is recordable the ambient context is returned unchanged, + so the span starts a new root trace. + + Only service/DB spans pass ``threaded`` (the ``parent_otel_span`` handed to + the service hook). Request-level spans — the LLM call and guardrails — are + created where the server span is genuinely ambient, so they never need it. + """ + ctx = get_current() + if is_recordable_span(threaded) and not is_recordable_span(get_current_span(ctx)): + ctx = context_from_span(threaded, context=ctx) # type: ignore[arg-type] + return ctx + + +def resolve_request_span_context() -> Context: + """The parent context for a request-level span (the LLM call, a guardrail). + + These are direct children of the request's root server span — siblings of the + ``auth`` phase span and of each other, never nested under whatever span is + momentarily active. So prefer the explicitly anchored root span; fall back to + ambient context only when there is no anchor (the SDK / no-proxy path), where + the span legitimately starts its own root trace. + + Unlike :func:`resolve_parent_context` (used by DB/service spans, which DO want + to nest under the active phase span, e.g. an auth DB lookup under ``auth``), + this never returns the active span when an anchor exists. + """ + root = request_root_span() + if root is not None: + return context_from_span(root) + return get_current() + + +def is_recordable_span(obj: object) -> bool: + """True if ``obj`` is a live span with a valid context (safe to parent under).""" + if not isinstance(obj, Span): + return False + try: + ctx = obj.get_span_context() + except Exception: + return False + return ctx is not None and ctx.is_valid + + +def extract_traceparent(headers: Mapping[str, str]) -> Context | None: + """Extract a remote parent context from incoming HTTP headers, if present.""" + if not any(key.lower() == "traceparent" for key in headers): + return None + carrier = {str(key).lower(): value for key, value in headers.items()} + return _PROPAGATOR.extract(carrier) diff --git a/litellm/integrations/otel/plumbing/metrics.py b/litellm/integrations/otel/plumbing/metrics.py new file mode 100644 index 00000000000..edd120f91e6 --- /dev/null +++ b/litellm/integrations/otel/plumbing/metrics.py @@ -0,0 +1,28 @@ +"""GenAI client metrics (token usage + operation duration histograms).""" + +from dataclasses import dataclass + +from opentelemetry.metrics import Histogram, Meter + +from litellm.integrations.otel.model.semconv import Metric + + +@dataclass(frozen=True) +class GenAIMetrics: + token_usage: Histogram + operation_duration: Histogram + + +def create_genai_metrics(meter: Meter) -> GenAIMetrics: + return GenAIMetrics( + token_usage=meter.create_histogram( + name=Metric.TOKEN_USAGE, + unit="{token}", + description="Number of tokens used per GenAI request.", + ), + operation_duration=meter.create_histogram( + name=Metric.OPERATION_DURATION, + unit="s", + description="GenAI operation duration.", + ), + ) diff --git a/litellm/integrations/otel/plumbing/providers.py b/litellm/integrations/otel/plumbing/providers.py new file mode 100644 index 00000000000..40a0e41b905 --- /dev/null +++ b/litellm/integrations/otel/plumbing/providers.py @@ -0,0 +1,220 @@ +"""Provider / exporter factory + the Baggage span processor.""" + +from typing import Callable, Iterable + +from opentelemetry import baggage +from opentelemetry.context import Context +from opentelemetry.sdk.resources import Resource +from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor, TracerProvider +from opentelemetry.sdk.trace.export import ( + BatchSpanProcessor, + ConsoleSpanExporter, + SimpleSpanProcessor, + SpanExporter, +) +from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( + InMemorySpanExporter, +) +from opentelemetry.trace import Span, SpanKind, Tracer + +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.model.semconv import LiteLLM +from litellm.integrations.otel.model.spans import LiteLLMSpanKind + +# Re-exported so ``providers.parse_headers`` remains a stable entry point. +from litellm.integrations.otel.model.utils import parse_headers as parse_headers + +_SPAN_KIND_BY_ROLE_KIND: dict[LiteLLMSpanKind, SpanKind] = { + LiteLLMSpanKind.SERVER: SpanKind.SERVER, + LiteLLMSpanKind.CLIENT: SpanKind.CLIENT, + LiteLLMSpanKind.INTERNAL: SpanKind.INTERNAL, + LiteLLMSpanKind.PRODUCER: SpanKind.PRODUCER, + LiteLLMSpanKind.CONSUMER: SpanKind.CONSUMER, +} + + +def to_otel_span_kind(kind: LiteLLMSpanKind) -> SpanKind: + return _SPAN_KIND_BY_ROLE_KIND[kind] + + +# Custom exporter factories keyed by ``ExporterSpec.kind``. A preset registers +# one here when its destination needs construction logic the built-in kinds +# can't express — e.g. an exporter that fetches an auth token lazily on its +# first export (off the event loop) instead of blocking at config-build time. +# Keeping the registry here lets this module stay vendor-agnostic: the factory +# lives with the integration that needs it. +_EXPORTER_FACTORIES: dict[str, Callable[[ExporterSpec], SpanExporter]] = {} + + +def register_exporter_factory( + kind: str, factory: Callable[[ExporterSpec], SpanExporter] +) -> None: + """Register a custom exporter ``factory`` for the exporter ``kind``.""" + _EXPORTER_FACTORIES[kind.lower()] = factory + + +class LiteLLMBaggageSpanProcessor(SpanProcessor): + """Stamps an allowlisted set of Baggage entries onto every span at start.""" + + def __init__( + self, + allowed_keys: Iterable[str], + allowed_prefixes: tuple[str, ...] = (LiteLLM.METADATA_PREFIX,), + ) -> None: + self._allowed_keys = frozenset(allowed_keys) + self._allowed_prefixes = tuple(allowed_prefixes) + + def _is_allowed(self, key: str) -> bool: + return key in self._allowed_keys or any( + key.startswith(prefix) for prefix in self._allowed_prefixes + ) + + def on_start(self, span: Span, parent_context: Context | None = None) -> None: + for key, value in baggage.get_all(parent_context).items(): + if self._is_allowed(key) and isinstance(value, (str, bool, int, float)): + span.set_attribute(key, value) + + def on_end(self, span: ReadableSpan) -> None: # noqa: D401 - no-op + return None + + def shutdown(self) -> None: + return None + + def force_flush(self, timeout_millis: int = 30000) -> bool: + return True + + +def _otlp_traces_endpoint(endpoint: str | None) -> str | None: + """Point an OTLP/HTTP base endpoint at the ``/v1/traces`` signal path. + + ``OTEL_EXPORTER_OTLP_ENDPOINT`` is a base URL (e.g. ``http://host:4318``). + The OTLP/HTTP exporter only appends the ``/v1/traces`` path when it reads + that env var itself; when an endpoint is passed explicitly it is used + verbatim, so a base URL would POST to the root and the collector returns + 404. Append the signal path here (leaving an already-correct path intact). + """ + if not endpoint: + return endpoint + endpoint = endpoint.rstrip("/") + # Splunk Observability uses ``/v2/trace/otlp``; never rewrite it. + if endpoint.endswith("/v1/traces") or "/v2/trace/otlp" in endpoint: + return endpoint + for other_signal in ("/v1/logs", "/v1/metrics"): + if endpoint.endswith(other_signal): + return endpoint[: -len(other_signal)] + "/v1/traces" + return endpoint + "/v1/traces" + + +def _exporter_from_spec(spec: ExporterSpec) -> SpanExporter: + kind = (spec.kind or "console").lower() + factory = _EXPORTER_FACTORIES.get(kind) + if factory is not None: + return factory(spec) + if kind in ("in_memory", "inmemory", "memory"): + return InMemorySpanExporter() + if kind in ("otlp_http", "http", "http/protobuf", "http/json"): + from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( + OTLPSpanExporter as HTTPExporter, + ) + + return HTTPExporter( + endpoint=_otlp_traces_endpoint(spec.endpoint), + headers=parse_headers(spec.headers), + ) + if kind in ("otlp_grpc", "grpc"): + from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( + OTLPSpanExporter as GRPCExporter, + ) + + return GRPCExporter(endpoint=spec.endpoint, headers=parse_headers(spec.headers)) + return ConsoleSpanExporter() + + +def _processor_for(exporter: SpanExporter, use_simple: bool | None) -> SpanProcessor: + """Pick a Simple or Batch span processor for ``exporter``. + + When ``use_simple`` is unset, default to Simple for console and in-memory + exporters (spans export synchronously, which tests rely on) and Batch for + everything else (the right export semantics for production). + """ + if use_simple is None: + use_simple = isinstance(exporter, (ConsoleSpanExporter, InMemorySpanExporter)) + return SimpleSpanProcessor(exporter) if use_simple else BatchSpanProcessor(exporter) + + +def build_span_exporter(config: OpenTelemetryV2Config) -> SpanExporter: + """Build a single exporter from the top-level config fields. + + Convenience for the common single-exporter case (and for tests): reads the + ``exporter`` / ``endpoint`` / ``headers`` fields. To configure multiple + exporters, populate ``config.exporters`` directly. + """ + return _exporter_from_spec( + ExporterSpec( + kind=config.exporter, endpoint=config.endpoint, headers=config.headers + ) + ) + + +def build_resource(config: OpenTelemetryV2Config) -> Resource: + attributes: dict[str, str] = {"service.name": config.service_name} + if config.deployment_environment: + attributes["deployment.environment"] = config.deployment_environment + attributes.update(config.resource_attributes) + return Resource.create(attributes) + + +def build_tracer_provider( + config: OpenTelemetryV2Config, + exporter: SpanExporter | None = None, + baggage_processor: SpanProcessor | None = None, + use_simple_processor: bool | None = None, +) -> TracerProvider: + """Build the shared :class:`TracerProvider`. + + Attach the Baggage processor first (so identity attributes land on each + span before any export decision), then add one ``SpanProcessor`` per + ``config.exporters`` entry — this is what fans spans out to multiple + backends. ``exporter`` and ``use_simple_processor`` are explicit overrides: + pass a single exporter to attach exactly that one (used by tests). + """ + provider = TracerProvider(resource=build_resource(config)) + if baggage_processor is None: + baggage_processor = LiteLLMBaggageSpanProcessor( + allowed_keys=config.baggage_promoted_keys + ) + provider.add_span_processor(baggage_processor) + + if exporter is not None: + provider.add_span_processor(_processor_for(exporter, use_simple_processor)) + return provider + + # ``config._normalize`` guarantees at least one spec (it folds the top-level + # ``exporter``/``endpoint``/``headers`` fields in when ``exporters`` is empty). + for spec in config.exporters: + exp = _exporter_from_spec(spec) + provider.add_span_processor( + _processor_for( + exp, + ( + spec.use_simple_processor + if spec.use_simple_processor is not None + else use_simple_processor + ), + ) + ) + return provider + + +def get_tracer(provider: TracerProvider, name: str = "litellm") -> Tracer: + return provider.get_tracer(name) + + +def in_memory_provider( + config: OpenTelemetryV2Config | None = None, +) -> tuple[TracerProvider, InMemorySpanExporter]: + """Convenience for tests: a provider exporting to an in-memory buffer.""" + cfg = config or OpenTelemetryV2Config(exporter="in_memory") + exporter = InMemorySpanExporter() + provider = build_tracer_provider(cfg, exporter=exporter) + return provider, exporter diff --git a/litellm/integrations/otel/plumbing/routing.py b/litellm/integrations/otel/plumbing/routing.py new file mode 100644 index 00000000000..4d0943a263a --- /dev/null +++ b/litellm/integrations/otel/plumbing/routing.py @@ -0,0 +1,101 @@ +"""Per-request multi-tenant tracer routing. + +When a request carries team/key vendor credentials in +``standard_callback_dynamic_params``, its spans must export through a +``TracerProvider`` whose OTLP headers carry those credentials. +``TenantTracerCache`` builds and caches one provider per distinct credential +set, and otherwise hands back the logger's default tracer. This lets a single +logger fan requests out to many tenants without needing a logger per tenant. +""" + +from collections import OrderedDict +from typing import Any, Mapping + +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.trace import Tracer + +from litellm._logging import verbose_logger +from litellm.integrations.otel.model.config import OpenTelemetryV2Config +from litellm.integrations.otel.presets import dynamic_otlp_headers +from litellm.integrations.otel.plumbing.providers import ( + build_tracer_provider, + get_tracer, +) + +# Exporter kinds that ignore headers — never rewritten with dynamic credentials. +_NON_OTLP_KINDS = ("console", "in_memory", "inmemory", "memory") + +# Cap on distinct credential-scoped providers held at once. ``dynamic_params`` +# can be populated from request metadata, so an unbounded cache lets a caller +# spawn one ``TracerProvider`` (plus its ``BatchSpanProcessor`` background +# thread) per unique credential set and exhaust the proxy. The LRU bound keeps +# the working set of active tenants resident while flushing and shutting down +# evicted providers so their threads are reclaimed. +_MAX_CACHED_PROVIDERS = 256 + + +def _shutdown_provider(provider: TracerProvider) -> None: + """Flush + stop an evicted provider's processors (reclaims their threads). + + ``TracerProvider.shutdown`` force-flushes each ``SpanProcessor`` before + stopping it, so any spans already handed to a ``BatchSpanProcessor`` are + exported rather than dropped. Best-effort: a shutdown failure must not break + the request that triggered the eviction. + """ + try: + provider.shutdown() + except Exception as e: # pragma: no cover - defensive + verbose_logger.debug("OTel V2: error shutting down evicted provider: %s", e) + + +class TenantTracerCache: + """Credential-scoped ``TracerProvider`` cache keyed by the dynamic headers.""" + + def __init__( + self, + config: OpenTelemetryV2Config, + callback_name: str | None, + tracer_name: str, + ) -> None: + self._config = config + self._callback_name = callback_name + self._tracer_name = tracer_name + self._providers: "OrderedDict[tuple[tuple[str, str], ...], TracerProvider]" = ( + OrderedDict() + ) + + def tracer_for(self, default: Tracer, dynamic_params: Any) -> Tracer: + """Return the tracer for this request. + + Use ``default`` unless the request's dynamic credentials require a + credential-scoped tracer, in which case build (or reuse) one. The cache + is a bounded LRU: the least-recently-used provider is flushed and shut + down on overflow so its exporter threads don't accumulate. + """ + headers = dynamic_otlp_headers(self._callback_name, dynamic_params) + if not headers: + return default + cache_key = tuple(sorted(headers.items())) + provider = self._providers.get(cache_key) + if provider is not None: + self._providers.move_to_end(cache_key) + else: + provider = build_tracer_provider(self._config_with_headers(headers)) + self._providers[cache_key] = provider + if len(self._providers) > _MAX_CACHED_PROVIDERS: + _, evicted = self._providers.popitem(last=False) + _shutdown_provider(evicted) + return get_tracer(provider, self._tracer_name) + + def _config_with_headers(self, headers: Mapping[str, str]) -> OpenTelemetryV2Config: + """Clone the config, replacing OTLP exporter headers with ``headers``.""" + header_str = ",".join(f"{key}={value}" for key, value in headers.items()) + exporters = [ + ( + spec + if spec.kind.lower() in _NON_OTLP_KINDS + else spec.model_copy(update={"headers": header_str}) + ) + for spec in self._config.exporters + ] + return self._config.model_copy(update={"exporters": exporters}) diff --git a/litellm/integrations/otel/presets/__init__.py b/litellm/integrations/otel/presets/__init__.py new file mode 100644 index 00000000000..c69d257ab52 --- /dev/null +++ b/litellm/integrations/otel/presets/__init__.py @@ -0,0 +1,78 @@ +"""Integration presets — each one returns an :class:`OpenTelemetryV2Config`. + +A preset is a callable that reads an integration's env vars and returns an +``OpenTelemetryV2Config`` describing the exporter destination, the mapper +vocabularies to apply, and any resource attributes. ``PRESET_BY_CALLBACK`` +maps a callback name (``"arize"``, ``"langfuse_otel"``, ...) to its preset so +the factory in ``litellm_logging`` can resolve a name and build a single +``OpenTelemetryV2`` instance from the result. +""" + +from typing import Callable + +from litellm.integrations.otel.presets.agentops import agentops_preset +from litellm.integrations.otel.presets.arize import arize_dynamic_headers, arize_preset +from litellm.integrations.otel.presets.base import Preset +from litellm.integrations.otel.presets.langfuse import ( + langfuse_dynamic_headers, + langfuse_preset, +) +from litellm.integrations.otel.presets.langtrace import langtrace_preset +from litellm.integrations.otel.presets.levo import levo_preset +from litellm.integrations.otel.presets.phoenix import phoenix_preset +from litellm.integrations.otel.presets.weave import weave_dynamic_headers, weave_preset +from litellm.types.utils import StandardCallbackDynamicParams + +#: Callback name → preset. The ``Preset`` annotation makes mypy verify every +#: registered value matches the preset interface. +PRESET_BY_CALLBACK: dict[str, Preset] = { + "agentops": agentops_preset, + "arize": arize_preset, + "arize_phoenix": phoenix_preset, + "langfuse_otel": langfuse_preset, + "langtrace": langtrace_preset, + "levo": levo_preset, + "weave_otel": weave_preset, +} + +#: Callback name → per-request OTLP header builder (team/key multi-tenant +#: routing). Only integrations that support dynamic credentials appear here — +#: Arize-Phoenix/Langtrace/Levo/AgentOps don't, so they use the logger's +#: default tracer. +DYNAMIC_HEADERS_BY_CALLBACK: dict[ + str, Callable[[StandardCallbackDynamicParams], dict[str, str]] +] = { + "arize": arize_dynamic_headers, + "langfuse_otel": langfuse_dynamic_headers, + "weave_otel": weave_dynamic_headers, +} + + +def dynamic_otlp_headers( + callback_name: str | None, + dynamic_params: StandardCallbackDynamicParams | None, +) -> dict[str, str] | None: + """Per-request OTLP headers for ``callback_name``, or ``None`` if N/A. + + ``None`` means "no per-request routing" — the caller uses its default tracer. + """ + builder = DYNAMIC_HEADERS_BY_CALLBACK.get(callback_name or "") + if builder is None or not dynamic_params: + return None + headers = builder(dynamic_params) + return headers or None + + +__all__ = [ + "PRESET_BY_CALLBACK", + "DYNAMIC_HEADERS_BY_CALLBACK", + "Preset", + "dynamic_otlp_headers", + "agentops_preset", + "arize_preset", + "langfuse_preset", + "langtrace_preset", + "levo_preset", + "phoenix_preset", + "weave_preset", +] diff --git a/litellm/integrations/otel/presets/agentops.py b/litellm/integrations/otel/presets/agentops.py new file mode 100644 index 00000000000..5a12818fd99 --- /dev/null +++ b/litellm/integrations/otel/presets/agentops.py @@ -0,0 +1,139 @@ +"""AgentOps preset — OTLP/HTTP to AgentOps' endpoint with a lazily-fetched JWT. + +AgentOps authenticates with a short-lived JWT minted from the API key. Fetching +it is blocking network I/O, so it must never run on the event loop: callback +construction (where presets are built) can run inside the proxy's async startup +or, in the SDK, on the first request. Instead of fetching at config-build time, +this preset registers a custom exporter (``kind="agentops"``) that mints the JWT +**on its first export** — which the ``BatchSpanProcessor`` runs in its own +worker thread, off any event loop — and caches it for the process lifetime. +""" + +from typing import Any + +import httpx +from pydantic import Field +from pydantic_settings import BaseSettings, SettingsConfigDict + +from litellm._logging import verbose_logger +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.plumbing.providers import register_exporter_factory + +_AGENTOPS_ENDPOINT = "https://otlp.agentops.cloud/v1/traces" +_AGENTOPS_AUTH_ENDPOINT = "https://api.agentops.ai/v3/auth/token" +_AGENTOPS_EXPORTER_KIND = "agentops" + + +class _AgentOpsSettings(BaseSettings): + model_config = SettingsConfigDict(case_sensitive=False, extra="ignore") + + api_key: str | None = Field(default=None, validation_alias="AGENTOPS_API_KEY") + service_name: str = Field( + default="agentops", validation_alias="AGENTOPS_SERVICE_NAME" + ) + environment: str | None = Field( + default=None, validation_alias="AGENTOPS_ENVIRONMENT" + ) + + +def agentops_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + """Build the AgentOps config without any network I/O. + + The ``agentops`` exporter mints (and caches) the JWT lazily on its first + export, so this stays non-blocking. ``project.id`` is therefore not a + resource attribute — it is encoded in the JWT, which AgentOps uses to route + the trace to the right project. + """ + settings = _AgentOpsSettings() + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind=_AGENTOPS_EXPORTER_KIND, + endpoint=_AGENTOPS_ENDPOINT, + options=( + {"api_key": settings.api_key} if settings.api_key else None + ), + ), + ], + "resource_attributes": { + **base.resource_attributes, + "service.name": settings.service_name, + "telemetry.sdk.name": "agentops", + **( + {"deployment.environment": settings.environment} + if settings.environment + else {} + ), + }, + } + ) + + +def _build_agentops_exporter(spec: ExporterSpec) -> Any: + """Factory for the ``agentops`` exporter kind: a lazy-auth OTLP/HTTP exporter.""" + from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( + OTLPSpanExporter, + ) + + class _LazyAuthAgentOpsExporter(OTLPSpanExporter): + """OTLP/HTTP exporter that mints the AgentOps JWT on its first export. + + ``export`` runs in the ``BatchSpanProcessor`` worker thread, so the + blocking token fetch never touches an event loop. The result is cached + after the first attempt (success or failure) so it runs at most once. + """ + + def __init__(self, *, endpoint: str | None, api_key: str | None) -> None: + super().__init__(endpoint=endpoint) + self._agentops_api_key = api_key + self._auth_resolved = False + + def _ensure_authenticated(self) -> None: + if self._auth_resolved: + return + self._auth_resolved = True + if not self._agentops_api_key: + return + try: + token = _fetch_agentops_jwt(self._agentops_api_key).get("token") + if token: + # ``_session`` is the requests.Session the base exporter + # POSTs through; updating its Authorization header is how the + # minted JWT reaches every subsequent export. + self._session.headers["Authorization"] = f"Bearer {token}" + except Exception as e: + verbose_logger.debug("AgentOps JWT fetch failed: %s", e) + + def export(self, spans: Any) -> Any: + self._ensure_authenticated() + return super().export(spans) + + options = spec.options or {} + return _LazyAuthAgentOpsExporter( + endpoint=spec.endpoint, api_key=options.get("api_key") + ) + + +def _fetch_agentops_jwt(api_key: str) -> dict[str, Any]: + # Own a short-lived client rather than ``_get_httpx_client()``: that returns + # a process-wide cached ``HTTPHandler`` whose connection pool is shared by + # every caller, so closing it here would break concurrent/subsequent + # requests. This one-shot auth call gets its own client to close. + with httpx.Client(timeout=10) as client: + response = client.post( + url=_AGENTOPS_AUTH_ENDPOINT, + headers={"Content-Type": "application/json", "Connection": "keep-alive"}, + json={"api_key": api_key}, + ) + if response.status_code != 200: + raise RuntimeError(f"Failed to fetch AgentOps token: {response.text}") + return response.json() + + +register_exporter_factory(_AGENTOPS_EXPORTER_KIND, _build_agentops_exporter) diff --git a/litellm/integrations/otel/presets/arize.py b/litellm/integrations/otel/presets/arize.py new file mode 100644 index 00000000000..4df15125f5a --- /dev/null +++ b/litellm/integrations/otel/presets/arize.py @@ -0,0 +1,75 @@ +"""Arize preset — OTLP exporter to Arize + OpenInference vocabulary.""" + +from pydantic import Field +from pydantic_settings import BaseSettings, SettingsConfigDict + +from litellm.integrations.arize.arize import ArizeLogger as _V1ArizeLogger +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.presets.utils import ensure_mappers +from litellm.types.utils import StandardCallbackDynamicParams + + +class _ArizeSettings(BaseSettings): + model_config = SettingsConfigDict(case_sensitive=False, extra="ignore") + + # Standard OTLP headers env var, used as the fallback when no Arize + # credentials are configured. + otlp_traces_headers: str | None = Field( + default=None, validation_alias="OTEL_EXPORTER_OTLP_TRACES_HEADERS" + ) + + +def arize_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + arize_cfg = _V1ArizeLogger.get_arize_config() + headers = _arize_headers(arize_cfg) + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind=arize_cfg.protocol or "otlp_grpc", + endpoint=arize_cfg.endpoint or "https://otlp.arize.com/v1", + headers=headers, + ), + ], + "mapper_names": ensure_mappers(base.mapper_names, "openinference"), + "resource_attributes": { + **base.resource_attributes, + **( + {"model_id": arize_cfg.project_name} + if arize_cfg.project_name + else {} + ), + }, + } + ) + + +def _arize_headers(arize_cfg) -> str | None: + pieces = [] + if arize_cfg.space_id or arize_cfg.space_key: + pieces.append(f"space_id={arize_cfg.space_id or arize_cfg.space_key}") + if arize_cfg.api_key: + pieces.append(f"api_key={arize_cfg.api_key}") + if not pieces: + # Fall back to the standard OTLP headers env var when no Arize + # credentials are configured. + return _ArizeSettings().otlp_traces_headers + return ",".join(pieces) + + +def arize_dynamic_headers(params: StandardCallbackDynamicParams) -> dict[str, str]: + """Per-request Arize OTLP headers from team/key dynamic params.""" + headers: dict[str, str] = {} + # ``arize_space_key`` is the suggested param and wins over ``arize_space_id``. + space = params.get("arize_space_key") or params.get("arize_space_id") + if space: + headers["arize-space-id"] = space + api_key = params.get("arize_api_key") + if api_key: + headers["api_key"] = api_key + return headers diff --git a/litellm/integrations/otel/presets/base.py b/litellm/integrations/otel/presets/base.py new file mode 100644 index 00000000000..b50908e7652 --- /dev/null +++ b/litellm/integrations/otel/presets/base.py @@ -0,0 +1,25 @@ +"""Preset interface. + +A preset is a callable that reads its integration's env vars and produces an +:class:`OpenTelemetryV2Config` (exporter list + mapper-name list + resource +attributes). This ``Protocol`` pins that contract so ``PRESET_BY_CALLBACK`` and +the factory in ``litellm_logging`` are type-checked structurally against it, +matching the ``AttributeMapper`` protocol the mappers use. +""" + +from typing import Protocol, runtime_checkable + +from litellm.integrations.otel.model.config import OpenTelemetryV2Config + + +@runtime_checkable +class Preset(Protocol): + """Reads an integration's env config and returns an ``OpenTelemetryV2Config``. + + ``config_overrides`` lets one preset layer onto another's config (or onto + test-supplied defaults); the factory calls presets with no arguments. + """ + + def __call__( + self, *, config_overrides: OpenTelemetryV2Config | None = None + ) -> OpenTelemetryV2Config: ... diff --git a/litellm/integrations/otel/presets/langfuse.py b/litellm/integrations/otel/presets/langfuse.py new file mode 100644 index 00000000000..011545384b9 --- /dev/null +++ b/litellm/integrations/otel/presets/langfuse.py @@ -0,0 +1,43 @@ +"""Langfuse-OTEL preset.""" + +from litellm.integrations.langfuse.langfuse_otel import ( + LangfuseOtelLogger as _V1Langfuse, +) +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.presets.utils import ensure_mappers +from litellm.types.utils import StandardCallbackDynamicParams + + +def langfuse_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + cfg = _V1Langfuse.get_langfuse_otel_config() + kind = cfg.exporter if isinstance(cfg.exporter, str) else "otlp_http" + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind=kind, + endpoint=cfg.endpoint, + headers=cfg.headers, + ), + ], + "mapper_names": ensure_mappers(base.mapper_names, "langfuse"), + } + ) + + +def langfuse_dynamic_headers(params: StandardCallbackDynamicParams) -> dict[str, str]: + """Per-request Langfuse OTLP headers from team/key dynamic params.""" + public_key = params.get("langfuse_public_key") + secret_key = params.get("langfuse_secret_key") + if public_key and secret_key: + return { + "Authorization": _V1Langfuse._get_langfuse_authorization_header( + public_key=public_key, secret_key=secret_key + ) + } + return {} diff --git a/litellm/integrations/otel/presets/langtrace.py b/litellm/integrations/otel/presets/langtrace.py new file mode 100644 index 00000000000..acdbaf870d3 --- /dev/null +++ b/litellm/integrations/otel/presets/langtrace.py @@ -0,0 +1,22 @@ +"""Langtrace preset — Langtrace consumes generic OTLP + a vendor mapper.""" + +from litellm.integrations.otel.model.config import OpenTelemetryV2Config +from litellm.integrations.otel.presets.utils import ensure_mappers + + +def langtrace_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + """Compose the Langtrace mapper on top of the customer's OTLP destination. + + Unlike Arize / Phoenix / Langfuse, Langtrace doesn't ship its own endpoint + — users point their existing OTLP collector at Langtrace and just + need the vendor attribute schema applied to outgoing spans. + """ + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "mapper_names": ensure_mappers(base.mapper_names, "langtrace"), + } + ) diff --git a/litellm/integrations/otel/presets/levo.py b/litellm/integrations/otel/presets/levo.py new file mode 100644 index 00000000000..4c4cba982a4 --- /dev/null +++ b/litellm/integrations/otel/presets/levo.py @@ -0,0 +1,24 @@ +"""Levo preset — OTLP/HTTP to a Levo collector with org+workspace headers.""" + +from litellm.integrations.levo.levo import LevoLogger as _V1Levo +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config + + +def levo_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + cfg = _V1Levo.get_levo_config() + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind="otlp_http", + endpoint=cfg.endpoint, + headers=cfg.otlp_auth_headers, + ), + ], + } + ) diff --git a/litellm/integrations/otel/presets/phoenix.py b/litellm/integrations/otel/presets/phoenix.py new file mode 100644 index 00000000000..4c2b165ffca --- /dev/null +++ b/litellm/integrations/otel/presets/phoenix.py @@ -0,0 +1,48 @@ +"""Arize-Phoenix preset.""" + +from pydantic import AliasChoices, Field +from pydantic_settings import BaseSettings, SettingsConfigDict + +from litellm.integrations.arize.arize_phoenix import ( + ArizePhoenixLogger as _V1Phoenix, +) +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.presets.utils import ensure_mappers + + +class _PhoenixSettings(BaseSettings): + model_config = SettingsConfigDict(case_sensitive=False, extra="ignore") + + project_name: str = Field( + default="default", + validation_alias=AliasChoices( + "PHOENIX_PROJECT_NAME", "PHOENIX_COLLECTOR_PROJECT_NAME" + ), + ) + + +def phoenix_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + cfg = _V1Phoenix.get_arize_phoenix_config() + headers = cfg.otlp_auth_headers if hasattr(cfg, "otlp_auth_headers") else None + project_name = _PhoenixSettings().project_name + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind=cfg.protocol if hasattr(cfg, "protocol") else "otlp_http", + endpoint=cfg.endpoint, + headers=headers, + ), + ], + "mapper_names": ensure_mappers(base.mapper_names, "openinference"), + "resource_attributes": { + **base.resource_attributes, + "openinference.project.name": project_name, + }, + } + ) diff --git a/litellm/integrations/otel/presets/utils.py b/litellm/integrations/otel/presets/utils.py new file mode 100644 index 00000000000..fdf8184441d --- /dev/null +++ b/litellm/integrations/otel/presets/utils.py @@ -0,0 +1,16 @@ +"""Shared helpers for the integration presets.""" + +from typing import Iterable + + +def ensure_mappers(mapper_names: Iterable[str], *names: str) -> list[str]: + """Return ``mapper_names`` with each of ``names`` appended if not already present. + + Order is preserved and duplicates are skipped, so composing several presets + (or re-applying one) never double-adds a vocabulary. + """ + result = list(mapper_names) + for name in names: + if name not in result: + result.append(name) + return result diff --git a/litellm/integrations/otel/presets/weave.py b/litellm/integrations/otel/presets/weave.py new file mode 100644 index 00000000000..9fc03c84a6d --- /dev/null +++ b/litellm/integrations/otel/presets/weave.py @@ -0,0 +1,43 @@ +"""Weave (W&B) preset.""" + +from litellm.integrations.otel.model.config import ExporterSpec, OpenTelemetryV2Config +from litellm.integrations.otel.presets.utils import ensure_mappers +from litellm.integrations.weave.weave_otel import ( + _get_weave_authorization_header, + get_weave_otel_config, +) +from litellm.types.utils import StandardCallbackDynamicParams + + +def weave_preset( + *, + config_overrides: OpenTelemetryV2Config | None = None, +) -> OpenTelemetryV2Config: + weave_cfg = get_weave_otel_config() + base = config_overrides or OpenTelemetryV2Config() + return base.model_copy( + update={ + "exporters": [ + *base.exporters, + ExporterSpec( + kind=weave_cfg.protocol or "otlp_http", + endpoint=weave_cfg.endpoint, + headers=weave_cfg.otlp_auth_headers, + ), + ], + # Weave consumes OpenInference + a small Weave-specific overlay. + "mapper_names": ensure_mappers(base.mapper_names, "openinference", "weave"), + } + ) + + +def weave_dynamic_headers(params: StandardCallbackDynamicParams) -> dict[str, str]: + """Per-request Weave OTLP headers from team/key dynamic params.""" + headers: dict[str, str] = {} + api_key = params.get("wandb_api_key") + if api_key: + headers["Authorization"] = _get_weave_authorization_header(api_key=api_key) + project_id = params.get("weave_project_id") + if project_id: + headers["project_id"] = project_id + return headers diff --git a/litellm/integrations/otel/runtime.py b/litellm/integrations/otel/runtime.py new file mode 100644 index 00000000000..ac3b991c971 --- /dev/null +++ b/litellm/integrations/otel/runtime.py @@ -0,0 +1,38 @@ +"""SDK-free entrypoints for proxy-core call sites (auth, …). + +Proxy code may run without the OpenTelemetry SDK installed, so it must not import +``litellm.integrations.otel.logger`` (which imports the SDK at module scope) at +module load. These wrappers import it lazily and no-op when the SDK is absent or +V2 is not the active logger — so a call site can wrap a request phase or seed +identity unconditionally. +""" + +from contextlib import contextmanager +from typing import Any, Iterator + + +@contextmanager +def phase_span(name: str) -> "Iterator[Any]": + """Run a request phase inside a live active span so its DB/service calls nest. + + Yields ``None`` (a plain no-op) when the OTel SDK is unavailable or V2 is not + the active logger. + """ + try: + from litellm.integrations.otel.logger import phase_span as _phase_span + except Exception: + yield None + return + with _phase_span(name) as span: + yield span + + +def seed_request_identity(user_api_key_dict: Any, model: Any = None) -> None: + """Seed request-identity Baggage at the auth boundary (no-op without V2).""" + try: + from litellm.integrations.otel.logger import ( + seed_request_identity as _seed_request_identity, + ) + except Exception: + return + _seed_request_identity(user_api_key_dict, model=model) diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 2c63455565c..5f052842122 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -166,6 +166,53 @@ def __init__( # noqa: PLR0915 labelnames=self.get_labels_for_metric("litellm_output_tokens_metric"), ) + # Token-type detail metrics. These break out cached, cache-creation, + # audio and reasoning tokens that providers report inside + # prompt_tokens_details / completion_tokens_details on the usage + # object. They are sparse (only incremented when the provider + # reports a non-zero value) and are additive to the existing + # input/output token totals — no breaking change for existing + # dashboards built on the totals. + self.litellm_input_cached_tokens_metric = self._counter_factory( + "litellm_input_cached_tokens_metric", + "Provider-side cached input tokens (e.g. OpenAI prompt_tokens_details.cached_tokens, Anthropic cache_read_input_tokens)", + labelnames=self.get_labels_for_metric( + "litellm_input_cached_tokens_metric" + ), + ) + + self.litellm_input_cache_creation_tokens_metric = self._counter_factory( + "litellm_input_cache_creation_tokens_metric", + "Provider-side input tokens written to prompt cache (e.g. Anthropic cache_creation_input_tokens)", + labelnames=self.get_labels_for_metric( + "litellm_input_cache_creation_tokens_metric" + ), + ) + + self.litellm_input_audio_tokens_metric = self._counter_factory( + "litellm_input_audio_tokens_metric", + "Audio input tokens reported in prompt_tokens_details.audio_tokens", + labelnames=self.get_labels_for_metric( + "litellm_input_audio_tokens_metric" + ), + ) + + self.litellm_output_reasoning_tokens_metric = self._counter_factory( + "litellm_output_reasoning_tokens_metric", + "Reasoning tokens reported in completion_tokens_details.reasoning_tokens", + labelnames=self.get_labels_for_metric( + "litellm_output_reasoning_tokens_metric" + ), + ) + + self.litellm_output_audio_tokens_metric = self._counter_factory( + "litellm_output_audio_tokens_metric", + "Audio output tokens reported in completion_tokens_details.audio_tokens", + labelnames=self.get_labels_for_metric( + "litellm_output_audio_tokens_metric" + ), + ) + # Remaining Budget for Team self.litellm_remaining_team_budget_metric = self._gauge_factory( "litellm_remaining_team_budget_metric", @@ -1301,6 +1348,101 @@ def _increment_token_metrics( amount=float(standard_logging_payload["completion_tokens"]), ) + # Token-type detail metrics — sparse, only emitted when the provider + # reports a non-zero value in usage.prompt_tokens_details / + # usage.completion_tokens_details. + self._increment_token_detail_metrics( + standard_logging_payload=standard_logging_payload, + enum_values=enum_values, + label_context=label_context, + ) + + def _increment_token_detail_metrics( + self, + standard_logging_payload: StandardLoggingPayload, + enum_values: UserAPIKeyLabelValues, + label_context: Optional[PrometheusLabelFactoryContext] = None, + ) -> None: + """ + Increment per-token-type counters from the Usage object that providers + attach to the request. The Usage dict is plumbed onto + ``standard_logging_payload["metadata"]["usage_object"]`` by + ``get_standard_logging_object_payload``. + + Each counter is only incremented when the underlying value is > 0, so + scrape output stays sparse for providers that don't report these + details (most non-OpenAI/Anthropic models). + """ + metadata = standard_logging_payload.get("metadata") or {} + usage_object = ( + metadata.get("usage_object") if isinstance(metadata, dict) else None + ) + if not isinstance(usage_object, dict): + return + + prompt_details = usage_object.get("prompt_tokens_details") or {} + completion_details = usage_object.get("completion_tokens_details") or {} + + detail_metrics: List[Tuple[Any, DEFINED_PROMETHEUS_METRICS, Any]] = [ + ( + self.litellm_input_cached_tokens_metric, + "litellm_input_cached_tokens_metric", + ( + prompt_details.get("cached_tokens") + if isinstance(prompt_details, dict) + else None + ), + ), + ( + self.litellm_input_cache_creation_tokens_metric, + "litellm_input_cache_creation_tokens_metric", + ( + prompt_details.get("cache_creation_tokens") + if isinstance(prompt_details, dict) + else None + ), + ), + ( + self.litellm_input_audio_tokens_metric, + "litellm_input_audio_tokens_metric", + ( + prompt_details.get("audio_tokens") + if isinstance(prompt_details, dict) + else None + ), + ), + ( + self.litellm_output_reasoning_tokens_metric, + "litellm_output_reasoning_tokens_metric", + ( + completion_details.get("reasoning_tokens") + if isinstance(completion_details, dict) + else None + ), + ), + ( + self.litellm_output_audio_tokens_metric, + "litellm_output_audio_tokens_metric", + ( + completion_details.get("audio_tokens") + if isinstance(completion_details, dict) + else None + ), + ), + ] + + for counter, metric_name, value in detail_metrics: + if not isinstance(value, (int, float)) or value <= 0: + continue + PrometheusLogger._inc_labeled_counter( + self, + counter, + metric_name, + enum_values, + label_context=label_context, + amount=float(value), + ) + def _increment_cache_metrics( self, standard_logging_payload: StandardLoggingPayload, diff --git a/litellm/litellm_core_utils/get_litellm_params.py b/litellm/litellm_core_utils/get_litellm_params.py index ad9538ac171..b32803b5dfc 100644 --- a/litellm/litellm_core_utils/get_litellm_params.py +++ b/litellm/litellm_core_utils/get_litellm_params.py @@ -1,5 +1,7 @@ from typing import Optional +from litellm.llms.openai.data_residency import infer_openai_data_residency + # Pre-define optional kwargs keys as frozenset for O(1) lookups # These are extracted from kwargs only if present, avoiding unnecessary .get() calls _OPTIONAL_KWARGS_KEYS = frozenset( @@ -103,6 +105,10 @@ def get_litellm_params( if litellm_trace_id is None: litellm_trace_id = _meta.get("trace_id") or _meta.get("session_id") + data_residency: Optional[str] = infer_openai_data_residency( + custom_llm_provider, api_base + ) + # Build base dict with explicit parameters (always included) litellm_params = { "acompletion": acompletion, @@ -112,6 +118,7 @@ def get_litellm_params( "verbose": verbose, "custom_llm_provider": custom_llm_provider, "api_base": api_base, + "data_residency": data_residency, "litellm_call_id": litellm_call_id, "model_alias_map": model_alias_map, "completion_call_id": completion_call_id, diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 2ab037afb0d..c127b3873a7 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1546,6 +1546,11 @@ def _response_cost_calculator( if self.optional_params else None ), + "data_residency": ( + self.litellm_params.get("data_residency") + if hasattr(self, "litellm_params") and self.litellm_params + else None + ), } except Exception as e: # error creating kwargs for cost calculation debug_info = StandardLoggingModelCostFailureDebugInformation( @@ -1607,6 +1612,90 @@ async def _response_cost_calculator_async( ) -> Optional[float]: return self._response_cost_calculator(result=result, cache_hit=cache_hit) + @staticmethod + def _is_sync_litellm_request(litellm_params: dict) -> bool: + """True for sync SDK entrypoints (``completion``), false for async (``acompletion``, etc.).""" + return ( + litellm_params.get(CallTypes.acompletion.value, False) is not True + and litellm_params.get(CallTypes.aresponses.value, False) is not True + and litellm_params.get(CallTypes.aembedding.value, False) is not True + and litellm_params.get(CallTypes.aimage_generation.value, False) is not True + and litellm_params.get(CallTypes.atranscription.value, False) is not True + ) + + def _is_assembled_stream_success(self, result=None) -> bool: + """Final assembled stream export (not a per-chunk success call). + + Per-chunk callers pass a ``ModelResponseStream`` (or ``None``); the + final assembled response is any other non-``None`` value (typically a + ``ModelResponse``). Treating a chunk as the assembled response would + prematurely set the ``has_dispatched_final_stream_success`` dedup + guard and silently suppress the real final stream log. + """ + if self.stream is not True: + return False + if result is not None and not isinstance(result, ModelResponseStream): + return True + return ( + "async_complete_streaming_response" in self.model_call_details + or self.model_call_details.get("complete_streaming_response") is not None + ) + + async def dispatch_success_handlers( + self, + result=None, + start_time=None, + end_time=None, + cache_hit=None, + prefer_async_handlers: bool = False, + **kwargs, + ) -> None: + """Route success logging to async and/or sync handlers for this request. + + ``prefer_async_handlers`` only bypasses the sync-SDK-only shortcut (e.g. + ``async for`` on a stream from ``completion()``). Legacy string callbacks + still run via ``executor.submit(success_handler)`` when configured. + """ + from litellm.litellm_core_utils.thread_pool_executor import executor + + if self._is_assembled_stream_success(result): + if self.model_call_details.get("has_dispatched_final_stream_success"): + return + self.model_call_details["has_dispatched_final_stream_success"] = True + + litellm_params = self.model_call_details.get("litellm_params", {}) or {} + sync_sdk = self._is_sync_litellm_request(litellm_params) + passthrough = self.call_type == CallTypes.pass_through.value + if sync_sdk and not prefer_async_handlers and not passthrough: + self.success_handler( + result, + start_time=start_time, + end_time=end_time, + cache_hit=cache_hit, + **kwargs, + ) + return + + await self.async_success_handler( + result, + start_time=start_time, + end_time=end_time, + cache_hit=cache_hit, + **kwargs, + ) + + if not self._should_run_sync_callbacks_for_async_calls(): + return + + executor.submit( + self.success_handler, + result, + start_time=start_time, + end_time=end_time, + cache_hit=cache_hit, + **kwargs, + ) + def should_run_logging( self, event_type: Literal[ @@ -2029,13 +2118,7 @@ def success_handler( # noqa: PLR0915 standard_logging_object=kwargs.get("standard_logging_object", None), ) litellm_params = self.model_call_details.get("litellm_params", {}) - is_sync_request = ( - litellm_params.get(CallTypes.acompletion.value, False) is not True - and litellm_params.get(CallTypes.aresponses.value, False) is not True - and litellm_params.get(CallTypes.aembedding.value, False) is not True - and litellm_params.get(CallTypes.aimage_generation.value, False) is not True - and litellm_params.get(CallTypes.atranscription.value, False) is not True - ) + is_sync_request = self._is_sync_litellm_request(litellm_params) try: ## BUILD COMPLETE STREAMED RESPONSE complete_streaming_response: Optional[ @@ -2491,9 +2574,11 @@ async def async_success_handler( # noqa: PLR0915 print_verbose( "Logging Details LiteLLM-Async Success Call, cache_hit={}".format(cache_hit) ) - if not self.should_run_logging( + if not self._is_assembled_stream_success( + result + ) and not self.should_run_logging( event_type="async_success" - ): # prevent double logging + ): # prevent double logging (non-streaming) return ## CALCULATE COST FOR BATCH JOBS @@ -2943,13 +3028,7 @@ def failure_handler( # noqa: PLR0915 ): # prevent double logging return litellm_params = self.model_call_details.get("litellm_params", {}) - is_sync_request = ( - litellm_params.get(CallTypes.acompletion.value, False) is not True - and litellm_params.get(CallTypes.aresponses.value, False) is not True - and litellm_params.get(CallTypes.aembedding.value, False) is not True - and litellm_params.get(CallTypes.aimage_generation.value, False) is not True - and litellm_params.get(CallTypes.atranscription.value, False) is not True - ) + is_sync_request = self._is_sync_litellm_request(litellm_params) try: start_time, end_time = self._failure_handler_helper_fn( @@ -3713,6 +3792,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 try: custom_logger_init_args = custom_logger_init_args or {} if logging_integration == "agentops": # Add AgentOps initialization + _v2 = _maybe_construct_otel_v2("agentops", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore for callback in _in_memory_loggers: if isinstance(callback, AgentOps): return callback # type: ignore @@ -3865,6 +3947,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(_opik_logger) return _opik_logger # type: ignore elif logging_integration == "arize": + _v2 = _maybe_construct_otel_v2("arize", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.opentelemetry import ( OpenTelemetry, OpenTelemetryConfig, @@ -3894,6 +3979,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(_arize_otel_logger) return _arize_otel_logger # type: ignore elif logging_integration == "arize_phoenix": + _v2 = _maybe_construct_otel_v2("arize_phoenix", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.opentelemetry import ( OpenTelemetry, OpenTelemetryConfig, @@ -3905,31 +3993,6 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 endpoint=arize_phoenix_config.endpoint, headers=arize_phoenix_config.otlp_auth_headers, ) - if arize_phoenix_config.project_name: - existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") - # Add openinference.project.name attribute - if existing_attrs: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"{existing_attrs},openinference.project.name={arize_phoenix_config.project_name}" - ) - else: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"openinference.project.name={arize_phoenix_config.project_name}" - ) - - # Set Phoenix project name from environment variable - phoenix_project_name = os.environ.get("PHOENIX_PROJECT_NAME", None) - if phoenix_project_name: - existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") - # Add openinference.project.name attribute - if existing_attrs: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"{existing_attrs},openinference.project.name={phoenix_project_name}" - ) - else: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"openinference.project.name={phoenix_project_name}" - ) # auth can be disabled on local deployments of arize phoenix if arize_phoenix_config.otlp_auth_headers is not None: @@ -3949,6 +4012,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(_arize_phoenix_otel_logger) return _arize_phoenix_otel_logger # type: ignore elif logging_integration == "levo": + _v2 = _maybe_construct_otel_v2("levo", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.levo.levo import LevoLogger from litellm.integrations.opentelemetry import ( OpenTelemetry, @@ -3974,6 +4040,28 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(_levo_otel_logger) return _levo_otel_logger # type: ignore elif logging_integration == "otel": + # Gate the new typed V2 adapter behind LITELLM_OTEL_V2. When off, + # the legacy 3,227-line god-class is used unchanged. The two are + # never registered simultaneously — the dedup loop below treats + # any module under ``litellm.integrations.otel`` or + # ``litellm.integrations.opentelemetry`` as "the OTel callback". + from litellm.integrations.otel.model.config import is_otel_v2_enabled + + if is_otel_v2_enabled(): + from litellm.integrations.otel.logger import OpenTelemetryV2 + + for callback in _in_memory_loggers: + if type(callback) is OpenTelemetryV2: + return callback # type: ignore + otel_logger_v2 = OpenTelemetryV2( + **_get_custom_logger_settings_from_proxy_server( + callback_name=logging_integration + ) + ) + _in_memory_loggers.append(otel_logger_v2) + _maybe_auto_initialize_arize_phoenix(_in_memory_loggers) + return otel_logger_v2 # type: ignore + from litellm.integrations.opentelemetry import OpenTelemetry for callback in _in_memory_loggers: @@ -4112,6 +4200,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 elif logging_integration == "langtrace": if "LANGTRACE_API_KEY" not in os.environ: raise ValueError("LANGTRACE_API_KEY not found in environment variables") + _v2 = _maybe_construct_otel_v2("langtrace", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.opentelemetry import ( OpenTelemetry, @@ -4152,6 +4243,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(langfuse_logger) return langfuse_logger # type: ignore elif logging_integration == "langfuse_otel": + _v2 = _maybe_construct_otel_v2("langfuse_otel", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.langfuse.langfuse_otel import LangfuseOtelLogger for callback in _in_memory_loggers: @@ -4168,6 +4262,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 _in_memory_loggers.append(_otel_logger) return _otel_logger # type: ignore elif logging_integration == "weave_otel": + _v2 = _maybe_construct_otel_v2("weave_otel", _in_memory_loggers) + if _v2 is not None: + return _v2 # type: ignore from litellm.integrations.opentelemetry import OpenTelemetryConfig from litellm.integrations.weave.weave_otel import ( WeaveOtelLogger, @@ -4316,6 +4413,42 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 return None +def _maybe_construct_otel_v2( + callback_name: str, _in_memory_loggers: list +) -> Optional[Any]: + """If ``LITELLM_OTEL_V2`` is on, build (or reuse) a single ``OpenTelemetryV2`` + instance configured via the preset for ``callback_name``. + + Returns ``None`` when V2 is off OR when there's no preset registered for + ``callback_name`` — callers should then fall through to the legacy path. + """ + from litellm.integrations.otel.model.config import is_otel_v2_enabled + + if not is_otel_v2_enabled(): + return None + from litellm.integrations.otel.logger import OpenTelemetryV2 + from litellm.integrations.otel.presets import PRESET_BY_CALLBACK + + preset_fn = PRESET_BY_CALLBACK.get(callback_name) + if preset_fn is None: + return None + for callback in _in_memory_loggers: + if ( + isinstance(callback, OpenTelemetryV2) + and getattr(callback, "callback_name", None) == callback_name + ): + return callback + try: + config = preset_fn() + except Exception: + # If env vars are missing or the preset raises, defer to the legacy path + # so customers get the same error story they had before V2 landed. + return None + v2_logger = OpenTelemetryV2(config=config, callback_name=callback_name) + _in_memory_loggers.append(v2_logger) + return v2_logger + + def _maybe_auto_initialize_arize_phoenix(_in_memory_loggers: list) -> None: """ Auto-initialize ArizePhoenixLogger when Phoenix env vars are detected. @@ -5140,13 +5273,17 @@ def get_error_information( ) -> StandardLoggingPayloadErrorInformation: from litellm.constants import MAXIMUM_TRACEBACK_LINES_TO_LOG - # Check for 'code' first (used by ProxyException), then fall back to 'status_code' (used by LiteLLM exceptions) - # Ensure error_code is always a string for Prisma Python JSON field compatibility + # ProxyException uses .code, LiteLLM exceptions use .status_code, + # httpx.HTTPStatusError exposes status only as .response.status_code. + # Stringified for Prisma JSON compatibility. error_code_attr = getattr(original_exception, "code", None) if error_code_attr is not None and str(error_code_attr) not in ("", "None"): error_status: str = str(error_code_attr) else: status_code_attr = getattr(original_exception, "status_code", None) + if status_code_attr is None: + response_attr = getattr(original_exception, "response", None) + status_code_attr = getattr(response_attr, "status_code", None) error_status = str(status_code_attr) if status_code_attr is not None else "" error_class: str = ( str(original_exception.__class__.__name__) if original_exception else "" diff --git a/litellm/litellm_core_utils/llm_cost_calc/utils.py b/litellm/litellm_core_utils/llm_cost_calc/utils.py index 59d0465e6d4..882561ed2e8 100644 --- a/litellm/litellm_core_utils/llm_cost_calc/utils.py +++ b/litellm/litellm_core_utils/llm_cost_calc/utils.py @@ -9,6 +9,7 @@ CacheCreationTokenDetails, CallTypes, CompletionTokensDetailsWrapper, + DataResidency, ImageResponse, ModelInfo, PassthroughCallTypes, @@ -29,6 +30,9 @@ } ) +# Pre-resolved DataResidency enum values for fast membership checks +_VALID_DATA_RESIDENCIES = frozenset(r.value for r in DataResidency) + def _is_above_128k(tokens: float) -> bool: if tokens > 128000: @@ -617,11 +621,46 @@ def _calculate_input_cost( return prompt_cost +def _get_regional_uplift_multiplier( + model_info: ModelInfo, data_residency: Optional[str] +) -> float: + """ + Resolve the per-model regional-processing uplift multiplier for a given + data-residency region. + + OpenAI applies a flat percentage uplift (e.g. +10%) on all token costs for + requests served from a regionalized hostname (eu./us.api.openai.com). The + multiplier is stored on the model entry as + ``regional_processing_uplift_multiplier_`` (e.g. 1.10). + + Returns 1.0 (no uplift) when ``data_residency`` is ``None`` or when the + model has no multiplier configured for the given region. + """ + if data_residency is None: + return 1.0 + residency = data_residency.lower() + if residency not in _VALID_DATA_RESIDENCIES: + return 1.0 + multiplier = model_info.get(f"regional_processing_uplift_multiplier_{residency}") + if multiplier is None: + return 1.0 + try: + return float(cast(float, multiplier)) + except (TypeError, ValueError): + verbose_logger.exception( + "Invalid regional_processing_uplift_multiplier_%s for model; " + "defaulting to 1.0", + residency, + ) + return 1.0 + + def generic_cost_per_token( # noqa: PLR0915 model: str, usage: Usage, custom_llm_provider: str, service_tier: Optional[str] = None, + data_residency: Optional[str] = None, ) -> Tuple[float, float]: """ Calculates the cost per token for a given model, prompt tokens, and completion tokens. @@ -631,6 +670,8 @@ def generic_cost_per_token( # noqa: PLR0915 Input: - model: str, the model name without provider prefix - usage: LiteLLM Usage block, containing anthropic caching information + - data_residency: optional OpenAI data-residency region (e.g. "eu", "us"), + used to apply the per-model regional-processing uplift multiplier. Returns: Tuple[float, float] - prompt_cost_in_usd, completion_cost_in_usd @@ -781,6 +822,14 @@ def generic_cost_per_token( # noqa: PLR0915 ) completion_cost += float(image_tokens) * _output_cost_per_image_token + ## REGIONAL DATA-RESIDENCY UPLIFT + # Applied as a flat multiplier across all token costs for the request + # when the upstream is a regionalized OpenAI host (eu./us.api.openai.com). + uplift = _get_regional_uplift_multiplier(model_info, data_residency) + if uplift != 1.0: + prompt_cost *= uplift + completion_cost *= uplift + return prompt_cost, completion_cost diff --git a/litellm/litellm_core_utils/prompt_templates/common_utils.py b/litellm/litellm_core_utils/prompt_templates/common_utils.py index 32ae61d7f58..b44d21368f8 100644 --- a/litellm/litellm_core_utils/prompt_templates/common_utils.py +++ b/litellm/litellm_core_utils/prompt_templates/common_utils.py @@ -3,6 +3,7 @@ """ import io +import json import mimetypes import re from os import PathLike @@ -132,6 +133,39 @@ def strip_none_values_from_message(message: AllMessageValues) -> AllMessageValue return cast(AllMessageValues, {k: v for k, v in message.items() if v is not None}) +def extract_search_results_text(search_results: object) -> str: + """ + Extract model-visible text from OpenAI tool-message ``search_results``. + + Used by token estimators and TPM limiters so large search result payloads + cannot bypass preflight checks via a small ``content`` field. + + Counts every string field forwarded on Bedrock ``SearchResultBlock``: + ``source``, ``title``, ``content[].text``, and ``citations``. + """ + if not isinstance(search_results, list): + return "" + texts = "" + for result in search_results: + if not isinstance(result, dict): + continue + for key in ("source", "title"): + value = result.get(key) + if isinstance(value, str): + texts += value + content = result.get("content") + if isinstance(content, list): + for block in content: + if isinstance(block, dict): + text = block.get("text") + if isinstance(text, str): + texts += text + citations = result.get("citations") + if citations is not None: + texts += json.dumps(citations, separators=(",", ":")) + return texts + + def convert_content_list_to_str( message: Union[AllMessageValues, ChatCompletionResponseMessage], ) -> str: @@ -152,6 +186,7 @@ def convert_content_list_to_str( elif message_content is not None and isinstance(message_content, str): texts = message_content + texts += extract_search_results_text(message.get("search_results")) return texts diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index f169f86079a..46e9b43a429 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -3658,6 +3658,7 @@ def stringify_json_tool_call_content(messages: List) -> List: ToolInputSchemaBlock as BedrockToolInputSchemaBlock, ) from litellm.types.llms.bedrock import ToolJsonSchemaBlock as BedrockToolJsonSchemaBlock +from litellm.types.llms.bedrock import SearchResultBlock from litellm.types.llms.bedrock import ToolResultBlock as BedrockToolResultBlock from litellm.types.llms.bedrock import ( ToolResultContentBlock as BedrockToolResultContentBlock, @@ -3997,7 +3998,7 @@ def _convert_to_bedrock_tool_call_invoke( for tool in tool_calls: if "function" in tool: tool_id = tool["id"] - name = tool["function"].get("name", "") + name = make_valid_bedrock_tool_name(tool["function"].get("name", "")) arguments = tool["function"].get("arguments", "") if not arguments or not arguments.strip(): @@ -4063,6 +4064,122 @@ def _convert_to_bedrock_tool_call_invoke( ) +def _append_bedrock_tool_result_media_block( + tool_result_content_blocks: List[BedrockToolResultContentBlock], + processed_block: BedrockContentBlock, + content: dict, + content_type: str, +) -> None: + if "image" in processed_block: + tool_result_content_blocks.append( + BedrockToolResultContentBlock(image=processed_block["image"]) + ) + elif "document" in processed_block: + tool_result_content_blocks.append( + BedrockToolResultContentBlock(document=processed_block["document"]) + ) + else: + verbose_logger.warning( + "Bedrock Converse: unrecognized BedrockContentBlock keys " + "%s for %s tool-result block %s; dropping.", + list(processed_block.keys()), + content_type, + content, + ) + + +def _append_bedrock_tool_result_image_url_block( + tool_result_content_blocks: List[BedrockToolResultContentBlock], + content: dict, +) -> None: + format: Optional[str] = None + if isinstance(content["image_url"], dict): + image_url = content["image_url"]["url"] + format = content["image_url"].get("format") + else: + image_url = content["image_url"] + processed_block = BedrockImageProcessor.process_image_sync( + image_url=image_url, + format=format, + ) + _append_bedrock_tool_result_media_block( + tool_result_content_blocks, processed_block, content, "image_url" + ) + + +def _append_bedrock_tool_result_file_block( + tool_result_content_blocks: List[BedrockToolResultContentBlock], + content: dict, +) -> None: + # Match the user-message path (_process_file_message): accept either + # file_data (base64 data URI) or file_id (server-side reference / URL). + file_obj = content.get("file") or {} + file_data = file_obj.get("file_data") + file_id = file_obj.get("file_id") + if file_data is None and file_id is None: + raise litellm.BadRequestError( + message="file_data and file_id cannot both be None. Got={}".format(content), + model="", + llm_provider="bedrock", + ) + processed_block = BedrockImageProcessor.process_image_sync( + image_url=cast(str, file_id or file_data), + format=file_obj.get("format"), + ) + _append_bedrock_tool_result_media_block( + tool_result_content_blocks, processed_block, content, "file" + ) + + +def _parse_bedrock_tool_result_content_list( + content_list: List, +) -> List[BedrockToolResultContentBlock]: + tool_result_content_blocks: List[BedrockToolResultContentBlock] = [] + for content in content_list: + if content["type"] == "text": + tool_result_content_blocks.append( + BedrockToolResultContentBlock(text=content["text"]) + ) + elif content["type"] == "image_url": + _append_bedrock_tool_result_image_url_block( + tool_result_content_blocks, content + ) + elif content["type"] == "file": + _append_bedrock_tool_result_file_block(tool_result_content_blocks, content) + return tool_result_content_blocks + + +def _build_bedrock_tool_result_content_blocks( + message: Union[ChatCompletionToolMessage, ChatCompletionFunctionMessage], +) -> tuple[List[BedrockToolResultContentBlock], bool]: + # Optional OpenAI tool-message extension: + # allow structured Bedrock search results on tool messages and map them + # directly to toolResult.content[].searchResult for Converse API. + # + # If `search_results` is present, we intentionally prefer it over `content` + # to avoid generating mixed text + searchResult blocks. + search_results = message.get("search_results") + if isinstance(search_results, list): + tool_result_content_blocks: List[BedrockToolResultContentBlock] = [] + for result in search_results: + if not isinstance(result, dict): + continue + tool_result_content_blocks.append( + BedrockToolResultContentBlock( + searchResult=cast(SearchResultBlock, result) + ) + ) + if tool_result_content_blocks: + return tool_result_content_blocks, True + + message_content = message["content"] + if isinstance(message_content, str): + return [BedrockToolResultContentBlock(text=message_content)], False + if isinstance(message_content, List): + return _parse_bedrock_tool_result_content_list(message_content), False + return [], False + + def _convert_to_bedrock_tool_call_result( message: Union[ChatCompletionToolMessage, ChatCompletionFunctionMessage], ) -> BedrockContentBlock: @@ -4106,90 +4223,18 @@ def _convert_to_bedrock_tool_call_result( """ - """ - tool_result_content_blocks: List[BedrockToolResultContentBlock] = [] - if isinstance(message["content"], str): - tool_result_content_blocks.append( - BedrockToolResultContentBlock(text=message["content"]) - ) - elif isinstance(message["content"], List): - content_list = message["content"] - for content in content_list: - if content["type"] == "text": - tool_result_content_blocks.append( - BedrockToolResultContentBlock(text=content["text"]) - ) - elif content["type"] == "image_url": - format: Optional[str] = None - if isinstance(content["image_url"], dict): - image_url = content["image_url"]["url"] - format = content["image_url"].get("format") - else: - image_url = content["image_url"] - _block: BedrockContentBlock = BedrockImageProcessor.process_image_sync( - image_url=image_url, - format=format, - ) - if "image" in _block: - tool_result_content_blocks.append( - BedrockToolResultContentBlock(image=_block["image"]) - ) - elif "document" in _block: - tool_result_content_blocks.append( - BedrockToolResultContentBlock(document=_block["document"]) - ) - else: - verbose_logger.warning( - "Bedrock Converse: unrecognized BedrockContentBlock keys " - "%s for image_url tool-result block %s; dropping.", - list(_block.keys()), - content, - ) - elif content["type"] == "file": - # Match the user-message path (_process_file_message): accept - # either file_data (base64 data URI) or file_id (server-side - # reference / URL) and hand off to BedrockImageProcessor. Raise - # BadRequestError on both-None rather than silently dropping. - file_obj = content.get("file") or {} - file_data = file_obj.get("file_data") - file_id = file_obj.get("file_id") - if file_data is None and file_id is None: - raise litellm.BadRequestError( - message="file_data and file_id cannot both be None. Got={}".format( - content - ), - model="", - llm_provider="bedrock", - ) - file_format = file_obj.get("format") - _file_block: BedrockContentBlock = ( - BedrockImageProcessor.process_image_sync( - image_url=cast(str, file_id or file_data), - format=file_format, - ) - ) - if "document" in _file_block: - tool_result_content_blocks.append( - BedrockToolResultContentBlock(document=_file_block["document"]) - ) - elif "image" in _file_block: - tool_result_content_blocks.append( - BedrockToolResultContentBlock(image=_file_block["image"]) - ) - else: - verbose_logger.warning( - "Bedrock Converse: unrecognized BedrockContentBlock keys " - "%s for file tool-result block %s; dropping.", - list(_file_block.keys()), - content, - ) + tool_result_content_blocks, used_search_results = ( + _build_bedrock_tool_result_content_blocks(message) + ) message.get("name", "") id = str(message.get("tool_call_id", str(uuid.uuid4()))) tool_result = BedrockToolResultBlock( - content=tool_result_content_blocks, - toolUseId=id, + content=tool_result_content_blocks, toolUseId=id ) + if used_search_results: + tool_result["status"] = cast(Literal["success"], "success") content_block = BedrockContentBlock(toolResult=tool_result) @@ -5323,16 +5368,10 @@ def _bedrock_converse_messages_pt( # noqa: PLR0915 def make_valid_bedrock_tool_name(input_tool_name: str) -> str: - """ - Replaces any invalid characters in the input tool name with underscores - and ensures the resulting string is a valid identifier for Bedrock tools - """ + """Normalize tool names to Bedrock pattern [a-zA-Z][a-zA-Z0-9_-]*.""" def replace_invalid(char): - """ - Bedrock tool names only supports alpha-numeric characters and underscores - """ - if char.isalnum() or char == "_": + if char.isalnum() or char in ("_", "-"): return char return "_" @@ -5492,7 +5531,7 @@ def _bedrock_tools_pt( raw_name = f"litellm_unnamed_tool_{tool_idx}" # related issue: https://github.com/BerriAI/litellm/issues/5007 - # Bedrock tool names must satisfy regular expression pattern: [a-zA-Z][a-zA-Z0-9_]* ensure this is true + # Bedrock tool names must satisfy pattern: [a-zA-Z][a-zA-Z0-9_-]* name = make_valid_bedrock_tool_name(input_tool_name=raw_name) if _tool_description: # bedrock doesn't accept empty "" or None descriptions description = _tool_description diff --git a/litellm/litellm_core_utils/realtime_streaming.py b/litellm/litellm_core_utils/realtime_streaming.py index c4528ff74e3..33bb6d7d2ea 100644 --- a/litellm/litellm_core_utils/realtime_streaming.py +++ b/litellm/litellm_core_utils/realtime_streaming.py @@ -86,6 +86,12 @@ def __init__( # When a text message is blocked, hold the guardrail reason so the next # response.create can be rewritten to include the failure context. self._pending_guardrail_message: Optional[str] = None + # Track whether session.created has already been sent to the client + # (e.g. synthetic event in deferred setup mode). + self._session_created_sent_to_client: bool = False + # Track whether we have already sent the guardrail turn-detection update + # that disables provider auto-response for transcription guardrails. + self._guardrail_turn_detection_update_sent: bool = False _SESSION_EVENT_TYPES = frozenset(["session.created", "session.updated"]) _AUDIO_FORMAT_MAP: Dict[str, Dict[str, Any]] = { @@ -248,40 +254,82 @@ async def log_messages(self): ## SYNC LOGGING executor.submit(self.logging_obj.success_handler(self.messages)) - async def _send_to_backend(self, message: str) -> None: + async def _send_to_backend(self, message: str) -> bool: """Send a message to the backend WebSocket. If a provider_config is set the message is first passed through transform_realtime_request so that provider-specific translation (e.g. dropping session.update for Vertex AI) is applied even for guardrail-injected messages. + + Returns True if at least one message was actually delivered to the + backend, False if the provider transformation produced no output and + the message was effectively dropped. """ if self.provider_config: transformed = self.provider_config.transform_realtime_request( message, self.model, self.session_configuration_request ) + sent = False for msg in transformed: + # Send first; only cache the setup payload once the backend + # has actually accepted it. Caching before send would leave + # ``session_configuration_request`` populated after a failed + # send, causing subsequent client session.update messages to + # be treated as "subsequent" and dropped even though the + # backend never received the original setup. await self.backend_ws.send(msg) # type: ignore[union-attr, attr-defined] - else: - await self.backend_ws.send(message) # type: ignore[union-attr, attr-defined] + self._cache_session_configuration_request(msg) + sent = True + return sent + await self.backend_ws.send(message) # type: ignore[union-attr, attr-defined] + return True + + def _cache_session_configuration_request(self, transformed_message: str) -> None: + """Store setup payload once sent to backend. + + Updates the cached setup on every successful setup send so follow-up + ``session.update`` messages (which produce a merged setup with new + ``generationConfig`` / ``systemInstruction`` / etc.) are reflected in + the cache used by downstream readers (``transform_session_created_event``, + ``return_new_content_delta_events`` modality lookup, ...). + """ + try: + message_obj = json.loads(transformed_message) + if "setup" in message_obj: + self.session_configuration_request = transformed_message + except (json.JSONDecodeError, TypeError): + return def _make_disable_auto_response_message(self) -> str: """Return a session.update that disables VAD auto-response.""" + turn_detection: Dict[str, Any] = { + "type": "server_vad", + "create_response": False, + } if self._backend_uses_beta_protocol: - session: Dict[str, Any] = { - "turn_detection": {"create_response": False}, - } + session: Dict[str, Any] = {"turn_detection": turn_detection} else: session = { "type": "realtime", - "audio": { - "input": { - "turn_detection": {"create_response": False}, - } - }, + "audio": {"input": {"turn_detection": turn_detection}}, } return json.dumps({"type": "session.update", "session": session}) + async def _maybe_send_guardrail_turn_detection_update(self) -> None: + """Disable provider auto-response once when transcription guardrails are enabled.""" + if self._guardrail_turn_detection_update_sent: + return + if not self._has_audio_transcription_guardrails(): + return + sent = await self._send_to_backend(self._make_disable_auto_response_message()) + # Only mark as sent when the provider transformation actually delivered + # the update to the backend. Otherwise (e.g. Gemini drops session.update + # after the initial setup), leave the flag unset so future opportunities + # — such as a duplicate session.created — can retry. + if sent: + self._guardrail_turn_detection_update_sent = True + def _has_realtime_guardrails(self) -> bool: """Return True if any callback is registered for realtime guardrail event types.""" from litellm.integrations.custom_guardrail import CustomGuardrail @@ -320,12 +368,20 @@ async def run_realtime_guardrails( self, transcript: str, item_id: Optional[str] = None, + pre_block_backend_message: Optional[str] = None, ) -> bool: """ Run registered guardrails on a completed speech transcription. Returns True if blocked (synthetic warning already sent to client). Returns False if clean (caller should send response.create to the backend). + + ``pre_block_backend_message`` (if provided) is sent to the backend + BEFORE any of the guardrail's own backend messages when a block is + triggered. This is needed for protocol contracts that require a + specific message to be sent first — e.g. Gemini Live requires a + matching ``toolResponse`` immediately after a ``toolCall`` before any + other client messages can be accepted. """ from litellm.integrations.custom_guardrail import CustomGuardrail from litellm.types.guardrails import GuardrailEventHooks @@ -385,6 +441,13 @@ async def run_realtime_guardrails( getattr(callback, "realtime_violation_message", None) or safe_msg ) + # Deliver any caller-supplied backend message FIRST so that + # protocol contracts requiring a specific ordering (e.g. + # Gemini Live's mandatory ``toolResponse`` after a + # ``toolCall``) are honored before the guardrail's own + # clientContent / cancel messages are sent. + if pre_block_backend_message is not None: + await self._send_to_backend(pre_block_backend_message) # Cancel any in-progress LLM response (e.g. VAD auto-response). await self._send_to_backend(json.dumps({"type": "response.cancel"})) # Send the policy violation hint (shows as small gray status text in UI). @@ -480,16 +543,34 @@ async def _handle_provider_config_message(self, raw_response) -> None: else [transformed_response] ) for event in events: + is_session_created_event = ( + isinstance(event, dict) and event.get("type") == "session.created" + ) + if is_session_created_event: + if self._session_created_sent_to_client: + # A synthetic session.created (with placeholder defaults) was + # already forwarded to the client when we connected. The + # provider's real session.created (e.g. emitted from Gemini + # `setupComplete`) carries the authoritative modalities/model + # from the client's session.update. Re-emit it as + # `session.updated` so the client learns the corrected + # configuration without seeing two `session.created` events. + event = {**event, "type": "session.updated"} + else: + self._session_created_sent_to_client = True event_str = json.dumps(event) - ## For audio/VAD guardrail path: forward session.created first, then inject. - if ( - isinstance(event, dict) - and event.get("type") == "session.created" - and self._has_audio_transcription_guardrails() - ): + ## For audio/VAD guardrail path: forward the (possibly retyped) + ## session.created first, then invoke the one-time guardrail + ## turn-detection update. ``_maybe_send_guardrail_turn_detection_update`` + ## is idempotent (gated by ``_guardrail_turn_detection_update_sent``), + ## so duplicate session.created events — including those emitted + ## after a synthetic session.created from ``llm_http_handler`` in + ## deferred-setup mode — still get a single chance to inject the + ## update if a prior attempt was dropped by the provider transform. + if is_session_created_event and self._has_audio_transcription_guardrails(): self.store_message(event_str) await self.websocket.send_text(event_str) - await self._send_to_backend(self._make_disable_auto_response_message()) + await self._maybe_send_guardrail_turn_detection_update() continue ## GUARDRAIL: run on transcription events in provider_config path too if ( @@ -564,10 +645,19 @@ async def backend_to_client_send_messages(self): try: raw_response = await self.backend_ws.recv( # type: ignore[union-attr] decode=False - ) # improves performance + ) except TypeError: raw_response = await self.backend_ws.recv() # type: ignore[union-attr, assignment] + if isinstance(raw_response, bytes): + try: + raw_response = raw_response.decode("utf-8") + except UnicodeDecodeError: + verbose_logger.warning( + "Received non-UTF-8 binary frame from backend, skipping." + ) + continue + if self.provider_config: try: await self._handle_provider_config_message(raw_response) @@ -783,12 +873,13 @@ def _translate_item_content_types(item: dict) -> dict: item["content"] = new_content return item - async def client_ack_messages(self): + async def client_ack_messages(self): # noqa: PLR0915 try: while True: message = await self.websocket.receive_text() ## GUARDRAIL: intercept conversation.item.create for text-based injection. + guardrail_turn_detection_injected = False try: msg_obj = json.loads(message) msg_type = msg_obj.get("type") @@ -796,7 +887,68 @@ async def client_ack_messages(self): if msg_type == "conversation.item.create": # Check user text messages for prompt injection item = msg_obj.get("item", {}) - if item.get("role") == "user": + # Check function_call_output first so a client cannot + # bypass the tool-result guardrail by also setting + # role="user" on a function_call_output item. + if item.get("type") == "function_call_output": + # Tool results are client-controlled and fed to the + # model; check them with the same guardrail used for + # user text so an attacker cannot smuggle blocked + # content into a function_call_output. + output = item.get("output", "") + output_text = ( + output + if isinstance(output, str) + else json.dumps(output) + ) + if output_text: + # Build the sanitized function_call_output up + # front so we can hand it to the guardrail + # runner as the pre-block message. Providers + # that pair every toolCall with a toolResponse + # (e.g. Gemini/Vertex Live) require the + # toolResponse to arrive BEFORE any other + # client message — otherwise the guardrail's + # own clientContent would violate the + # pending-tool-call protocol contract and the + # backend could close the connection before + # the sanitized response ever lands. Dropping + # the blocked item outright would similarly + # leave such providers waiting indefinitely. + # The sanitized payload carries no blocked + # content — only a generic policy marker. + sanitized_msg = json.dumps( + { + **msg_obj, + "item": { + **item, + "output": json.dumps( + { + "error": "Tool output blocked by content policy", + } + ), + }, + } + ) + blocked = await self.run_realtime_guardrails( + output_text, + pre_block_backend_message=sanitized_msg, + ) + if blocked: + # ``_pending_guardrail_message`` is + # intentionally NOT set here. That flag + # exists to swallow the reflexive + # ``response.create`` an OpenAI client + # sends immediately after a user text + # message. In a tool-calling flow the + # client may not send a ``response.create`` + # at all (e.g. Gemini SDKs auto-respond), + # so leaving the flag set would + # incorrectly drop an unrelated + # ``response.create`` from a later + # interaction turn. + continue + elif item.get("role") == "user": content_list = item.get("content", []) texts = [ c.get("text", "") @@ -824,6 +976,89 @@ async def client_ack_messages(self): self._pending_guardrail_message = None continue + ## GUARDRAIL: Inject turn_detection into first session.update + # if needed. Done BEFORE the GA remap so the injected + # ``create_response`` rides along with any client-provided + # turn_detection fields (e.g. silence_duration_ms) into the + # nested ``audio.input.turn_detection`` path produced by the + # remap. Doing this after the remap would create a separate + # minimal root-level ``turn_detection`` and silently drop + # the client's nested settings. + if ( + msg_type == "session.update" + and self.session_configuration_request is None + and not self._guardrail_turn_detection_update_sent + and self._has_audio_transcription_guardrails() + ): + session = msg_obj.setdefault("session", {}) + if isinstance(session, dict): + existing_td = session.get("turn_detection") + if not isinstance(existing_td, dict): + existing_td = {} + existing_td["create_response"] = False + session["turn_detection"] = existing_td + message = json.dumps(msg_obj) + guardrail_turn_detection_injected = True + verbose_logger.debug( + "Injected turn_detection into first session.update for audio transcription guardrails" + ) + + ## GUARDRAIL: Force ``create_response`` to False in any + # client-provided ``turn_detection`` so a later + # ``session.update`` cannot re-enable VAD auto-response + # and bypass the transcription guardrail after the + # initial disable. Covers both the flat beta key and the + # nested GA ``audio.input.turn_detection`` shape, since + # the GA remap below also accepts either form. Skipped + # when the injection block above already ran for this + # message, to avoid redundant double-serialization. + if ( + msg_type == "session.update" + and not guardrail_turn_detection_injected + and self._has_audio_transcription_guardrails() + ): + session = msg_obj.get("session") + if isinstance(session, dict): + td_overridden = False + flat_td = session.get("turn_detection") + flat_td_present = flat_td is not None + if flat_td_present: + if not isinstance(flat_td, dict): + flat_td = {} + if flat_td.get("create_response") is not False: + flat_td["create_response"] = False + session["turn_detection"] = flat_td + td_overridden = True + nested_td_present = False + audio = session.get("audio") + if isinstance(audio, dict): + audio_input = audio.get("input") + if isinstance(audio_input, dict): + nested_td = audio_input.get("turn_detection") + if nested_td is not None: + nested_td_present = True + if not isinstance(nested_td, dict): + nested_td = {} + if ( + nested_td.get("create_response") + is not False + ): + nested_td["create_response"] = False + audio_input["turn_detection"] = nested_td + td_overridden = True + # Symmetric with the first-update injection block: + # if the client omitted turn_detection entirely on + # a subsequent session.update, still inject the + # ``create_response: False`` override so the + # transcription guardrail cannot be re-enabled by + # any downstream merge that drops the original + # disable. + if not flat_td_present and not nested_td_present: + session["turn_detection"] = {"create_response": False} + td_overridden = True + if td_overridden: + message = json.dumps(msg_obj) + # GA compatibility: remap beta-style session fields only when # the upstream is in GA mode. Beta upstreams expect the flat # session shape unchanged. @@ -841,17 +1076,20 @@ async def client_ack_messages(self): pass ## LOGGING + # Log after any in-place modifications (GA remap, guardrail + # turn_detection injection) so audit logs reflect what we + # actually forward to the backend. self.store_input(message=message) - ## FORWARD TO BACKEND - if self.provider_config: - message = self.provider_config.transform_realtime_request( - message, self.model - ) - for msg in message: - await self.backend_ws.send(msg) # type: ignore[union-attr] - else: - await self.backend_ws.send(message) # type: ignore[union-attr] + ## FORWARD TO BACKEND + # Only mark the guardrail turn_detection update as sent after the + # backend actually accepted the message. Setting the flag earlier + # would permanently disable the injection if ``_send_to_backend`` + # raised — neither this loop nor + # ``_maybe_send_guardrail_turn_detection_update`` would retry. + sent = await self._send_to_backend(message) + if guardrail_turn_detection_injected and sent: + self._guardrail_turn_detection_update_sent = True except Exception as e: verbose_logger.debug(f"Error in client ack messages: {e}") diff --git a/litellm/litellm_core_utils/sensitive_data_masker.py b/litellm/litellm_core_utils/sensitive_data_masker.py index d7803455b4a..4928dd08386 100644 --- a/litellm/litellm_core_utils/sensitive_data_masker.py +++ b/litellm/litellm_core_utils/sensitive_data_masker.py @@ -146,6 +146,37 @@ def mask_dict( return masked_data +_default_masker = SensitiveDataMasker() + + +def mask_sensitive_keys( + data: Dict[str, Any], sensitive_fields: Set[str] +) -> Dict[str, Any]: + """Return a new dict with values masked for keys listed in ``sensitive_fields``. + + Unlike :meth:`SensitiveDataMasker.mask_dict`, this does exact key-name + matching (not segment matching), so callers explicitly enumerate which + fields to mask. Non-string and None values are passed through unchanged. + + Values shorter than ``visible_prefix + visible_suffix`` (8 by default) + fall outside :meth:`SensitiveDataMasker._mask_value`'s partial-reveal + range and are replaced with a fixed-length all-mask string, so a short + credential is never returned verbatim. + """ + masked: Dict[str, Any] = {} + mask_char = _default_masker.mask_char + min_visible = _default_masker.visible_prefix + _default_masker.visible_suffix + for key, value in data.items(): + if value is not None and key in sensitive_fields and isinstance(value, str): + if len(value) < min_visible: + masked[key] = mask_char * len(value) if value else value + else: + masked[key] = _default_masker._mask_value(value) + else: + masked[key] = value + return masked + + # Usage example: """ masker = SensitiveDataMasker() diff --git a/litellm/litellm_core_utils/streaming_handler.py b/litellm/litellm_core_utils/streaming_handler.py index fa7faf3035d..55042a733ed 100644 --- a/litellm/litellm_core_utils/streaming_handler.py +++ b/litellm/litellm_core_utils/streaming_handler.py @@ -59,6 +59,8 @@ _SYNC_ITER_EXHAUSTED = object() +_GCHUNK_FIELDS: frozenset = frozenset(GChunk.__annotations__) + def _next_sync_or_exhausted(it: Any) -> Any: """ @@ -181,6 +183,30 @@ def __init__( self.created: Optional[int] = None self._last_returned_hidden_params: Optional[dict] = None + _cached_logging_provider = self.logging_obj.model_call_details.get( + "custom_llm_provider", None + ) + self._cached_logging_llm_provider: Optional[str] = _cached_logging_provider + _effective_model = model or "" + if ( + custom_llm_provider == "openai" + and custom_llm_provider != _cached_logging_provider + ): + _effective_model = "{}/{}".format( + _cached_logging_provider, _effective_model + ) + self._cached_model_name: str = _effective_model + + # Snapshot assumes self._hidden_params is populated from litellm_params + # at init and never mutated during the stream. If that ever changes, + # this cache must be removed. + self._base_hidden_params: Dict[str, Any] = { + **self._hidden_params, + "response_cost": None, + } + + self._post_streaming_hooks: Optional[List] = None + def _check_max_streaming_duration(self) -> None: """Raise litellm.Timeout if the stream has exceeded LITELLM_MAX_STREAMING_DURATION_SECONDS.""" from litellm.constants import LITELLM_MAX_STREAMING_DURATION_SECONDS @@ -681,29 +707,16 @@ def handle_triton_stream(self, chunk): def model_response_creator( self, chunk: Optional[dict] = None, hidden_params: Optional[dict] = None ): - _model = self.model - _received_llm_provider = self.custom_llm_provider - _logging_obj_llm_provider = self.logging_obj.model_call_details.get("custom_llm_provider", None) # type: ignore - if ( - _received_llm_provider == "openai" - and _received_llm_provider != _logging_obj_llm_provider - ): - _model = "{}/{}".format(_logging_obj_llm_provider, _model) + _model = self._cached_model_name + _logging_obj_llm_provider = self._cached_logging_llm_provider + if chunk is None: - chunk = {} + args: Dict[str, Any] = {"model": _model} else: - # pop model keyword chunk.pop("model", None) - - chunk_dict = {} - for key, value in chunk.items(): - if key != "stream": - chunk_dict[key] = value - - args = { - "model": _model, - **chunk_dict, - } + args = {"model": _model} + if chunk: + args.update({k: v for k, v in chunk.items() if k != "stream"}) model_response = ModelResponseStream(**args) if self.response_id is not None: @@ -717,15 +730,23 @@ def model_response_creator( model_response.created = self.created else: self.created = model_response.created + + # Spread order is load-bearing: _base_hidden_params (model_id, api_base, ...) + # must win over both caller-supplied hidden_params and the computed + # custom_llm_provider/created_at values, so it comes last. if hidden_params is not None: - model_response._hidden_params = hidden_params - model_response._hidden_params["custom_llm_provider"] = _logging_obj_llm_provider - model_response._hidden_params["created_at"] = time.time() - model_response._hidden_params = { - **model_response._hidden_params, - **self._hidden_params, - "response_cost": None, - } + model_response._hidden_params = { + **hidden_params, + "custom_llm_provider": _logging_obj_llm_provider, + "created_at": time.time(), + **self._base_hidden_params, + } + else: + model_response._hidden_params = { + "custom_llm_provider": _logging_obj_llm_provider, + "created_at": time.time(), + **self._base_hidden_params, + } if ( len(model_response.choices) > 0 @@ -1627,7 +1648,17 @@ async def _call_post_streaming_deployment_hook(self, chunk): from litellm.integrations.custom_logger import CustomLogger from litellm.types.utils import CallTypes - # Get request kwargs from logging object + if self._post_streaming_hooks is None: + self._post_streaming_hooks = [ + cb + for cb in litellm.callbacks + if isinstance(cb, CustomLogger) + and hasattr(cb, "async_post_call_streaming_deployment_hook") + ] + + if not self._post_streaming_hooks: + return chunk + request_data = self.logging_obj.model_call_details call_type_str = self.logging_obj.call_type @@ -1636,18 +1667,14 @@ async def _call_post_streaming_deployment_hook(self, chunk): except ValueError: typed_call_type = None - # Call hooks for all callbacks - for callback in litellm.callbacks: - if isinstance(callback, CustomLogger) and hasattr( - callback, "async_post_call_streaming_deployment_hook" - ): - result = await callback.async_post_call_streaming_deployment_hook( - request_data=request_data, - response_chunk=chunk, - call_type=typed_call_type, - ) - if result is not None: - chunk = result + for callback in self._post_streaming_hooks: + result = await callback.async_post_call_streaming_deployment_hook( + request_data=request_data, + response_chunk=chunk, + call_type=typed_call_type, + ) + if result is not None: + chunk = result return chunk except Exception as e: @@ -1808,8 +1835,10 @@ def run_success_logging_and_cache_storage(self, processed_chunk, cache_hit: bool processed_chunk, None, None, cache_hit ) ) - ## SYNC LOGGING - self.logging_obj.success_handler(processed_chunk, None, None, cache_hit) + ## SYNC LOGGING — only for sync SDK entrypoints; async proxy paths export via async_success_handler + litellm_params = self.logging_obj.model_call_details.get("litellm_params", {}) + if self.logging_obj._is_sync_litellm_request(litellm_params): + self.logging_obj.success_handler(processed_chunk, None, None, cache_hit) def finish_reason_handler(self): model_response = self.model_response_creator() @@ -1888,17 +1917,15 @@ def __next__(self) -> "ModelResponseStream": # noqa: PLR0915 response = self._add_mcp_list_tools_to_first_chunk(response) self.sent_first_chunk = True - if hasattr( - response, "usage" - ): # remove usage from chunk, only send on final chunk - # Convert the object to a dictionary + # ModelResponseStream declares `usage` as a field, so + # hasattr(response, "usage") is always True — must check + # `is not None` to avoid running this path on every chunk. + if getattr(response, "usage", None) is not None: obj_dict = response.model_dump() - # Remove an attribute (e.g., 'attr2') if "usage" in obj_dict: del obj_dict["usage"] - # Create a new object without the removed attribute response = self.model_response_creator( chunk=obj_dict, hidden_params=response._hidden_params ) @@ -2206,23 +2233,19 @@ async def __anext__(self) -> "ModelResponseStream": # noqa: PLR0915 cache_hit, ) else: + # prefer_async_handlers routes CustomLogger to async_success_handler + # when consumers use ``async for`` on sync-SDK streams. Legacy string + # callbacks still run via executor.submit inside dispatch_success_handlers. asyncio.create_task( - self.logging_obj.async_success_handler( + self.logging_obj.dispatch_success_handlers( complete_streaming_response, cache_hit=cache_hit, start_time=None, end_time=None, + prefer_async_handlers=True, ) ) - executor.submit( - self.logging_obj.success_handler, - complete_streaming_response, - cache_hit=cache_hit, - start_time=None, - end_time=None, - ) - raise StopAsyncIteration # Re-raise StopIteration else: self.sent_last_chunk = True @@ -2398,10 +2421,7 @@ def generic_chunk_has_all_required_fields(chunk: dict) -> bool: :param chunk: The dictionary to check. :return: True if all required fields are present, False otherwise. """ - _all_fields = GChunk.__annotations__ - - decision = all(key in _all_fields for key in chunk) - return decision + return all(key in _GCHUNK_FIELDS for key in chunk) def convert_generic_chunk_to_model_response_stream( diff --git a/litellm/litellm_core_utils/token_counter.py b/litellm/litellm_core_utils/token_counter.py index e6a68de07e9..74b41062174 100644 --- a/litellm/litellm_core_utils/token_counter.py +++ b/litellm/litellm_core_utils/token_counter.py @@ -486,6 +486,14 @@ def _count_messages( use_default_image_token_count, default_token_count, ) + elif key == "search_results" and isinstance(value, list): + from litellm.litellm_core_utils.prompt_templates.common_utils import ( + extract_search_results_text, + ) + + search_results_text = extract_search_results_text(value) + if search_results_text: + num_tokens += params.count_function(search_results_text) else: # Skip unsupported keys instead of raising an error continue @@ -764,11 +772,29 @@ def _format_function_definitions(tools): lines.append("namespace functions {") lines.append("") for tool in tools: + if not isinstance(tool, dict): + continue function = tool.get("function") + if not isinstance(function, dict): + # Anthropic tool shape → OpenAI function dict for token counting. + params = tool.get("input_schema") or tool.get("parameters") or {} + if not isinstance(params, dict): + params = {} + function = { + "name": tool.get("name"), + "description": tool.get("description"), + "parameters": params, + } + function_name = function.get("name") + if not function_name: + # Skip malformed tools missing a name to avoid emitting + # ``type None = ...`` which would produce inaccurate token counts. + continue if function_description := function.get("description"): lines.append(f"// {function_description}") - function_name = function.get("name") - parameters = function.get("parameters", {}) + parameters = function.get("parameters") or {} + if not isinstance(parameters, dict): + parameters = {} properties = parameters.get("properties") if properties and properties.keys(): lines.append(f"type {function_name} = (_: {{") diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 0b56eb86d9c..57609cfcd26 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -337,13 +337,12 @@ def _is_opus_4_7_model(model: str) -> bool: ) @staticmethod - def _supports_effort_level(model: str, level: str) -> bool: - """Check ``supports_{level}_reasoning_effort`` in the model map. + def _supports_model_capability(model: str, key: str) -> bool: + """Check a boolean capability ``key`` in the model map. Strips bedrock/vertex prefixes so a provider-routed Claude still resolves to the Anthropic model-map entry. """ - key = f"supports_{level}_reasoning_effort" try: if _supports_factory( model=model, @@ -372,8 +371,6 @@ def _supports_effort_level(model: str, level: str) -> bool: except Exception: pass try: - import litellm - for cand in candidates: if cand in litellm.model_cost and ( litellm.model_cost[cand].get(key) is True @@ -383,6 +380,13 @@ def _supports_effort_level(model: str, level: str) -> bool: pass return False + @staticmethod + def _supports_effort_level(model: str, level: str) -> bool: + """Check ``supports_{level}_reasoning_effort`` in the model map.""" + return AnthropicConfig._supports_model_capability( + model, f"supports_{level}_reasoning_effort" + ) + @staticmethod def _validate_effort_for_model(model: str, effort: Optional[str]) -> Optional[str]: """Return ``None`` if ``effort`` is allowed on ``model``, else an error message.""" @@ -400,7 +404,15 @@ def _validate_effort_for_model(model: str, effort: Optional[str]) -> Optional[st @staticmethod def _model_supports_effort_param(model: str) -> bool: - """Whether the model accepts ``output_config.effort`` at all.""" + """Whether the model accepts ``output_config.effort`` at all. + + A model qualifies if its map entry advertises ``supports_output_config`` + or any ``supports_*_reasoning_effort`` flag. The two are independent + signals: e.g. Claude Opus 4.5 supports ``output_config`` without + advertising a non-default (max/xhigh) effort level. + """ + if AnthropicConfig._supports_model_capability(model, "supports_output_config"): + return True return any( AnthropicConfig._supports_effort_level(model, level) for level in ("low", "minimal", "medium", "high", "xhigh", "max") @@ -1793,7 +1805,10 @@ def update_headers_with_optional_anthropic_beta( self._ensure_context_management_beta_header( headers, optional_params["context_management"] ) - if optional_params.get("output_format") is not None: + output_config = optional_params.get("output_config") + if optional_params.get("output_format") is not None or ( + isinstance(output_config, dict) and output_config.get("format") is not None + ): self._ensure_beta_header( headers, ANTHROPIC_BETA_HEADER_VALUES.STRUCTURED_OUTPUT_2025_09_25.value ) diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py b/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py index 8ed6126d2eb..efb913f709a 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py @@ -4,6 +4,7 @@ AsyncIterator, Coroutine, Dict, + Iterator, List, Optional, Tuple, @@ -12,9 +13,16 @@ ) import litellm +from litellm._logging import verbose_logger +from litellm.litellm_core_utils.asyncify import run_async_function from litellm.llms.anthropic.experimental_pass_through.adapters.transformation import ( AnthropicAdapter, ) +from litellm.llms.anthropic.experimental_pass_through.context_management import ( + AnthropicContextManagementError, + PolyfillResult, + apply_context_management, +) from litellm.llms.anthropic.experimental_pass_through.utils import ( is_reasoning_auto_summary_enabled, ) @@ -28,15 +36,266 @@ pass -# Anthropic-only fields that the translator above already maps into the -# OpenAI-format completion_kwargs (output_config → reasoning_effort / -# response_format, etc.). They must be filtered out of the raw -# extra_kwargs re-merge below or non-Anthropic backends reject the call -# with 400 "Extra inputs are not permitted". Add new entries here when -# extending AnthropicMessagesRequestOptionalParams with another Anthropic- -# specific key. +# Anthropic-only keys already mapped by the translator; strip on extra_kwargs re-merge. ANTHROPIC_ONLY_REQUEST_KEYS: frozenset[str] = frozenset({"output_config"}) + +def _messages_have_compaction_block(messages: List[Dict]) -> bool: + """Return True when any message carries a ``compaction`` content block.""" + for msg in messages: + content = msg.get("content") + if not isinstance(content, list): + continue + for block in content: + if isinstance(block, dict) and block.get("type") == "compaction": + return True + return False + + +def _extract_proxy_litellm_metadata(kwargs: Dict[str, Any]) -> Optional[Dict[str, Any]]: + """Return ``kwargs["litellm_metadata"]`` when it's a dict; ``None`` otherwise. + + The proxy attaches its auth/spend-attribution fields (``user_api_key``, + ``user_api_key_team_id``, ``litellm_call_id``, the full ``UserAPIKeyAuth`` + object under ``user_api_key_auth``, ...) to ``data["litellm_metadata"]`` + for ``/v1/messages`` (see + ``LiteLLMProxyRequestSetup.add_user_api_key_auth_to_request_metadata`` and + ``LITELLM_METADATA_ROUTES``). The Anthropic-shape ``metadata`` arg only + carries ``user_id`` and must not be conflated. Returns ``None`` for SDK + callers that bypass the proxy entirely. + """ + litellm_metadata = kwargs.get("litellm_metadata") + if not isinstance(litellm_metadata, dict): + return None + return litellm_metadata + + +async def _prepare_context_managed_request( + *, + model: str, + messages: List[Dict], + tools: Optional[List[Dict]], + system: Optional[Any], + context_management_spec: Any, + litellm_metadata: Optional[Dict], + drop_params: Optional[bool], + llm_router: Any, + user_api_key_auth: Any = None, +) -> Optional[PolyfillResult]: + """Apply client compaction history, then optional context_management polyfill.""" + from litellm.llms.anthropic.experimental_pass_through.context_management.editors.compact import ( + apply_client_compaction_block_history, + ) + + # Skip the client-history pre-processing when a ``compact_20260112`` + # polyfill spec will run: that editor already slices around any client-sent + # compaction block in its Phase A (and uses the full post-compaction tail + # for its token-threshold check). Pre-collapsing to just the latest user + # question here would starve the polyfill of conversation context and + # silently drop intermediate turns. + polyfill_will_run = _polyfill_will_run( + context_management_spec=context_management_spec, + drop_params=drop_params, + ) + + if polyfill_will_run: + history_result: Optional[PolyfillResult] = None + working_messages: List[Dict] = messages + working_system: Optional[Any] = system + else: + history_result = apply_client_compaction_block_history( + messages=cast(List[Dict[str, Any]], messages), + system=system, + ) + working_messages = ( + history_result.messages if history_result is not None else messages + ) + working_system = history_result.system if history_result is not None else system + + polyfill_result = await _run_polyfill_if_enabled( + model=model, + messages=working_messages, + tools=tools, + system=working_system, + context_management_spec=context_management_spec, + litellm_metadata=litellm_metadata, + drop_params=drop_params, + llm_router=llm_router, + user_api_key_auth=user_api_key_auth, + ) + + if polyfill_result is not None: + return polyfill_result + + # Safety net: if we skipped client-history pre-processing because a + # ``compact_20260112`` polyfill was expected to handle the compaction + # block itself but the polyfill ultimately did not produce a result + # (e.g. it crashed and was best-effort swallowed in + # ``_run_polyfill_if_enabled``), apply the slice-only fallback now so + # Anthropic-specific ``compaction`` content blocks don't leak through + # to non-Anthropic backends that would reject them. + if polyfill_will_run and history_result is None: + history_result = apply_client_compaction_block_history( + messages=cast(List[Dict[str, Any]], messages), + system=system, + ) + return history_result + + +def _polyfill_will_run( + *, + context_management_spec: Any, + drop_params: Optional[bool], +) -> bool: + """Return True when ``compact_20260112`` will run via the polyfill dispatcher. + + Mirrors the gating in ``_run_polyfill_if_enabled``: an empty spec or + effective ``drop_params`` short-circuits the polyfill. The pre-processing + skip only applies when the dispatcher will actually invoke + ``apply_compact_20260112`` (which has its own compaction-block slicing). + """ + edits = _normalize_spec_edits( + context_management_spec=context_management_spec, + drop_params=drop_params, + ) + if edits is None: + return False + + from litellm.llms.anthropic.experimental_pass_through.context_management.constants import ( + COMPACT_EDIT_TYPE, + ) + + return any( + isinstance(edit, dict) and edit.get("type") == COMPACT_EDIT_TYPE + for edit in edits + ) + + +def _spec_has_non_compact_edits( + *, + context_management_spec: Any, + drop_params: Optional[bool], +) -> bool: + """Return True when the spec includes edits other than ``compact_20260112``. + + Used to decide whether a polyfill failure can be silently swallowed + (compact-only specs have a safe compaction-block slicing fallback) or + must be surfaced (other editors like ``clear_tool_uses_20250919`` have + no slice-only fallback and would otherwise be dropped without notice). + """ + edits = _normalize_spec_edits( + context_management_spec=context_management_spec, + drop_params=drop_params, + ) + if edits is None: + return False + + from litellm.llms.anthropic.experimental_pass_through.context_management.constants import ( + COMPACT_EDIT_TYPE, + ) + + return any( + isinstance(edit, dict) + and isinstance(edit.get("type"), str) + and edit.get("type") != COMPACT_EDIT_TYPE + for edit in edits + ) + + +def _normalize_spec_edits( + *, + context_management_spec: Any, + drop_params: Optional[bool], +) -> Optional[List[Dict[str, Any]]]: + """Return the normalized ``edits`` list, or ``None`` if the polyfill won't run. + + Delegates spec-shape normalization to the dispatcher's ``_normalize_spec`` + so the prediction here can't drift from what the dispatcher actually does. + """ + if not context_management_spec: + return None + + effective_drop_params = ( + drop_params if drop_params is not None else litellm.drop_params + ) + if effective_drop_params: + return None + + from litellm.llms.anthropic.experimental_pass_through.context_management.dispatcher import ( + _normalize_spec, + ) + + try: + return _normalize_spec(context_management_spec) + except Exception: + return None + + +async def _run_polyfill_if_enabled( + *, + model: str, + messages: List[Dict], + tools: Optional[List[Dict]], + system: Optional[Any], + context_management_spec: Any, + litellm_metadata: Optional[Dict], + drop_params: Optional[bool], + llm_router: Any, + user_api_key_auth: Any = None, +) -> Optional[PolyfillResult]: + """Run the async context_management polyfill if a spec is present. + + Returns ``None`` when the spec is empty or drop_params is on. Raises + ``AnthropicContextManagementError`` so the /v1/messages endpoint can + emit an Anthropic-format 400. All other exceptions are best-effort + swallowed (matches v0 behavior). + """ + if not context_management_spec: + return None + + effective_drop_params = ( + drop_params if drop_params is not None else litellm.drop_params + ) + if effective_drop_params: + return None + + try: + return await apply_context_management( + model=model, + messages=messages, + tools=tools, + system=system, + context_management_spec=context_management_spec, + litellm_metadata=litellm_metadata, + llm_router=llm_router, + user_api_key_auth=user_api_key_auth, + ) + except AnthropicContextManagementError: + # Surface validation errors so the endpoint can emit an Anthropic-format + # 400. Other exception types fall into the best-effort branch below. + raise + except Exception as e: + verbose_logger.exception( + "context_management polyfill: skipping edits due to error: %s", e + ) + # Best-effort swallow is only safe for compact-only specs, where the + # caller's compaction-block-slicing safety net produces a correct + # (if degraded) result. When the spec also requested non-compact + # edits (e.g. ``clear_tool_uses_20250919``), the safety net does + # NOT re-run those editors, so silently returning ``None`` would + # drop them with no error surface. Raise instead so the endpoint + # emits an Anthropic-format error. + if _spec_has_non_compact_edits( + context_management_spec=context_management_spec, + drop_params=drop_params, + ): + raise AnthropicContextManagementError( + status_code=500, + message=f"context_management polyfill failed: {e}", + ) from e + return None + + ######################################################## # init adapter ANTHROPIC_ADAPTER = AnthropicAdapter() @@ -163,7 +422,7 @@ def _prepare_completion_kwargs( metadata: Optional[Dict] = None, stop_sequences: Optional[List[str]] = None, stream: Optional[bool] = False, - system: Optional[str] = None, + system: Optional[Union[str, List[Dict[str, Any]]]] = None, temperature: Optional[float] = None, thinking: Optional[Dict] = None, tool_choice: Optional[Dict] = None, @@ -307,19 +566,56 @@ async def async_anthropic_messages_handler( top_p: Optional[float] = None, output_format: Optional[Dict] = None, **kwargs, - ) -> Union[AnthropicMessagesResponse, AsyncIterator]: + ) -> Union[AnthropicMessagesResponse, AsyncIterator[Any], Iterator[bytes]]: """Handle non-Anthropic models asynchronously using the adapter""" + context_management = kwargs.pop("context_management", None) + drop_params: Optional[bool] = kwargs.get("drop_params", None) + litellm_router = kwargs.pop("litellm_router", None) + if litellm_router is None: + try: + from litellm.proxy.proxy_server import llm_router as _proxy_router + + litellm_router = _proxy_router + except Exception: + pass + + proxy_litellm_metadata = _extract_proxy_litellm_metadata(kwargs) + user_api_key_auth = ( + proxy_litellm_metadata.get("user_api_key_auth") + if proxy_litellm_metadata is not None + else None + ) + + polyfill_result = await _prepare_context_managed_request( + model=model, + messages=messages, + tools=tools, + system=system, + context_management_spec=context_management, + litellm_metadata=proxy_litellm_metadata, + drop_params=drop_params, + llm_router=litellm_router, + user_api_key_auth=user_api_key_auth, + ) + + effective_messages = ( + polyfill_result.messages if polyfill_result is not None else messages + ) + effective_system = ( + polyfill_result.system if polyfill_result is not None else system + ) + ( completion_kwargs, tool_name_mapping, ) = LiteLLMMessagesToCompletionTransformationHandler._prepare_completion_kwargs( max_tokens=max_tokens, - messages=messages, + messages=effective_messages, model=model, metadata=metadata, stop_sequences=stop_sequences, stream=stream, - system=system, + system=effective_system, temperature=temperature, thinking=thinking, tool_choice=tool_choice, @@ -338,6 +634,8 @@ async def async_anthropic_messages_handler( completion_response, model=model, tool_name_mapping=tool_name_mapping, + polyfill_result=polyfill_result, + is_async=True, ) ) if transformed_stream is not None: @@ -347,6 +645,7 @@ async def async_anthropic_messages_handler( anthropic_response = ANTHROPIC_ADAPTER.translate_completion_output_params( cast(ModelResponse, completion_response), tool_name_mapping=tool_name_mapping, + polyfill_result=polyfill_result, ) if anthropic_response is not None: return anthropic_response @@ -372,8 +671,13 @@ def anthropic_messages_handler( **kwargs, ) -> Union[ AnthropicMessagesResponse, + Iterator[bytes], AsyncIterator[Any], - Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], + Coroutine[ + Any, + Any, + Union[AnthropicMessagesResponse, AsyncIterator[Any], Iterator[bytes]], + ], ]: """Handle non-Anthropic models using the adapter.""" if _is_async is True: @@ -395,17 +699,72 @@ def anthropic_messages_handler( **kwargs, ) + # Run the context_management polyfill on the sync path too so that + # ``litellm.messages.create()`` callers don't silently lose edits like + # ``clear_tool_uses_20250919``. The dispatcher is async (so the + # ``compact_20260112`` editor can ``await`` the summarization model); + # bridge to it via ``run_async_function``. + context_management = kwargs.pop("context_management", None) + drop_params: Optional[bool] = kwargs.get("drop_params", None) + # Deliberately do NOT auto-attach the proxy ``llm_router`` here: + # ``run_async_function`` spawns a new event loop in a worker thread + # to bridge to the async dispatcher, but the proxy router's httpx + # ``AsyncClient`` instances are bound to the proxy's main event loop. + # Reusing them from the new thread's loop violates httpx's single-loop + # invariant and can raise ``RuntimeError: Event loop is closed`` or + # produce stalled connections. The summary editor falls back to + # ``litellm.acompletion`` (which creates a fresh client per call) when + # ``llm_router`` is ``None``, which is safe to call from the bridged + # loop. The async ``async_anthropic_messages_handler`` path is + # unaffected because it ``await``s within the original event loop. + litellm_router = kwargs.pop("litellm_router", None) + + # Skip the async bridge entirely when there is nothing for either the + # polyfill or the client-history slice-only fallback to do. The vast + # majority of sync ``litellm.messages.create()`` requests carry no + # ``context_management`` spec and no client-sent ``compaction`` block, + # and bridging through a worker-thread event loop just to discover + # there is no work is pure overhead. + if context_management is None and not _messages_have_compaction_block(messages): + polyfill_result: Optional[PolyfillResult] = None + else: + proxy_litellm_metadata = _extract_proxy_litellm_metadata(kwargs) + user_api_key_auth = ( + proxy_litellm_metadata.get("user_api_key_auth") + if proxy_litellm_metadata is not None + else None + ) + polyfill_result = run_async_function( + _prepare_context_managed_request, + model=model, + messages=messages, + tools=tools, + system=system, + context_management_spec=context_management, + litellm_metadata=proxy_litellm_metadata, + drop_params=drop_params, + llm_router=litellm_router, + user_api_key_auth=user_api_key_auth, + ) + + effective_messages = ( + polyfill_result.messages if polyfill_result is not None else messages + ) + effective_system = ( + polyfill_result.system if polyfill_result is not None else system + ) + ( completion_kwargs, tool_name_mapping, ) = LiteLLMMessagesToCompletionTransformationHandler._prepare_completion_kwargs( max_tokens=max_tokens, - messages=messages, + messages=effective_messages, model=model, metadata=metadata, stop_sequences=stop_sequences, stream=stream, - system=system, + system=effective_system, temperature=temperature, thinking=thinking, tool_choice=tool_choice, @@ -424,6 +783,8 @@ def anthropic_messages_handler( completion_response, model=model, tool_name_mapping=tool_name_mapping, + polyfill_result=polyfill_result, + is_async=False, ) ) if transformed_stream is not None: @@ -433,6 +794,7 @@ def anthropic_messages_handler( anthropic_response = ANTHROPIC_ADAPTER.translate_completion_output_params( cast(ModelResponse, completion_response), tool_name_mapping=tool_name_mapping, + polyfill_result=polyfill_result, ) if anthropic_response is not None: return anthropic_response diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py index c65dfb22730..bacb9f8ddf6 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py @@ -3,11 +3,26 @@ import json import traceback from collections import deque -from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Iterator, Literal, Optional - -from litellm import verbose_logger +from typing import ( + TYPE_CHECKING, + Any, + AsyncIterator, + Dict, + Iterator, + List, + Literal, + Optional, +) + +from litellm._logging import verbose_logger from litellm._uuid import uuid -from litellm.types.llms.anthropic import UsageDelta +from litellm.types.llms.anthropic import ( + AppliedEdit, + CompactionBlock, + ContextManagementResponse, + UsageDelta, + UsageIteration, +) from litellm.types.utils import AdapterCompletionStreamWrapper if TYPE_CHECKING: @@ -37,22 +52,208 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper): holding_stop_reason_chunk: Optional[Any] = None queued_usage_chunk: bool = False current_content_block_index: int = 0 - current_content_block_start: ContentBlockContentBlockDict = TextBlock( - type="text", - text="", - ) - chunk_queue: deque = deque() # Queue for buffering multiple chunks def __init__( self, completion_stream: Any, model: str, tool_name_mapping: Optional[Dict[str, str]] = None, + applied_edits: Optional[List[AppliedEdit]] = None, + compaction_block: Optional[CompactionBlock] = None, + iterations_usage: Optional[List[UsageIteration]] = None, ): super().__init__(completion_stream) self.model = model # Mapping of truncated tool names to original names (for OpenAI's 64-char limit) self.tool_name_mapping = tool_name_mapping or {} + # Polyfill applied_edits on final message_delta. + self.applied_edits: List[AppliedEdit] = list(applied_edits or []) + # Synthesized compaction block from compact_20260112 polyfill (streaming). + self.compaction_block = compaction_block + self.iterations_usage = iterations_usage + self.sent_compaction_block: bool = False + # Per-phase flags so the compaction block's start/delta/stop events + # are emitted (and the public state machine is advanced) in + # lock-step with the caller actually consuming each event. Pre- + # queuing all three would set ``sent_content_block_finish=True`` + # before the client received ``content_block_stop``, leaving the + # observable state inconsistent during the drain window. + self.sent_compaction_block_start: bool = False + self.sent_compaction_block_delta: bool = False + # Per-instance queue for buffering multiple chunks. Must be initialized + # here (not at class level) so concurrent streams don't share the same + # deque and corrupt each other's SSE event order. + self.chunk_queue: deque = deque() + # Per-instance default content block. Must be initialized here (not at + # class level) so concurrent streams don't share the same mutable dict + # — `_should_start_new_content_block` mutates `tool_block["name"]` in + # place, which would otherwise leak across streams. + self.current_content_block_start: ( + "AnthropicStreamWrapper.ContentBlockContentBlockDict" + ) = self.TextBlock( + type="text", + text="", + ) + + def _merge_usage_into_held_stop_reason_chunk(self, chunk: Any) -> Dict[str, Any]: + """Merge usage data from ``chunk`` into the held ``message_delta`` chunk. + + Shared by both the sync ``__next__`` and async ``__anext__`` paths so + the subtle hold-and-merge logic (cache tokens, ``context_management`` + attachment, ``UsageDelta`` shape) lives in exactly one place. + + Caller is responsible for managing ``self.holding_stop_reason_chunk`` + and ``self.queued_usage_chunk`` state and for queuing the returned + merged chunk. + """ + assert self.holding_stop_reason_chunk is not None + merged_chunk = self.holding_stop_reason_chunk.copy() + if "delta" not in merged_chunk: + merged_chunk["delta"] = {} + + uncached_input_tokens = chunk.usage.prompt_tokens or 0 + if ( + hasattr(chunk.usage, "prompt_tokens_details") + and chunk.usage.prompt_tokens_details + ): + cached_tokens = ( + getattr(chunk.usage.prompt_tokens_details, "cached_tokens", 0) or 0 + ) + uncached_input_tokens -= cached_tokens + + usage_dict: UsageDelta = { + "input_tokens": uncached_input_tokens, + "output_tokens": chunk.usage.completion_tokens or 0, + } + if ( + hasattr(chunk.usage, "_cache_creation_input_tokens") + and chunk.usage._cache_creation_input_tokens > 0 + ): + usage_dict["cache_creation_input_tokens"] = ( + chunk.usage._cache_creation_input_tokens + ) + if ( + hasattr(chunk.usage, "_cache_read_input_tokens") + and chunk.usage._cache_read_input_tokens > 0 + ): + usage_dict["cache_read_input_tokens"] = chunk.usage._cache_read_input_tokens + merged_chunk["usage"] = usage_dict + if self.applied_edits and "context_management" not in merged_chunk: + merged_chunk["context_management"] = ContextManagementResponse( + applied_edits=list(self.applied_edits) + ) + return self._augment_message_delta_usage(merged_chunk) + + def _ensure_context_management_attached( + self, message_delta_chunk: Dict[str, Any] + ) -> Dict[str, Any]: + """Attach ``context_management`` to a ``message_delta`` chunk if + ``self.applied_edits`` is non-empty and the chunk does not already + carry it. Returns the (possibly new) chunk dict. + + Centralizing this guard ensures every ``message_delta`` emission + path (merge-with-usage and direct-flush-of-held) consistently + surfaces ``applied_edits`` to the client. + """ + if not self.applied_edits or "context_management" in message_delta_chunk: + return message_delta_chunk + augmented = message_delta_chunk.copy() + augmented["context_management"] = ContextManagementResponse( + applied_edits=list(self.applied_edits) + ) + return augmented + + def _augment_message_delta_usage( + self, message_delta_chunk: Dict[str, Any] + ) -> Dict[str, Any]: + """Attach polyfill compaction iteration usage to the final message_delta. + + Also defensively re-attaches ``context_management`` so the direct + held-chunk flush path stays in sync with the merge path's guarantee + when ``self.applied_edits`` is non-empty. + """ + message_delta_chunk = self._ensure_context_management_attached( + message_delta_chunk + ) + if self.iterations_usage is None: + return message_delta_chunk + usage = message_delta_chunk.get("usage") + if not isinstance(usage, dict) or "iterations" in usage: + return message_delta_chunk + + input_tokens = usage.get("input_tokens", 0) or 0 + output_tokens = usage.get("output_tokens", 0) or 0 + augmented = message_delta_chunk.copy() + augmented_usage = dict(usage) + iterations: List[UsageIteration] = list(self.iterations_usage) + # Only emit a ``message`` iteration when we have real token data. + # Without a separate usage chunk (e.g. provider sent finish_reason + # alone), the held ``message_delta`` carries placeholder zeros from + # the translate step; reporting a zero-token iteration would be + # misleading and inconsistent with the non-streaming path. + if input_tokens > 0 or output_tokens > 0: + message_iteration: UsageIteration = { + "type": "message", + "input_tokens": input_tokens, + "output_tokens": output_tokens, + } + iterations.append(message_iteration) + augmented_usage["iterations"] = iterations # type: ignore[typeddict-unknown-key] + augmented["usage"] = augmented_usage + return augmented + + def _next_compaction_event(self) -> Optional[Dict[str, Any]]: + """Return the next compaction content-block SSE event, or ``None``. + + Anthropic delivers compaction as a single delta (no token-by-token + streaming), but we still surface it as a proper + start → delta → stop trio. Each call returns exactly one event so + the state machine (``sent_content_block_finish``, + ``current_content_block_index``) is advanced *only* when the + terminal stop event is actually handed back to the caller. This + prevents an observable window where the flags claim the block is + finished while the stop event is still buffered. + """ + if self.compaction_block is None or self.sent_compaction_block: + return None + + compaction_index = self.current_content_block_index + + if not self.sent_compaction_block_start: + self.sent_compaction_block_start = True + return { + "type": "content_block_start", + "index": compaction_index, + # Mirror the text-block shape ({"type": "text", "text": ""}): + # send an empty ``content`` field so clients that introspect + # ``content_block_start`` see the full block schema. The + # actual summary text arrives via the ``content_block_delta`` + # below. + "content_block": {"type": "compaction", "content": ""}, + } + + if not self.sent_compaction_block_delta: + self.sent_compaction_block_delta = True + summary_content = self.compaction_block.get("content") or "" + return { + "type": "content_block_delta", + "index": compaction_index, + "delta": {"type": "compaction_delta", "content": summary_content}, + } + + stop_event = { + "type": "content_block_stop", + "index": compaction_index, + } + # Don't touch ``sent_content_block_finish`` here: that flag is the + # state machine for the regular text/tool_use/thinking block and is + # independent of the synthetic compaction block lifecycle. Conflating + # them would let outside observers (subclass overrides, introspection + # hooks, exception paths) see ``sent_content_block_finish=True`` + # without any regular content block ever having started. + self._increment_content_block_index() + self.sent_compaction_block = True + return stop_event def _create_initial_usage_delta(self) -> UsageDelta: """ @@ -75,7 +276,7 @@ def _create_initial_usage_delta(self) -> UsageDelta: cache_read_input_tokens=0, ) - def __next__(self): + def __next__(self): # noqa: PLR0915 from .transformation import LiteLLMAnthropicMessagesAdapter try: @@ -103,8 +304,17 @@ def __next__(self): ) return self.chunk_queue.popleft() + if ( + self.sent_compaction_block is False + and self.compaction_block is not None + ): + compaction_event = self._next_compaction_event() + if compaction_event is not None: + return compaction_event + if self.sent_content_block_start is False: self.sent_content_block_start = True + self.sent_content_block_finish = False self.chunk_queue.append( { "type": "content_block_start", @@ -122,11 +332,45 @@ def __next__(self): if should_start_new_block: self._increment_content_block_index() + # applied_edits only needs to flow to the final message_delta + # (when finish_reason is set); skip threading it through every + # intermediate chunk. For the hold-and-merge path below, + # context_management is attached directly to the merged chunk, + # so the translated ``processed_chunk`` would be discarded — + # skip the applied_edits attachment in that case to avoid + # allocating a throwaway ``MessageBlockDelta``. + will_merge_into_held = ( + self.holding_stop_reason_chunk is not None + and getattr(chunk, "usage", None) is not None + ) + is_final_chunk = chunk.choices[0].finish_reason is not None processed_chunk = LiteLLMAnthropicMessagesAdapter().translate_streaming_openai_response_to_anthropic( response=chunk, current_content_block_index=self.current_content_block_index, + applied_edits=( + self.applied_edits + if is_final_chunk and not will_merge_into_held + else None + ), ) + # Check if this is a usage chunk and we have a held stop_reason chunk + if will_merge_into_held: + merged_chunk = self._merge_usage_into_held_stop_reason_chunk(chunk) + self.chunk_queue.append(merged_chunk) + self.queued_usage_chunk = True + self.holding_stop_reason_chunk = None + return self.chunk_queue.popleft() + + if self.queued_usage_chunk: + # Usage has already been merged + emitted. Any trailing + # provider events would violate Anthropic SSE ordering + # (no chunks may follow the final ``message_delta``), so + # silently drop them — matches the async ``__anext__`` + # behavior where the block-handling logic is gated on + # ``not self.queued_usage_chunk``. + continue + if should_start_new_block and not self.sent_content_block_finish: # Queue the sequence: content_block_stop -> content_block_start # For text blocks the trigger chunk is not emitted as a separate @@ -178,20 +422,64 @@ def __next__(self): } ) self.sent_content_block_finish = True - self.chunk_queue.append(processed_chunk) + if processed_chunk.get("delta", {}).get("stop_reason") is not None: + self.holding_stop_reason_chunk = processed_chunk + else: + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) + self.chunk_queue.append(processed_chunk) return self.chunk_queue.popleft() elif self.holding_chunk is not None: self.chunk_queue.append(self.holding_chunk) + if processed_chunk.get("type") == "message_delta": + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) self.chunk_queue.append(processed_chunk) self.holding_chunk = None return self.chunk_queue.popleft() else: + if processed_chunk.get("type") == "message_delta": + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) self.chunk_queue.append(processed_chunk) return self.chunk_queue.popleft() - # Handle any remaining held chunks after stream ends - if self.holding_chunk is not None: - self.chunk_queue.append(self.holding_chunk) + # Handle any remaining held chunks after stream ends. The + # buffered ``holding_chunk`` (a ``content_block_delta``) must + # precede the final ``message_delta`` so Anthropic SSE event + # ordering is preserved. When ``queued_usage_chunk`` is True, + # the final ``message_delta`` has already been emitted; any + # buffered content delta is dropped rather than emitted after + # ``message_delta`` (which would violate SSE ordering and may + # confuse strict Anthropic SDK clients). + if not self.queued_usage_chunk: + if self.holding_chunk is not None: + self.chunk_queue.append(self.holding_chunk) + self.holding_chunk = None + if self.holding_stop_reason_chunk is not None: + # A final ``message_delta`` must be preceded by + # ``content_block_stop`` so the emitted SSE stays in + # valid Anthropic order (... -> content_block_stop -> + # message_delta). Emit ``content_block_stop`` here if + # the active content block was not already closed. + if not self.sent_content_block_finish: + self.chunk_queue.append( + { + "type": "content_block_stop", + "index": self.current_content_block_index, + } + ) + self.sent_content_block_finish = True + self.chunk_queue.append( + self._augment_message_delta_usage( + self.holding_stop_reason_chunk + ) + ) + self.holding_stop_reason_chunk = None + else: self.holding_chunk = None if not self.sent_last_message: @@ -205,6 +493,26 @@ def __next__(self): except StopIteration: if self.chunk_queue: return self.chunk_queue.popleft() + # Handle any held stop_reason chunk. Emit ``content_block_stop`` + # first if the active content block was not already closed, so + # Anthropic SSE ordering is preserved (content_block_stop -> + # message_delta). + if self.holding_stop_reason_chunk is not None: + if not self.sent_content_block_finish: + self.sent_content_block_finish = True + self.chunk_queue.append( + self._augment_message_delta_usage( + self.holding_stop_reason_chunk + ) + ) + self.holding_stop_reason_chunk = None + return { + "type": "content_block_stop", + "index": self.current_content_block_index, + } + held = self._augment_message_delta_usage(self.holding_stop_reason_chunk) + self.holding_stop_reason_chunk = None + return held if self.sent_last_message is False: self.sent_last_message = True return {"type": "message_stop"} @@ -213,7 +521,7 @@ def __next__(self): verbose_logger.error( "Anthropic Adapter - {}\n{}".format(e, traceback.format_exc()) ) - raise StopAsyncIteration + raise StopIteration async def __anext__(self): # noqa: PLR0915 from .transformation import LiteLLMAnthropicMessagesAdapter @@ -243,8 +551,17 @@ async def __anext__(self): # noqa: PLR0915 ) return self.chunk_queue.popleft() + if ( + self.sent_compaction_block is False + and self.compaction_block is not None + ): + compaction_event = self._next_compaction_event() + if compaction_event is not None: + return compaction_event + if self.sent_content_block_start is False: self.sent_content_block_start = True + self.sent_content_block_finish = False self.chunk_queue.append( { "type": "content_block_start", @@ -263,57 +580,31 @@ async def __anext__(self): # noqa: PLR0915 if should_start_new_block: self._increment_content_block_index() + # applied_edits only needs to flow to the final message_delta + # (when finish_reason is set); skip threading it through every + # intermediate chunk. For the hold-and-merge path below, + # context_management is attached directly to the merged chunk, + # so the translated ``processed_chunk`` would be discarded — + # skip the applied_edits attachment in that case to avoid + # allocating a throwaway ``MessageBlockDelta``. + will_merge_into_held = ( + self.holding_stop_reason_chunk is not None + and getattr(chunk, "usage", None) is not None + ) + is_final_chunk = chunk.choices[0].finish_reason is not None processed_chunk = LiteLLMAnthropicMessagesAdapter().translate_streaming_openai_response_to_anthropic( response=chunk, current_content_block_index=self.current_content_block_index, + applied_edits=( + self.applied_edits + if is_final_chunk and not will_merge_into_held + else None + ), ) # Check if this is a usage chunk and we have a held stop_reason chunk - if ( - self.holding_stop_reason_chunk is not None - and getattr(chunk, "usage", None) is not None - ): - # Merge usage into the held stop_reason chunk - merged_chunk = self.holding_stop_reason_chunk.copy() - if "delta" not in merged_chunk: - merged_chunk["delta"] = {} - - # Add usage to the held chunk - uncached_input_tokens = chunk.usage.prompt_tokens or 0 - if ( - hasattr(chunk.usage, "prompt_tokens_details") - and chunk.usage.prompt_tokens_details - ): - cached_tokens = ( - getattr( - chunk.usage.prompt_tokens_details, "cached_tokens", 0 - ) - or 0 - ) - uncached_input_tokens -= cached_tokens - - usage_dict: UsageDelta = { - "input_tokens": uncached_input_tokens, - "output_tokens": chunk.usage.completion_tokens or 0, - } - # Add cache tokens if available (for prompt caching support) - if ( - hasattr(chunk.usage, "_cache_creation_input_tokens") - and chunk.usage._cache_creation_input_tokens > 0 - ): - usage_dict["cache_creation_input_tokens"] = ( - chunk.usage._cache_creation_input_tokens - ) - if ( - hasattr(chunk.usage, "_cache_read_input_tokens") - and chunk.usage._cache_read_input_tokens > 0 - ): - usage_dict["cache_read_input_tokens"] = ( - chunk.usage._cache_read_input_tokens - ) - merged_chunk["usage"] = usage_dict - - # Queue the merged chunk and reset + if will_merge_into_held: + merged_chunk = self._merge_usage_into_held_stop_reason_chunk(chunk) self.chunk_queue.append(merged_chunk) self.queued_usage_chunk = True self.holding_stop_reason_chunk = None @@ -379,28 +670,63 @@ async def __anext__(self): # noqa: PLR0915 ): self.holding_stop_reason_chunk = processed_chunk else: + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) self.chunk_queue.append(processed_chunk) return self.chunk_queue.popleft() elif self.holding_chunk is not None: # Queue both chunks self.chunk_queue.append(self.holding_chunk) + if processed_chunk.get("type") == "message_delta": + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) self.chunk_queue.append(processed_chunk) self.holding_chunk = None return self.chunk_queue.popleft() else: - # Queue the current chunk + if processed_chunk.get("type") == "message_delta": + processed_chunk = self._augment_message_delta_usage( + processed_chunk + ) self.chunk_queue.append(processed_chunk) return self.chunk_queue.popleft() - # Handle any remaining held chunks after stream ends + # Handle any remaining held chunks after stream ends. The + # buffered ``holding_chunk`` (a ``content_block_delta``) must + # precede the final ``message_delta`` so Anthropic SSE event + # ordering is preserved. When ``queued_usage_chunk`` is True, + # the final ``message_delta`` has already been emitted; any + # buffered content delta is dropped rather than emitted after + # ``message_delta`` (which would violate SSE ordering and may + # confuse strict Anthropic SDK clients). if not self.queued_usage_chunk: - if self.holding_stop_reason_chunk is not None: - self.chunk_queue.append(self.holding_stop_reason_chunk) - self.holding_stop_reason_chunk = None - if self.holding_chunk is not None: self.chunk_queue.append(self.holding_chunk) self.holding_chunk = None + if self.holding_stop_reason_chunk is not None: + # A final ``message_delta`` must be preceded by + # ``content_block_stop`` so the emitted SSE stays in + # valid Anthropic order (... -> content_block_stop -> + # message_delta). Emit ``content_block_stop`` here if + # the active content block was not already closed. + if not self.sent_content_block_finish: + self.chunk_queue.append( + { + "type": "content_block_stop", + "index": self.current_content_block_index, + } + ) + self.sent_content_block_finish = True + self.chunk_queue.append( + self._augment_message_delta_usage( + self.holding_stop_reason_chunk + ) + ) + self.holding_stop_reason_chunk = None + else: + self.holding_chunk = None if not self.sent_last_message: self.sent_last_message = True @@ -416,9 +742,28 @@ async def __anext__(self): # noqa: PLR0915 # Handle any remaining queued chunks before stopping if self.chunk_queue: return self.chunk_queue.popleft() - # Handle any held stop_reason chunk + # Handle any held stop_reason chunk — clear after capturing so a + # subsequent ``__anext__`` call doesn't re-emit the same chunk + # (matches the sync ``__next__`` path). Emit ``content_block_stop`` + # first if the active content block was not already closed, so + # Anthropic SSE ordering is preserved (content_block_stop -> + # message_delta). if self.holding_stop_reason_chunk is not None: - return self.holding_stop_reason_chunk + if not self.sent_content_block_finish: + self.sent_content_block_finish = True + self.chunk_queue.append( + self._augment_message_delta_usage( + self.holding_stop_reason_chunk + ) + ) + self.holding_stop_reason_chunk = None + return { + "type": "content_block_stop", + "index": self.current_content_block_index, + } + held = self._augment_message_delta_usage(self.holding_stop_reason_chunk) + self.holding_stop_reason_chunk = None + return held if not self.sent_last_message: self.sent_last_message = True return {"type": "message_stop"} diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index 51a1e739a0f..02e0c562654 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -6,6 +6,7 @@ Any, AsyncIterator, Dict, + Iterator, List, Literal, Optional, @@ -75,6 +76,9 @@ def create_tool_name_mapping( from litellm.litellm_core_utils.prompt_templates.factory import ( THOUGHT_SIGNATURE_SEPARATOR, ) +from litellm.llms.anthropic.experimental_pass_through.context_management import ( + PolyfillResult, +) from litellm.types.llms.anthropic import ( ANTHROPIC_HOSTED_TOOLS, AllAnthropicToolsValues, @@ -87,14 +91,17 @@ def create_tool_name_mapping( AnthropicResponseContentBlockText, AnthropicResponseContentBlockThinking, AnthropicResponseContentBlockToolUse, + AppliedEdit, ContentBlockDelta, ContentJsonBlockDelta, ContentTextBlockDelta, ContentThinkingBlockDelta, ContentThinkingSignatureBlockDelta, + ContextManagementResponse, MessageBlockDelta, MessageDelta, UsageDelta, + UsageIteration, ) from litellm.types.llms.anthropic_messages.anthropic_response import ( AnthropicMessagesResponse, @@ -195,6 +202,7 @@ def translate_completion_output_params( self, response: ModelResponse, tool_name_mapping: Optional[Dict[str, str]] = None, + polyfill_result: Optional[PolyfillResult] = None, ) -> Optional[AnthropicMessagesResponse]: """ Translate OpenAI response to Anthropic format. @@ -204,10 +212,12 @@ def translate_completion_output_params( tool_name_mapping: Optional mapping of truncated tool names to original names. Used to restore original names for tools that exceeded OpenAI's 64-char limit. + polyfill_result: PolyfillResult from context_management polyfill. """ return LiteLLMAnthropicMessagesAdapter().translate_openai_response_to_anthropic( response=response, tool_name_mapping=tool_name_mapping, + polyfill_result=polyfill_result, ) def translate_completion_output_params_streaming( @@ -215,7 +225,9 @@ def translate_completion_output_params_streaming( completion_stream: Any, model: str, tool_name_mapping: Optional[Dict[str, str]] = None, - ) -> Union[AsyncIterator[bytes], None]: + polyfill_result: Optional[PolyfillResult] = None, + is_async: bool = True, + ) -> Union[AsyncIterator[bytes], Iterator[bytes], None]: """ Translate OpenAI streaming response to Anthropic format. @@ -223,14 +235,35 @@ def translate_completion_output_params_streaming( completion_stream: The OpenAI streaming response model: The model name tool_name_mapping: Optional mapping of truncated tool names to original names. + polyfill_result: PolyfillResult from context_management polyfill. + is_async: When ``True`` (default, for back-compat with existing + async callers) returns an ``AsyncIterator[bytes]``. When + ``False`` returns a sync ``Iterator[bytes]`` so sync callers + (e.g. ``litellm.anthropic.messages.create(stream=True)`` via + the sync handler) don't get back an async iterator they + can't iterate without an event loop. """ + applied_edits = ( + polyfill_result.applied_edits_for_response() if polyfill_result else None + ) + compaction_block = ( + polyfill_result.compaction_block if polyfill_result is not None else None + ) + iterations_usage = ( + polyfill_result.iterations_usage if polyfill_result is not None else None + ) anthropic_wrapper = AnthropicStreamWrapper( completion_stream=completion_stream, model=model, tool_name_mapping=tool_name_mapping, + applied_edits=applied_edits, + compaction_block=compaction_block, + iterations_usage=iterations_usage, ) - # Return the SSE-wrapped version for proper event formatting - return anthropic_wrapper.async_anthropic_sse_wrapper() + # Return the SSE-wrapped version for proper event formatting. + if is_async: + return anthropic_wrapper.async_anthropic_sse_wrapper() + return anthropic_wrapper.anthropic_sse_wrapper() class LiteLLMAnthropicMessagesAdapter: @@ -1342,6 +1375,7 @@ def translate_openai_response_to_anthropic( self, response: ModelResponse, tool_name_mapping: Optional[Dict[str, str]] = None, + polyfill_result: Optional[PolyfillResult] = None, ) -> AnthropicMessagesResponse: """ Translate OpenAI response to Anthropic format. @@ -1351,12 +1385,17 @@ def translate_openai_response_to_anthropic( tool_name_mapping: Optional mapping of truncated tool names to original names. Used to restore original names for tools that exceeded OpenAI's 64-char limit. + polyfill_result: PolyfillResult from context_management polyfill. """ ## translate content block anthropic_content = self._translate_openai_content_to_anthropic( choices=response.choices, # type: ignore tool_name_mapping=tool_name_mapping, ) + + if polyfill_result is not None and polyfill_result.compaction_block is not None: + anthropic_content.insert(0, polyfill_result.compaction_block) # type: ignore[arg-type] + ## extract finish reason anthropic_finish_reason = self._translate_openai_finish_reason_to_anthropic( openai_finish_reason=response.choices[0].finish_reason # type: ignore @@ -1385,6 +1424,14 @@ def translate_openai_response_to_anthropic( if cached_tokens > 0: anthropic_usage["cache_read_input_tokens"] = cached_tokens + if polyfill_result is not None and polyfill_result.iterations_usage is not None: + message_iteration: UsageIteration = { + "type": "message", + "input_tokens": uncached_input_tokens, + "output_tokens": usage.completion_tokens or 0, + } + anthropic_usage["iterations"] = list(polyfill_result.iterations_usage) + [message_iteration] # type: ignore[typeddict-unknown-key] + translated_obj = AnthropicMessagesResponse( id=response.id, type="message", @@ -1396,6 +1443,14 @@ def translate_openai_response_to_anthropic( stop_reason=anthropic_finish_reason, ) + applied_edits = ( + polyfill_result.applied_edits_for_response() if polyfill_result else None + ) + if applied_edits: + translated_obj["context_management"] = ContextManagementResponse( + applied_edits=list(applied_edits) + ) + return translated_obj def _translate_streaming_openai_chunk_to_anthropic_content_block( @@ -1528,7 +1583,10 @@ def _translate_streaming_openai_chunk_to_anthropic( return "text_delta", ContentTextBlockDelta(type="text_delta", text=text) def translate_streaming_openai_response_to_anthropic( - self, response: ModelResponse, current_content_block_index: int + self, + response: ModelResponse, + current_content_block_index: int, + applied_edits: Optional[List[AppliedEdit]] = None, ) -> Union[ContentBlockDelta, MessageBlockDelta]: ## base case - final chunk w/ finish reason if response.choices[0].finish_reason is not None: @@ -1578,9 +1636,14 @@ def translate_streaming_openai_response_to_anthropic( usage_delta["cache_read_input_tokens"] = cached_tokens else: usage_delta = UsageDelta(input_tokens=0, output_tokens=0) - return MessageBlockDelta( + message_block = MessageBlockDelta( type="message_delta", delta=delta, usage=usage_delta # type: ignore ) + if applied_edits: + message_block["context_management"] = ContextManagementResponse( + applied_edits=list(applied_edits) + ) + return message_block ( type_of_content, content_block_delta, diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/__init__.py b/litellm/llms/anthropic/experimental_pass_through/context_management/__init__.py new file mode 100644 index 00000000000..729b2864524 --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/__init__.py @@ -0,0 +1,11 @@ +from .constants import CLEARED_TOOL_RESULT_PLACEHOLDER +from .dispatcher import apply_context_management +from .errors import AnthropicContextManagementError +from .result import PolyfillResult + +__all__ = [ + "apply_context_management", + "AnthropicContextManagementError", + "CLEARED_TOOL_RESULT_PLACEHOLDER", + "PolyfillResult", +] diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/constants.py b/litellm/llms/anthropic/experimental_pass_through/context_management/constants.py new file mode 100644 index 00000000000..ebbc182c427 --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/constants.py @@ -0,0 +1,45 @@ +"""Constants for the in-gateway context-management polyfill.""" + +CLEAR_TOOL_USES_EDIT_TYPE = "clear_tool_uses_20250919" + +DEFAULT_INPUT_TOKENS_TRIGGER = 100_000 +DEFAULT_KEEP_TOOL_USES = 3 + +CLEARED_TOOL_RESULT_PLACEHOLDER = "[Cleared by context management]" + +# compact_20260112 +COMPACT_EDIT_TYPE = "compact_20260112" +COMPACT_DEFAULT_TRIGGER_TOKENS = 150_000 +COMPACT_MIN_TRIGGER_TOKENS = 50_000 +# Default ``max_tokens`` for the summary call. Required by providers like +# Anthropic that reject requests without it; safely accepted by providers that +# don't strictly require it. Chosen to comfortably fit a long structured +# summary. Operators can override via +# ``general_settings.context_management_summary_max_tokens``. +COMPACT_SUMMARY_MAX_TOKENS = 4096 +COMPACT_SUMMARY_MAX_TOKENS_SETTING_KEY = "context_management_summary_max_tokens" +# Wall-clock bound for the summary sub-call. Without this a slow or +# unresponsive summary model would hang the parent ``/v1/messages`` request +# with no escape hatch; on timeout the editor falls into the standard +# ``summary_call_failed`` path and forwards the request without compaction. +COMPACT_SUMMARY_TIMEOUT_SECONDS = 60.0 +COMPACT_SUMMARY_MODEL_SETTING_KEY = "context_management_summary_model" +COMPACT_SUMMARY_SYSTEM_PREFIX = "Previous conversation summary: " + +# Default summarization prompt from the Anthropic spec. +COMPACT_DEFAULT_INSTRUCTIONS = ( + "You have written a partial transcript for the initial task above. Please " + "write a summary of the transcript. The purpose of this summary is to " + "provide continuity so you can continue to make progress towards solving " + "the task in a future context, where the raw history above may not be " + "accessible and will be replaced with this summary. Write down anything " + "that would be helpful, including the state, next steps, learnings etc. " + "You must wrap your summary in a

block." +) + +# Appended to the default prompt when ``tools`` are present and the caller +# did not supply custom ``instructions``. Matches the guidance in the +# Anthropic docs under "Compaction might fail when tools are defined". +COMPACT_NO_TOOL_CALLS_SUFFIX = ( + " Do not call any tools while writing this summary; respond with text only." +) diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/dispatcher.py b/litellm/llms/anthropic/experimental_pass_through/context_management/dispatcher.py new file mode 100644 index 00000000000..f7af09ee62a --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/dispatcher.py @@ -0,0 +1,127 @@ +"""Dispatch ``context_management`` edits to registered polyfill editors.""" + +import inspect +from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Union, cast + +from litellm._logging import verbose_logger +from litellm.types.llms.anthropic import AppliedEdit + +from .constants import CLEAR_TOOL_USES_EDIT_TYPE, COMPACT_EDIT_TYPE +from .editors import apply_clear_tool_uses_20250919, apply_compact_20260112 +from .result import PolyfillResult + +EditorFn = Callable[..., Any] + +_EDITOR_REGISTRY: Dict[str, EditorFn] = { + CLEAR_TOOL_USES_EDIT_TYPE: apply_clear_tool_uses_20250919, + COMPACT_EDIT_TYPE: apply_compact_20260112, +} + + +def _normalize_spec( + spec: Union[Dict[str, Any], List[Dict[str, Any]], None], +) -> Optional[List[Dict[str, Any]]]: + """Accept Anthropic-native dict form or OpenAI list form; return edits list.""" + if isinstance(spec, list): + # Local import to avoid an import cycle at module load. + from litellm.llms.anthropic.chat.transformation import AnthropicConfig + + spec = AnthropicConfig.map_openai_context_management_to_anthropic(spec) + + edits = spec.get("edits") if isinstance(spec, dict) else None + if not edits or not isinstance(edits, list): + return None + return [edit for edit in edits if isinstance(edit, dict)] + + +def _wrap_editor_return(raw: Any, *, fallback_system: Any) -> PolyfillResult: + """Coerce an editor's native return shape into a ``PolyfillResult``. + + v0 sync editors (e.g. ``clear_tool_uses_20250919``) return a 2-tuple + ``(messages, Optional[AppliedEdit])``. The new async ``compact_20260112`` + editor returns a ``PolyfillResult`` directly. + """ + if isinstance(raw, PolyfillResult): + return raw + # Legacy 2-tuple return — sync editors don't mutate ``system``, so + # carry the caller's value forward. + messages, applied = cast(Tuple[List[Dict[str, Any]], Any], raw) + return PolyfillResult( + messages=messages, + system=fallback_system, + applied_edits=[applied] if applied is not None else [], + ) + + +async def apply_context_management( + *, + model: str, + messages: List[Dict[str, Any]], + tools: Optional[List[Dict[str, Any]]], + system: Any, + context_management_spec: Union[Dict[str, Any], List[Dict[str, Any]], None], + litellm_metadata: Optional[Dict[str, Any]] = None, + llm_router: Any = None, + user_api_key_auth: Any = None, +) -> PolyfillResult: + """Run edits in order; return a single ``PolyfillResult``. + + The dispatcher is async so async editors (``compact_20260112``) can + ``await`` the configured summarization model. Sync editors are called + inline — ``inspect.iscoroutinefunction`` decides how each editor is + invoked. + """ + edits = _normalize_spec(context_management_spec) + if not edits: + return PolyfillResult(messages=messages, system=system, applied_edits=[]) + + current_messages = messages + current_system = system + aggregated_applied: List[AppliedEdit] = [] + aggregated_compaction_block = None + aggregated_iterations_usage = None + + for edit_spec in edits: + edit_type = edit_spec.get("type") + editor = _EDITOR_REGISTRY.get(edit_type) if isinstance(edit_type, str) else None + if editor is None: + verbose_logger.debug( + "context_management polyfill: unknown edit type '%s' — skipping", + edit_type, + ) + continue + + kwargs: Dict[str, Any] = { + "model": model, + "messages": current_messages, + "tools": tools, + "system": current_system, + "edit_spec": edit_spec, + } + # Only async editors accept these — passing them to sync v0 editors + # would break their signature. + if inspect.iscoroutinefunction(editor): + kwargs["litellm_metadata"] = litellm_metadata + kwargs["llm_router"] = llm_router + kwargs["user_api_key_auth"] = user_api_key_auth + raw_result = await cast(Callable[..., Awaitable[Any]], editor)(**kwargs) + else: + raw_result = editor(**kwargs) + + result = _wrap_editor_return(raw_result, fallback_system=current_system) + + current_messages = result.messages + current_system = result.system + aggregated_applied.extend(result.applied_edits) + if result.compaction_block is not None: + aggregated_compaction_block = result.compaction_block + if result.iterations_usage is not None: + aggregated_iterations_usage = result.iterations_usage + + return PolyfillResult( + messages=current_messages, + system=current_system, + applied_edits=aggregated_applied, + compaction_block=aggregated_compaction_block, + iterations_usage=aggregated_iterations_usage, + ) diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/__init__.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/__init__.py new file mode 100644 index 00000000000..3e933a9880a --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/__init__.py @@ -0,0 +1,4 @@ +from .clear_tool_uses import apply_clear_tool_uses_20250919 +from .compact import apply_compact_20260112 + +__all__ = ["apply_clear_tool_uses_20250919", "apply_compact_20260112"] diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py new file mode 100644 index 00000000000..7b1c20ff522 --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py @@ -0,0 +1,210 @@ +"""``clear_tool_uses_20250919`` polyfill (v0: ``trigger`` and ``keep`` only).""" + +from typing import Any, Dict, List, Optional, Tuple, cast + +import litellm +from litellm._logging import verbose_logger +from litellm.types.llms.anthropic import AppliedEdit + +from ..constants import ( + CLEAR_TOOL_USES_EDIT_TYPE, + DEFAULT_INPUT_TOKENS_TRIGGER, + DEFAULT_KEEP_TOOL_USES, +) +from ..placeholders import build_cleared_tool_result_content + + +def _count_tool_uses(messages: List[Dict[str, Any]]) -> int: + """Return the number of tool_use content blocks across all messages. + + Only counts blocks with a string ``id`` to stay consistent with + :func:`_collect_tool_use_ids_in_order`, which is the source of truth for + which blocks are clearable. + """ + count = 0 + for msg in messages: + content = msg.get("content") + if isinstance(content, list): + for block in content: + if isinstance(block, dict) and block.get("type") == "tool_use": + if isinstance(block.get("id"), str): + count += 1 + return count + + +def _collect_tool_use_ids_in_order(messages: List[Dict[str, Any]]) -> List[str]: + """Return tool_use ids in the chronological order they appear in messages.""" + ids: List[str] = [] + for msg in messages: + content = msg.get("content") + if isinstance(content, list): + for block in content: + if isinstance(block, dict) and block.get("type") == "tool_use": + block_id = block.get("id") + if isinstance(block_id, str): + ids.append(block_id) + return ids + + +def _trigger_met( + trigger: Dict[str, Any], + model: str, + messages: List[Dict[str, Any]], + tools: Optional[List[Dict[str, Any]]], +) -> Tuple[bool, Optional[int]]: + """Return (trigger_met, input_tokens if counted for reuse).""" + trigger_type = trigger.get("type", "input_tokens") + threshold = trigger.get("value") + + if trigger_type == "tool_uses": + if not isinstance(threshold, int): + return False, None + return _count_tool_uses(messages) > threshold, None + + if not isinstance(threshold, int): + threshold = DEFAULT_INPUT_TOKENS_TRIGGER + current_tokens = litellm.token_counter( + model=model, + messages=messages, + tools=cast(Any, tools), + ) + verbose_logger.debug( + f"context_management polyfill: current_tokens: {current_tokens}" + ) + verbose_logger.debug(f"context_management polyfill: threshold: {threshold}") + return current_tokens > threshold, current_tokens + + +def _resolve_keep_count(keep: Dict[str, Any]) -> int: + keep_type = keep.get("type", "tool_uses") + if keep_type != "tool_uses": + return DEFAULT_KEEP_TOOL_USES + value = keep.get("value") + if not isinstance(value, int) or value < 0: + return DEFAULT_KEEP_TOOL_USES + return value + + +def _last_completed_tool_use_id( + messages: List[Dict[str, Any]], +) -> Optional[str]: + """Latest completed tool_result id; never cleared.""" + last_id: Optional[str] = None + for msg in messages: + content = msg.get("content") + if isinstance(content, list): + for block in content: + if isinstance(block, dict) and block.get("type") == "tool_result": + block_id = block.get("tool_use_id") + if isinstance(block_id, str): + last_id = block_id + return last_id + + +def _clear_tool_results( + messages: List[Dict[str, Any]], ids_to_clear: set +) -> Tuple[List[Dict[str, Any]], int]: + """Clear matching tool_result content; return (messages, cleared_count).""" + cleared = 0 + new_messages: List[Dict[str, Any]] = [] + for msg in messages: + content = msg.get("content") + if not isinstance(content, list): + new_messages.append(msg) + continue + + new_blocks: List[Any] = [] + mutated = False + for block in content: + if ( + isinstance(block, dict) + and block.get("type") == "tool_result" + and block.get("tool_use_id") in ids_to_clear + ): + new_block = { + **block, + "content": build_cleared_tool_result_content(block.get("content")), + } + new_blocks.append(new_block) + mutated = True + cleared += 1 + else: + new_blocks.append(block) + + if mutated: + new_messages.append({**msg, "content": new_blocks}) + else: + new_messages.append(msg) + + return new_messages, cleared + + +def apply_clear_tool_uses_20250919( + *, + model: str, + messages: List[Dict[str, Any]], + tools: Optional[List[Dict[str, Any]]], + system: Any, + edit_spec: Dict[str, Any], +) -> Tuple[List[Dict[str, Any]], Optional[AppliedEdit]]: + """Apply clear_tool_uses; return (messages, AppliedEdit or None).""" + ignored_knobs = [ + knob + for knob in ("clear_at_least", "exclude_tools", "clear_tool_inputs") + if knob in edit_spec + ] + for ignored_knob in ignored_knobs: + verbose_logger.warning( + "context_management polyfill: ignoring '%s' on %s " + "(supported only on Anthropic-family forwarding path in v0)", + ignored_knob, + CLEAR_TOOL_USES_EDIT_TYPE, + ) + + trigger = edit_spec.get("trigger") or { + "type": "input_tokens", + "value": DEFAULT_INPUT_TOKENS_TRIGGER, + } + keep = edit_spec.get("keep") or { + "type": "tool_uses", + "value": DEFAULT_KEEP_TOOL_USES, + } + + met, tokens_before = _trigger_met(trigger, model, messages, tools) + if not met: + return messages, None + + keep_count = _resolve_keep_count(keep) + tool_use_ids = _collect_tool_use_ids_in_order(messages) + if len(tool_use_ids) <= keep_count: + return messages, None + + ids_to_clear = set(tool_use_ids[: len(tool_use_ids) - keep_count]) + + # Never clear the latest completed tool_result (reply context). + last_completed_id = _last_completed_tool_use_id(messages) + if last_completed_id is not None: + ids_to_clear.discard(last_completed_id) + + edited, cleared_count = _clear_tool_results(messages, ids_to_clear) + verbose_logger.debug("context_management polyfill: edited: %s", edited) + if cleared_count == 0: + return messages, None + + if tokens_before is None: + tokens_before = litellm.token_counter( + model=model, messages=messages, tools=cast(Any, tools) + ) + tokens_after = litellm.token_counter( + model=model, messages=edited, tools=cast(Any, tools) + ) + cleared_input_tokens = max(tokens_before - tokens_after, 0) + + applied: AppliedEdit = { + "type": CLEAR_TOOL_USES_EDIT_TYPE, + "cleared_tool_uses": cleared_count, + "cleared_input_tokens": cleared_input_tokens, + } + if ignored_knobs: + applied["warnings"] = [f"{knob}_ignored" for knob in ignored_knobs] + return edited, applied diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py new file mode 100644 index 00000000000..4aae85b17fe --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py @@ -0,0 +1,1206 @@ +"""``compact_20260112`` polyfill (server-side context compaction). + +Mirrors Anthropic's native ``compact_20260112`` for non-Anthropic providers: + +- Scans the message history for an existing ``compaction`` block; everything + before it is dropped (slice). +- If still over the configured trigger, calls a separately-configured + summarization model and synthesizes a fresh ``compaction`` block. +- The summary is injected as a system-message prefix on the downstream call + (the user/assistant log carries no ``compaction`` block downstream). +- The synthesized ``compaction`` block is returned via ``PolyfillResult`` so + the response adapter can prepend it to the response ``content`` array. +""" + +import re +from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast + +import litellm +from litellm._logging import verbose_logger +from litellm.types.llms.anthropic import ( + AppliedEdit, + CompactionBlock, + UsageIteration, +) + +from ..constants import ( + COMPACT_DEFAULT_INSTRUCTIONS, + COMPACT_DEFAULT_TRIGGER_TOKENS, + COMPACT_EDIT_TYPE, + COMPACT_MIN_TRIGGER_TOKENS, + COMPACT_NO_TOOL_CALLS_SUFFIX, + COMPACT_SUMMARY_MAX_TOKENS, + COMPACT_SUMMARY_MAX_TOKENS_SETTING_KEY, + COMPACT_SUMMARY_MODEL_SETTING_KEY, + COMPACT_SUMMARY_SYSTEM_PREFIX, + COMPACT_SUMMARY_TIMEOUT_SECONDS, +) +from ..errors import AnthropicContextManagementError +from ..result import PolyfillResult + +# Auth metadata fields propagated from the parent request to the summary call +# so the summary's spend is attributed to the same scopes. The list mirrors the +# fields populated by +# ``LiteLLMProxyRequestSetup.add_user_api_key_auth_to_request_metadata``. +# ``user_api_key_model_max_budget`` / ``user_api_key_end_user_model_max_budget`` +# are what ``_PROXY_VirtualKeyModelMaxBudgetLimiter`` reads post-call to update +# the per-model spend caches, so without them the summary spend would never +# count against the caller's model budget. ``user_api_key_end_user_id`` / +# ``user_api_key_project_id`` are the scope identifiers the post-call spend hook +# and rate limiter key their counters on, and ``user_api_end_user_max_budget`` +# is the end-user budget the cost callback enforces — without these the summary +# tokens escape the caller's end-user/project budgets and counters. +_PROPAGATED_METADATA_KEYS = ( + "user_api_key", + "user_api_key_alias", + "user_api_key_team_id", + "user_api_key_team_alias", + "user_api_key_user_id", + "user_api_key_user_email", + "user_api_key_org_id", + "user_api_key_project_id", + "user_api_key_end_user_id", + "user_api_end_user_max_budget", + "user_api_key_model_max_budget", + "user_api_key_end_user_model_max_budget", + "litellm_call_id", + "litellm_parent_otel_span", +) + +_SUMMARY_TAG_RE = re.compile(r"(.*?)", re.IGNORECASE | re.DOTALL) + + +def _read_summary_model_setting() -> Optional[str]: + """Look up the configured summarization model from proxy general_settings.""" + try: + from litellm.proxy.proxy_server import general_settings + except Exception: + return None + value = general_settings.get(COMPACT_SUMMARY_MODEL_SETTING_KEY) + return value if isinstance(value, str) and value else None + + +def _read_summary_max_tokens_setting() -> int: + """Look up the configured summary ``max_tokens`` from proxy general_settings. + + Falls back to :data:`COMPACT_SUMMARY_MAX_TOKENS` when the setting is + missing or invalid (non-positive int, wrong type). Operators tune this + when the default doesn't fit their chosen summary model's output budget. + """ + try: + from litellm.proxy.proxy_server import general_settings + except Exception: + return COMPACT_SUMMARY_MAX_TOKENS + value = general_settings.get(COMPACT_SUMMARY_MAX_TOKENS_SETTING_KEY) + if isinstance(value, int) and value > 0: + return value + return COMPACT_SUMMARY_MAX_TOKENS + + +async def _check_summary_model_access( # noqa: PLR0915 + user_api_key_auth: Any, + summary_model: str, + llm_router: Any, +) -> bool: + """Return True when every model-allowlist scope on the parent request is + satisfied for ``summary_model``. + + The summary subrequest does not pass through ``user_api_key_auth`` again, + so without this gate a caller whose configured scope at any of these + levels excludes ``context_management_summary_model`` could still get the + proxy to invoke that model and return its ```` output as a + compaction block. Mirrors the model-scope enforcement that + ``litellm.proxy.auth.common_checks`` runs for the client-requested model: + key, team, user (personal), project, and team-member allowlists. + + Returns True (allow) when ``user_api_key_auth`` is not present — SDK + callers and tests run outside the proxy, where no key/team policy exists. + Returns False when any of the active allowlists denies the summary model + (``ProxyException`` from ``_can_object_call_model`` / ``can_*_model``). + Unexpected errors during an access check fail closed but are logged + separately so operators can distinguish them from a real access-denied + response. DB-lookup failures (object missing from cache or DB) skip the + corresponding scope — matching ``common_checks``, which only enforces a + scope when its backing object can be loaded. + """ + if user_api_key_auth is None: + return True + try: + from litellm.proxy._types import ProxyException + from litellm.proxy.auth.auth_checks import ( + _can_object_call_model, + can_project_access_model, + can_user_call_model, + get_project_object, + get_team_membership, + get_user_object, + ) + from litellm.proxy.proxy_server import ( + prisma_client, + proxy_logging_obj, + user_api_key_cache, + ) + except Exception: + return True + + key_models = list(getattr(user_api_key_auth, "models", None) or []) + team_id = getattr(user_api_key_auth, "team_id", None) + team_model_aliases = getattr(user_api_key_auth, "team_model_aliases", None) + team_models = list(getattr(user_api_key_auth, "team_models", None) or []) + user_id = getattr(user_api_key_auth, "user_id", None) + project_id = getattr(user_api_key_auth, "project_id", None) + + checks: Tuple[Tuple[Literal["key", "team"], List[str]], ...] = ( + ("key", key_models), + ("team", team_models), + ) + for object_type, models in checks: + if not models: + continue + try: + _can_object_call_model( + model=summary_model, + llm_router=llm_router, + models=models, + team_model_aliases=team_model_aliases, + team_id=team_id, + object_type=object_type, + ) + except ProxyException: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during %s-level access " + "check for summary_model=%s; denying access: %s", + object_type, + summary_model, + e, + ) + return False + + if user_id is not None and prisma_client is not None: + try: + user_obj = await get_user_object( + user_id=user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + user_id_upsert=False, + proxy_logging_obj=proxy_logging_obj, + ) + except Exception as e: + verbose_logger.debug( + "compact_20260112: user object lookup failed for " + "summary_model=%s access check; skipping user-level scope: %s", + summary_model, + e, + ) + user_obj = None + if user_obj is not None: + try: + await can_user_call_model( + model=summary_model, + llm_router=llm_router, + user_object=user_obj, + ) + except ProxyException: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during user-level " + "access check for summary_model=%s; denying access: %s", + summary_model, + e, + ) + return False + + if project_id is not None and prisma_client is not None: + try: + project_obj = await get_project_object( + project_id=project_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) + except Exception as e: + verbose_logger.debug( + "compact_20260112: project object lookup failed for " + "summary_model=%s access check; skipping project-level scope: %s", + summary_model, + e, + ) + project_obj = None + if project_obj is not None and project_obj.models: + try: + can_project_access_model( + model=summary_model, + project_object=project_obj, + llm_router=llm_router, + ) + except ProxyException: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during project-level " + "access check for summary_model=%s; denying access: %s", + summary_model, + e, + ) + return False + + if user_id is not None and team_id is not None and prisma_client is not None: + try: + team_membership = await get_team_membership( + user_id=user_id, + team_id=team_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) + except Exception as e: + verbose_logger.debug( + "compact_20260112: team membership lookup failed for " + "summary_model=%s access check; skipping member-level scope: %s", + summary_model, + e, + ) + team_membership = None + member_allowed_models = ( + team_membership.litellm_budget_table.allowed_models + if team_membership is not None + and team_membership.litellm_budget_table is not None + else None + ) + if member_allowed_models: + try: + _can_object_call_model( + model=summary_model, + llm_router=llm_router, + models=list(member_allowed_models), + team_model_aliases=team_model_aliases, + team_id=team_id, + object_type="team", + ) + except ProxyException: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during member-level " + "access check for summary_model=%s; denying access: %s", + summary_model, + e, + ) + return False + + return True + + +async def _check_summary_model_budget( + user_api_key_auth: Any, + summary_model: str, +) -> bool: + """Return True when the caller is within their per-model budget for + ``summary_model``. + + The summary subrequest never passes back through ``user_api_key_auth``, so + without this gate a caller whose ``model_max_budget`` for + ``context_management_summary_model`` is exhausted could keep consuming that + model via compaction. Mirrors the ``model_max_budget`` / + ``end_user_model_max_budget`` enforcement that ``user_api_key_auth`` runs for + the client-requested model. Returns True outside the proxy or when no + per-model budget is configured. + """ + if user_api_key_auth is None: + return True + try: + from litellm.proxy.proxy_server import model_max_budget_limiter + except Exception: + return True + + model_max_budget = getattr(user_api_key_auth, "model_max_budget", None) + token = getattr(user_api_key_auth, "token", None) + if isinstance(model_max_budget, dict) and model_max_budget and token is not None: + try: + await model_max_budget_limiter.is_key_within_model_budget( + user_api_key_dict=user_api_key_auth, + model=summary_model, + ) + except litellm.BudgetExceededError: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during key model-budget " + "check for summary_model=%s; denying: %s", + summary_model, + e, + ) + return False + + end_user_model_max_budget = getattr( + user_api_key_auth, "end_user_model_max_budget", None + ) + end_user_id = getattr(user_api_key_auth, "end_user_id", None) + if ( + isinstance(end_user_model_max_budget, dict) + and end_user_model_max_budget + and end_user_id is not None + ): + try: + await model_max_budget_limiter.is_end_user_within_model_budget( + end_user_id=end_user_id, + end_user_model_max_budget=end_user_model_max_budget, + model=summary_model, + ) + except litellm.BudgetExceededError: + return False + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during end-user model-budget " + "check for summary_model=%s; denying: %s", + summary_model, + e, + ) + return False + + return True + + +async def _check_summary_model_rate_limit( + user_api_key_auth: Any, + summary_model: str, +) -> bool: + """Return True when the caller is within their configured RPM/TPM limits + for ``summary_model``. + + The summary subrequest never passes back through the proxy's pre-call + rate limiter, so without this gate a caller already at their key / team / + user RPM or TPM could still drive an extra summary-model completion per + allowed ``/v1/messages`` request. This mirrors the read side of + ``_PROXY_MaxParallelRequestsHandler_v3.async_pre_call_hook`` for the + summary model: it builds the same descriptor set and runs the check in + ``read_only`` mode so no counter is reserved or incremented — the summary + call's actual usage is still charged exactly once by the limiter's + post-call success hook (via the propagated ``litellm_metadata``). + + Returns True (allow) outside the proxy, when the active limiter does not + expose the read-only descriptor check (legacy limiter), or when the + descriptor set cannot be built — the only deny signal is a definitive + ``OVER_LIMIT`` response, so an internal error here forwards the request + uncompacted rather than blocking every summary. + """ + if user_api_key_auth is None: + return True + try: + from litellm.proxy.proxy_server import proxy_logging_obj + except Exception: + return True + + limiter = getattr(proxy_logging_obj, "max_parallel_request_limiter", None) + if ( + limiter is None + or not hasattr(limiter, "should_rate_limit") + or not hasattr(limiter, "_create_rate_limit_descriptors") + ): + return True + + try: + metadata = getattr(user_api_key_auth, "metadata", None) or {} + data = {"model": summary_model} + descriptors = limiter._create_rate_limit_descriptors( + user_api_key_dict=user_api_key_auth, + data=data, + rpm_limit_type=metadata.get("rpm_limit_type"), + tpm_limit_type=metadata.get("tpm_limit_type"), + model_has_failures=False, + ) + limiter._add_team_model_rate_limit_descriptor_from_metadata( + user_api_key_dict=user_api_key_auth, + requested_model=summary_model, + descriptors=descriptors, + ) + limiter._add_project_model_rate_limit_descriptor_from_metadata( + user_api_key_dict=user_api_key_auth, + requested_model=summary_model, + descriptors=descriptors, + ) + descriptors.extend( + limiter.create_organization_rate_limit_descriptor( + user_api_key_auth, summary_model + ) + ) + if not descriptors: + return True + response = await limiter.should_rate_limit( + descriptors=descriptors, + parent_otel_span=getattr(user_api_key_auth, "parent_otel_span", None), + read_only=True, + ) + except Exception as e: + verbose_logger.warning( + "compact_20260112: unexpected error during rate-limit check for " + "summary_model=%s; allowing: %s", + summary_model, + e, + ) + return True + return response.get("overall_code") != "OVER_LIMIT" + + +def _find_latest_compaction_index( + messages: List[Dict[str, Any]], +) -> Tuple[Optional[int], Optional[int]]: + """Return (message_index, block_index) of the most recent compaction block. + + ``None, None`` if no compaction block is present. Iterates from the end so + only the latest one is considered. + """ + for msg_idx in range(len(messages) - 1, -1, -1): + content = messages[msg_idx].get("content") + if not isinstance(content, list): + continue + for blk_idx in range(len(content) - 1, -1, -1): + block = content[blk_idx] + if isinstance(block, dict) and block.get("type") == "compaction": + return msg_idx, blk_idx + return None, None + + +def _slice_around_compaction_block( + messages: List[Dict[str, Any]], +) -> Tuple[List[Dict[str, Any]], Optional[Dict[str, Any]]]: + """Apply Anthropic's "drop everything before the compaction block" rule. + + Returns ``(sliced_messages_with_compaction_block, compaction_block_dict)`` + if a block was found, else ``(original_messages, None)``. The sliced result + keeps the compaction block in the assistant turn that originally carried + it (in practice it's the only block in that turn) so callers can still + extract the summary text from it. + """ + msg_idx, blk_idx = _find_latest_compaction_index(messages) + if msg_idx is None or blk_idx is None: + return messages, None + + original_msg = messages[msg_idx] + original_content = original_msg["content"] + compaction_block = cast(Dict[str, Any], original_content[blk_idx]) + + # Per Anthropic's contract everything before the compaction block is + # dropped, including earlier blocks within the same assistant message. + sliced_content = list(original_content[blk_idx:]) + sliced_first_msg = {**original_msg, "content": sliced_content} + + sliced_messages: List[Dict[str, Any]] = [sliced_first_msg] + sliced_messages.extend(messages[msg_idx + 1 :]) + return sliced_messages, compaction_block + + +def _strip_compaction_blocks( + messages: List[Dict[str, Any]], +) -> List[Dict[str, Any]]: + """Drop any ``compaction`` content blocks from messages. + + Used to build the downstream-bound message list — the adapter has no + concept of a compaction block, so it must not see one. + """ + cleaned: List[Dict[str, Any]] = [] + for msg in messages: + content = msg.get("content") + if not isinstance(content, list): + cleaned.append(msg) + continue + filtered = [ + block + for block in content + if not (isinstance(block, dict) and block.get("type") == "compaction") + ] + if not filtered: + # The compaction block was the only content; drop the whole turn. + continue + cleaned.append({**msg, "content": filtered}) + return cleaned + + +def _augment_system_with_summary( + system: Optional[Union[str, List[Dict[str, Any]]]], + summary_text: str, +) -> Union[str, List[Dict[str, Any]]]: + """Prepend a "Previous conversation summary: ..." block to ``system``.""" + prefix = f"{COMPACT_SUMMARY_SYSTEM_PREFIX}{summary_text}\n\n" + if system is None: + return prefix.rstrip() + if isinstance(system, str): + return f"{prefix}{system}" + # List of content blocks: prepend the prefix to the first text block, + # otherwise insert a new text block at the head. + for idx, block in enumerate(system): + if isinstance(block, dict) and block.get("type") == "text": + existing = block.get("text", "") or "" + new_block = {**block, "text": f"{prefix}{existing}"} + return [*system[:idx], new_block, *system[idx + 1 :]] + return [{"type": "text", "text": prefix.rstrip()}, *system] + + +def _resolve_trigger_tokens(edit_spec: Dict[str, Any]) -> Tuple[int, List[str]]: + """Validate and resolve ``trigger.value``. + + Raises ``AnthropicContextManagementError`` if the explicitly-supplied value + is below the 50k minimum. Unknown ``trigger.type`` values fall back to + ``input_tokens`` with a warning. + """ + warnings: List[str] = [] + trigger = edit_spec.get("trigger") or {} + if not isinstance(trigger, dict): + warnings.append("trigger_not_a_dict_using_default") + return COMPACT_DEFAULT_TRIGGER_TOKENS, warnings + + trigger_type = trigger.get("type", "input_tokens") + if trigger_type != "input_tokens": + warnings.append(f"unsupported_trigger_type_{trigger_type}_using_input_tokens") + + value = trigger.get("value") + if value is None: + return COMPACT_DEFAULT_TRIGGER_TOKENS, warnings + if not isinstance(value, int): + warnings.append("trigger_value_not_int_using_default") + return COMPACT_DEFAULT_TRIGGER_TOKENS, warnings + if value < COMPACT_MIN_TRIGGER_TOKENS: + raise AnthropicContextManagementError( + status_code=400, + message=( + f"context_management.compact_20260112.trigger.value must be at " + f"least {COMPACT_MIN_TRIGGER_TOKENS} tokens" + ), + ) + return value, warnings + + +def _build_summary_prompt( + edit_spec: Dict[str, Any], tools: Optional[List[Dict[str, Any]]] +) -> str: + custom = edit_spec.get("instructions") + if isinstance(custom, str) and custom.strip(): + return custom + prompt = COMPACT_DEFAULT_INSTRUCTIONS + if tools: + prompt = f"{prompt}{COMPACT_NO_TOOL_CALLS_SUFFIX}" + return prompt + + +def _propagate_metadata( + parent_litellm_metadata: Optional[Dict[str, Any]], +) -> Dict[str, Any]: + """Extract the parent request's auth/spend-attribution fields for the summary subcall. + + The proxy attaches ``user_api_key``, ``user_api_key_team_id`` etc. to + ``data["litellm_metadata"]`` (see + ``LiteLLMProxyRequestSetup.add_user_api_key_auth_to_request_metadata``). + Without these on the summary subrequest, the router's post-call hooks + cannot attribute summary tokens to the caller's key/team budget. + """ + if not parent_litellm_metadata: + return {} + propagated: Dict[str, Any] = {} + for key in _PROPAGATED_METADATA_KEYS: + if key in parent_litellm_metadata: + propagated[key] = parent_litellm_metadata[key] + return propagated + + +def _count_effective_tokens( + model: str, + effective_messages: List[Dict[str, Any]], + compaction_block: Optional[Dict[str, Any]], + tools: Optional[List[Dict[str, Any]]], + system: Optional[Union[str, List[Dict[str, Any]]]] = None, +) -> int: + """Token-count the conversation as it will appear downstream. + + The compaction block (if any) becomes a system prefix on the downstream + call, so its content still counts even though it isn't in ``messages``. + The system prompt (which may already include a prior compaction summary + prepended via ``_augment_system_with_summary``) is also counted so the + threshold check matches the downstream ``input_tokens`` metric. + """ + # Local import to avoid pulling the adapter at module load time. + from litellm.llms.anthropic.experimental_pass_through.adapters.transformation import ( + LiteLLMAnthropicMessagesAdapter, + ) + + messages_without_compaction = _strip_compaction_blocks(effective_messages) + adapter = LiteLLMAnthropicMessagesAdapter() + try: + openai_shape = adapter.translate_anthropic_messages_to_openai( + messages=cast(Any, messages_without_compaction) + ) + except Exception as e: + verbose_logger.debug( + "compact_20260112: anthropic→openai translation failed during token " + "count, falling back to raw messages: %s", + e, + ) + openai_shape = cast(Any, messages_without_compaction) + + # Translate Anthropic-shaped tools (``input_schema``) to OpenAI-shaped + # tools (``{"type": "function", "function": {...}}``) so ``token_counter`` + # gets a consistent format regardless of which counting path it uses. + # An inaccurate tool token count here could cause the polyfill to skip + # needed compaction or trigger unnecessary summarization. + openai_tools: Optional[List[Dict[str, Any]]] = None + if tools: + try: + translated_tools, _ = adapter.translate_anthropic_tools_to_openai( + tools=cast(Any, tools) + ) + openai_tools = cast(List[Dict[str, Any]], translated_tools) + except Exception as e: + verbose_logger.debug( + "compact_20260112: anthropic→openai tools translation failed " + "during token count, falling back to raw tools: %s", + e, + ) + openai_tools = tools + + total = litellm.token_counter( + model=model, + messages=cast(Any, openai_shape), + tools=cast(Any, openai_tools), + ) + if compaction_block is not None: + content = compaction_block.get("content") or "" + if content: + total += litellm.token_counter(model=model, text=content) + system_text = _system_to_text(system) + if system_text: + total += litellm.token_counter(model=model, text=system_text) + return total + + +def _system_to_text( + system: Optional[Union[str, List[Dict[str, Any]]]], +) -> str: + """Flatten an Anthropic-style ``system`` value into a single string for + token counting. Returns ``""`` when ``system`` carries no text.""" + if system is None: + return "" + if isinstance(system, str): + return system + parts: List[str] = [] + for block in system: + if isinstance(block, dict) and block.get("type") == "text": + text = block.get("text") + if isinstance(text, str) and text: + parts.append(text) + return "\n".join(parts) + + +def _select_last_user_question( + messages: List[Dict[str, Any]], +) -> List[Dict[str, Any]]: + """Pick the most recent ``user`` turn that is a real question. + + Returns a one-element message list with any ``tool_result`` blocks + stripped: after compaction the paired ``tool_use`` assistant turn no + longer exists in the downstream context, so forwarding ``tool_result`` + blocks would translate to orphaned ``role=tool`` messages on + non-Anthropic providers (OpenAI, Gemini, …) and cause a 400 error. + + Falls back to a synthetic continuation prompt if no eligible turn + exists (e.g. the conversation only ever contained ``tool_result`` + turns, or contained no user turns at all). The downstream call always + needs a non-empty user message. + """ + for msg in reversed(messages): + if msg.get("role") != "user": + continue + content = msg.get("content") + if isinstance(content, list): + filtered = [ + blk + for blk in content + if not (isinstance(blk, dict) and blk.get("type") == "tool_result") + ] + if not filtered: + # Purely tool_result — skip and look for an earlier turn. + continue + if len(filtered) < len(content): + return [{**msg, "content": filtered}] + return [msg] + return [ + { + "role": "user", + "content": "Please continue based on the conversation summary above.", + } + ] + + +def _extract_summary_text(raw: Optional[str]) -> Optional[str]: + if not raw: + return None + match = _SUMMARY_TAG_RE.search(raw) + if match is None: + return None + summary = match.group(1).strip() + return summary or None + + +def _system_to_openai_message( + system: Optional[Union[str, List[Dict[str, Any]]]], +) -> Optional[Dict[str, Any]]: + """Translate Anthropic-shaped ``system`` to an OpenAI system message. + + Accepts a bare string or a list of Anthropic content blocks; returns + ``None`` if no usable text is present. Only ``type=="text"`` blocks are + carried over — the summary model has no use for ``cache_control`` or + other non-text metadata. + """ + if isinstance(system, str): + return {"role": "system", "content": system} if system else None + if isinstance(system, list): + parts = [ + block.get("text", "") + for block in system + if isinstance(block, dict) and block.get("type") == "text" + ] + joined = "\n\n".join(part for part in parts if part) + return {"role": "system", "content": joined} if joined else None + return None + + +def _build_summary_messages( + effective_messages: List[Dict[str, Any]], + prompt: str, + system: Optional[Union[str, List[Dict[str, Any]]]] = None, +) -> List[Dict[str, Any]]: + """Build the OpenAI-shape message list for the summary call. + + The caller's ``system`` prompt is prepended (the default summarization + instructions reference "the initial task above", which lives in that + system prompt); the conversation history is translated to OpenAI shape; + the summarization prompt is appended as a final user turn. + """ + from litellm.llms.anthropic.experimental_pass_through.adapters.transformation import ( + LiteLLMAnthropicMessagesAdapter, + ) + + stripped = _strip_compaction_blocks(effective_messages) + try: + openai_messages = ( + LiteLLMAnthropicMessagesAdapter().translate_anthropic_messages_to_openai( + messages=cast(Any, stripped) + ) + ) + except Exception as e: + verbose_logger.warning( + "compact_20260112: anthropic→openai translation failed when " + "building summary call; falling back to raw shape: %s", + e, + ) + openai_messages = cast(Any, stripped) + + summary_messages: List[Dict[str, Any]] = [] + system_message = _system_to_openai_message(system) + if system_message is not None: + summary_messages.append(system_message) + summary_messages.extend(openai_messages) + # If the last turn is already a user message, merge the summarization + # prompt into it. Some providers (and strict OpenAI-compatible endpoints) + # reject two consecutive ``role=user`` messages, which would otherwise + # silently fall into the ``summary_call_failed`` error path. + if summary_messages and _is_user_message(summary_messages[-1]): + last_msg = summary_messages[-1] + summary_messages[-1] = { + **last_msg, + "content": _append_text_to_content(last_msg.get("content"), prompt), + } + else: + summary_messages.append({"role": "user", "content": prompt}) + return summary_messages + + +def _is_user_message(msg: Any) -> bool: + return isinstance(msg, dict) and msg.get("role") == "user" + + +def _append_text_to_content(content: Any, extra_text: str) -> Any: + """Append ``extra_text`` to an OpenAI-shape message ``content`` field. + + Handles the two common shapes: ``str`` and ``list`` of content parts. + For unexpected/empty shapes, fall back so the caller gets a usable value. + """ + if content is None or content == "": + return extra_text + if isinstance(content, str): + return f"{content}\n\n{extra_text}" + if isinstance(content, list): + return [*content, {"type": "text", "text": extra_text}] + return [content, {"type": "text", "text": extra_text}] + + +async def _call_summary_model( + *, + summary_model: str, + summary_messages: List[Dict[str, Any]], + metadata: Dict[str, Any], + llm_router: Any, + allowed_model_region: Optional[str] = None, + max_tokens: int = COMPACT_SUMMARY_MAX_TOKENS, +) -> Any: + """Invoke the configured summary model. + + Prefers ``llm_router.acompletion`` so the model alias resolves against the + proxy's ``model_list``; falls back to ``litellm.acompletion`` if no router + is available (e.g. SDK usage outside the proxy). + """ + # ``max_tokens`` is required by providers like Anthropic and silently + # accepted by providers that don't strictly require it (OpenAI etc.). + # Setting a sensible default here means the feature works regardless of + # which model an admin configures as ``context_management_summary_model``; + # operators can override via ``context_management_summary_max_tokens`` in + # ``general_settings`` when the default doesn't fit the chosen model's + # output budget. + # The propagated proxy auth/spend-attribution fields (``user_api_key`` etc.) + # must travel as ``litellm_metadata`` — that is the parameter the proxy's + # post-call spend hooks read for budget attribution. The provider-level + # ``metadata`` kwarg corresponds to the upstream API request body and would + # not flow into spend tracking. + # ``allowed_model_region`` must travel as a top-level kwarg because the + # router enforces region restrictions by reading ``request_kwargs`` directly + # (see ``Router._common_checks_available_deployment``); without this the + # summary subrequest could be routed to a deployment outside the caller's + # permitted region. + # ``timeout`` bounds how long a slow/unresponsive summary model can stall + # the parent ``/v1/messages`` request. On timeout the caller catches the + # exception and surfaces ``applied_edits[0].error = "summary_call_failed"``, + # forwarding the request without compaction rather than hanging. + call_kwargs: Dict[str, Any] = { + "model": summary_model, + "messages": summary_messages, + "max_tokens": max_tokens, + "timeout": COMPACT_SUMMARY_TIMEOUT_SECONDS, + "litellm_metadata": metadata, + } + # The end-user id must also travel as the top-level ``user`` kwarg: legacy + # limiter hooks and prometheus end-user tracking read it from there rather + # than from ``litellm_metadata``, so without it the summary tokens would not + # debit the caller's end-user counters. + end_user_id = metadata.get("user_api_key_end_user_id") + if end_user_id: + call_kwargs["user"] = end_user_id + if allowed_model_region is not None: + call_kwargs["allowed_model_region"] = allowed_model_region + if llm_router is not None and hasattr(llm_router, "acompletion"): + return await llm_router.acompletion(**call_kwargs) + return await litellm.acompletion(**call_kwargs) + + +def _extract_response_text(response: Any) -> Optional[str]: + try: + choice = response.choices[0] + message = choice.message + content = getattr(message, "content", None) + if isinstance(content, str): + return content + # Some providers return a list of content parts. + if isinstance(content, list): + text_parts = [ + part.get("text", "") + for part in content + if isinstance(part, dict) and part.get("type") == "text" + ] + return "".join(text_parts) or None + except (AttributeError, IndexError, KeyError): + return None + return None + + +def _extract_usage(response: Any) -> Tuple[int, int]: + usage = getattr(response, "usage", None) + if usage is None: + return 0, 0 + return ( + int(getattr(usage, "prompt_tokens", 0) or 0), + int(getattr(usage, "completion_tokens", 0) or 0), + ) + + +def apply_client_compaction_block_history( + *, + messages: List[Dict[str, Any]], + system: Optional[Union[str, List[Dict[str, Any]]]], +) -> Optional[PolyfillResult]: + """Honor client-sent compaction blocks without a ``compact_20260112`` edit. + + When the request omits ``context_management`` but the message history already + contains a ``compaction`` content block (e.g. Claude Code client-side + compaction), apply the same slice-only forwarding as the under-threshold + path: the prior summary is prepended to ``system`` and the post-compaction + tail is forwarded unchanged (with compaction blocks stripped) so recent + turns the summary does not cover are preserved. + """ + effective_messages, prior_compaction_block = _slice_around_compaction_block( + messages + ) + if prior_compaction_block is None: + return None + + verbose_logger.info( + "compact_20260112: client compaction block in message history; " + "applying slice-only forwarding (no context_management edit)" + ) + + prior_summary_text = prior_compaction_block.get("content") or "" + augmented_system: Union[str, List[Dict[str, Any]], None] = system + if isinstance(prior_summary_text, str) and prior_summary_text: + augmented_system = _augment_system_with_summary(system, prior_summary_text) + verbose_logger.info( + "compact_20260112: compaction summary added to main call system prefix (%s chars)", + len(prior_summary_text), + ) + + # Post-compaction turns are recent context the prior summary does not cover, + # so forward them unchanged. Only fall back to the last user question if the + # strip leaves the downstream call with nothing to answer. + downstream_messages = _strip_compaction_blocks(effective_messages) + if not downstream_messages: + downstream_messages = _select_last_user_question(effective_messages) + + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[], + ) + + +async def apply_compact_20260112( # noqa: PLR0915 + *, + model: str, + messages: List[Dict[str, Any]], + tools: Optional[List[Dict[str, Any]]], + system: Optional[Union[str, List[Dict[str, Any]]]], + edit_spec: Dict[str, Any], + litellm_metadata: Optional[Dict[str, Any]] = None, + llm_router: Any = None, + user_api_key_auth: Any = None, +) -> PolyfillResult: + """Apply ``compact_20260112``; return a ``PolyfillResult``. + + See module docstring for the algorithm. Errors are best-effort: when the + summary call fails or the response is malformed, the editor returns the + pre-summary state (with ``applied_edits[0].error`` populated) so the + original request still proceeds. + """ + # Validation runs first. Raising AnthropicContextManagementError here is + # the only path on which the polyfill aborts the request. + trigger_tokens, warnings = _resolve_trigger_tokens(edit_spec) + verbose_logger.info( + "compact_20260112: request has compaction trigger (input_tokens threshold=%s)", + trigger_tokens, + ) + if edit_spec.get("pause_after_compaction"): + warnings.append("pause_after_compaction_ignored") + + applied: AppliedEdit = {"type": COMPACT_EDIT_TYPE} + if warnings: + applied["warnings"] = warnings + + # Phase A: slice around any existing compaction block. Runs before the + # opt-in gate below so that even when summarization is disabled we still + # strip Anthropic-only ``compaction`` blocks from messages going to + # non-Anthropic backends (which would reject them). + effective_messages, prior_compaction_block = _slice_around_compaction_block( + messages + ) + prior_summary_text = ( + prior_compaction_block.get("content") if prior_compaction_block else None + ) + augmented_system: Union[str, List[Dict[str, Any]], None] = system + if isinstance(prior_summary_text, str) and prior_summary_text: + augmented_system = _augment_system_with_summary(system, prior_summary_text) + verbose_logger.info( + "compact_20260112: compaction summary added to main call system prefix (%s chars)", + len(prior_summary_text), + ) + + downstream_messages = _strip_compaction_blocks(effective_messages) + + # Opt-in gate: no summary model configured → no-op (but still return the + # Phase A-sliced/stripped messages so compaction blocks don't leak). + summary_model = _read_summary_model_setting() + if summary_model is None: + applied["error"] = "summary_model_not_configured" + # Slice-only forwarding: ``augmented_system`` already carries any prior + # compaction summary, and the post-compaction tail in + # ``downstream_messages`` is recent context the summary does not cover, + # so forward it unchanged. Only fall back to the last user question when + # the strip leaves nothing for the downstream call to answer. + if not downstream_messages: + downstream_messages = _select_last_user_question(effective_messages) + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + # Phase B: threshold check. + try: + current_tokens = _count_effective_tokens( + model=model, + effective_messages=effective_messages, + # ``augmented_system`` already carries the prior compaction summary + # (prepended via ``_augment_system_with_summary``); pass ``None`` + # here so we don't double-count the summary text. + compaction_block=None, + tools=tools, + system=augmented_system, + ) + except Exception as e: + verbose_logger.warning( + "compact_20260112: token_counter failed; assuming under threshold: %s", e + ) + current_tokens = 0 + + verbose_logger.debug( + "compact_20260112: current_tokens=%s trigger=%s", current_tokens, trigger_tokens + ) + + if current_tokens <= trigger_tokens: + # Slice-only path: the prior compaction summary already lives in + # ``augmented_system``. Post-compaction turns are recent context the + # summary does not cover, so forward ``downstream_messages`` (the + # post-compaction tail with compaction blocks stripped) unchanged. + # Only fall back to the last user question when the strip leaves + # nothing for the downstream call to answer. + if not downstream_messages: + downstream_messages = _select_last_user_question(effective_messages) + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + # Phase C: summarize. ``augmented_system`` carries any prior compaction + # summary so multi-round compaction does not lose accumulated history — + # ``effective_messages`` only contains turns since the last compaction. + if not await _check_summary_model_access( + user_api_key_auth=user_api_key_auth, + summary_model=summary_model, + llm_router=llm_router, + ): + verbose_logger.warning( + "compact_20260112: caller not authorized for summary_model=%s; " + "skipping summary call", + summary_model, + ) + applied["error"] = "summary_model_access_denied" + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + if not await _check_summary_model_budget( + user_api_key_auth=user_api_key_auth, + summary_model=summary_model, + ): + verbose_logger.warning( + "compact_20260112: caller over model budget for summary_model=%s; " + "skipping summary call", + summary_model, + ) + applied["error"] = "summary_model_budget_exceeded" + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + if not await _check_summary_model_rate_limit( + user_api_key_auth=user_api_key_auth, + summary_model=summary_model, + ): + verbose_logger.warning( + "compact_20260112: caller over rate limit for summary_model=%s; " + "skipping summary call", + summary_model, + ) + applied["error"] = "summary_model_rate_limit_exceeded" + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + prompt = _build_summary_prompt(edit_spec, tools) + summary_messages = _build_summary_messages( + effective_messages, prompt, system=augmented_system + ) + propagated_metadata = _propagate_metadata(litellm_metadata) + allowed_model_region = getattr(user_api_key_auth, "allowed_model_region", None) + + try: + response = await _call_summary_model( + summary_model=summary_model, + summary_messages=summary_messages, + metadata=propagated_metadata, + llm_router=llm_router, + allowed_model_region=allowed_model_region, + max_tokens=_read_summary_max_tokens_setting(), + ) + except Exception as e: + verbose_logger.warning("compact_20260112: summary call failed: %s", e) + applied["error"] = "summary_call_failed" + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + summary_text = _extract_summary_text(_extract_response_text(response)) + if summary_text is None: + applied["error"] = "summary_extraction_failed" + return PolyfillResult( + messages=downstream_messages, + system=augmented_system, + applied_edits=[applied], + ) + + summary_input_tokens, summary_output_tokens = _extract_usage(response) + applied["summary_input_tokens"] = summary_input_tokens + applied["summary_output_tokens"] = summary_output_tokens + + compaction_block: CompactionBlock = { + "type": "compaction", + "content": summary_text, + } + iterations_usage: List[UsageIteration] = [ + { + "type": "compaction", + "input_tokens": summary_input_tokens, + "output_tokens": summary_output_tokens, + } + ] + + # Per Anthropic's contract, everything before the compaction block is + # dropped. Phase D: the user/assistant log goes empty; the summary lives + # on the system message instead. Anthropic requires a non-empty messages + # array, so keep the most recent original user *question* turn so the + # model has something to answer. Skip ``tool_result``-only user turns: + # in Anthropic's format those are role=user but represent the response + # from a tool, and surfacing one as the sole downstream message would + # produce an orphaned ``tool``-role message on non-Anthropic providers + # with no matching ``tool_calls`` in the prior assistant history. If no + # eligible turn exists, fall back to a synthetic continuation prompt so + # the downstream call still has a non-empty user message. + summarized_system = _augment_system_with_summary(system, summary_text) + verbose_logger.info( + "compact_20260112: compaction summary added to main call system prefix (%s chars)", + len(summary_text), + ) + downstream_messages_after_summary = _select_last_user_question(effective_messages) + + return PolyfillResult( + messages=downstream_messages_after_summary, + system=summarized_system, + applied_edits=[applied], + compaction_block=compaction_block, + iterations_usage=iterations_usage, + ) diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/errors.py b/litellm/llms/anthropic/experimental_pass_through/context_management/errors.py new file mode 100644 index 00000000000..1b14089a451 --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/errors.py @@ -0,0 +1,14 @@ +"""Exceptions raised by the context_management polyfill.""" + + +class AnthropicContextManagementError(Exception): + """Validation error from the polyfill, surfaced as an Anthropic-format 4xx. + + The `/v1/messages` endpoint catches this in its exception handler and + emits an Anthropic-shaped error body instead of the default OpenAI shape. + """ + + def __init__(self, *, status_code: int, message: str) -> None: + super().__init__(message) + self.status_code = status_code + self.message = message diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/placeholders.py b/litellm/llms/anthropic/experimental_pass_through/context_management/placeholders.py new file mode 100644 index 00000000000..f684d970df4 --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/placeholders.py @@ -0,0 +1,14 @@ +"""Placeholder content for cleared ``tool_result`` blocks (string or block list).""" + +from typing import Any, List, Union + +from .constants import CLEARED_TOOL_RESULT_PLACEHOLDER + + +def build_cleared_tool_result_content( + original_content: Any, +) -> Union[str, List[dict]]: + """Return a string or single text block list, matching ``original_content`` shape.""" + if isinstance(original_content, list): + return [{"type": "text", "text": CLEARED_TOOL_RESULT_PLACEHOLDER}] + return CLEARED_TOOL_RESULT_PLACEHOLDER diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/result.py b/litellm/llms/anthropic/experimental_pass_through/context_management/result.py new file mode 100644 index 00000000000..36bcde98d0c --- /dev/null +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/result.py @@ -0,0 +1,53 @@ +"""``PolyfillResult`` — the shape returned by the context-management dispatcher. + +Threaded from the dispatcher through ``async_anthropic_messages_handler`` into +the adapter so it can prepend the ``compaction`` block to the response and +attach ``iterations`` to ``usage``. +""" + +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional, Union + +from litellm.types.llms.anthropic import ( + AppliedEdit, + CompactionBlock, + UsageIteration, +) + +from .constants import COMPACT_EDIT_TYPE + + +@dataclass +class PolyfillResult: + messages: List[Dict[str, Any]] + system: Optional[Union[str, List[Dict[str, Any]]]] + applied_edits: List[AppliedEdit] = field(default_factory=list) + compaction_block: Optional[CompactionBlock] = None + iterations_usage: Optional[List[UsageIteration]] = None + + def applied_edits_for_response(self) -> Optional[List[AppliedEdit]]: + """``applied_edits`` to attach on the client-visible response. + + ``compact_20260112`` is included when a new compaction block was + synthesized (success), when the edit carries an ``error`` field + (``summary_model_not_configured``, ``summary_call_failed``, + ``summary_extraction_failed``), or when the edit carries + ``warnings`` (e.g. ``unsupported_trigger_type_X_using_input_tokens``, + ``pause_after_compaction_ignored``) — operators and clients need to + see why compaction was requested but not applied as expected. + Slice-only / under-threshold paths that produced no edit at all + (no block, no error, no warnings) are omitted. Other edit types are + included when the editor returned an ``AppliedEdit``. + """ + visible: List[AppliedEdit] = [] + for edit in self.applied_edits: + if edit.get("type") == COMPACT_EDIT_TYPE: + if ( + self.compaction_block is not None + or edit.get("error") + or edit.get("warnings") + ): + visible.append(edit) + else: + visible.append(edit) + return visible or None diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py index 009ba6ef306..62eced8e6f0 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py @@ -8,7 +8,17 @@ import asyncio import contextvars from functools import partial -from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union, cast +from typing import ( + Any, + AsyncIterator, + Coroutine, + Dict, + Iterator, + List, + Optional, + Union, + cast, +) import litellm from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj @@ -189,7 +199,7 @@ async def anthropic_messages( client: Optional[AsyncHTTPHandler] = None, custom_llm_provider: Optional[str] = None, **kwargs, -) -> Union[AnthropicMessagesResponse, AsyncIterator]: +) -> Union[AnthropicMessagesResponse, Iterator[bytes], AsyncIterator[Any]]: """ Async: Make llm api request in Anthropic /messages API spec. @@ -293,6 +303,12 @@ async def anthropic_messages( api_base=api_base, client=client, custom_llm_provider=custom_llm_provider, + # messages were already empty-text-block sanitized at the top of this + # function and are NOT reassigned before this dispatch, so the handler + # can skip its (otherwise redundant) second full-messages scan. Passed + # explicitly (not via **kwargs) so it only affects this direct + # dispatch -- interceptor / sync entry points still sanitize. + _litellm_messages_presanitized=True, **kwargs, ) ctx = contextvars.copy_context() @@ -340,8 +356,11 @@ def anthropic_messages_handler( **kwargs, ) -> Union[ AnthropicMessagesResponse, + Iterator[bytes], AsyncIterator[Any], - Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], + Coroutine[ + Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any], Iterator[bytes]] + ], ]: """ Makes Anthropic `/v1/messages` API calls In the Anthropic API Spec @@ -351,10 +370,14 @@ def anthropic_messages_handler( """ from litellm.types.utils import LlmProviders - # Sanitize empty text blocks here too so the sync entry point + # Sanitize empty text blocks so the sync entry point # (litellm.messages.create -> anthropic_messages_handler) gets the same - # protection as the async wrapper. Idempotent when called twice. - messages = strip_empty_text_blocks_from_anthropic_messages(messages) + # protection as the async wrapper. The async wrapper already sanitized and + # does not reassign messages before dispatch, so it sets + # ``_litellm_messages_presanitized`` to skip this redundant second + # full-messages scan. Pop it so it never leaks into provider params. + if not kwargs.pop("_litellm_messages_presanitized", False): + messages = strip_empty_text_blocks_from_anthropic_messages(messages) metadata = validate_anthropic_api_metadata(metadata) @@ -446,9 +469,14 @@ def anthropic_messages_handler( return LiteLLMMessagesToResponsesAPIHandler.anthropic_messages_handler( **_shared_kwargs ) + + # The in-gateway context_management polyfill runs inside + # ``async_anthropic_messages_handler`` so it can ``await`` the + # summarization model for ``compact_20260112``. ``context_management`` + # is passed through as a regular kwarg. return ( LiteLLMMessagesToCompletionTransformationHandler.anthropic_messages_handler( - **_shared_kwargs + **_shared_kwargs, ) ) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py index 35495d59610..3a2c09f2183 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py @@ -230,6 +230,8 @@ def _translate_legacy_thinking_for_adaptive_model( """Translate legacy ``thinking.type=enabled`` to adaptive for 4.6/4.7. Caller-provided ``output_config.effort`` is never overridden. """ + from litellm.llms.anthropic.chat.transformation import AnthropicConfig + if not AnthropicModelInfo._is_adaptive_thinking_model(model): return thinking = optional_params.get("thinking") @@ -237,7 +239,7 @@ def _translate_legacy_thinking_for_adaptive_model( return budget = int(thinking.get("budget_tokens") or 0) - if budget >= 24000: + if budget >= 24000 and AnthropicConfig._supports_effort_level(model, "xhigh"): effort = "xhigh" elif budget >= 10000: effort = "high" @@ -312,7 +314,10 @@ def transform_anthropic_messages_request( ) ####### get required params for all anthropic messages requests ###### - verbose_logger.debug(f"TRANSFORMATION DEBUG - Messages: {messages}") + # Lazy %s: the f-string previously stringified the entire messages + # payload on every request regardless of log level (a full scan of the + # request body on the hot path). Defer it to when DEBUG is enabled. + verbose_logger.debug("TRANSFORMATION DEBUG - Messages: %s", messages) # Auto-strip advisor blocks from history if advisor tool is absent. # Prevents Anthropic 400: advisor_tool_result in history requires advisor tool. @@ -424,8 +429,13 @@ def _update_headers_with_anthropic_beta( ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_MANAGEMENT_2025_06_27.value ) - # Check for structured outputs - if optional_params.get("output_format") is not None: + # Check for structured outputs. Anthropic's newer request shape nests + # the schema under output_config.format; the older top-level + # output_format remains supported for backwards compatibility. + output_config = optional_params.get("output_config") + if optional_params.get("output_format") is not None or ( + isinstance(output_config, dict) and output_config.get("format") is not None + ): beta_values.add( ANTHROPIC_BETA_HEADER_VALUES.STRUCTURED_OUTPUT_2025_09_25.value ) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/utils.py b/litellm/llms/anthropic/experimental_pass_through/messages/utils.py index fa951ebd2e5..88832fb3f63 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/utils.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/utils.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, cast, get_type_hints +from functools import lru_cache +from typing import Any, Dict, FrozenSet, List, cast, get_type_hints from litellm.types.llms.anthropic import AnthropicMessagesRequestOptionalParams from litellm.types.llms.anthropic_messages.anthropic_response import ( @@ -6,6 +7,18 @@ ) +@lru_cache(maxsize=1) +def _anthropic_messages_optional_param_keys() -> FrozenSet[str]: + """ + Valid AnthropicMessagesRequestOptionalParams keys. + + ``typing.get_type_hints`` is ~80us/call and this TypedDict is static, so + resolving it once per process instead of once per request removes a fixed + full-pass cost from the /v1/messages request-parse path. + """ + return frozenset(get_type_hints(AnthropicMessagesRequestOptionalParams).keys()) + + class AnthropicMessagesRequestUtils: @staticmethod def get_requested_anthropic_messages_optional_param( @@ -20,7 +33,7 @@ def get_requested_anthropic_messages_optional_param( Returns: AnthropicMessagesRequestOptionalParams instance with only the valid parameters """ - valid_keys = get_type_hints(AnthropicMessagesRequestOptionalParams).keys() + valid_keys = _anthropic_messages_optional_param_keys() filtered_params = { k: v for k, v in params.items() if k in valid_keys and v is not None } diff --git a/litellm/llms/azure/audio_transcription/__init__.py b/litellm/llms/azure/audio_transcription/__init__.py new file mode 100644 index 00000000000..cedd0c6dbeb --- /dev/null +++ b/litellm/llms/azure/audio_transcription/__init__.py @@ -0,0 +1,3 @@ +from .transformation import AzureSpeechAudioTranscriptionConfig + +__all__ = ["AzureSpeechAudioTranscriptionConfig"] diff --git a/litellm/llms/azure/audio_transcription/transformation.py b/litellm/llms/azure/audio_transcription/transformation.py new file mode 100644 index 00000000000..e478c8ebf35 --- /dev/null +++ b/litellm/llms/azure/audio_transcription/transformation.py @@ -0,0 +1,224 @@ +""" +Azure AI Speech (Cognitive Services) speech-to-text transformation. + +Maps OpenAI-compatible audio transcription calls to Azure Speech REST +recognition for short audio. +""" + +from typing import Any, Dict, List, Optional, Union +from urllib.parse import urlencode, urlparse + +import httpx + +from litellm.litellm_core_utils.audio_utils.utils import process_audio_file +from litellm.llms.base_llm.audio_transcription.transformation import ( + AudioTranscriptionRequestData, + BaseAudioTranscriptionConfig, +) +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from litellm.types.llms.openai import ( + AllMessageValues, + OpenAIAudioTranscriptionOptionalParams, +) +from litellm.secret_managers.main import get_secret_str +from litellm.types.utils import FileTypes, TranscriptionResponse + + +class AzureSpeechAudioTranscriptionException(BaseLLMException): + pass + + +class AzureSpeechAudioTranscriptionConfig(BaseAudioTranscriptionConfig): + """ + Configuration for Azure AI Speech (Cognitive Services) STT. + + Reference: + https://learn.microsoft.com/en-us/azure/ai-services/speech-service/rest-speech-to-text-short + """ + + COGNITIVE_SERVICES_DOMAIN = "api.cognitive.microsoft.com" + STT_SPEECH_DOMAIN = "stt.speech.microsoft.com" + STT_ENDPOINT_PATH = "/speech/recognition/conversation/cognitiveservices/v1" + DEFAULT_LANGUAGE = "en-US" + + def get_supported_openai_params( + self, model: str + ) -> List[OpenAIAudioTranscriptionOptionalParams]: + return ["language", "response_format"] + + def map_openai_params( + self, + non_default_params: dict, + optional_params: dict, + model: str, + drop_params: bool, + ) -> dict: + supported_params = self.get_supported_openai_params(model=model) + for key, value in non_default_params.items(): + if key in supported_params: + optional_params[key] = value + return optional_params + + def validate_environment( + self, + headers: dict, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + api_key: Optional[str] = None, + api_base: Optional[str] = None, + ) -> dict: + api_key = api_key or get_secret_str("AZURE_SPEECH_API_KEY") + if not api_key: + raise AzureSpeechAudioTranscriptionException( + message="api_key is required for Azure AI Speech transcription.", + status_code=401, + ) + + validated_headers = headers.copy() + validated_headers["Ocp-Apim-Subscription-Key"] = api_key + validated_headers["Content-Type"] = validated_headers.get( + "Content-Type", "audio/wav" + ) + validated_headers["Accept"] = "application/json" + return validated_headers + + def get_complete_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: dict, + litellm_params: dict, + stream: Optional[bool] = None, + ) -> str: + api_base = api_base or get_secret_str("AZURE_SPEECH_API_BASE") + if api_base is None: + raise AzureSpeechAudioTranscriptionException( + message=( + "api_base is required for Azure AI Speech transcription. " + "Use a Cognitive Services endpoint like " + "https://{region}.api.cognitive.microsoft.com or an STT " + "endpoint like https://{region}.stt.speech.microsoft.com." + ), + status_code=400, + ) + + base_url = self._resolve_stt_base_url(api_base=api_base) + query_params = { + "language": optional_params.get("language", self.DEFAULT_LANGUAGE), + "format": self._get_azure_response_format( + optional_params.get("response_format") + ), + } + return f"{base_url}{self.STT_ENDPOINT_PATH}?{urlencode(query_params)}" + + def transform_audio_transcription_request( + self, + model: str, + audio_file: FileTypes, + optional_params: dict, + litellm_params: dict, + ) -> AudioTranscriptionRequestData: + processed_audio = process_audio_file(audio_file) + return AudioTranscriptionRequestData( + data=processed_audio.file_content, + files=None, + content_type=processed_audio.content_type, + ) + + def transform_audio_transcription_response( + self, + raw_response: httpx.Response, + ) -> TranscriptionResponse: + response_json = raw_response.json() + recognition_status = response_json.get("RecognitionStatus") + if recognition_status is not None and recognition_status != "Success": + raise AzureSpeechAudioTranscriptionException( + message=( + "Azure AI Speech transcription failed with " + f"RecognitionStatus={recognition_status}." + ), + status_code=raw_response.status_code, + headers=raw_response.headers, + ) + + text = self._extract_text(response_json) + response = TranscriptionResponse(text=text) + response._hidden_params = response_json + return response + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] + ) -> BaseLLMException: + return AzureSpeechAudioTranscriptionException( + message=error_message, + status_code=status_code, + headers=headers, + ) + + def _resolve_stt_base_url(self, api_base: str) -> str: + api_base = api_base.rstrip("/") + parsed_url = urlparse(api_base) + hostname = parsed_url.hostname or "" + + if self._is_cognitive_services_endpoint(hostname=hostname): + region = self._extract_region_from_hostname( + hostname=hostname, domain=self.COGNITIVE_SERVICES_DOMAIN + ) + return self._build_stt_base_url(region=region) + + if self._is_stt_endpoint(hostname=hostname): + return f"{parsed_url.scheme}://{hostname}" + + if self._is_azure_openai_endpoint(hostname=hostname): + raise AzureSpeechAudioTranscriptionException( + message=( + "Azure AI Speech transcription requires a Cognitive Services " + "or STT Speech endpoint, not an Azure OpenAI endpoint." + ), + status_code=400, + ) + + return api_base + + def _is_cognitive_services_endpoint(self, hostname: str) -> bool: + return hostname == self.COGNITIVE_SERVICES_DOMAIN or hostname.endswith( + f".{self.COGNITIVE_SERVICES_DOMAIN}" + ) + + def _is_stt_endpoint(self, hostname: str) -> bool: + return hostname == self.STT_SPEECH_DOMAIN or hostname.endswith( + f".{self.STT_SPEECH_DOMAIN}" + ) + + def _is_azure_openai_endpoint(self, hostname: str) -> bool: + return hostname.endswith(".openai.azure.com") + + def _extract_region_from_hostname(self, hostname: str, domain: str) -> str: + if hostname.endswith(f".{domain}"): + return hostname[: -len(f".{domain}")] + return "" + + def _build_stt_base_url(self, region: str) -> str: + if region: + return f"https://{region}.{self.STT_SPEECH_DOMAIN}" + return f"https://{self.STT_SPEECH_DOMAIN}" + + def _get_azure_response_format(self, response_format: Optional[str]) -> str: + if response_format == "verbose_json": + return "detailed" + return "simple" + + def _extract_text(self, response_json: Dict[str, Any]) -> str: + if isinstance(response_json.get("DisplayText"), str): + return response_json["DisplayText"] + + nbest = response_json.get("NBest") + if isinstance(nbest, list) and nbest: + best = nbest[0] + if isinstance(best, dict): + return best.get("Display") or best.get("Lexical") or "" + + return "" diff --git a/litellm/llms/azure/common_utils.py b/litellm/llms/azure/common_utils.py index 4fc1ae960b8..e1ac1858912 100644 --- a/litellm/llms/azure/common_utils.py +++ b/litellm/llms/azure/common_utils.py @@ -1,3 +1,5 @@ +import asyncio +import hashlib import json import os from typing import Any, Callable, Dict, Literal, NamedTuple, Optional, Union, cast @@ -449,6 +451,25 @@ def get_azure_openai_client( ] = None client_initialization_params: dict = locals() client_initialization_params["is_async"] = _is_async + _lp = litellm_params or {} + _ad_provider = _lp.get("azure_ad_token_provider") + _ad_token = _lp.get("azure_ad_token") + _client_secret = _lp.get("client_secret") + _azure_password = _lp.get("azure_password") + client_initialization_params["azure_ad_token"] = ( + hashlib.sha256(_ad_token.encode()).hexdigest() + if isinstance(_ad_token, str) + else None + ) + client_initialization_params["azure_ad_token_provider"] = ( + f"provider_id={id(_ad_provider) if callable(_ad_provider) else None}" + f"|tenant_id={_lp.get('tenant_id')}" + f"|client_id={_lp.get('client_id')}" + f"|client_secret={hashlib.sha256(_client_secret.encode()).hexdigest() if isinstance(_client_secret, str) else None}" + f"|azure_username={_lp.get('azure_username')}" + f"|azure_password={hashlib.sha256(_azure_password.encode()).hexdigest() if isinstance(_azure_password, str) else None}" + f"|azure_scope={_lp.get('azure_scope')}" + ) if client is None: cached_client = self.get_cached_openai_client( client_initialization_params=client_initialization_params, @@ -474,8 +495,29 @@ def get_azure_openai_client( if self._is_azure_v1_api_version(api_version): # Extract only params that OpenAI client accepts # Always use /openai/v1/ regardless of whether user passed "v1", "latest", or "preview" - v1_params = { - "api_key": azure_client_params.get("api_key"), + # The OpenAI client accepts a callable for `api_key` and re-invokes it + # on every request (via `_refresh_api_key`), so passing + # `azure_ad_token_provider` directly preserves Azure AD token refresh + # behavior that the regular AzureOpenAI client provides. + v1_api_key: Optional[Union[str, Callable[[], Any]]] = ( + azure_client_params.get("api_key") + or azure_client_params.get("azure_ad_token_provider") + or azure_client_params.get("azure_ad_token") + ) + if _is_async is True and callable(v1_api_key): + # AsyncOpenAI expects an async provider; wrap the sync provider + # returned by azure-identity. Offload to a thread so a token + # refresh (blocking HTTP call to AAD on cache miss) does not + # stall the event loop. + _sync_provider = v1_api_key + + async def _async_v1_api_key() -> str: + return await asyncio.to_thread(_sync_provider) + + v1_api_key = _async_v1_api_key + + v1_params: Dict[str, Any] = { + "api_key": v1_api_key, "base_url": f"{api_base}/openai/v1/", } if "timeout" in azure_client_params: diff --git a/litellm/llms/base_llm/chat/transformation.py b/litellm/llms/base_llm/chat/transformation.py index bec25916c4b..5f35a58ce1f 100644 --- a/litellm/llms/base_llm/chat/transformation.py +++ b/litellm/llms/base_llm/chat/transformation.py @@ -108,10 +108,9 @@ def get_json_schema_from_pydantic_object( return type_to_response_format_param(response_format=response_format) def is_thinking_enabled(self, non_default_params: dict) -> bool: - return ( - non_default_params.get("thinking", {}).get("type") == "enabled" - or non_default_params.get("reasoning_effort") is not None - ) + return (non_default_params.get("thinking") or {}).get( + "type" + ) == "enabled" or non_default_params.get("reasoning_effort") is not None def is_max_tokens_in_request(self, non_default_params: dict) -> bool: """ diff --git a/litellm/llms/base_llm/managed_resources/__init__.py b/litellm/llms/base_llm/managed_resources/__init__.py index 5eb9b46f89f..a5543e631c0 100644 --- a/litellm/llms/base_llm/managed_resources/__init__.py +++ b/litellm/llms/base_llm/managed_resources/__init__.py @@ -24,10 +24,12 @@ generate_unified_id_string, is_base64_encoded_unified_id, parse_unified_id, + resolve_passthrough_managed_id_provider, ) __all__ = [ "BaseManagedResource", + "resolve_passthrough_managed_id_provider", "is_base64_encoded_unified_id", "extract_target_model_names_from_unified_id", "extract_resource_type_from_unified_id", diff --git a/litellm/llms/base_llm/managed_resources/utils.py b/litellm/llms/base_llm/managed_resources/utils.py index 59f5ff0d845..e9a6aef689e 100644 --- a/litellm/llms/base_llm/managed_resources/utils.py +++ b/litellm/llms/base_llm/managed_resources/utils.py @@ -7,7 +7,40 @@ import base64 import re -from typing import List, Optional, Union, Literal +from typing import Any, List, Literal, Optional, Union + +PASSTHROUGH_MANAGED_ID_AZURE_PROVIDERS = ("azure", "azure_ai") + + +def resolve_passthrough_managed_id_provider( + custom_llm_provider: Any, +) -> Optional[str]: + """Map a pass-through ``custom_llm_provider`` to the provider scope that + namespaces passthrough managed object IDs, or ``None`` when the route is not + an OpenAI/Azure pass-through and managed IDs must not apply. + + Scoping is keyed on the explicit provider that the pass-through route + forwards (``openai``, ``azure``, ``azure_ai``), not on the upstream URL, so + a third-party OpenAI-compatible endpoint never triggers managed-ID minting. + + ``azure`` and ``azure_ai`` deliberately collapse to one ``"azure"`` scope: + they expose the same Azure OpenAI files/batches surface, so an ID minted + while routing as one must still resolve while routing as the other. + Splitting them would make a managed ID minted on ``azure`` fail to resolve + when replayed on ``azure_ai`` and vice versa. + """ + provider = str( + getattr(custom_llm_provider, "value", custom_llm_provider) or "" + ).lower() + if not provider: + return None + if provider in PASSTHROUGH_MANAGED_ID_AZURE_PROVIDERS or provider.endswith( + (".azure", ".azure_ai") + ): + return "azure" + if provider == "openai" or provider.endswith(".openai"): + return "openai" + return None def is_base64_encoded_unified_id( @@ -177,8 +210,14 @@ def extract_model_id_from_unified_id( if decoded_id: unified_id = decoded_id - # Extract model ID - match = re.search(r"model_id,([^;]+)", unified_id) + # Extract model ID. Anchor to a field boundary (start of string or + # after `;`) so this regex doesn't substring-match the `model_id,` + # inside file_id encodings' `llm_output_file_model_id,` + # field — that would feed the deployment UUID as a model candidate + # into the team-access check and 403 every team-BYOK file attach + # with `Tried to access ` (LIT-3244 patch/1.86.0 second-order + # finding). + match = re.search(r"(?:^|;)model_id,([^;]+)", unified_id) if match: return match.group(1).strip() diff --git a/litellm/llms/base_llm/realtime/transformation.py b/litellm/llms/base_llm/realtime/transformation.py index d5531a532b9..0f239b4ad45 100644 --- a/litellm/llms/base_llm/realtime/transformation.py +++ b/litellm/llms/base_llm/realtime/transformation.py @@ -3,6 +3,7 @@ import httpx +from litellm.types.llms.openai import OpenAIRealtimeStreamSessionEvents from litellm.types.realtime import ( RealtimeResponseTransformInput, RealtimeResponseTypedDict, @@ -69,6 +70,20 @@ def session_configuration_request( ) -> Optional[str]: # message sent to setup the realtime session return None + def transform_session_created_event( + self, + model: str, + logging_session_id: str, + session_configuration_request: Optional[str] = None, + ) -> Optional[Union[dict, OpenAIRealtimeStreamSessionEvents]]: + """ + Optional hook for providers that defer session setup until client `session.update`. + + Return an OpenAI-compatible `session.created` payload when the proxy should + emit a synthetic event immediately after backend websocket connection. + """ + return None + @abstractmethod def transform_realtime_response( self, diff --git a/litellm/llms/base_llm/videos/transformation.py b/litellm/llms/base_llm/videos/transformation.py index 87289ad6a0c..9b4cf777280 100644 --- a/litellm/llms/base_llm/videos/transformation.py +++ b/litellm/llms/base_llm/videos/transformation.py @@ -321,6 +321,23 @@ def transform_video_get_character_response( "video get character is not supported for this provider" ) + def get_video_edit_prefetch_params( + self, + video_id: str, + api_base: str, + litellm_params: GenericLiteLLMParams, + headers: dict, + ) -> Optional[Tuple[str, Dict]]: + """ + Return (url, body) for a pre-fetch HTTP call that must be made before + transform_video_edit_request, or None if no pre-fetch is required. + + Providers that need to retrieve the source video before constructing the + edit request (e.g. Vertex AI) should override this method. The handler + uses the existing shared httpx client so the call is properly async. + """ + return None + def transform_video_edit_request( self, prompt: str, @@ -329,6 +346,7 @@ def transform_video_edit_request( litellm_params: GenericLiteLLMParams, headers: dict, extra_body: Optional[Dict[str, Any]] = None, + prefetched_source_data: Optional[Dict[str, Any]] = None, ) -> Tuple[str, Dict]: """ Transform the video edit request into a URL and JSON data. @@ -343,6 +361,7 @@ def transform_video_edit_response( raw_response: httpx.Response, logging_obj: LiteLLMLoggingObj, custom_llm_provider: Optional[str] = None, + request_data: Optional[Dict] = None, ) -> VideoObject: raise NotImplementedError("video edit is not supported for this provider") diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index efc890d9ee2..90dfa13e938 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -30,6 +30,7 @@ BedrockConverseMessagesProcessor, _bedrock_converse_messages_pt, _bedrock_tools_pt, + make_valid_bedrock_tool_name, ) from litellm.llms.anthropic.chat.transformation import ( DROP_UNSUPPORTED_OUTPUT_CONFIG_WARNING, @@ -40,6 +41,7 @@ from litellm.types.llms.bedrock import * from litellm.types.llms.openai import ( AllMessageValues, + ChatCompletionAnnotation, ChatCompletionAssistantMessage, ChatCompletionRedactedThinkingBlock, ChatCompletionResponseMessage, @@ -77,6 +79,7 @@ get_anthropic_beta_from_headers, get_bedrock_tool_name, is_claude_4_5_on_bedrock, + normalize_bedrock_opus_output_config_effort, ) # Computer use tool prefixes supported by Bedrock @@ -447,10 +450,20 @@ def _handle_reasoning_effort_parameter( value=reasoning_effort, llm_provider="bedrock_converse", ) + existing_output_config = optional_params.get("output_config") + if not isinstance(existing_output_config, dict): + existing_output_config = {} + existing_output_config.setdefault("effort", mapped_effort) + normalize_bedrock_opus_output_config_effort( + model=model, + output_config=existing_output_config, + ) + mapped_effort = existing_output_config["effort"] self._validate_anthropic_adaptive_effort( model=model, effort=mapped_effort ) - optional_params["output_config"] = {"effort": mapped_effort} + optional_params["output_config"] = existing_output_config + optional_params["_output_config_normalized"] = True @staticmethod def _validate_anthropic_adaptive_effort(model: str, effort: str) -> None: @@ -573,6 +586,9 @@ def get_supported_openai_params(self, model: str) -> List[str]: ): supported_params.append("thinking") supported_params.append("reasoning_effort") + + if base_model.startswith("anthropic"): + supported_params.append("context_management") return supported_params def map_tool_choice_values( @@ -595,7 +611,9 @@ def map_tool_choice_values( elif isinstance(tool_choice, dict): # only supported for anthropic + mistral models - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html specific_tool = SpecificToolChoiceBlock( - name=tool_choice.get("function", {}).get("name", "") + name=make_valid_bedrock_tool_name( + tool_choice.get("function", {}).get("name", "") + ) ) return ToolChoiceValuesBlock(tool=specific_tool) else: @@ -932,10 +950,10 @@ def map_openai_params( self._handle_reasoning_effort_parameter( model=model, reasoning_effort=value, optional_params=optional_params ) + elif param == "context_management" and isinstance(value, (dict, list)): + self._map_context_management_param(value, optional_params) if param == "requestMetadata": - if value is not None and isinstance(value, dict): - self._validate_request_metadata(value) # type: ignore - optional_params["requestMetadata"] = value + self._map_request_metadata_param(value, optional_params) if param == "service_tier" and isinstance(value, str): self._map_service_tier_param(value, optional_params) @@ -968,6 +986,32 @@ def map_openai_params( return optional_params + def _map_request_metadata_param(self, value: Any, optional_params: dict) -> None: + if value is not None and isinstance(value, dict): + self._validate_request_metadata(value) # type: ignore + optional_params["requestMetadata"] = value + + def _map_context_management_param( + self, value: Union[dict, list], optional_params: dict + ) -> None: + # Match the dispatcher's ``_normalize_spec`` behavior: only run the + # OpenAI→Anthropic mapper for list inputs. Dict inputs are already in + # Anthropic-native shape (``{"edits": [...]}``) and should pass + # through unchanged so an Anthropic-format ``context_management`` + # value isn't silently dropped when the mapper can't classify it. + if isinstance(value, list): + mapped = AnthropicConfig.map_openai_context_management_to_anthropic( + cast(Union[dict, list], value) + ) + else: + mapped = value + # Skip when the mapper returned None for malformed input — leaving the + # key out is safer than passing `context_management: null` downstream, + # which Bedrock would reject and which can confuse intermediate checks + # before the final _filter_context_management_for_bedrock_converse step. + if mapped is not None: + optional_params["context_management"] = mapped + def _map_service_tier_param(self, value: str, optional_params: dict) -> None: """Map OpenAI service_tier (string) to Bedrock serviceTier (object). @@ -1198,6 +1242,12 @@ def _prepare_request_params( self, optional_params: dict, model: str ) -> Tuple[dict, dict, dict, Optional[OutputConfigBlock]]: """Prepare and separate request parameters.""" + # Consume the internal ``_output_config_normalized`` marker set by + # ``_handle_reasoning_effort_parameter`` so it does not linger on the + # caller's ``optional_params`` after the transformation returns. + anthropic_output_config_already_normalized = bool( + optional_params.pop("_output_config_normalized", False) + ) # Filter out exception objects before deepcopy to prevent deepcopy failures # Exceptions should not be stored in optional_params (this is a defensive fix) cleaned_params = filter_exceptions_from_params(optional_params) @@ -1216,8 +1266,17 @@ def _prepare_request_params( # Anthropic-only ``output_config`` (snake_case) — re-attached to # ``additionalModelRequestFields`` for Anthropic models below. The - # Bedrock-native ``outputConfig`` (camelCase) is handled separately. + # structured-output ``format`` subfield is consumed into Bedrock's + # native ``outputConfig`` (camelCase), which is handled separately. anthropic_output_config = inference_params.pop("output_config", None) + output_config_format = None + if isinstance(anthropic_output_config, dict): + anthropic_output_config = dict(anthropic_output_config) + candidate_output_config_format = anthropic_output_config.pop("format", None) + if isinstance(candidate_output_config_format, dict): + output_config_format = candidate_output_config_format + if not anthropic_output_config: + anthropic_output_config = None # Extract requestMetadata before processing other parameters request_metadata = inference_params.pop("requestMetadata", None) @@ -1227,6 +1286,30 @@ def _prepare_request_params( output_config: Optional[OutputConfigBlock] = inference_params.pop( "outputConfig", None ) + base_model = BedrockModelInfo.get_base_model(model) + if ( + output_config is None + and output_config_format is not None + and output_config_format.get("type") == "json_schema" + and base_model.startswith("anthropic") + and self._supports_native_structured_outputs( + model, self.custom_llm_provider + ) + ): + output_config = self._create_output_config_for_response_format( + json_schema=output_config_format.get("schema"), + name=output_config_format.get("name"), + description=output_config_format.get("description"), + ) + elif output_config is None and output_config_format is not None: + litellm.verbose_logger.warning( + "Bedrock Converse: dropping `output_config.format` for model=%s — " + "model does not advertise `supports_native_structured_output` in " + "model_prices_and_context_window.json. The schema will not be " + "enforced; pass `response_format` to use the synthetic tool-call " + "fallback.", + model, + ) # keep supported params in 'inference_params', and set all model-specific params in 'additional_request_params' additional_request_params = { @@ -1272,7 +1355,6 @@ def _prepare_request_params( if anthropic_output_config is not None and isinstance( anthropic_output_config, dict ): - base_model = BedrockModelInfo.get_base_model(model) if base_model.startswith("anthropic"): if ( litellm.drop_params is True @@ -1283,6 +1365,11 @@ def _prepare_request_params( model, ) else: + if not anthropic_output_config_already_normalized: + normalize_bedrock_opus_output_config_effort( + model=model, + output_config=anthropic_output_config, + ) effort = anthropic_output_config.get("effort") if effort is not None: self._validate_anthropic_adaptive_effort( @@ -1430,6 +1517,11 @@ def _process_tools_and_beta( if ANTHROPIC_EFFORT_BETA_HEADER not in anthropic_beta_list: anthropic_beta_list.append(ANTHROPIC_EFFORT_BETA_HEADER) + # Bedrock Converse: compact_20260112 edits only (+ beta header). + AmazonConverseConfig._filter_context_management_for_bedrock_converse( + additional_request_params, anthropic_beta_list + ) + # Set anthropic_beta in additional_request_params if we have any beta features # ONLY apply to Anthropic/Claude models - other models (e.g., Qwen, Llama) don't support this field if anthropic_beta_list and base_model.startswith("anthropic"): @@ -1437,6 +1529,42 @@ def _process_tools_and_beta( return bedrock_tools, anthropic_beta_list + @staticmethod + def _filter_context_management_for_bedrock_converse( + additional_request_params: dict, + anthropic_beta_list: list, + ) -> None: + """Keep only compact_20260112 edits for Bedrock; add beta header or drop field.""" + from litellm.llms.anthropic.experimental_pass_through.context_management.constants import ( + COMPACT_EDIT_TYPE, + ) + from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES + + cm = additional_request_params.get("context_management") + if not isinstance(cm, dict): + additional_request_params.pop("context_management", None) + return + edits = cm.get("edits") + if not isinstance(edits, list): + additional_request_params.pop("context_management", None) + return + + compact_edits = [ + e + for e in edits + if isinstance(e, dict) and e.get("type") == COMPACT_EDIT_TYPE + ] + if compact_edits: + compact_beta = ANTHROPIC_BETA_HEADER_VALUES.COMPACT_2026_01_12.value + if compact_beta not in anthropic_beta_list: + anthropic_beta_list.append(compact_beta) + additional_request_params["context_management"] = { + **cm, + "edits": compact_edits, + } + else: + additional_request_params.pop("context_management", None) + def _transform_request_helper( self, model: str, @@ -1887,6 +2015,75 @@ def _translate_message_content(self, content_blocks: List[ContentBlock]) -> Tupl return content_str, tools, reasoningContentBlocks, citationsContentBlocks + @staticmethod + def _transform_citations_to_annotations( + citations_content_blocks: Optional[List[CitationsContentBlock]], + ) -> Tuple[Optional[str], Optional[List[ChatCompletionAnnotation]]]: + """ + Convert Bedrock citationsContent blocks into OpenAI-style annotations. + + Returns: + citations_text: concatenated text from citationsContent.content + annotations: OpenAI URL citation annotations + """ + if not citations_content_blocks: + return None, None + + annotations: List[ChatCompletionAnnotation] = [] + citations_text_parts: List[str] = [] + content_offset = 0 + + for citations_block in citations_content_blocks: + block_text = "" + raw_content = citations_block.get("content") + if isinstance(raw_content, list): + for content_part in raw_content: + if isinstance(content_part, dict): + _text = content_part.get("text") + if isinstance(_text, str): + block_text += _text + + block_offset = content_offset + if block_text: + citations_text_parts.append(block_text) + content_offset += len(block_text) + + raw_citations = citations_block.get("citations") + if not isinstance(raw_citations, list): + continue + + for citation in raw_citations: + if not isinstance(citation, dict): + continue + + location = citation.get("location") + if not isinstance(location, dict): + continue + + search_location = location.get("searchResultLocation") + if not isinstance(search_location, dict): + continue + + start = search_location.get("start") + end = search_location.get("end") + if not isinstance(start, int) or not isinstance(end, int): + continue + + annotations.append( + ChatCompletionAnnotation( + type="url_citation", + url_citation={ + "start_index": block_offset + start, + "end_index": block_offset + end, + "title": str(citation.get("title") or ""), + "url": str(citation.get("source") or ""), + }, + ) + ) + + citations_text = "".join(citations_text_parts) if citations_text_parts else None + return citations_text, annotations or None + @staticmethod def _unwrap_bedrock_properties(json_str: str) -> str: """ @@ -2069,6 +2266,24 @@ def _transform_response( # noqa: PLR0915 provider_specific_fields ) + citations_text, annotations = self._transform_citations_to_annotations( + citationsContentBlocks + ) + citations_included_in_content = False + if citations_text: + stripped_content = content_str.strip() + if not stripped_content: + content_str = citations_text + citations_included_in_content = True + elif not any(char.isalnum() for char in stripped_content): + # Bedrock may emit the cited sentence in citationsContent and only + # punctuation in the text blocks; stitch citations_text in front so + # its annotation span indices stay aligned with the final content. + content_str = citations_text + content_str + citations_included_in_content = True + if annotations and citations_included_in_content: + chat_completion_message["annotations"] = annotations + if reasoningContentBlocks is not None: chat_completion_message["reasoning_content"] = ( self._transform_reasoning_content(reasoningContentBlocks) diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py index d9599b8b9c4..a13336b6c88 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -16,8 +16,11 @@ AmazonInvokeConfig, ) from litellm.llms.bedrock.common_utils import ( + convert_bedrock_invoke_output_format_to_inline_schema, get_anthropic_beta_from_headers, + normalize_bedrock_opus_output_config_effort, normalize_tool_input_schema_types_for_bedrock_invoke, + pop_bedrock_invoke_output_config_format, remove_custom_field_from_tools, ) from litellm.types.llms.anthropic import ANTHROPIC_TOOL_SEARCH_BETA_HEADER @@ -75,6 +78,17 @@ def map_openai_params( # Use a model name that forces tool-based approach model = "claude-3-sonnet-20240229" + # Clamp ``reasoning_effort`` to the Bedrock effort ceiling before the + # parent mapping converts it to ``output_config.effort`` and the + # downstream effort gate runs. Mirrors the converse path's + # ``_handle_reasoning_effort_parameter`` and the messages path's + # ``_clamp_adaptive_reasoning_effort_for_bedrock`` so adaptive Claude + # requests degrade ``xhigh`` -> ``max`` rather than 400-ing on + # models like Opus 4.6 that don't natively advertise xhigh. + self._clamp_adaptive_reasoning_effort_for_bedrock( + model=original_model, params=non_default_params + ) + optional_params = AnthropicConfig.map_openai_params( self, non_default_params, @@ -88,6 +102,27 @@ def map_openai_params( return optional_params + @staticmethod + def _clamp_adaptive_reasoning_effort_for_bedrock(model: str, params: dict) -> None: + """Lower ``reasoning_effort`` to the Bedrock effort ceiling before mapping. + + Bedrock's adaptive Claude models accept the OpenAI-style + ``reasoning_effort`` tier, but the request validator can reject tiers + the model does not natively advertise (e.g. ``xhigh`` on Opus 4.6). + Clamp the raw tier to the model's + ``bedrock_output_config_effort_ceiling`` so Claude Code "goal mode" + keeps working. Non-adaptive models and models without a ceiling are + left untouched. + """ + if not AnthropicConfig._is_adaptive_thinking_model(model): + return + effort = params.get("reasoning_effort") + if not isinstance(effort, str): + return + clamped = {"effort": effort} + normalize_bedrock_opus_output_config_effort(model=model, output_config=clamped) + params["reasoning_effort"] = clamped["effort"] + def transform_request( self, model: str, @@ -157,6 +192,13 @@ def _build_bedrock_anthropic_request_base( for k, v in optional_params.items() if k not in self.aws_authentication_params } + output_config = filtered_params.get("output_config") + if isinstance(output_config, dict): + filtered_params["output_config"] = dict(output_config) + normalize_bedrock_opus_output_config_effort( + model=model, + output_config=filtered_params["output_config"], + ) filtered_params = self._normalize_bedrock_tool_search_tools(filtered_params) anthropic_request = AnthropicConfig.transform_request( @@ -170,7 +212,20 @@ def _build_bedrock_anthropic_request_base( anthropic_request.pop("model", None) anthropic_request.pop("stream", None) - anthropic_request.pop("output_format", None) + output_format = anthropic_request.pop("output_format", None) + output_config_format = pop_bedrock_invoke_output_config_format( + anthropic_request + ) + if output_format: + convert_bedrock_invoke_output_format_to_inline_schema( + output_format=output_format, + request_body=anthropic_request, + ) + elif output_config_format: + convert_bedrock_invoke_output_format_to_inline_schema( + output_format=output_config_format, + request_body=anthropic_request, + ) if not ( _supports_factory( model=model, diff --git a/litellm/llms/bedrock/common_utils.py b/litellm/llms/bedrock/common_utils.py index 4f4729e4019..bdc5da321c6 100644 --- a/litellm/llms/bedrock/common_utils.py +++ b/litellm/llms/bedrock/common_utils.py @@ -34,6 +34,15 @@ class BedrockError(BaseLLMException): # Lazy import cache to avoid circular imports and performance impact _get_model_info = None +BedrockOutputConfigEffort = Literal["low", "medium", "high", "max", "xhigh"] +_BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER: Dict[BedrockOutputConfigEffort, int] = { + "low": 0, + "medium": 1, + "high": 2, + "max": 3, + "xhigh": 4, +} + def get_cached_model_info(): """ @@ -51,6 +60,79 @@ def get_cached_model_info(): return _get_model_info +@functools.lru_cache(maxsize=1) +def _get_local_model_cost_map() -> Dict: + from litellm.litellm_core_utils.get_model_cost_map import GetModelCostMap + + return GetModelCostMap.load_local_model_cost_map() + + +def pop_bedrock_invoke_output_config_format(request_body: Dict) -> Optional[Dict]: + """ + Remove and return Anthropic's nested ``output_config.format`` field. + + Bedrock Invoke paths convert the schema to inline message text. Any remaining + ``output_config`` keys, such as ``effort``, are left in place. + """ + output_config = request_body.get("output_config") + if not isinstance(output_config, dict): + return None + + output_format = output_config.pop("format", None) + if not output_config: + request_body.pop("output_config", None) + + if isinstance(output_format, dict): + return output_format + return None + + +def convert_bedrock_invoke_output_format_to_inline_schema( + output_format: Dict, + request_body: Dict, +) -> None: + """ + Embed an Anthropic structured-output schema into the last user message. + + Bedrock Invoke does not support ``output_format`` directly, so the schema is + appended to the final user message for prompt-engineered structured output. + The caller's ``messages`` list, message dict, and content list are not + mutated; a fresh ``messages`` list with a copied final user message is + written back to ``request_body``. + """ + schema = output_format.get("schema") + if not schema: + return + + messages = request_body.get("messages") + if not isinstance(messages, list) or not messages: + return + + last_user_idx = None + for i in range(len(messages) - 1, -1, -1): + message = messages[i] + if isinstance(message, dict) and message.get("role") == "user": + last_user_idx = i + break + + if last_user_idx is None: + return + + original = messages[last_user_idx] + content = original.get("content", []) + schema_block = {"type": "text", "text": json.dumps(schema)} + if isinstance(content, str): + new_content = [{"type": "text", "text": content}, schema_block] + elif isinstance(content, list): + new_content = [*content, schema_block] + else: + return + + new_messages = list(messages) + new_messages[last_user_idx] = {**original, "content": new_content} + request_body["messages"] = new_messages + + def remove_custom_field_from_tools(request_body: dict) -> None: """ Remove ``custom`` field from each tool in the request body. @@ -603,6 +685,62 @@ def is_claude_4_5_on_bedrock(model: str) -> bool: return any(pattern in model_lower for pattern in claude_4_5_patterns) +def normalize_bedrock_opus_output_config_effort(model: str, output_config: Any) -> None: + """ + Normalize Anthropic ``output_config.effort`` values for Bedrock Opus ids. + + Bedrock's Claude Opus request validator can accept a narrower effort + vocabulary than Anthropic's compatibility surface. The Bedrock ceiling is + read from ``model_prices_and_context_window.json`` via + ``bedrock_output_config_effort_ceiling``. + + Mutates ``output_config`` in place so callers can accept Claude Code's + ``xhigh`` input without forwarding a provider-invalid value. + """ + if not isinstance(output_config, dict): + return + + effort = output_config.get("effort") + if effort not in _BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER: + return + + ceiling = _get_bedrock_output_config_effort_ceiling(model) + if ceiling is None: + return + + if ( + _BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER[effort] + > _BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER[ceiling] + ): + output_config["effort"] = ceiling + + +def _get_bedrock_output_config_effort_ceiling( + model: str, +) -> Optional[BedrockOutputConfigEffort]: + try: + model_info = get_cached_model_info()( + model=model, + custom_llm_provider="bedrock", + ) + except Exception: + return None + + ceiling = model_info.get("bedrock_output_config_effort_ceiling") + if isinstance(ceiling, str) and ceiling in _BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER: + return ceiling # type: ignore[return-value] + + model_cost_key = model_info.get("key") + if not isinstance(model_cost_key, str): + return None + + local_model_info = _get_local_model_cost_map().get(model_cost_key, {}) + ceiling = local_model_info.get("bedrock_output_config_effort_ceiling") + if isinstance(ceiling, str) and ceiling in _BEDROCK_OUTPUT_CONFIG_EFFORT_ORDER: + return ceiling # type: ignore[return-value] + return None + + # Import after standalone functions to avoid circular imports from litellm.llms.bedrock.count_tokens.bedrock_token_counter import BedrockTokenCounter diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index 69b61298d33..42c3bd517a9 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -32,13 +32,19 @@ AmazonInvokeConfig, ) from litellm.llms.bedrock.common_utils import ( + convert_bedrock_invoke_output_format_to_inline_schema, ensure_bedrock_anthropic_messages_tool_names, get_anthropic_beta_from_headers, is_claude_4_5_on_bedrock, + normalize_bedrock_opus_output_config_effort, normalize_tool_input_schema_types_for_bedrock_invoke, + pop_bedrock_invoke_output_config_format, remove_custom_field_from_tools, ) -from litellm.types.llms.anthropic import ANTHROPIC_TOOL_SEARCH_BETA_HEADER +from litellm.types.llms.anthropic import ( + ANTHROPIC_BETA_HEADER_VALUES, + ANTHROPIC_TOOL_SEARCH_BETA_HEADER, +) from litellm.types.llms.bedrock import BedrockInvokeAnthropicMessagesRequest from litellm.types.llms.openai import AllMessageValues from litellm.types.router import GenericLiteLLMParams @@ -442,7 +448,7 @@ def _filter_context_management_for_bedrock_invoke( if isinstance(e, dict) and e.get("type") == "compact_20260112" ] if compact_edits: - beta_set.add("compact-2026-01-12") + beta_set.add(ANTHROPIC_BETA_HEADER_VALUES.COMPACT_2026_01_12.value) anthropic_messages_request["context_management"] = { **cm, "edits": compact_edits, @@ -450,59 +456,113 @@ def _filter_context_management_for_bedrock_invoke( else: anthropic_messages_request.pop("context_management", None) - def _convert_output_format_to_inline_schema( + def _get_bedrock_invoke_anthropic_beta_headers( self, - output_format: Dict, + model: str, + messages: List[Dict], + anthropic_messages_optional_request_params: Dict, + headers: dict, anthropic_messages_request: Dict, - ) -> None: - """ - Convert Anthropic output_format to inline schema in message content. - - Bedrock Invoke doesn't support the output_format parameter, so we embed - the schema directly into the user message content as text instructions. + injected_thinking_for_clear_thinking: bool, + ) -> List[str]: + anthropic_model_info = AnthropicModelInfo() + tools = anthropic_messages_optional_request_params.get("tools") + messages_typed = cast(List[AllMessageValues], messages) + tool_search_used = anthropic_model_info.is_tool_search_used(tools) + programmatic_tool_calling_used = ( + anthropic_model_info.is_programmatic_tool_calling_used(tools) + ) + input_examples_used = anthropic_model_info.is_input_examples_used(tools) - This approach adds the schema to the last user message, instructing the model - to respond in the specified JSON format. + user_beta_set = set(get_anthropic_beta_from_headers(headers)) + beta_set = set(user_beta_set) + auto_betas = anthropic_model_info.get_anthropic_beta_list( + model=model, + optional_params=anthropic_messages_optional_request_params, + computer_tool_used=anthropic_model_info.is_computer_tool_used(tools), + prompt_caching_set=False, + file_id_used=anthropic_model_info.is_file_id_used(messages_typed), + mcp_server_used=anthropic_model_info.is_mcp_server_used( + anthropic_messages_optional_request_params.get("mcp_servers") + ), + ) + beta_set.update(auto_betas) - Args: - output_format: The output_format dict with 'type' and 'schema' - anthropic_messages_request: The request dict to modify in-place + if injected_thinking_for_clear_thinking: + beta_set.add("interleaved-thinking-2025-05-14") - Ref: https://aws.amazon.com/blogs/machine-learning/structured-data-response-with-amazon-bedrock-prompt-engineering-and-tool-use/ - """ - import json + self._filter_context_management_for_bedrock_invoke( + anthropic_messages_request=anthropic_messages_request, + beta_set=beta_set, + ) - # Extract schema from output_format - schema = output_format.get("schema") - if not schema: - return + self._get_tool_search_beta_header_for_bedrock( + model=model, + tool_search_used=tool_search_used, + programmatic_tool_calling_used=programmatic_tool_calling_used, + input_examples_used=input_examples_used, + beta_set=beta_set, + ) - # Get messages from the request - messages = anthropic_messages_request.get("messages", []) - if not messages: - return + if "tool-search-tool-2025-10-19" in beta_set: + beta_set.add("tool-examples-2025-10-29") - # Find the last user message - last_user_message_idx = None - for idx in range(len(messages) - 1, -1, -1): - if messages[idx].get("role") == "user": - last_user_message_idx = idx - break + filtered_betas = sorted( + filter_and_transform_beta_headers( + beta_headers=list(beta_set), + provider="bedrock", + ) + ) - if last_user_message_idx is None: - return + dropped_user_betas = sorted( + b + for b in user_beta_set + if not filter_and_transform_beta_headers([b], provider="bedrock") + ) + if dropped_user_betas: + verbose_logger.warning( + "Bedrock Invoke: dropping unsupported anthropic-beta values " + "from client headers: %s. Bedrock has no mapping entry for " + "these; forwarding them would cause a 400.", + dropped_user_betas, + ) - last_user_message = messages[last_user_message_idx] - content = last_user_message.get("content", []) + return filtered_betas - # Ensure content is a list - if isinstance(content, str): - content = [{"type": "text", "text": content}] - last_user_message["content"] = content + def _strip_unsupported_bedrock_invoke_fields( + self, + anthropic_messages_request: Dict, + ) -> Dict: + allowed = self.BEDROCK_INVOKE_ALLOWED_TOP_LEVEL_FIELDS + stripped = sorted(k for k in anthropic_messages_request if k not in allowed) + if stripped: + verbose_logger.debug( + "Bedrock Invoke: stripping unsupported top-level request fields: %s", + stripped, + ) + return {k: v for k, v in anthropic_messages_request.items() if k in allowed} - # Add schema as text content to the message - schema_text = {"type": "text", "text": json.dumps(schema)} - content.append(schema_text) + @staticmethod + def _clamp_adaptive_reasoning_effort_for_bedrock( + model: str, optional_params: Dict + ) -> None: + """Lower ``reasoning_effort`` to the Bedrock effort ceiling before validation. + + The shared ``/v1/messages`` effort gate rejects tiers a model does not + natively support (e.g. ``xhigh`` on Opus 4.6). Bedrock's chat paths instead + clamp the tier to the model's ``bedrock_output_config_effort_ceiling`` so + Claude Code "goal mode" keeps working; mirror that here so the messages + path degrades ``xhigh`` -> ``max`` rather than 400-ing. Non-adaptive models + and models without a ceiling are left untouched. + """ + if not AnthropicModelInfo._is_adaptive_thinking_model(model): + return + effort = optional_params.get("reasoning_effort") + if not isinstance(effort, str): + return + clamped = {"effort": effort} + normalize_bedrock_opus_output_config_effort(model=model, output_config=clamped) + optional_params["reasoning_effort"] = clamped["effort"] def transform_anthropic_messages_request( self, @@ -512,6 +572,10 @@ def transform_anthropic_messages_request( litellm_params: GenericLiteLLMParams, headers: dict, ) -> Dict: + self._clamp_adaptive_reasoning_effort_for_bedrock( + model=model, + optional_params=anthropic_messages_optional_request_params, + ) anthropic_messages_request = AnthropicMessagesConfig.transform_anthropic_messages_request( self=self, model=model, @@ -550,13 +614,32 @@ def transform_anthropic_messages_request( anthropic_messages_request=anthropic_messages_request, model=model ) - # 5. Convert `output_format` to inline schema (Bedrock invoke doesn't support output_format) + # 5. Convert structured-output params to inline schema. + # Bedrock Invoke doesn't support top-level `output_format`; its + # accepted `output_config` subset is also narrower than Anthropic's, so + # consume the newer `output_config.format` shape here instead of + # forwarding it as an unknown nested key. + existing_output_config = anthropic_messages_request.get("output_config") + if isinstance(existing_output_config, dict): + anthropic_messages_request["output_config"] = dict(existing_output_config) output_format = anthropic_messages_request.pop("output_format", None) + output_config_format = pop_bedrock_invoke_output_config_format( + anthropic_messages_request + ) if output_format: - self._convert_output_format_to_inline_schema( + convert_bedrock_invoke_output_format_to_inline_schema( output_format=output_format, - anthropic_messages_request=anthropic_messages_request, + request_body=anthropic_messages_request, + ) + elif output_config_format: + convert_bedrock_invoke_output_format_to_inline_schema( + output_format=output_config_format, + request_body=anthropic_messages_request, ) + normalize_bedrock_opus_output_config_effort( + model=model, + output_config=anthropic_messages_request.get("output_config"), + ) # 5a. Bedrock Invoke supports output_config (effort) for Claude 4.6+ models, # but older models do not — strip it to avoid request rejection. @@ -589,68 +672,15 @@ def transform_anthropic_messages_request( ensure_bedrock_anthropic_messages_tool_names(anthropic_messages_request) # 6. AUTO-INJECT beta headers based on features used - anthropic_model_info = AnthropicModelInfo() - tools = anthropic_messages_optional_request_params.get("tools") - messages_typed = cast(List[AllMessageValues], messages) - tool_search_used = anthropic_model_info.is_tool_search_used(tools) - programmatic_tool_calling_used = ( - anthropic_model_info.is_programmatic_tool_calling_used(tools) - ) - input_examples_used = anthropic_model_info.is_input_examples_used(tools) - - user_beta_set = set(get_anthropic_beta_from_headers(headers)) - beta_set = set(user_beta_set) - auto_betas = anthropic_model_info.get_anthropic_beta_list( + filtered_betas = self._get_bedrock_invoke_anthropic_beta_headers( model=model, - optional_params=anthropic_messages_optional_request_params, - computer_tool_used=anthropic_model_info.is_computer_tool_used(tools), - prompt_caching_set=False, - file_id_used=anthropic_model_info.is_file_id_used(messages_typed), - mcp_server_used=anthropic_model_info.is_mcp_server_used( - anthropic_messages_optional_request_params.get("mcp_servers") - ), - ) - beta_set.update(auto_betas) - - if injected_thinking_for_clear_thinking: - beta_set.add("interleaved-thinking-2025-05-14") - - self._filter_context_management_for_bedrock_invoke( + messages=messages, + anthropic_messages_optional_request_params=anthropic_messages_optional_request_params, + headers=headers, anthropic_messages_request=anthropic_messages_request, - beta_set=beta_set, + injected_thinking_for_clear_thinking=injected_thinking_for_clear_thinking, ) - self._get_tool_search_beta_header_for_bedrock( - model=model, - tool_search_used=tool_search_used, - programmatic_tool_calling_used=programmatic_tool_calling_used, - input_examples_used=input_examples_used, - beta_set=beta_set, - ) - - if "tool-search-tool-2025-10-19" in beta_set: - beta_set.add("tool-examples-2025-10-29") - - filtered_betas = sorted( - filter_and_transform_beta_headers( - beta_headers=list(beta_set), - provider="bedrock", - ) - ) - - dropped_user_betas = sorted( - b - for b in user_beta_set - if not filter_and_transform_beta_headers([b], provider="bedrock") - ) - if dropped_user_betas: - verbose_logger.warning( - "Bedrock Invoke: dropping unsupported anthropic-beta values " - "from client headers: %s. Bedrock has no mapping entry for " - "these; forwarding them would cause a 400.", - dropped_user_betas, - ) - if filtered_betas: anthropic_messages_request["anthropic_beta"] = filtered_betas @@ -669,16 +699,9 @@ def transform_anthropic_messages_request( # Catches Anthropic-only extensions (output_config, speed, mcp_servers, ...) # and any future additions Claude Code may start sending. ``context_management`` # has already been pre-filtered to its Bedrock-supported subset above. - allowed = self.BEDROCK_INVOKE_ALLOWED_TOP_LEVEL_FIELDS - stripped = sorted(k for k in anthropic_messages_request if k not in allowed) - if stripped: - verbose_logger.debug( - "Bedrock Invoke: stripping unsupported top-level request fields: %s", - stripped, - ) - anthropic_messages_request = { - k: v for k, v in anthropic_messages_request.items() if k in allowed - } + anthropic_messages_request = self._strip_unsupported_bedrock_invoke_fields( + anthropic_messages_request + ) return anthropic_messages_request diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 96fdf4494f9..941fe59e825 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -890,6 +890,18 @@ def embedding( headers=headers, ) + # Some providers (e.g. OCI) require request signing after the body is built. + # The default BaseConfig.sign_request returns (headers, None) — a no-op for + # providers that don't need signing. + headers, signed_body = provider_config.sign_request( + headers=headers, + optional_params=optional_params, + request_data=data, + api_base=api_base, + api_key=api_key, + model=model, + ) + ## LOGGING logging_obj.pre_call( input=input, @@ -916,6 +928,7 @@ def embedding( client=client, optional_params=optional_params, litellm_params=litellm_params, + signed_body=signed_body, ) if client is None or not isinstance(client, HTTPHandler): @@ -926,12 +939,20 @@ def embedding( sync_httpx_client = client try: - response = sync_httpx_client.post( - url=api_base, - headers=headers, - data=json.dumps(data), - timeout=timeout, - ) + if signed_body is not None: + response = sync_httpx_client.post( + url=api_base, + headers=headers, + data=signed_body, + timeout=timeout, + ) + else: + response = sync_httpx_client.post( + url=api_base, + headers=headers, + data=json.dumps(data), + timeout=timeout, + ) except Exception as e: raise self._handle_error( e=e, @@ -964,6 +985,7 @@ async def aembedding( api_key: Optional[str] = None, timeout: Optional[Union[float, httpx.Timeout]] = None, client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None, + signed_body: Optional[bytes] = None, ) -> EmbeddingResponse: if client is None or not isinstance(client, AsyncHTTPHandler): async_httpx_client = get_async_httpx_client( @@ -974,12 +996,20 @@ async def aembedding( async_httpx_client = client try: - response = await async_httpx_client.post( - url=api_base, - headers=headers, - json=request_data, - timeout=timeout, - ) + if signed_body is not None: + response = await async_httpx_client.post( + url=api_base, + headers=headers, + data=signed_body, + timeout=timeout, + ) + else: + response = await async_httpx_client.post( + url=api_base, + headers=headers, + json=request_data, + timeout=timeout, + ) except Exception as e: raise self._handle_error(e=e, provider_config=provider_config) @@ -1177,6 +1207,8 @@ def _prepare_audio_transcription_request( data = transformed_result.data files = transformed_result.files + if transformed_result.content_type is not None: + headers["Content-Type"] = transformed_result.content_type ## LOGGING logging_obj.pre_call( @@ -1856,7 +1888,9 @@ async def _async_post_anthropic_messages_with_http_error_retry( async_httpx_client: AsyncHTTPHandler, request_url: str, headers: dict, - signed_json_body: Optional[bytes], + # str when the caller passes a pre-serialized (unsigned) body to avoid + # re-dumping; bytes when a provider signed the request (e.g. Bedrock). + signed_json_body: Optional[Union[str, bytes]], request_body: dict, stream: bool, logging_obj: LiteLLMLoggingObj, @@ -2047,8 +2081,18 @@ async def async_anthropic_messages_handler( model=model, ) + # The request body was serialized once for the pre-call log input and + # again for the wire (json.dumps is O(payload), large for long-context + # Claude Code history). Serialize once and reuse for both. Only when + # the provider didn't sign the request (sign_request no-op for the + # native anthropic path -> signed_json_body is None); signed providers + # (e.g. Bedrock) keep their signed body untouched. The HTTP-error + # retry path mutates + re-signs the body, so it still re-serializes + # internally -- this only deduplicates the success path. + request_body_json = json.dumps(request_body) + logging_obj.pre_call( - input=[{"role": "user", "content": json.dumps(request_body)}], + input=[{"role": "user", "content": request_body_json}], api_key="", additional_args={ "complete_input_dict": request_body, @@ -2061,7 +2105,9 @@ async def async_anthropic_messages_handler( async_httpx_client=async_httpx_client, request_url=request_url, headers=headers, - signed_json_body=signed_json_body, + signed_json_body=( + signed_json_body if signed_json_body is not None else request_body_json + ), request_body=request_body, stream=stream or False, logging_obj=logging_obj, @@ -2083,6 +2129,14 @@ async def async_anthropic_messages_handler( litellm_logging_obj=logging_obj, ) + if not self._has_agentic_completion_hook(logging_obj): + # No callback overrides async_should_run_agentic_loop, so the + # agentic wrapper's only effect would be buffering every chunk + # and rebuilding the response from SSE at end-of-stream to call + # hooks that all return (False, {}). Stream through directly and + # skip that per-chunk + end-of-stream overhead. + return completion_stream + from litellm.llms.anthropic.experimental_pass_through.messages.agentic_streaming_iterator import ( AgenticAnthropicStreamingIterator, ) @@ -4590,6 +4644,51 @@ def _get_agentic_loop_settings(kwargs: Dict) -> Tuple[int, int, List[str]]: fingerprints = list(kwargs.get("_agentic_loop_fingerprints", []) or []) return depth, max(max_loops, 1), fingerprints + @staticmethod + def _has_agentic_completion_hook(logging_obj: Any) -> bool: + """ + True if any registered callback actually overrides + ``async_should_run_agentic_loop`` (the gate every agentic hook goes + through). The base ``CustomLogger`` implementation returns + ``(False, {})``, so when nothing overrides it the agentic + post-processing is a guaranteed no-op and the streaming wrapper that + buffers + rebuilds the whole response from SSE just to call it can be + skipped entirely. + + Function-identity comparison (not a leaf ``__dict__`` check) so an + override inherited through any intermediate class is still detected -- + a false negative here would silently disable agentic features. + + String entries in ``litellm.callbacks`` (e.g. ``"datadog"``) are + resolved to their ``CustomLogger`` instance via + ``get_custom_logger_compatible_class`` -- same pattern as + ``ProxyLogging._callback_capabilities`` -- so a string-registered + agentic callback is detected too. + """ + from litellm.integrations.custom_logger import CustomLogger + from litellm.litellm_core_utils.litellm_logging import ( + get_custom_logger_compatible_class, + ) + + base_func = CustomLogger.async_should_run_agentic_loop + callbacks = litellm.callbacks + ( + getattr(logging_obj, "dynamic_success_callbacks", None) or [] + ) + for cb in callbacks: + if isinstance(cb, str): + resolved = get_custom_logger_compatible_class(cb) # type: ignore[arg-type] + if resolved is None: + continue + cb = resolved + if not isinstance(cb, CustomLogger): + continue + cb_func = getattr(type(cb), "async_should_run_agentic_loop", base_func) + if getattr(cb_func, "__func__", cb_func) is not getattr( + base_func, "__func__", base_func + ): + return True + return False + @staticmethod def _check_agentic_loop_safety( tool_calls: Any, @@ -5217,6 +5316,28 @@ async def async_realtime( ) if _session_config: realtime_streaming.session_configuration_request = _session_config + + # For providers that defer setup until client session.update, optionally + # send synthetic session.created to unblock clients waiting on connect. + if not provider_config.requires_session_configuration(): + synthetic_session = provider_config.transform_session_created_event( + model=model, + logging_session_id=logging_obj.litellm_trace_id, + session_configuration_request=None, + ) + if synthetic_session is not None: + synthetic_session_str = json.dumps(synthetic_session) + # Record before sending so the synthetic session.created is + # captured in the session log alongside provider-driven + # events; without this it would be silently absent from + # success_handler / async_success_handler payloads. + realtime_streaming.store_message(synthetic_session_str) + await websocket.send_text(synthetic_session_str) + realtime_streaming._session_created_sent_to_client = True + verbose_logger.debug( + "Sent synthetic session.created to client to unblock connection" + ) + await realtime_streaming.bidirectional_forward() except websockets.exceptions.InvalidStatusCode as e: # type: ignore @@ -6439,6 +6560,7 @@ def video_remix_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: @@ -6521,6 +6643,7 @@ async def async_video_remix_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: @@ -6613,6 +6736,7 @@ def video_create_character_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6684,6 +6808,7 @@ async def async_video_create_character_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6767,6 +6892,7 @@ def video_get_character_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6824,6 +6950,7 @@ async def async_video_get_character_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6900,6 +7027,7 @@ def video_edit_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6910,27 +7038,49 @@ def video_edit_handler( litellm_params=dict(litellm_params), ) - url, data = video_provider_config.transform_video_edit_request( - prompt=prompt, + prefetched_source_data = None + prefetch_params = video_provider_config.get_video_edit_prefetch_params( video_id=video_id, api_base=api_base, litellm_params=litellm_params, headers=headers, - extra_body=extra_body, - ) - - logging_obj.pre_call( - input=prompt, - api_key="", - additional_args={ - "complete_input_dict": data, - "api_base": url, - "headers": headers, - "video_id": video_id, - }, ) + if prefetch_params is not None: + prefetch_url, prefetch_body = prefetch_params + try: + prefetch_resp = sync_httpx_client.post( + url=prefetch_url, + headers=headers, + json=prefetch_body, + timeout=timeout, + ) + prefetch_resp.raise_for_status() + except Exception as e: + raise self._handle_error(e=e, provider_config=video_provider_config) + prefetched_source_data = prefetch_resp.json() try: + url, data = video_provider_config.transform_video_edit_request( + prompt=prompt, + video_id=video_id, + api_base=api_base, + litellm_params=litellm_params, + headers=headers, + extra_body=extra_body, + prefetched_source_data=prefetched_source_data, + ) + + logging_obj.pre_call( + input=prompt, + api_key="", + additional_args={ + "complete_input_dict": data, + "api_base": url, + "headers": headers, + "video_id": video_id, + }, + ) + response = sync_httpx_client.post( url=url, headers=headers, @@ -6942,6 +7092,7 @@ def video_edit_handler( raw_response=response, logging_obj=logging_obj, custom_llm_provider=custom_llm_provider, + request_data=data, ) except Exception as e: raise self._handle_error(e=e, provider_config=video_provider_config) @@ -6972,6 +7123,7 @@ async def async_video_edit_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -6982,27 +7134,49 @@ async def async_video_edit_handler( litellm_params=dict(litellm_params), ) - url, data = video_provider_config.transform_video_edit_request( - prompt=prompt, + prefetched_source_data = None + prefetch_params = video_provider_config.get_video_edit_prefetch_params( video_id=video_id, api_base=api_base, litellm_params=litellm_params, headers=headers, - extra_body=extra_body, - ) - - logging_obj.pre_call( - input=prompt, - api_key="", - additional_args={ - "complete_input_dict": data, - "api_base": url, - "headers": headers, - "video_id": video_id, - }, ) + if prefetch_params is not None: + prefetch_url, prefetch_body = prefetch_params + try: + prefetch_resp = await async_httpx_client.post( + url=prefetch_url, + headers=headers, + json=prefetch_body, + timeout=timeout, + ) + prefetch_resp.raise_for_status() + except Exception as e: + raise self._handle_error(e=e, provider_config=video_provider_config) + prefetched_source_data = prefetch_resp.json() try: + url, data = video_provider_config.transform_video_edit_request( + prompt=prompt, + video_id=video_id, + api_base=api_base, + litellm_params=litellm_params, + headers=headers, + extra_body=extra_body, + prefetched_source_data=prefetched_source_data, + ) + + logging_obj.pre_call( + input=prompt, + api_key="", + additional_args={ + "complete_input_dict": data, + "api_base": url, + "headers": headers, + "video_id": video_id, + }, + ) + response = await async_httpx_client.post( url=url, headers=headers, @@ -7014,6 +7188,7 @@ async def async_video_edit_handler( raw_response=response, logging_obj=logging_obj, custom_llm_provider=custom_llm_provider, + request_data=data, ) except Exception as e: raise self._handle_error(e=e, provider_config=video_provider_config) @@ -7061,6 +7236,7 @@ def video_extension_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -7135,6 +7311,7 @@ async def async_video_extension_handler( api_key=api_key or litellm_params.get("api_key", None), headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: headers.update(extra_headers) @@ -7346,6 +7523,7 @@ async def async_video_delete_handler( api_key=api_key, headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: diff --git a/litellm/llms/gemini/realtime/transformation.py b/litellm/llms/gemini/realtime/transformation.py index 4378db06358..cf1fc75ef10 100644 --- a/litellm/llms/gemini/realtime/transformation.py +++ b/litellm/llms/gemini/realtime/transformation.py @@ -3,8 +3,10 @@ """ import json +from collections import OrderedDict from typing import Any, Dict, List, Optional, Union, cast +import litellm from litellm import verbose_logger from litellm._uuid import uuid from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj @@ -29,6 +31,7 @@ OpenAIRealtimeDoneEvent, OpenAIRealtimeEvents, OpenAIRealtimeEventTypes, + OpenAIRealtimeFunctionCallArgumentsDone, OpenAIRealtimeOutputItemDone, OpenAIRealtimeResponseAudioDone, OpenAIRealtimeResponseContentPartAdded, @@ -36,10 +39,12 @@ OpenAIRealtimeResponseDoneObject, OpenAIRealtimeResponseTextDone, OpenAIRealtimeStreamResponseBaseObject, + OpenAIRealtimeStreamResponseOutputItem, OpenAIRealtimeStreamResponseOutputItemAdded, OpenAIRealtimeStreamSession, OpenAIRealtimeStreamSessionEvents, OpenAIRealtimeTurnDetection, + ResponsesAPIStreamEvents, ) from litellm.types.llms.vertex_ai import ( GeminiResponseModalities, @@ -56,15 +61,43 @@ from ..common_utils import encode_unserializable_types, get_api_key_from_env -MAP_GEMINI_FIELD_TO_OPENAI_EVENT: Dict[str, OpenAIRealtimeEventTypes] = { +MAP_GEMINI_FIELD_TO_OPENAI_EVENT: Dict[ + str, Union[OpenAIRealtimeEventTypes, ResponsesAPIStreamEvents] +] = { "setupComplete": OpenAIRealtimeEventTypes.SESSION_CREATED, "serverContent.generationComplete": OpenAIRealtimeEventTypes.RESPONSE_TEXT_DONE, "serverContent.turnComplete": OpenAIRealtimeEventTypes.RESPONSE_DONE, "serverContent.interrupted": OpenAIRealtimeEventTypes.RESPONSE_DONE, + "toolCall": ResponsesAPIStreamEvents.FUNCTION_CALL_ARGUMENTS_DONE, +} + +# Top-level keys in a Gemini realtime message that map_openai_event knows how +# to handle. Other keys (e.g. ``usageMetadata``) can appear alongside these as +# siblings and must be skipped by the main transform loop — otherwise +# map_openai_event raises ``ValueError`` and the WebSocket session terminates. +_KNOWN_GEMINI_TOP_LEVEL_KEYS: set = { + map_key.split(".", 1)[0] for map_key in MAP_GEMINI_FIELD_TO_OPENAI_EVENT } class GeminiRealtimeConfig(BaseRealtimeConfig): + # Cap the LRU of in-flight tool calls so long sessions with many tool + # calls don't grow the dict without bound. Sized large enough to cover + # bursts of pending tool responses; the oldest entry is evicted when a + # new call beyond the cap arrives. + _TOOL_CALL_ID_TO_NAME_MAX = 256 + + def __init__(self): + super().__init__() + # Store call_id → function_name mapping for tool call round-trip + self._tool_call_id_to_name: "OrderedDict[str, str]" = OrderedDict() + # Buffer ``usageMetadata`` that Gemini Live emits as a standalone + # frame (between turns) so the next ``response.done`` attributes the + # tokens consumed. Without this an authenticated client can drive + # tool-call or normal turns whose token usage is recorded as zero, + # bypassing spend and budget accounting. + self._pending_usage_metadata: Optional[dict] = None + def validate_environment( self, headers: dict, model: str, api_key: Optional[str] = None ) -> dict: @@ -190,10 +223,9 @@ def map_openai_params( ) vertex_gemini_config = VertexGeminiConfig() - optional_params["generationConfig"]["tools"] = ( - vertex_gemini_config._map_function( - value=value, optional_params=optional_params - ) + # Tools should be at the top level of setup, not inside generationConfig + optional_params["tools"] = vertex_gemini_config._map_function( + value=value, optional_params=optional_params ) elif key == "input_audio_transcription" and value is not None: optional_params["inputAudioTranscription"] = {} @@ -214,6 +246,272 @@ def map_openai_params( optional_params.pop("generationConfig") return optional_params + @staticmethod + def _extract_turn_detection(session: dict) -> Optional[dict]: + """Extract turn_detection from a session.update payload. + + Handles both the flat beta shape (``session.turn_detection``) and the + GA shape (``session.audio.input.turn_detection``). + """ + if not isinstance(session, dict): + return None + td = session.get("turn_detection") + if isinstance(td, dict): + return td + audio = session.get("audio") + if isinstance(audio, dict): + input_cfg = audio.get("input") + if isinstance(input_cfg, dict): + td = input_cfg.get("turn_detection") + if isinstance(td, dict): + return td + return None + + @staticmethod + def _normalize_session_payload_for_mapping(session: dict) -> dict: + """Normalize GA-remapped session fields back to their beta keys. + + ``map_openai_params`` only recognises the flat OpenAI-beta key names + (``modalities``, ``input_audio_transcription``, ``turn_detection``). + For GA clients the upstream shim renames these into the nested GA + schema (``output_modalities``, ``audio.input.transcription``, + ``audio.input.turn_detection``), which would otherwise be silently + dropped here. Surface them back at the top level so the existing + mapping logic picks them up without duplicating provider-specific + knowledge of the GA schema in ``map_openai_params``. + """ + if not isinstance(session, dict): + return session + + normalized = dict(session) + + if "modalities" not in normalized and "output_modalities" in normalized: + normalized["modalities"] = normalized["output_modalities"] + + audio = normalized.get("audio") + if isinstance(audio, dict): + input_cfg = audio.get("input") + if isinstance(input_cfg, dict): + if ( + "input_audio_transcription" not in normalized + and "transcription" in input_cfg + ): + normalized["input_audio_transcription"] = input_cfg["transcription"] + + extracted_turn_detection = GeminiRealtimeConfig._extract_turn_detection( + normalized + ) + if extracted_turn_detection is not None and not isinstance( + normalized.get("turn_detection"), dict + ): + normalized["turn_detection"] = extracted_turn_detection + + return normalized + + def _handle_session_update( + self, + json_message: dict, + model: str, + session_configuration_request: Optional[str], + ) -> List[str]: + """ + Handle session.update by sending setup to Gemini. + + On the FIRST session.update (when session_configuration_request is None), + the full setup with all configuration is sent. + + Subsequent session.update messages are forwarded as a follow-up setup + with the new fields merged into the original setup. Gemini Live treats + a follow-up BidiGenerateContentSetup as a full session replacement + rather than a partial merge, so we carry forward the previous setup + (tools, generationConfig, inputAudioTranscription, systemInstruction, + ...) and overlay the new fields on top. This preserves the old + behavior where clients could refine the session via session.update + (e.g. add tools after the auto-setup on connect), and also keeps the + guardrail-driven turn_detection update working. + """ + session_payload = json_message.get("session") or {} + # Normalize GA-remapped fields (``output_modalities``, + # nested ``audio.input.transcription``, + # ``audio.input.turn_detection``) back to their flat beta keys so + # ``map_openai_params`` picks them up. Without this, GA clients' + # explicit modality / transcription / turn-detection settings + # would be silently dropped because ``map_openai_params`` only + # recognises the flat OpenAI-beta key names. + session_payload = self._normalize_session_payload_for_mapping(session_payload) + new_overrides = self.map_openai_params( + optional_params={}, non_default_params=session_payload + ) + + if session_configuration_request is None: + generation_config = new_overrides.setdefault("generationConfig", {}) + generation_config.setdefault("responseModalities", ["AUDIO"]) + new_overrides.setdefault("inputAudioTranscription", {}) + new_overrides["model"] = f"models/{model}" + verbose_logger.debug( + "Gemini Realtime: Sending initial setup with tools to backend" + ) + return [json.dumps({"setup": new_overrides})] + + if not new_overrides: + verbose_logger.debug( + "Gemini Realtime: Ignoring session.update (no mappable fields)" + ) + return [] + + try: + original_setup = cast( + BidiGenerateContentSetup, + json.loads(session_configuration_request).get("setup", {}), + ) + except (json.JSONDecodeError, AttributeError): + original_setup = {} + + # Deep-merge ``generationConfig`` and ``realtimeInputConfig`` so a + # partial session.update (e.g. only ``temperature`` or only + # ``modalities``) does not silently drop unrelated sub-keys + # (``responseModalities``, ``maxOutputTokens``, ...) from the original + # setup. + follow_up_setup: BidiGenerateContentSetup = { + **original_setup, + **new_overrides, + "model": f"models/{model}", + } + original_generation_config = original_setup.get("generationConfig") + new_generation_config = new_overrides.get("generationConfig") + if isinstance(original_generation_config, dict) and isinstance( + new_generation_config, dict + ): + follow_up_setup["generationConfig"] = { + **original_generation_config, + **new_generation_config, + } + original_realtime_input_config = original_setup.get("realtimeInputConfig") + new_realtime_input_config = new_overrides.get("realtimeInputConfig") + if isinstance(original_realtime_input_config, dict) and isinstance( + new_realtime_input_config, dict + ): + merged_realtime_input_config = { + **original_realtime_input_config, + **new_realtime_input_config, + } + # Deep-merge ``automaticActivityDetection`` so a partial VAD + # update (e.g. the guardrail-injected ``disabled: True`` from + # ``create_response: False``) does not silently drop unrelated + # knobs like ``silenceDurationMs`` / ``prefixPaddingMs`` from + # the original setup. + original_automatic_activity_detection = original_realtime_input_config.get( + "automaticActivityDetection" + ) + new_automatic_activity_detection = new_realtime_input_config.get( + "automaticActivityDetection" + ) + if isinstance(original_automatic_activity_detection, dict) and isinstance( + new_automatic_activity_detection, dict + ): + merged_realtime_input_config["automaticActivityDetection"] = { + **original_automatic_activity_detection, + **new_automatic_activity_detection, + } + follow_up_setup["realtimeInputConfig"] = cast( + BidiGenerateContentRealtimeInputConfig, + merged_realtime_input_config, + ) + verbose_logger.debug( + "Gemini Realtime: Forwarding session.update as follow-up setup" + ) + return [json.dumps({"setup": follow_up_setup})] + + def _handle_conversation_item(self, json_message: dict) -> List[str]: + """ + Handle conversation.item.create for user text or function call output. + + Converts OpenAI format to Gemini's clientContent (for user text) or + toolResponse (for function outputs). + """ + item = json_message.get("item", {}) + item_type = item.get("type") + + # Handle function call output (tool response) + if item_type == "function_call_output": + return self._handle_function_call_output(item) + + # Handle regular text content + return self._handle_user_text_content(item) + + def _handle_function_call_output(self, item: dict) -> List[str]: + """Transform function_call_output to Gemini toolResponse format.""" + call_id = item.get("call_id", "") + output = item.get("output", "{}") + + verbose_logger.debug( + f"Gemini Realtime: Transforming function_call_output for call_id={call_id}" + ) + + # Parse the output to get the result. Gemini's + # functionResponses[].response field is a Struct, so it must be a + # dict; wrap any non-dict (primitives, lists, invalid JSON) under a + # `result` key. + try: + parsed_output = json.loads(output) if isinstance(output, str) else output + except json.JSONDecodeError: + parsed_output = output + output_dict = ( + parsed_output + if isinstance(parsed_output, dict) + else {"result": parsed_output} + ) + + # Look up the function name from stored mapping. Keep the entry so a + # client SDK that retries function_call_output (or sends it twice for + # the same tool call) still produces a Gemini toolResponse with the + # required ``name`` field; refresh the LRU position so an active + # call_id stays warm across long sessions. + function_name = self._tool_call_id_to_name.get(call_id) + if function_name: + self._tool_call_id_to_name.move_to_end(call_id) + else: + verbose_logger.warning( + f"Gemini Realtime: Function name not found for call_id={call_id}. " + "This may cause Gemini to reject the response." + ) + + # Build Gemini toolResponse format + function_response = { + "id": call_id, + "response": output_dict, + } + if function_name: + function_response["name"] = function_name + + tool_response_message = { + "toolResponse": {"functionResponses": [function_response]} + } + + return [json.dumps(tool_response_message)] + + def _handle_user_text_content(self, item: dict) -> List[str]: + """Transform user text content to Gemini clientContent format.""" + content_list = item.get("content", []) + text_parts = [ + c.get("text", "") + for c in content_list + if isinstance(c, dict) and c.get("type") == "input_text" + ] + text = " ".join(filter(None, text_parts)) + if not text: + return [] + + # Build clientContent message with turns (proper Gemini Live API format) + client_content_message = { + "clientContent": { + "turns": [{"role": "user", "parts": [{"text": text}]}], + "turnComplete": True, + } + } + + return [json.dumps(client_content_message)] + def transform_realtime_request( self, message: str, @@ -233,55 +531,42 @@ def transform_realtime_request( messages: List[str] = [] msg_type = json_message.get("type") - ## HANDLE SESSION UPDATE — translate to Gemini setup; no realtime_input needed ## + ## HANDLE SESSION UPDATE — translate to Gemini setup ## if msg_type == "session.update": - client_session_configuration_request = self.map_openai_params( - optional_params={}, non_default_params=json_message["session"] + return self._handle_session_update( + json_message, model, session_configuration_request ) - client_session_configuration_request["model"] = f"models/{model}" - messages.append(json.dumps({"setup": client_session_configuration_request})) - return messages ## HANDLE response.create — Gemini responds automatically; nothing to forward ## if msg_type == "response.create": return [] - ## HANDLE INPUT AUDIO BUFFER ## + ## HANDLE conversation.item.create — extract user text or function call output ## + if msg_type == "conversation.item.create": + return self._handle_conversation_item(json_message) + + ## HANDLE INPUT AUDIO BUFFER - use realtimeInput for audio streaming ## if msg_type == "input_audio_buffer.append": realtime_input_dict["audio"] = HttpxBlobType( mimeType=self.get_audio_mime_type(), data=json_message["audio"] ) - ## HANDLE conversation.item.create — extract actual user text ## - elif msg_type == "conversation.item.create": - item = json_message.get("item", {}) - content_list = item.get("content", []) - text_parts = [ - c.get("text", "") - for c in content_list - if isinstance(c, dict) and c.get("type") == "input_text" - ] - text = " ".join(filter(None, text_parts)) - if not text: - return [] - realtime_input_dict["text"] = text - else: - # Unknown/unsupported OpenAI event type — drop silently rather than - # forwarding raw JSON as text input to the model. - return [] - if len(realtime_input_dict) != 1: - raise ValueError( - f"Only one argument can be set, got {len(realtime_input_dict)}:" - f" {list(realtime_input_dict.keys())}" + realtime_input_dict = cast( + BidiGenerateContentRealtimeInput, + encode_unserializable_types( + cast(Dict[str, object], realtime_input_dict) + ), ) - realtime_input_dict = cast( - BidiGenerateContentRealtimeInput, - encode_unserializable_types(cast(Dict[str, object], realtime_input_dict)), - ) - - messages.append(json.dumps({"realtime_input": realtime_input_dict})) - return messages + gemini_msg = json.dumps({"realtimeInput": realtime_input_dict}) + verbose_logger.debug( + "Gemini Realtime: Sending audio realtimeInput to backend" + ) + messages.append(gemini_msg) + return messages + # Unknown/unsupported OpenAI event type — drop silently rather than + # forwarding raw JSON as text input to the model. + return [] def transform_session_created_event( self, @@ -300,7 +585,7 @@ def transform_session_created_event( generation_config = ( session_configuration_request_dict.get("generationConfig", {}) or {} ) - gemini_modalities = generation_config.get("responseModalities", ["TEXT"]) + gemini_modalities = generation_config.get("responseModalities", ["AUDIO"]) _modalities = [ modality.lower() for modality in cast(List[str], gemini_modalities) ] @@ -352,18 +637,18 @@ def return_new_content_delta_events( delta_type: ALL_DELTA_TYPES, session_configuration_request: Optional[str] = None, ) -> List[OpenAIRealtimeEvents]: - if session_configuration_request is None: - raise ValueError( - "session_configuration_request is required for Gemini API calls" - ) - - session_configuration_request_dict: BidiGenerateContentSetup = json.loads( - session_configuration_request - ).get("setup", {}) + session_configuration_request_dict: BidiGenerateContentSetup = {} + if session_configuration_request is not None: + try: + session_configuration_request_dict = json.loads( + session_configuration_request + ).get("setup", {}) + except json.JSONDecodeError: + session_configuration_request_dict = {} generation_config = session_configuration_request_dict.get( "generationConfig", {} ) - gemini_modalities = generation_config.get("responseModalities", ["TEXT"]) + gemini_modalities = generation_config.get("responseModalities", ["AUDIO"]) _modalities = [ modality.lower() for modality in cast(List[str], gemini_modalities) ] @@ -576,6 +861,86 @@ def return_additional_content_done_events( returned_items.append(response_output_item_done) return returned_items + def _consume_usage_metadata_for_response_done(self, frame: dict) -> Optional[dict]: + """Return the ``usageMetadata`` to attribute to a ``response.done``. + + Gemini Live emits ``usageMetadata`` either alongside the closing + frame (``serverContent.turnComplete`` / ``toolCall``) or as a + standalone frame between turns. The standalone form would otherwise + be discarded by the no-op branch in ``transform_realtime_response`` + and the consumed tokens silently dropped from spend/budget + accounting. ``_pending_usage_metadata`` buffers any such standalone + frames so the next emitted ``response.done`` carries the deferred + token counts. + + Returns the in-frame ``usageMetadata`` if present (and clears the + buffer since the in-frame counts are the authoritative attribution + for this turn), otherwise returns the buffered counts. ``None`` is + returned when neither is available so the caller can fall back to + ``get_empty_usage()``. + """ + # ``pop`` (rather than ``get``) so a single Gemini frame containing + # multiple closing keys (e.g. both ``toolCall`` and + # ``serverContent.turnComplete``) cannot attribute the same + # ``usageMetadata`` to two ``response.done`` events and double-count + # tokens in spend/budget accounting. + in_frame = frame.pop("usageMetadata", None) if isinstance(frame, dict) else None + if isinstance(in_frame, dict): + self._pending_usage_metadata = None + return in_frame + buffered = self._pending_usage_metadata + self._pending_usage_metadata = None + return buffered + + def transform_tool_call_events( + self, + tool_call_message: dict, + response_id: Optional[str] = None, + output_item_id: Optional[str] = None, + ) -> List[OpenAIRealtimeFunctionCallArgumentsDone]: + """ + Transform Gemini toolCall message to OpenAI function call events. + + Converts Gemini's functionCalls format to OpenAI's response.function_call_arguments.done events. + Also stores call_id → name mapping for later use in function_call_output responses. + """ + function_calls = tool_call_message.get("functionCalls", []) + resolved_response_id = response_id or f"resp_{uuid.uuid4()}" + resolved_output_item_id = output_item_id or f"item_{uuid.uuid4()}" + + verbose_logger.debug( + f"Gemini Realtime: Transforming {len(function_calls)} tool call(s) to OpenAI format" + ) + + events: List[OpenAIRealtimeFunctionCallArgumentsDone] = [] + for idx, fc in enumerate(function_calls): + call_id = fc.get("id", "") + name = fc.get("name", "") + + # Store call_id → name mapping for round-trip. Use an LRU so + # repeated function_call_output lookups (retries) still hit, while + # sessions with many tool calls don't grow the dict unboundedly. + if call_id and name: + self._tool_call_id_to_name[call_id] = name + self._tool_call_id_to_name.move_to_end(call_id) + while len(self._tool_call_id_to_name) > self._TOOL_CALL_ID_TO_NAME_MAX: + self._tool_call_id_to_name.popitem(last=False) + + events.append( + OpenAIRealtimeFunctionCallArgumentsDone( + type="response.function_call_arguments.done", + event_id=f"event_{uuid.uuid4()}", + response_id=resolved_response_id, + item_id=f"{resolved_output_item_id}_tool_{idx}", + output_index=idx, + call_id=call_id, + name=name, + arguments=json.dumps(fc.get("args", {})), + ) + ) + + return events + @staticmethod def get_nested_value(obj: dict, path: str) -> Any: keys = path.split(".") @@ -681,14 +1046,20 @@ def transform_response_done_event( "generationConfig", {} ) temperature = generation_config.get("temperature") - max_output_tokens = generation_config.get("max_output_tokens") - gemini_modalities = generation_config.get("responseModalities", ["TEXT"]) + max_output_tokens = generation_config.get("maxOutputTokens") + gemini_modalities = generation_config.get("responseModalities", ["AUDIO"]) _modalities = [ modality.lower() for modality in cast(List[str], gemini_modalities) ] - if "usageMetadata" in message: + resolved_usage_metadata = self._consume_usage_metadata_for_response_done( + cast(dict, message) + ) + if resolved_usage_metadata is not None: _chat_completion_usage = VertexGeminiConfig._calculate_usage( - completion_response=message, + completion_response=cast( + BidiGenerateContentServerMessage, + {**cast(dict, message), "usageMetadata": resolved_usage_metadata}, + ), ) else: _chat_completion_usage = get_empty_usage() @@ -716,7 +1087,9 @@ def transform_response_done_event( if temperature is not None: response_done_event["response"]["temperature"] = temperature if max_output_tokens is not None: - response_done_event["response"]["max_output_tokens"] = max_output_tokens + response_done_event["response"]["max_output_tokens"] = cast( + int, max_output_tokens + ) return response_done_event @@ -808,13 +1181,18 @@ def handle_openai_modality_event( def map_openai_event( self, key: str, - value: dict, + value: Any, current_delta_type: Optional[ALL_DELTA_TYPES], - json_message: dict, - ) -> OpenAIRealtimeEventTypes: - model_turn_event = value.get("modelTurn") - generation_complete_event = value.get("generationComplete") - openai_event: Optional[OpenAIRealtimeEventTypes] = None + ) -> Union[OpenAIRealtimeEventTypes, ResponsesAPIStreamEvents]: + if isinstance(value, dict): + model_turn_event = value.get("modelTurn") + generation_complete_event = value.get("generationComplete") + else: + model_turn_event = None + generation_complete_event = None + openai_event: Optional[ + Union[OpenAIRealtimeEventTypes, ResponsesAPIStreamEvents] + ] = None if model_turn_event: # check if model turn event openai_event = self.map_model_turn_event(model_turn_event) elif generation_complete_event: @@ -822,15 +1200,27 @@ def map_openai_event( delta_type=current_delta_type ) else: - # Check if this key or any nested key matches our mapping - for map_key, openai_event in MAP_GEMINI_FIELD_TO_OPENAI_EVENT.items(): - if map_key == key or ( - "." in map_key - and GeminiRealtimeConfig.get_nested_value(json_message, map_key) - is not None - ): - openai_event = openai_event + # Check if this key or any nested key matches our mapping. Use a + # distinct loop variable so we don't shadow ``openai_event`` and + # leak the last dict value when no entry matches. Scope dotted-key + # lookups to the current ``key``/``value`` pair — checking the + # whole ``json_message`` would let a sibling key (e.g. + # ``serverContent.turnComplete``) misclassify the event currently + # being processed (e.g. ``toolCall``). + for map_key, candidate_event in MAP_GEMINI_FIELD_TO_OPENAI_EVENT.items(): + if map_key == key: + openai_event = candidate_event break + if "." in map_key: + prefix, _, nested_path = map_key.partition(".") + if ( + prefix == key + and isinstance(value, dict) + and GeminiRealtimeConfig.get_nested_value(value, nested_path) + is not None + ): + openai_event = candidate_event + break if openai_event is None: raise ValueError(f"Unknown openai event: {key}, value: {value}") return openai_event @@ -854,6 +1244,15 @@ def transform_realtime_response( # noqa: PLR0915 message_str = str(message) raise ValueError(f"Invalid JSON message: {message_str}") + verbose_logger.debug( + "Realtime Response Transform: Gemini frame keys=%s", + ( + sorted(json_message.keys()) + if isinstance(json_message, dict) + else type(json_message).__name__ + ), + ) + logging_session_id = logging_obj.litellm_trace_id current_output_item_id = realtime_response_transform_input[ @@ -913,32 +1312,44 @@ def transform_realtime_response( # noqa: PLR0915 ) # If serverContent only contained transcription(s) and no model - # content, return early — the main loop would fail on unknown keys. + # content, mark it as already handled so the main loop skips it + # (map_openai_event would raise on an unknown serverContent + # subkey). Fall through so sibling top-level keys such as + # ``toolCall`` are still processed in the main loop. _model_content_keys = { "modelTurn", "turnComplete", "interrupted", "generationComplete", } - if not any(k in server_content for k in _model_content_keys): - return { - "response": returned_message, - "current_output_item_id": current_output_item_id, - "current_response_id": current_response_id, - "current_delta_chunks": current_delta_chunks, - "current_conversation_id": current_conversation_id, - "current_item_chunks": current_item_chunks, - "current_delta_type": current_delta_type, - "session_configuration_request": session_configuration_request, - } - - for key, value in json_message.items(): + server_content_handled = not any( + k in server_content for k in _model_content_keys + ) + else: + server_content_handled = False + + tool_call_handled = False + # Snapshot the items so handlers below can safely mutate + # ``json_message`` (e.g. ``_consume_usage_metadata_for_response_done`` + # pops ``usageMetadata`` to prevent a single frame from attributing + # the same token counts to two ``response.done`` events). + for key, value in list(json_message.items()): + # Skip sibling metadata keys (e.g. ``usageMetadata``) that can + # accompany a primary payload like ``toolCall`` or ``serverContent``. + # ``map_openai_event`` raises ValueError on unknown keys, which + # would otherwise terminate the WebSocket session. + if key not in _KNOWN_GEMINI_TOP_LEVEL_KEYS: + continue + # serverContent was a transcription-only payload already emitted + # above; skip it here so map_openai_event doesn't raise on the + # missing model-content subkeys. + if key == "serverContent" and server_content_handled: + continue # Check if this key or any nested key matches our mapping openai_event = self.map_openai_event( key=key, value=value, current_delta_type=current_delta_type, - json_message=json_message, ) if openai_event == OpenAIRealtimeEventTypes.SESSION_CREATED: @@ -947,8 +1358,226 @@ def transform_realtime_response( # noqa: PLR0915 logging_session_id, realtime_response_transform_input["session_configuration_request"], ) - session_configuration_request = json.dumps(transformed_message) returned_message.append(transformed_message) + elif openai_event == ResponsesAPIStreamEvents.FUNCTION_CALL_ARGUMENTS_DONE: + # Handle toolCall from Gemini. If the payload has no function + # calls, emit nothing — an orphaned response.created/done pair + # with no output items would confuse OpenAI-compatible clients. + # Mark the key as intentionally consumed (mirroring + # ``server_content_handled``) so any sibling keys in the same + # frame are still processed by the rest of the loop and the + # post-loop guard doesn't treat the no-op as fatal. + if not value.get("functionCalls"): + tool_call_handled = True + continue + + if current_conversation_id is None: + current_conversation_id = f"conv_{uuid.uuid4()}" + + # Extract session-level response metadata once so both + # response.created and response.done can include matching + # modalities/temperature/max_output_tokens fields. + session_setup: BidiGenerateContentSetup = {} + if session_configuration_request is not None: + try: + session_setup = json.loads(session_configuration_request).get( + "setup", {} + ) + except (json.JSONDecodeError, TypeError): + session_setup = {} + tool_call_generation_config = ( + session_setup.get("generationConfig", {}) or {} + ) + tool_call_modalities = [ + modality.lower() + for modality in cast( + List[str], + tool_call_generation_config.get( + "responseModalities", ["AUDIO"] + ), + ) + ] + + # Emit response.created preamble if this is the first event in the response + if current_response_id is None: + current_response_id = f"resp_{uuid.uuid4()}" + current_output_item_id = f"item_{uuid.uuid4()}" + + # Mirror the audio/text path: include modalities, + # temperature, and max_output_tokens on response.created so + # spec-compliant clients see consistent response metadata + # regardless of whether the response starts with content or + # a tool call. + returned_message.append( + { + "type": "response.created", + "event_id": f"event_{uuid.uuid4()}", + "response": { + "object": "realtime.response", + "id": current_response_id, + "status": "in_progress", + "output": [], + "conversation_id": current_conversation_id, + "modalities": tool_call_modalities, + "temperature": tool_call_generation_config.get( + "temperature" + ), + "max_output_tokens": tool_call_generation_config.get( + "maxOutputTokens" + ), + }, + } + ) + + tool_call_events = self.transform_tool_call_events( + value, + response_id=current_response_id, + output_item_id=current_output_item_id, + ) + # Emit output_item.added and conversation.item.created for each function call + for idx, tool_call in enumerate(tool_call_events): + item_id = tool_call["item_id"] + function_call_item: OpenAIRealtimeStreamResponseOutputItem = { + "id": item_id, + "object": "realtime.item", + "type": "function_call", + "status": "completed", + "call_id": tool_call["call_id"], + "name": tool_call["name"], + "arguments": tool_call["arguments"], + } + # response.output_item.added + returned_message.append( + OpenAIRealtimeStreamResponseOutputItemAdded( + type="response.output_item.added", + event_id=f"event_{uuid.uuid4()}", + response_id=current_response_id, + output_index=idx, + item={ + **function_call_item, + "status": "in_progress", + "arguments": "", + }, + ) + ) + # response.function_call_arguments.delta — Gemini delivers + # the full arguments string in a single toolCall frame + # rather than streaming partial chunks, so emit one delta + # carrying the complete payload before the matching + # ``.done`` event. Spec-compliant OpenAI Realtime SDK + # clients accumulate ``delta.delta`` and rely on at least + # one delta before ``.done``. + returned_message.append( + cast( + OpenAIRealtimeEvents, + { + "type": "response.function_call_arguments.delta", + "event_id": f"event_{uuid.uuid4()}", + "response_id": current_response_id, + "item_id": item_id, + "output_index": idx, + "call_id": tool_call["call_id"], + "delta": tool_call["arguments"], + }, + ) + ) + # response.function_call_arguments.done + returned_message.append(tool_call) + # response.output_item.done — pass a fresh copy so + # downstream handlers that mutate the item dict (e.g. the + # beta-protocol translator) don't corrupt the references + # used by sibling events sharing the same function_call_item. + returned_message.append( + OpenAIRealtimeOutputItemDone( + type="response.output_item.done", + event_id=f"event_{uuid.uuid4()}", + response_id=current_response_id, + output_index=idx, + item={**function_call_item}, + ) + ) + # conversation.item.created + returned_message.append( + OpenAIRealtimeConversationItemCreated( + type="conversation.item.created", + event_id=f"event_{uuid.uuid4()}", + item={**function_call_item}, + ) + ) + + # response.done - close the response so clients can submit tool + # results. Mirror the non-tool-call RESPONSE_DONE path: if Gemini + # delivered ``usageMetadata`` alongside this ``toolCall`` frame, + # propagate the real token counts so spend/budget accounting + # records the tokens consumed by the tool-call turn. Standalone + # ``usageMetadata`` frames emitted in a separate WebSocket frame + # are buffered on the instance so the next ``response.done`` + # picks them up (otherwise an authenticated client could drive + # tool-call turns whose token usage is recorded as zero, + # bypassing budgets). Falls back to an empty usage block when + # neither is available (OpenAI-compatible clients expect + # ``usage`` to always be present on response.done). + resolved_tool_call_usage_metadata = ( + self._consume_usage_metadata_for_response_done(json_message) + ) + if resolved_tool_call_usage_metadata is not None: + _tool_call_chat_completion_usage = ( + VertexGeminiConfig._calculate_usage( + completion_response=cast( + BidiGenerateContentServerMessage, + { + **json_message, + "usageMetadata": resolved_tool_call_usage_metadata, + }, + ), + ) + ) + else: + _tool_call_chat_completion_usage = get_empty_usage() + tool_call_responses_api_usage = LiteLLMCompletionResponsesConfig._transform_chat_completion_usage_to_responses_usage( + _tool_call_chat_completion_usage, + ) + tool_call_done_event = OpenAIRealtimeDoneEvent( + type="response.done", + event_id=f"event_{uuid.uuid4()}", + response=OpenAIRealtimeResponseDoneObject( + id=current_response_id, + object="realtime.response", + status="completed", + output=[ + { + "id": te["item_id"], + "object": "realtime.item", + "type": "function_call", + "status": "completed", + "call_id": te["call_id"], + "name": te["name"], + "arguments": te["arguments"], + } + for te in tool_call_events + ], + conversation_id=current_conversation_id, + modalities=tool_call_modalities, + usage=tool_call_responses_api_usage.model_dump(), + ), + ) + tool_call_temperature = tool_call_generation_config.get("temperature") + if tool_call_temperature is not None: + tool_call_done_event["response"][ + "temperature" + ] = tool_call_temperature + tool_call_max_output_tokens = tool_call_generation_config.get( + "maxOutputTokens" + ) + if tool_call_max_output_tokens is not None: + tool_call_done_event["response"]["max_output_tokens"] = cast( + int, tool_call_max_output_tokens + ) + returned_message.append(tool_call_done_event) + # Reset IDs so the next model turn (after tool results) starts a + # fresh response with its own response.created preamble. + current_output_item_id = None + current_response_id = None elif openai_event == OpenAIRealtimeEventTypes.RESPONSE_DONE: transformed_response_done_event = self.transform_response_done_event( message=BidiGenerateContentServerMessage(**json_message), # type: ignore @@ -958,16 +1587,37 @@ def transform_realtime_response( # noqa: PLR0915 output_items=None, ) returned_message.append(transformed_response_done_event) + # Reset IDs so a subsequent turn (e.g. a `toolCall` arriving in + # a later WebSocket frame after `turnComplete`) starts a fresh + # response with its own `response.created` preamble instead of + # reusing the just-completed response ID. + current_output_item_id = None + current_response_id = None elif ( openai_event == OpenAIRealtimeEventTypes.RESPONSE_TEXT_DELTA or openai_event == OpenAIRealtimeEventTypes.RESPONSE_TEXT_DONE or openai_event == OpenAIRealtimeEventTypes.RESPONSE_AUDIO_DELTA or openai_event == OpenAIRealtimeEventTypes.RESPONSE_AUDIO_DONE ): + # Pass the locally-updated state (rather than the original + # input snapshot) so that prior iterations of this loop — + # e.g. a tool-call or response.done that just reset + # current_response_id/current_output_item_id to None — are + # honoured by the modality handler. + _modality_input: RealtimeResponseTransformInput = { + **realtime_response_transform_input, + "current_output_item_id": current_output_item_id, + "current_response_id": current_response_id, + "current_conversation_id": current_conversation_id, + "current_delta_chunks": current_delta_chunks, + "current_item_chunks": current_item_chunks, + "current_delta_type": current_delta_type, + "session_configuration_request": session_configuration_request, + } _returned_message = self.handle_openai_modality_event( openai_event, json_message, - realtime_response_transform_input, + _modality_input, delta_type="text" if "text" in openai_event.value else "audio", ) returned_message.extend(_returned_message["returned_message"]) @@ -979,6 +1629,41 @@ def transform_realtime_response( # noqa: PLR0915 else: raise ValueError(f"Unknown openai event: {openai_event}") if len(returned_message) == 0: + # A frame whose only top-level keys are sibling metadata (e.g. + # a standalone ``{"usageMetadata": {...}}`` emitted by Gemini + # Live between turns) is not an error — there is just nothing + # to forward to the OpenAI-shaped client. Returning the + # unchanged state keeps the WebSocket alive; raising would + # terminate the session for a benign no-op frame. + # serverContent already consumed by the transcription handler is + # a benign no-op for downstream — treat it like a metadata-only + # key when deciding whether to raise. + unhandled_known_keys = [ + key + for key in json_message + if key in _KNOWN_GEMINI_TOP_LEVEL_KEYS + and not (key == "serverContent" and server_content_handled) + and not (key == "toolCall" and tool_call_handled) + ] + # Buffer standalone usage metadata so the next response.done can + # attribute the token counts. Without this, an authenticated + # client driving turns whose usageMetadata is emitted in a + # separate frame would have those tokens recorded as zero spend, + # bypassing budget enforcement. + standalone_usage_metadata = json_message.get("usageMetadata") + if isinstance(standalone_usage_metadata, dict): + self._pending_usage_metadata = standalone_usage_metadata + if not unhandled_known_keys: + return { + "response": returned_message, + "current_output_item_id": current_output_item_id, + "current_response_id": current_response_id, + "current_delta_chunks": current_delta_chunks, + "current_conversation_id": current_conversation_id, + "current_item_chunks": current_item_chunks, + "current_delta_type": current_delta_type, + "session_configuration_request": session_configuration_request, + } if isinstance(message, bytes): message_str = message.decode("utf-8", errors="replace") else: @@ -993,6 +1678,13 @@ def transform_realtime_response( # noqa: PLR0915 transformed_message=returned_message, current_item_chunks=current_item_chunks, ) + + for msg in returned_message: + event_type = msg.get("type") if isinstance(msg, dict) else "unknown" + verbose_logger.debug( + "Realtime Response Transform: OpenAI event=%s", event_type + ) + return { "response": returned_message, "current_output_item_id": current_output_item_id, @@ -1005,7 +1697,10 @@ def transform_realtime_response( # noqa: PLR0915 } def requires_session_configuration(self) -> bool: - return True + # Default behavior is backwards-compatible: send setup on connect. + # Opt-in to deferred setup for tool-injection flow via: + # litellm.gemini_live_defer_setup = True + return not litellm.gemini_live_defer_setup def session_configuration_request(self, model: str) -> str: """ diff --git a/litellm/llms/gemini/videos/transformation.py b/litellm/llms/gemini/videos/transformation.py index 9714c8a3923..77a95bfa5ab 100644 --- a/litellm/llms/gemini/videos/transformation.py +++ b/litellm/llms/gemini/videos/transformation.py @@ -581,12 +581,23 @@ def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Gemini") def transform_video_edit_request( - self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + self, + prompt, + video_id, + api_base, + litellm_params, + headers, + extra_body=None, + prefetched_source_data=None, ): raise NotImplementedError("video edit is not supported for Gemini") def transform_video_edit_response( - self, raw_response, logging_obj, custom_llm_provider=None + self, + raw_response, + logging_obj, + custom_llm_provider=None, + request_data=None, ): raise NotImplementedError("video edit is not supported for Gemini") diff --git a/litellm/llms/langgraph/chat/transformation.py b/litellm/llms/langgraph/chat/transformation.py index 00cc3a8f516..9808b665b54 100644 --- a/litellm/llms/langgraph/chat/transformation.py +++ b/litellm/llms/langgraph/chat/transformation.py @@ -139,14 +139,16 @@ def _get_assistant_id(self, model: str, optional_params: dict) -> str: def _convert_messages_to_langgraph_format( self, messages: List[AllMessageValues] - ) -> List[Dict[str, str]]: + ) -> List[Dict[str, Any]]: """ Convert OpenAI-format messages to LangGraph format. OpenAI format: {"role": "user", "content": "..."} LangGraph format: {"role": "human", "content": "..."} + + Preserves per-message ``metadata`` when present (e.g. A2A ``skillId``). """ - langgraph_messages: List[Dict[str, str]] = [] + langgraph_messages: List[Dict[str, Any]] = [] for msg in messages: role = msg.get("role", "user") content = msg.get("content", "") @@ -169,7 +171,15 @@ def _convert_messages_to_langgraph_format( if not isinstance(content, str): content = str(content) - langgraph_messages.append({"role": langgraph_role, "content": content}) + langgraph_message: Dict[str, Any] = { + "role": langgraph_role, + "content": content, + } + message_metadata = msg.get("metadata") + if isinstance(message_metadata, dict) and message_metadata: + langgraph_message["metadata"] = message_metadata + + langgraph_messages.append(langgraph_message) return langgraph_messages diff --git a/litellm/llms/oci/chat/cohere.py b/litellm/llms/oci/chat/cohere.py new file mode 100644 index 00000000000..ac92fd22aa8 --- /dev/null +++ b/litellm/llms/oci/chat/cohere.py @@ -0,0 +1,386 @@ +""" +OCI Generative AI — Cohere-specific chat transformation helpers. + +Handles message history building, tool definition adaptation, non-streaming +response parsing, and streaming chunk parsing for models served with +``apiFormat="COHERE"`` (e.g. ``cohere.command-*``). +""" + +import datetime +import json +from typing import Any, Dict, List, Optional + +import httpx +from pydantic import ValidationError + +from litellm.llms.oci.chat.generic import ( + _normalize_oci_finish_reason, + _synthesize_oci_tool_call_id, +) +from litellm.llms.oci.common_utils import ( + OCI_JSON_TO_PYTHON_TYPES, + OCIError, + enrich_cohere_param_description, + resolve_oci_schema_anyof, + resolve_oci_schema_refs, + sanitize_oci_schema, +) +from litellm.types.llms.oci import ( + CohereChatResult, + CohereMessage, + CohereParameterDefinition, + CohereStreamChunk, + CohereTool, + CohereToolCall, + CohereToolMessage, + CohereToolResult, +) +from litellm.types.llms.openai import AllMessageValues +from litellm.types.utils import ( + Choices, + Delta, + ModelResponse, + ModelResponseStream, + StreamingChoices, +) +from litellm.types.utils import Usage + + +def _extract_text_content(content: Any) -> str: + """Return the plain-text representation of a message content value.""" + if content is None: + return "" + if isinstance(content, str): + return content + if isinstance(content, list): + return "".join( + item.get("text", "") + for item in content + if isinstance(item, dict) and item.get("type") == "text" + ) + return str(content) + + +def adapt_messages_to_cohere_standard( + messages: List[AllMessageValues], +) -> List[CohereMessage]: + """Build a Cohere ``chatHistory`` list from an OpenAI-format message array. + + - All messages except the *last user message* are included. The caller pulls + the last user message into the request's top-level ``message`` field, so + trailing tool results (the standard agentic continuation pattern) still + appear in ``chatHistory`` and reach the model. + - If no user message exists, every message is included (no slice). + - System messages must be filtered out by the caller (they are routed into + ``preambleOverride`` separately) — they are not represented in + ``chatHistory``. + - Tool results are expressed as OCI ``CohereToolMessage.toolResults`` entries, + with the originating call's name and parameters resolved from the preceding + assistant message via a ``tool_call_id`` lookup. + """ + # First pass: build tool_call_id → CohereToolCall so tool-result messages can + # reference the originating call by name and parameters. + tool_call_lookup: Dict[str, CohereToolCall] = {} + for msg in messages: + if msg.get("role") == "assistant": + tool_calls_raw: Any = msg.get("tool_calls") or [] + for tc in tool_calls_raw: + tc_id = tc.get("id", "") + raw_args: Any = tc.get("function", {}).get("arguments", "{}") + try: + params: Dict[str, Any] = ( + json.loads(raw_args) if isinstance(raw_args, str) else raw_args + ) + except json.JSONDecodeError: + params = {} + tool_call_lookup[tc_id] = CohereToolCall( + name=str(tc.get("function", {}).get("name", "")), + parameters=params, + ) + + last_user_index = next( + ( + i + for i in range(len(messages) - 1, -1, -1) + if messages[i].get("role") == "user" + ), + None, + ) + history_source = ( + messages + if last_user_index is None + else [m for i, m in enumerate(messages) if i != last_user_index] + ) + + chat_history: List[CohereMessage] = [] + for msg in history_source: + role = msg.get("role") + content = _extract_text_content(msg.get("content")) + + tool_calls: Optional[List[CohereToolCall]] = None + if role == "assistant" and msg.get("tool_calls"): # type: ignore[union-attr,typeddict-item] + tool_calls = [] + for tc in msg["tool_calls"]: # type: ignore[union-attr,typeddict-item] + raw_arguments: Any = tc.get("function", {}).get("arguments", {}) + if isinstance(raw_arguments, str): + try: + arguments: Dict[str, Any] = json.loads(raw_arguments) + except json.JSONDecodeError: + arguments = {} + else: + arguments = raw_arguments + tool_calls.append( + CohereToolCall( + name=str(tc.get("function", {}).get("name", "")), + parameters=arguments, + ) + ) + + if role == "user": + chat_history.append(CohereMessage(role="USER", message=content)) + elif role == "assistant": + chat_history.append( + CohereMessage(role="CHATBOT", message=content, toolCalls=tool_calls) + ) + elif role == "tool": + tool_call_id = str(msg.get("tool_call_id", "") or "") + cohere_call = tool_call_lookup.get( + tool_call_id, CohereToolCall(name="", parameters={}) + ) + tool_result = CohereToolResult( + call=cohere_call, + outputs=[{"output": content}], + ) + # OpenAI emits one tool-role message per parallel tool call, but + # the OCI Cohere API expects all results from a single assistant + # turn to share one TOOL history entry with multiple toolResults. + # Merge consecutive tool messages so the model sees the parallel + # call/result pairing correctly during agentic loops. + if chat_history and isinstance(chat_history[-1], CohereToolMessage): + chat_history[-1].toolResults.append(tool_result) + else: + chat_history.append(CohereToolMessage(toolResults=[tool_result])) + + return chat_history + + +def adapt_tool_definitions_to_cohere_standard( + tools: List[Dict[str, Any]], +) -> List[CohereTool]: + """Adapt OpenAI-format tool definitions to the OCI Cohere format. + + - Resolves ``$ref``/``$defs`` and ``anyOf`` patterns that OCI rejects. + - Maps JSON Schema type names to Python type names (``"string"`` → ``"str"``). + - Embeds unsupported constraints (enum, format, range, pattern) into the + parameter description so the model can still see them. + """ + cohere_tools = [] + for tool in tools: + function_def = tool.get("function", {}) + raw_params = function_def.get("parameters", {}) + + resolved = sanitize_oci_schema( + resolve_oci_schema_anyof(resolve_oci_schema_refs(raw_params)) + ) + properties = resolved.get("properties", {}) + required = resolved.get("required", []) + + parameter_definitions = {} + for param_name, param_schema in properties.items(): + json_type = param_schema.get("type", "string") + python_type = OCI_JSON_TO_PYTHON_TYPES.get(json_type, json_type) + parameter_definitions[param_name] = CohereParameterDefinition( + description=enrich_cohere_param_description( + param_schema.get("description", ""), param_schema + ), + type=python_type, + isRequired=param_name in required, + ) + + cohere_tools.append( + CohereTool( + name=function_def.get("name", ""), + description=function_def.get("description", ""), + parameterDefinitions=parameter_definitions, + ) + ) + + return cohere_tools + + +def handle_cohere_response( + json_response: dict, + model: str, + model_response: ModelResponse, + raw_response: httpx.Response, +) -> ModelResponse: + """Parse a non-streaming Cohere OCI response into a LiteLLM ModelResponse.""" + try: + cohere_response = CohereChatResult(**json_response) + except (TypeError, ValidationError) as e: + raise OCIError( + message=f"Response cannot be casted to CohereChatResult: {str(e)}", + status_code=raw_response.status_code, + ) + + model_response.model = model + model_response.created = int(datetime.datetime.now().timestamp()) + + response_text = cohere_response.chatResponse.text + finish_reason = _normalize_oci_finish_reason( + cohere_response.chatResponse.finishReason + ) + + tool_calls: Optional[List[Dict[str, Any]]] = None + if cohere_response.chatResponse.toolCalls: + tool_calls = [ + { + "id": _synthesize_oci_tool_call_id( + i, tc.name, json.dumps(tc.parameters, sort_keys=True) + ), + "type": "function", + "function": { + "name": tc.name, + "arguments": json.dumps(tc.parameters), + }, + } + for i, tc in enumerate(cohere_response.chatResponse.toolCalls) + ] + + content: Optional[str] = response_text if response_text else None + + # Only include ``tool_calls`` in the message dict when actually present. + # Passing an explicit ``None`` would let downstream consumers that key off + # ``"tool_calls" in message`` (rather than truthiness) incorrectly conclude + # that tool calls were attempted. Matches the generic handler's behaviour, + # which only sets ``message.tool_calls`` when tool calls are present. + message: Dict[str, Any] = {"role": "assistant", "content": content} + if tool_calls is not None: + message["tool_calls"] = tool_calls + + model_response.choices = [ + Choices( + index=0, + message=message, + finish_reason=finish_reason, + ) + ] + + usage_info = cohere_response.chatResponse.usage + if usage_info is not None: + model_response.usage = Usage( # type: ignore[attr-defined] + prompt_tokens=usage_info.promptTokens, + completion_tokens=usage_info.completionTokens, + total_tokens=usage_info.totalTokens, + ) + else: + model_response.usage = Usage(prompt_tokens=0, completion_tokens=0, total_tokens=0) # type: ignore[attr-defined] + + return model_response + + +def handle_cohere_stream_chunk( + dict_chunk: dict, + prior_tool_calls_emitted: bool = False, + prior_text_emitted: bool = False, +) -> ModelResponseStream: + """Parse a single Cohere SSE chunk into a LiteLLM ModelResponseStream. + + ``prior_tool_calls_emitted`` lets the caller signal whether tool calls + were already emitted in earlier chunks of the same stream. When set, the + terminal consolidation chunk's tool calls are suppressed (they would + duplicate prior deltas); otherwise they are passed through so a stream + that delivers tool calls only on the terminal chunk doesn't silently + drop them. + + ``prior_text_emitted`` plays the analogous role for the ``text`` field: + when set, the terminal consolidation chunk's ``text`` is suppressed + (it would re-emit the full assembled response on top of prior deltas); + when unset (e.g. a degenerate stream that delivers the entire response + in a single SSE event carrying both ``chatHistory`` and ``finishReason``), + the text is passed through so the response content isn't silently lost. + """ + try: + typed_chunk = CohereStreamChunk(**dict_chunk) + except (TypeError, ValidationError) as e: + raise OCIError( + status_code=500, + message=f"Chunk cannot be parsed as CohereStreamChunk: {str(e)}", + ) + + if typed_chunk.index is None: + typed_chunk.index = 0 + + # OCI Cohere's terminal SSE event re-sends the full assembled response in + # `text` alongside a populated `chatHistory` and a non-null `finishReason`. + # Emitting that text would concatenate the whole response onto the + # already-streamed deltas. We require both signals to be present so that a + # future API change which adds `chatHistory` to intermediate chunks (or a + # rare early-populated case) doesn't silently drop legitimate token deltas. + is_terminal_consolidation = ( + typed_chunk.chatHistory is not None and typed_chunk.finishReason is not None + ) + # On non-terminal text-free chunks (e.g. tool-call-only or keep-alive + # chunks) emit ``content=None`` rather than ``content=""`` so downstream + # stream-mergers that distinguish "no text in this delta" from "an + # explicitly empty text delta" behave correctly. + # + # We only suppress the terminal chunk's ``text`` when the caller has + # confirmed that text deltas were already emitted earlier — otherwise + # (e.g. a degenerate stream that delivers the whole response in a + # single SSE event), passing it through is the only chance to surface it. + text: Optional[str] = ( + None if (is_terminal_consolidation and prior_text_emitted) else typed_chunk.text + ) + + # Tool calls on the terminal consolidation chunk (whether from + # `typed_chunk.toolCalls` or from `chatHistory`) typically restate what + # was already streamed in intermediate chunks. Re-emitting them would + # mint fresh `uuid4` IDs and cause downstream consumers to execute each + # tool call twice. We only suppress when the caller has confirmed that + # tool calls were already emitted earlier — otherwise (e.g. a short + # response that delivers tool calls exclusively on the terminal chunk), + # passing them through is the only chance to surface them. + cohere_tool_calls = ( + None + if (is_terminal_consolidation and prior_tool_calls_emitted) + else typed_chunk.toolCalls + ) + + tool_calls: Optional[List[Dict[str, Any]]] = None + if cohere_tool_calls: + tool_calls = [ + { + # Cohere protocol has no tool-call id, so we synthesize one + # deterministically from the call's content/position. A random + # uuid4 per chunk would cause downstream stream-mergers to + # treat each chunk as a distinct tool call. + "id": _synthesize_oci_tool_call_id( + i, tc.name, json.dumps(tc.parameters, sort_keys=True) + ), + "type": "function", + "function": { + "name": tc.name, + "arguments": json.dumps(tc.parameters), + }, + } + for i, tc in enumerate(cohere_tool_calls) + ] + + finish_reason = _normalize_oci_finish_reason(typed_chunk.finishReason) + + return ModelResponseStream( + choices=[ + StreamingChoices( + index=typed_chunk.index, + delta=Delta( + content=text, + tool_calls=tool_calls, + provider_specific_fields=None, + thinking_blocks=None, + reasoning_content=None, + ), + finish_reason=finish_reason, + ) + ] + ) diff --git a/litellm/llms/oci/chat/generic.py b/litellm/llms/oci/chat/generic.py new file mode 100644 index 00000000000..2cc1ac77a40 --- /dev/null +++ b/litellm/llms/oci/chat/generic.py @@ -0,0 +1,477 @@ +""" +OCI Generative AI — Generic-format chat transformation helpers. + +Handles message building, tool definition adaptation, non-streaming response +parsing, and streaming chunk parsing for models served with +``apiFormat="GENERIC"`` (e.g. Meta Llama, xAI Grok, Google Gemini). +""" + +import datetime +import hashlib +from typing import Any, Dict, List, Optional, Union + +import httpx +from pydantic import ValidationError + +from litellm.llms.oci.common_utils import ( + OCIError, + resolve_oci_schema_anyof, + resolve_oci_schema_refs, + sanitize_oci_schema, +) +from litellm.types.llms.oci import ( + OCICompletionResponse, + OCIContentPartUnion, + OCIImageContentPart, + OCIImageUrl, + OCIMessage, + OCIRoles, + OCIStreamChunk, + OCITextContentPart, + OCIToolCall, + OCIToolDefinition, + OCIVendors, +) +from litellm.types.llms.openai import AllMessageValues +from litellm.types.utils import ( + Delta, + ModelResponse, + ModelResponseStream, + StreamingChoices, +) +from litellm.types.utils import ChatCompletionMessageToolCall, Usage + +# Maps OpenAI role names to OCI GENERIC role names. +open_ai_to_generic_oci_role_map: Dict[str, OCIRoles] = { + "system": "SYSTEM", + "user": "USER", + "assistant": "ASSISTANT", + "tool": "TOOL", +} + + +# --------------------------------------------------------------------------- +# Message building +# --------------------------------------------------------------------------- + + +def adapt_messages_to_generic_oci_standard_content_message( + role: str, content: Union[str, list] +) -> OCIMessage: + """Convert a plain-text or multipart content message to OCI format.""" + new_content: List[OCIContentPartUnion] = [] + if isinstance(content, str): + return OCIMessage( + role=open_ai_to_generic_oci_role_map[role], + content=[OCITextContentPart(text=content)], + toolCalls=None, + toolCallId=None, + ) + + for content_item in content: + if not isinstance(content_item, dict): + raise OCIError( + status_code=400, message="Each content item must be a dictionary" + ) + + item_type = content_item.get("type") + if not isinstance(item_type, str): + raise OCIError( + status_code=400, + message="Each content item must have a string `type` field", + ) + if item_type not in ["text", "image_url"]: + raise OCIError( + status_code=400, + message=f"Content type `{item_type}` is not supported by OCI", + ) + + if item_type == "text": + text = content_item.get("text") + if not isinstance(text, str): + raise OCIError( + status_code=400, + message="Content item of type `text` must have a string `text` field", + ) + new_content.append(OCITextContentPart(text=text)) + + elif item_type == "image_url": + image_url = content_item.get("image_url") + if isinstance(image_url, dict): + image_url = image_url.get("url") + if not isinstance(image_url, str): + raise OCIError( + status_code=400, + message="Prop `image_url` must be a string or an object with a `url` property", + ) + new_content.append(OCIImageContentPart(imageUrl=OCIImageUrl(url=image_url))) + + return OCIMessage( + role=open_ai_to_generic_oci_role_map[role], + content=new_content, + toolCalls=None, + toolCallId=None, + ) + + +def adapt_messages_to_generic_oci_standard_tool_call( + role: str, tool_calls: list +) -> OCIMessage: + """Convert an assistant tool-call message to OCI format.""" + tool_calls_formatted = [] + for tool_call in tool_calls: + if not isinstance(tool_call, dict): + raise OCIError( + status_code=400, message="Each tool call must be a dictionary" + ) + if tool_call.get("type") != "function": + raise OCIError( + status_code=400, message="OCI only supports function tool calls" + ) + + tool_call_id = tool_call.get("id") + if not isinstance(tool_call_id, str): + raise OCIError(status_code=400, message="Tool call `id` must be a string") + + tool_function = tool_call.get("function") + if not isinstance(tool_function, dict): + raise OCIError( + status_code=400, message="Tool call `function` must be a dictionary" + ) + + function_name = tool_function.get("name") + if not isinstance(function_name, str): + raise OCIError( + status_code=400, message="Tool call `function.name` must be a string" + ) + + arguments = tool_call["function"].get("arguments", "{}") + if not isinstance(arguments, str): + raise OCIError( + status_code=400, + message="Tool call `function.arguments` must be a JSON string", + ) + + tool_calls_formatted.append( + OCIToolCall( + id=tool_call_id, + type="FUNCTION", + name=function_name, + arguments=arguments, + ) + ) + + return OCIMessage( + role=open_ai_to_generic_oci_role_map[role], + content=None, + toolCalls=tool_calls_formatted, + toolCallId=None, + ) + + +def adapt_messages_to_generic_oci_standard_tool_response( + role: str, tool_call_id: str, content: str +) -> OCIMessage: + """Convert a tool-result message to OCI format.""" + return OCIMessage( + role=open_ai_to_generic_oci_role_map[role], + content=[OCITextContentPart(text=content)], + toolCalls=None, + toolCallId=tool_call_id, + ) + + +def adapt_messages_to_generic_oci_standard( + messages: List[AllMessageValues], +) -> List[OCIMessage]: + """Convert an OpenAI-format message array to OCI GENERIC format.""" + new_messages = [] + for message in messages: + role = message["role"] + content = message.get("content") + tool_calls = message.get("tool_calls") + tool_call_id = message.get("tool_call_id") + + if role == "assistant" and tool_calls is not None: + if not isinstance(tool_calls, list): + raise OCIError( + status_code=400, message="Message `tool_calls` must be a list" + ) + new_messages.append( + adapt_messages_to_generic_oci_standard_tool_call(role, tool_calls) + ) + + elif role in ["system", "user", "assistant"] and content is not None: + if not isinstance(content, (str, list)): + raise OCIError( + status_code=400, + message="Message `content` must be a string or list of content parts", + ) + new_messages.append( + adapt_messages_to_generic_oci_standard_content_message(role, content) + ) + + elif role == "tool": + if not isinstance(tool_call_id, str): + raise OCIError( + status_code=400, + message="Tool result message must have a string `tool_call_id`", + ) + if not isinstance(content, str): + raise OCIError( + status_code=400, + message="Tool result message `content` must be a string", + ) + new_messages.append( + adapt_messages_to_generic_oci_standard_tool_response( + role, tool_call_id, content + ) + ) + + return new_messages + + +# --------------------------------------------------------------------------- +# Tool definition adaptation +# --------------------------------------------------------------------------- + + +def adapt_tool_definition_to_oci_standard( + tools: List[Dict], vendor: OCIVendors +) -> List[OCIToolDefinition]: + """Convert OpenAI-format tool definitions to OCI GENERIC format. + + Resolves ``$ref``/``$defs`` and ``anyOf`` that the OCI endpoint rejects. + """ + new_tools = [] + for tool in tools: + if tool["type"] != "function": + raise OCIError(status_code=400, message="OCI only supports function tools") + + tool_function = tool.get("function") + if not isinstance(tool_function, dict): + raise OCIError( + status_code=400, message="Tool `function` must be a dictionary" + ) + + raw_params = tool_function.get("parameters", {}) + resolved_params = sanitize_oci_schema( + resolve_oci_schema_anyof(resolve_oci_schema_refs(raw_params)) + ) + + new_tools.append( + OCIToolDefinition( + type="FUNCTION", + name=tool_function.get("name"), + description=tool_function.get("description", ""), + parameters=resolved_params, + ) + ) + + return new_tools + + +def _normalize_oci_finish_reason(raw: Optional[str]) -> Optional[str]: + """Map an OCI-specific finish reason to its OpenAI-standard equivalent. + + OCI emits ``COMPLETE`` / ``MAX_TOKENS`` / ``TOOL_CALL(S)`` plus a long tail + of error/cancel reasons (``ERROR``, ``ERROR_TOXIC``, ``ERROR_LIMIT``, + ``USER_CANCEL``, ``CONTENT_FILTERED``, ``CANCELLED``, ...). The OpenAI + spec only defines ``stop`` / ``length`` / ``tool_calls`` / ... — anything + else is collapsed to ``"stop"`` so downstream consumers switching on + ``finish_reason`` keep working. A ``None`` input passes through unchanged. + """ + if raw is None: + return None + if raw == "COMPLETE": + return "stop" + if raw == "MAX_TOKENS": + return "length" + if raw in ("TOOL_CALL", "TOOL_CALLS"): + return "tool_calls" + return "stop" + + +def _synthesize_oci_tool_call_id(position: int, name: str, arguments: str) -> str: + """Deterministic synthetic tool-call id derived from chunk content. + + Used as a fallback when OCI omits ``id`` (always the case for the OCI + Cohere protocol, occasionally the case for OCI GENERIC streaming chunks). + A random ``uuid4`` per chunk would cause downstream stream-merging + consumers — which key off the tool-call ``id`` — to treat re-emissions of + the same logical call (e.g. terminal consolidation chunks, retries) as + distinct calls. A content-derived digest stays stable across identical + re-emissions while differing across truly distinct calls. + """ + digest = hashlib.sha256( + f"{position}|{name}|{arguments}".encode("utf-8"), + usedforsecurity=False, + ).hexdigest()[:24] + return f"call_{digest}" + + +def adapt_tools_to_openai_standard( + tools: List[OCIToolCall], +) -> List[ChatCompletionMessageToolCall]: + """Convert OCI tool-call objects in a response to the OpenAI format.""" + return [ + ChatCompletionMessageToolCall( + id=tool.id or _synthesize_oci_tool_call_id(i, tool.name, tool.arguments), + type="function", + function={"name": tool.name, "arguments": tool.arguments}, + ) + for i, tool in enumerate(tools) + ] + + +# --------------------------------------------------------------------------- +# Response parsing +# --------------------------------------------------------------------------- + + +def handle_generic_response( + json_data: dict, + model: str, + model_response: ModelResponse, + raw_response: httpx.Response, +) -> ModelResponse: + """Parse a non-streaming GENERIC OCI response into a LiteLLM ModelResponse.""" + try: + completion_response = OCICompletionResponse(**json_data) + except (TypeError, ValidationError) as e: + raise OCIError( + message=f"Response cannot be casted to OCICompletionResponse: {str(e)}", + status_code=raw_response.status_code, + ) + + iso_str = completion_response.chatResponse.timeCreated + dt = datetime.datetime.fromisoformat(iso_str.replace("Z", "+00:00")) + model_response.created = int(dt.timestamp()) + model_response.model = completion_response.modelId + + if not completion_response.chatResponse.choices: + raise OCIError( + message="OCI response contained no choices", + status_code=raw_response.status_code, + ) + + response_choice = completion_response.chatResponse.choices[0] + message = model_response.choices[0].message # type: ignore + response_message = response_choice.message + if response_message is not None: + if response_message.content: + # Concatenate all text parts — matches the streaming handler, which + # iterates the full content array. Skips non-text parts (e.g. image + # parts) so a leading non-text part doesn't suppress trailing text. + text: Optional[str] = None + for item in response_message.content: + if isinstance(item, OCITextContentPart): + text = (text or "") + item.text + if text is not None: + message.content = text + if response_message.toolCalls: + message.tool_calls = adapt_tools_to_openai_standard( + response_message.toolCalls + ) + + model_response.choices[0].finish_reason = _normalize_oci_finish_reason( # type: ignore[union-attr,assignment] + response_choice.finishReason + ) + + oci_usage = completion_response.chatResponse.usage + reasoning_tokens: Optional[int] = None + if ( + oci_usage.completionTokensDetails + and oci_usage.completionTokensDetails.reasoningTokens is not None + ): + reasoning_tokens = oci_usage.completionTokensDetails.reasoningTokens + model_response.usage = Usage( # type: ignore[attr-defined] + prompt_tokens=oci_usage.promptTokens, + completion_tokens=oci_usage.completionTokens or 0, + total_tokens=oci_usage.totalTokens, + reasoning_tokens=reasoning_tokens, + ) + + return model_response + + +def handle_generic_stream_chunk(dict_chunk: dict) -> ModelResponseStream: + """Parse a single GENERIC SSE chunk into a LiteLLM ModelResponseStream.""" + # OCI streams tool calls progressively — early chunks may omit required fields. + if dict_chunk.get("message") and dict_chunk["message"].get("toolCalls"): + for tool_call in dict_chunk["message"]["toolCalls"]: + tool_call.setdefault("arguments", "") + tool_call.setdefault("id", "") + tool_call.setdefault("name", "") + + try: + typed_chunk = OCIStreamChunk(**dict_chunk) + except (TypeError, ValidationError) as e: + raise OCIError( + status_code=500, + message=f"Chunk cannot be parsed as OCIStreamChunk: {str(e)}", + ) + + if typed_chunk.index is None: + typed_chunk.index = 0 + + # Emit ``content=None`` rather than ``content=""`` on chunks with no text + # parts (e.g. tool-call-only or keep-alive chunks) so downstream + # stream-mergers that distinguish "no text in this delta" from "an + # explicitly empty text delta" behave correctly. + text: Optional[str] = None + if typed_chunk.message and typed_chunk.message.content: + for item in typed_chunk.message.content: + if isinstance(item, OCITextContentPart): + text = (text or "") + item.text + elif isinstance(item, OCIImageContentPart): + raise OCIError( + status_code=500, + message="OCI returned image content in a streaming response — not supported", + ) + else: + raise OCIError( + status_code=500, + message=f"Unsupported content type in OCI streaming response: {item.type}", + ) + + # Build plain tool-call dicts inline (matching the shape produced by + # ``handle_cohere_stream_chunk``) rather than calling + # ``adapt_tools_to_openai_standard`` and ``model_dump``-ing the typed + # objects. Both code paths feed ``Delta.tool_calls``, so emitting the + # same minimal ``{"id", "type", "function": {"name", "arguments"}}`` + # shape keeps downstream stream-mergers behaving identically across + # GENERIC and Cohere chunks. + tool_calls: Optional[List[Dict[str, Any]]] = None + if typed_chunk.message and typed_chunk.message.toolCalls: + tool_calls = [ + { + "id": tc.id or _synthesize_oci_tool_call_id(i, tc.name, tc.arguments), + "type": "function", + "function": { + "name": tc.name, + "arguments": tc.arguments, + }, + } + for i, tc in enumerate(typed_chunk.message.toolCalls) + ] + + finish_reason: Optional[str] = _normalize_oci_finish_reason( + typed_chunk.finishReason + ) + + return ModelResponseStream( + choices=[ + StreamingChoices( + index=typed_chunk.index, + delta=Delta( + content=text, + tool_calls=tool_calls, + provider_specific_fields=None, + thinking_blocks=None, + reasoning_content=None, + ), + finish_reason=finish_reason, + ) + ] + ) diff --git a/litellm/llms/oci/chat/transformation.py b/litellm/llms/oci/chat/transformation.py index 62104e921a4..f050f9eea36 100644 --- a/litellm/llms/oci/chat/transformation.py +++ b/litellm/llms/oci/chat/transformation.py @@ -1,20 +1,26 @@ -import base64 -import datetime -import hashlib +""" +OCI Generative AI — chat transformation orchestrator. + +This module wires together the Cohere-specific and Generic-model helpers to +implement the LiteLLM BaseConfig interface. Heavy-lifting lives in: + + - :mod:`litellm.llms.oci.chat.cohere` — Cohere message/tool/response logic + - :mod:`litellm.llms.oci.chat.generic` — Generic message/tool/response logic + - :mod:`litellm.llms.oci.common_utils` — auth, signing, schema utilities +""" + import json -from dataclasses import dataclass from typing import ( TYPE_CHECKING, Any, AsyncIterator, Dict, + Iterator, List, Optional, - Protocol, Tuple, Union, ) -from urllib.parse import urlparse import httpx @@ -28,43 +34,43 @@ get_async_httpx_client, version, ) -from litellm.llms.oci.common_utils import OCIError +from litellm.llms.oci.chat.cohere import ( + _extract_text_content, + adapt_messages_to_cohere_standard, + adapt_tool_definitions_to_cohere_standard, + handle_cohere_response, + handle_cohere_stream_chunk, +) +from litellm.llms.oci.chat.generic import ( + adapt_messages_to_generic_oci_standard, + adapt_tool_definition_to_oci_standard, + handle_generic_response, + handle_generic_stream_chunk, +) +from litellm.llms.oci.common_utils import ( + OCI_API_VERSION, + OCIError, + OCIRequestWrapper, # re-exported for backwards compatibility + get_oci_base_url, + resolve_oci_credentials, + sign_oci_request, + validate_oci_environment, +) from litellm.types.llms.oci import ( CohereChatRequest, - CohereMessage, - CohereChatResult, - CohereParameterDefinition, - CohereStreamChunk, - CohereTool, - CohereToolCall, OCIChatRequestPayload, OCICompletionPayload, - OCICompletionResponse, - OCIContentPartUnion, - OCIImageContentPart, - OCIImageUrl, - OCIMessage, - OCIRoles, OCIServingMode, - OCIStreamChunk, - OCITextContentPart, - OCIToolCall, - OCIToolDefinition, OCIVendors, ) from litellm.types.llms.openai import AllMessageValues from litellm.types.utils import ( - Delta, LlmProviders, ModelResponse, ModelResponseStream, - StreamingChoices, -) -from litellm.utils import ( - ChatCompletionMessageToolCall, - CustomStreamWrapper, - Usage, ) +from litellm.utils import supports_reasoning +from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper if TYPE_CHECKING: from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj @@ -74,142 +80,157 @@ LiteLLMLoggingObj = Any -class OCISignerProtocol(Protocol): - """ - Protocol for OCI request signers (e.g., oci.signer.Signer). - - This protocol defines the interface expected for OCI SDK signer objects. - Compatible with the OCI Python SDK's Signer class. - - See: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/signing.html - """ - - def do_request_sign( - self, request: Any, *, enforce_content_headers: bool = False - ) -> None: - """ - Sign an HTTP request by adding authentication headers. - - Args: - request: Request object with method, url, headers, body, and path_url attributes - enforce_content_headers: Whether to enforce content-type and content-length headers - """ - ... +# Streaming timeout — generous because OCI models may need to warm up on first request +STREAMING_TIMEOUT = 60 * 5 -@dataclass -class OCIRequestWrapper: - """ - Wrapper for HTTP requests compatible with OCI signer interface. +def _model_uses_max_completion_tokens(model: str) -> bool: + """Return True for OCI-hosted models that require ``maxCompletionTokens``. - This class wraps request data in a format compatible with OCI SDK signers, - which expect objects with method, url, headers, body, and path_url attributes. + Reasoning models on OCI (e.g. the OpenAI GPT-5 family) reject ``maxTokens`` + with HTTP 400 and require ``maxCompletionTokens`` per OpenAI's reasoning-API + convention. Driven by ``supports_reasoning`` in + ``model_prices_and_context_window.json`` so new model families are picked + up via a catalog update rather than a code change. """ + if not model: + return False + name = model[4:] if model.lower().startswith("oci/") else model + return supports_reasoning(model=name, custom_llm_provider="oci") - method: str - url: str - headers: dict - body: bytes - - @property - def path_url(self) -> str: - """Returns the path + query string for OCI signing.""" - parsed_url = urlparse(self.url) - return parsed_url.path + ("?" + parsed_url.query if parsed_url.query else "") +def _iter_sse_events(stream: Iterator[str]) -> Iterator[str]: + """Yield one ``data:`` SSE line at a time from a sync text stream. -def sha256_base64(data: bytes) -> str: - digest = hashlib.sha256(data).digest() - return base64.b64encode(digest).decode() - - -def build_signature_string(method, path, headers, signed_headers): - lines = [] - for header in signed_headers: - if header == "(request-target)": - value = f"{method.lower()} {path}" + The OCI streaming endpoint does not align SSE event boundaries with HTTP + read boundaries. A single read may carry multiple events, a single event + may straddle two reads, and some events arrive separated by only ``\\n`` + instead of ``\\n\\n``. This helper buffers across reads and yields each + complete ``data:`` line so JSON parsing downstream never sees a partial + payload. + """ + buffer = "" + for item in stream: + buffer += item + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + stripped = line.strip() + if stripped.startswith("data:"): + yield stripped + stripped = buffer.strip() + if stripped.startswith("data:"): + yield stripped + + +async def _aiter_sse_events(stream: AsyncIterator[str]) -> AsyncIterator[str]: + """Async twin of :func:`_iter_sse_events`.""" + buffer = "" + async for item in stream: + buffer += item + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + stripped = line.strip() + if stripped.startswith("data:"): + yield stripped + stripped = buffer.strip() + if stripped.startswith("data:"): + yield stripped + + +def _normalize_tool_choice(selected_params: Dict) -> None: + tc = selected_params.get("toolChoice") + if tc is None: + return + if isinstance(tc, str): + tc_map = { + "auto": {"type": "AUTO"}, + "none": {"type": "NONE"}, + "required": {"type": "REQUIRED"}, + "any": {"type": "REQUIRED"}, + } + selected_params["toolChoice"] = tc_map.get( + tc.lower(), {"type": "FUNCTION", "name": tc} + ) + return + if isinstance(tc, dict): + raw_type = tc.get("type") + if not isinstance(raw_type, str): + raise OCIError( + status_code=400, + message=f"Invalid tool_choice for OCI: missing or non-string 'type' in {tc!r}", + ) + upper = raw_type.upper() + if upper == "FUNCTION": + fn = tc.get("function") + name = fn.get("name") if isinstance(fn, dict) else tc.get("name") + if not (isinstance(name, str) and name): + raise OCIError( + status_code=400, + message="Invalid tool_choice for OCI: 'FUNCTION' type requires a non-empty function name", + ) + selected_params["toolChoice"] = {"type": "FUNCTION", "name": name} + elif upper in {"AUTO", "NONE", "REQUIRED"}: + selected_params["toolChoice"] = {"type": upper} else: - value = headers[header] - lines.append(f"{header}: {value}") - return "\n".join(lines) - - -def load_private_key_from_str(key_str: str): - try: - from cryptography.hazmat.primitives import serialization - from cryptography.hazmat.primitives.asymmetric import rsa - except ImportError as e: - raise ImportError( - "cryptography package is required for OCI authentication. " - "Please install it with: pip install cryptography" - ) from e - - key = serialization.load_pem_private_key( - key_str.encode("utf-8"), - password=None, + raise OCIError( + status_code=400, + message=( + f"Invalid tool_choice for OCI: unsupported type {raw_type!r}; " + "expected one of 'FUNCTION', 'AUTO', 'NONE', 'REQUIRED'" + ), + ) + return + raise OCIError( + status_code=400, + message=( + f"Invalid tool_choice for OCI: expected str or dict, got " + f"{type(tc).__name__}" + ), ) - if not isinstance(key, rsa.RSAPrivateKey): - raise TypeError( - "The provided private key is not an RSA key, which is required for OCI signing." - ) - return key - -def load_private_key_from_file(file_path: str): - """Loads a private key from a file path""" - try: - with open(file_path, "r", encoding="utf-8") as f: - key_str = f.read().strip() - except FileNotFoundError: - raise FileNotFoundError(f"Private key file not found: {file_path}") - except OSError as e: - raise OSError(f"Failed to read private key file '{file_path}': {e}") from e - if not key_str: - raise ValueError(f"Private key file is empty: {file_path}") - - return load_private_key_from_str(key_str) +def _normalize_response_format(selected_params: Dict, vendor: OCIVendors) -> None: + rf = selected_params.get("responseFormat") + if not isinstance(rf, dict) or "type" not in rf: + return + rf_payload = dict(rf) + selected_params["responseFormat"] = rf_payload + response_type = rf_payload["type"] + if "json_schema" in rf_payload: + raw_schema = rf_payload.pop("json_schema") + rf_payload["jsonSchema"] = ( + dict(raw_schema) if isinstance(raw_schema, dict) else raw_schema + ) + if vendor == OCIVendors.COHERE: + rf_payload["type"] = response_type + else: + fmt = response_type.upper() + rf_payload["type"] = "JSON_OBJECT" if fmt == "JSON" else fmt def get_vendor_from_model(model: str) -> OCIVendors: - """ - Extracts the vendor from the model name. + """Return the OCI vendor enum for a model name. - OCI GenAI API uses two apiFormat values: - - "COHERE" for Cohere models (command-r, command-a, etc.) - - "GENERIC" for all other models (Meta Llama, xAI Grok, Google Gemini, etc.) + OCI GenAI uses two ``apiFormat`` values: - Args: - model (str): The model name (e.g., "cohere.command-a-03-2025", "meta.llama-3.3-70b-instruct"). - Returns: - OCIVendors: The vendor enum value. + - ``"COHERE"`` for Cohere models (``cohere.*``) + - ``"GENERIC"`` for all others (Meta Llama, xAI Grok, Google Gemini, …) """ - vendor = model.split(".")[0].lower() + name = model[4:] if model.lower().startswith("oci/") else model + vendor = name.split(".")[0].lower() if vendor == "cohere": return OCIVendors.COHERE - else: - return OCIVendors.GENERIC - - -# 5 minute timeout (models may need to load) -STREAMING_TIMEOUT = 60 * 5 + return OCIVendors.GENERIC class OCIChatConfig(BaseConfig): - """ - Configuration class for OCI's API interface. - """ + """LiteLLM BaseConfig implementation for OCI Generative AI chat.""" - def __init__( - self, - ) -> None: - locals_ = locals().copy() - for key, value in locals_.items(): - if key != "self" and value is not None: - setattr(self.__class__, key, value) - # mark the class as using a custom stream wrapper because the default only iterates on lines - setattr(self.__class__, "has_custom_stream_wrapper", True) + @property + def has_custom_stream_wrapper(self) -> bool: + return True + def __init__(self) -> None: self.openai_to_oci_generic_param_map = { "stream": "isStream", "max_tokens": "maxTokens", @@ -221,6 +242,7 @@ def __init__( "logit_bias": "logitBias", "n": "numGenerations", "presence_penalty": "presencePenalty", + "reasoning_effort": "reasoningEffort", "seed": "seed", "stop": "stop", "tool_choice": "toolChoice", @@ -239,25 +261,43 @@ def __init__( "response_format": "responseFormat", } - # Cohere and Gemini use the same parameter mapping as GENERIC - self.openai_to_oci_cohere_param_map = ( - self.openai_to_oci_generic_param_map.copy() - ) + # Cohere param map differs from GENERIC in three ways: + # - tool_choice is unsupported + # - stop sequences key is "stopSequences" not "stop" + # - n (numGenerations) is GENERIC-only + # The unsupported keys are kept in the map with value ``False`` so + # ``map_openai_params`` either drops them (under drop_params) or raises + # a clear error, rather than silently passing them through. + self.openai_to_oci_cohere_param_map = { + k: ("stopSequences" if k == "stop" else v) + for k, v in self.openai_to_oci_generic_param_map.items() + } + self.openai_to_oci_cohere_param_map["tool_choice"] = False + self.openai_to_oci_cohere_param_map["n"] = False + # ``top_k`` is not a standard OpenAI param, but Cohere's chat request + # accepts ``topK`` and LiteLLM commonly forwards ``top_k`` as a + # passthrough param. Cohere-only — ``OCIChatRequestPayload`` (GENERIC) + # has no ``topK`` field. + self.openai_to_oci_cohere_param_map["top_k"] = "topK" + # OCI Cohere models are not reasoning models; mark reasoning_effort + # explicitly unsupported so callers either get a clear error or have + # the param dropped under drop_params, rather than silently passing + # through and tripping Pydantic validation on CohereChatRequest. + self.openai_to_oci_cohere_param_map["reasoning_effort"] = False + # CohereChatRequest has no logProbs/logitBias fields, so passing these + # through would be silently dropped by Pydantic. Mark them unsupported + # so get_supported_openai_params doesn't advertise them and callers + # get a clear error (or drop_params behaviour) instead. + self.openai_to_oci_cohere_param_map["logprobs"] = False + self.openai_to_oci_cohere_param_map["logit_bias"] = False def get_supported_openai_params(self, model: str) -> List[str]: - supported_params = [] - vendor = get_vendor_from_model(model) - if vendor == OCIVendors.COHERE: - open_ai_to_oci_param_map = self.openai_to_oci_cohere_param_map - open_ai_to_oci_param_map.pop("tool_choice") - open_ai_to_oci_param_map.pop("max_retries") - else: - open_ai_to_oci_param_map = self.openai_to_oci_generic_param_map - for key, value in open_ai_to_oci_param_map.items(): - if value: - supported_params.append(key) - - return supported_params + param_map = ( + self.openai_to_oci_cohere_param_map + if get_vendor_from_model(model) == OCIVendors.COHERE + else self.openai_to_oci_generic_param_map + ) + return [key for key, value in param_map.items() if value] def map_openai_params( self, @@ -268,238 +308,34 @@ def map_openai_params( ) -> dict: adapted_params = {} vendor = get_vendor_from_model(model) - if vendor == OCIVendors.COHERE: - open_ai_to_oci_param_map = self.openai_to_oci_cohere_param_map - else: - open_ai_to_oci_param_map = self.openai_to_oci_generic_param_map - - all_params = {**non_default_params, **optional_params} - - for key, value in all_params.items(): - alias = open_ai_to_oci_param_map.get(key) + param_map = ( + self.openai_to_oci_cohere_param_map + if vendor == OCIVendors.COHERE + else self.openai_to_oci_generic_param_map + ) + for key, value in {**non_default_params, **optional_params}.items(): + alias = param_map.get(key) if alias is False: - # Workaround for mypy issue if drop_params or litellm.drop_params: continue - raise Exception(f"param `{key}` is not supported on OCI") - + raise OCIError( + status_code=400, + message=f"param `{key}` is not supported on OCI", + ) if alias is None: adapted_params[key] = value continue - adapted_params[alias] = value - + # Preserve the original OpenAI ``response_format`` key alongside the + # OCI-mapped ``responseFormat`` so downstream litellm framework code + # (e.g. ``json_mode`` detection, logging) that inspects + # ``optional_params["response_format"]`` continues to work. if alias == "responseFormat": adapted_params["response_format"] = value return adapted_params - def _sign_with_oci_signer( - self, - headers: dict, - optional_params: dict, - request_data: dict, - api_base: str, - ) -> Tuple[dict, bytes]: - """ - Sign request using OCI SDK Signer object. - - Args: - headers: Request headers to be signed - optional_params: Optional parameters including oci_signer - request_data: The request body dict to be sent in HTTP request - api_base: The complete URL for the HTTP request - - Returns: - Tuple of (signed_headers, encoded_body) - - Raises: - OCIError: If signing fails - ValueError: If HTTP method is unsupported - """ - oci_signer = optional_params.get("oci_signer") - body = json.dumps(request_data).encode("utf-8") - method = str(optional_params.get("method", "POST")).upper() - - if method not in ["POST", "GET", "PUT", "DELETE", "PATCH"]: - raise ValueError(f"Unsupported HTTP method: {method}") - - prepared_headers = headers.copy() - prepared_headers.setdefault("content-type", "application/json") - prepared_headers.setdefault("content-length", str(len(body))) - - request_wrapper = OCIRequestWrapper( - method=method, url=api_base, headers=prepared_headers, body=body - ) - - if oci_signer is None: - raise ValueError( - "oci_signer cannot be None when calling _sign_with_oci_signer" - ) - - try: - oci_signer.do_request_sign(request_wrapper, enforce_content_headers=True) - except Exception as e: - raise OCIError( - status_code=500, - message=( - f"Failed to sign request with provided oci_signer: {str(e)}. " - "The signer must implement the OCI SDK Signer interface with a " - "do_request_sign(request, enforce_content_headers=True) method. " - "See: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/signing.html" - ), - ) from e - - headers.update(request_wrapper.headers) - return headers, body - - def _sign_with_manual_credentials( - self, - headers: dict, - optional_params: dict, - request_data: dict, - api_base: str, - ) -> Tuple[dict, None]: - """ - Sign request using manual OCI credentials. - - Args: - headers: Request headers to be signed - optional_params: Optional parameters including OCI credentials - request_data: The request body dict to be sent in HTTP request - api_base: The complete URL for the HTTP request - - Returns: - Tuple of (signed_headers, None) - - Raises: - Exception: If required credentials are missing - ImportError: If cryptography package is not installed - """ - oci_region = optional_params.get("oci_region", "us-ashburn-1") - api_base = ( - api_base - or litellm.api_base - or f"https://inference.generativeai.{oci_region}.oci.oraclecloud.com" - ) - oci_user = optional_params.get("oci_user") - oci_fingerprint = optional_params.get("oci_fingerprint") - oci_tenancy = optional_params.get("oci_tenancy") - oci_key = optional_params.get("oci_key") - oci_key_file = optional_params.get("oci_key_file") - - if ( - not oci_user - or not oci_fingerprint - or not oci_tenancy - or not (oci_key or oci_key_file) - ): - raise Exception( - "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, " - "and at least one of oci_key or oci_key_file." - ) - - method = str(optional_params.get("method", "POST")).upper() - body = json.dumps(request_data).encode("utf-8") - parsed = urlparse(api_base) - path = parsed.path or "/" - host = parsed.netloc - - date = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") - content_type = headers.get("content-type", "application/json") - content_length = str(len(body)) - x_content_sha256 = sha256_base64(body) - - headers_to_sign = { - "date": date, - "host": host, - "content-type": content_type, - "content-length": content_length, - "x-content-sha256": x_content_sha256, - } - - signed_headers = [ - "date", - "(request-target)", - "host", - "content-length", - "content-type", - "x-content-sha256", - ] - signing_string = build_signature_string( - method, path, headers_to_sign, signed_headers - ) - - try: - from cryptography.hazmat.primitives import hashes - from cryptography.hazmat.primitives.asymmetric import padding - except ImportError as e: - raise ImportError( - "cryptography package is required for OCI authentication. " - "Please install it with: pip install cryptography" - ) from e - - # Handle oci_key - it should be a string (PEM content) - oci_key_content = None - if oci_key: - if isinstance(oci_key, str): - oci_key_content = oci_key - # Fix common issues with PEM content - # Replace escaped newlines with actual newlines - oci_key_content = oci_key_content.replace("\\n", "\n") - # Ensure proper line endings - if "\r\n" in oci_key_content: - oci_key_content = oci_key_content.replace("\r\n", "\n") - else: - raise OCIError( - status_code=400, - message=f"oci_key must be a string containing the PEM private key content. " - f"Got type: {type(oci_key).__name__}", - ) - - private_key = ( - load_private_key_from_str(oci_key_content) - if oci_key_content - else load_private_key_from_file(oci_key_file) if oci_key_file else None - ) - - if private_key is None: - raise OCIError( - status_code=400, - message="Private key is required for OCI authentication. Please provide either oci_key or oci_key_file.", - ) - - signature = private_key.sign( - signing_string.encode("utf-8"), - padding.PKCS1v15(), - hashes.SHA256(), - ) - signature_b64 = base64.b64encode(signature).decode() - - key_id = f"{oci_tenancy}/{oci_user}/{oci_fingerprint}" - - authorization = ( - 'Signature version="1",' - f'keyId="{key_id}",' - 'algorithm="rsa-sha256",' - f'headers="{" ".join(signed_headers)}",' - f'signature="{signature_b64}"' - ) - - headers.update( - { - "authorization": authorization, - "date": date, - "host": host, - "content-type": content_type, - "content-length": content_length, - "x-content-sha256": x_content_sha256, - } - ) - - return headers, None - def sign_request( self, headers: dict, @@ -510,61 +346,16 @@ def sign_request( model: Optional[str] = None, stream: Optional[bool] = None, fake_stream: Optional[bool] = None, - ) -> Tuple[dict, Optional[bytes]]: - """ - Sign the OCI request by adding authentication headers. - - Supports two signing modes: - 1. OCI SDK Signer: Use an oci_signer object to sign the request - 2. Manual Signing: Use OCI credentials to manually sign the request - - Args: - headers: Request headers to be signed - optional_params: Optional parameters including auth credentials or oci_signer - request_data: The request body dict to be sent in HTTP request - api_base: The complete URL for the HTTP request - api_key: Optional API key (not used for OCI) - model: Optional model name - stream: Optional streaming flag - fake_stream: Optional fake streaming flag - - Returns: - Tuple of (signed_headers, encoded_body): - - If oci_signer is provided: Returns (headers, body) where body is the encoded JSON - - If manual credentials are provided: Returns (headers, None) as body is not returned - for the manual signing path - - Raises: - OCIError: If signing fails with oci_signer - Exception: If required credentials are missing - ImportError: If cryptography package is not installed (manual signing only) - - Example: - >>> from oci.signer import Signer - >>> signer = Signer( - ... tenancy="ocid1.tenancy.oc1..", - ... user="ocid1.user.oc1..", - ... fingerprint="xx:xx:xx", - ... private_key_file_location="~/.oci/key.pem" - ... ) - >>> headers, body = config.sign_request( - ... headers={}, - ... optional_params={"oci_signer": signer}, - ... request_data={"message": "Hello"}, - ... api_base="https://inference.generativeai.us-ashburn-1.oci.oraclecloud.com/..." - ... ) - """ - oci_signer = optional_params.get("oci_signer") - - # If a signer is provided, use it for request signing - if oci_signer is not None: - return self._sign_with_oci_signer( - headers, optional_params, request_data, api_base - ) - - # Standard manual credential signing - return self._sign_with_manual_credentials( - headers, optional_params, request_data, api_base + ) -> Tuple[dict, bytes]: + return sign_oci_request( + headers=headers, + optional_params=optional_params, + request_data=request_data, + api_base=api_base, + api_key=api_key, + model=model, + stream=stream, + fake_stream=fake_stream, ) def validate_environment( @@ -577,80 +368,35 @@ def validate_environment( api_key: Optional[str] = None, api_base: Optional[str] = None, ) -> dict: - """ - Validate the OCI environment and credentials. - - Supports two authentication modes: - 1. OCI SDK Signer: Pass an oci_signer object (e.g., oci.signer.Signer) - 2. Manual Credentials: Pass oci_user, oci_fingerprint, oci_tenancy, and oci_key/oci_key_file - - Args: - headers: Request headers to populate - model: Model name - messages: List of chat messages - optional_params: Optional parameters including authentication credentials - litellm_params: LiteLLM parameters - api_key: Optional API key (not used for OCI) - api_base: Optional API base URL - - Returns: - Updated headers dict - - Raises: - Exception: If required parameters are missing or invalid - """ - oci_signer = optional_params.get("oci_signer") - oci_region = optional_params.get("oci_region", "us-ashburn-1") - - # Determine api_base - api_base = ( - api_base - or litellm.api_base - or f"https://inference.generativeai.{oci_region}.oci.oraclecloud.com" - ) - - if not api_base: - raise Exception( - "Either `api_base` must be provided or `litellm.api_base` must be set. " - "Alternatively, you can set the `oci_region` optional parameter to use the default OCI region." - ) - - # Validate credentials only if signer is not provided - if oci_signer is None: - oci_user = optional_params.get("oci_user") - oci_fingerprint = optional_params.get("oci_fingerprint") - oci_tenancy = optional_params.get("oci_tenancy") - oci_key = optional_params.get("oci_key") - oci_key_file = optional_params.get("oci_key_file") - oci_compartment_id = optional_params.get("oci_compartment_id") - - if ( - not oci_user - or not oci_fingerprint - or not oci_tenancy - or not (oci_key or oci_key_file) - or not oci_compartment_id - ): - raise Exception( - "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, oci_compartment_id " - "and at least one of oci_key or oci_key_file. " - "Alternatively, provide an oci_signer object from the OCI SDK." - ) - - # Common header setup - headers.update( - { - "content-type": "application/json", - "user-agent": f"litellm/{version}", - } - ) - if not messages: - raise Exception( - "kwarg `messages` must be an array of messages that follow the openai chat standard" + raise OCIError( + status_code=400, + message="kwarg `messages` must be an array of messages that follow the openai chat standard", ) - - return headers + if optional_params.get("oci_signer") is None: + creds = resolve_oci_credentials(optional_params) + missing = [ + k + for k in ( + "oci_user", + "oci_fingerprint", + "oci_tenancy", + "oci_compartment_id", + ) + if not creds.get(k) + ] + if missing or not (creds.get("oci_key") or creds.get("oci_key_file")): + raise OCIError( + status_code=401, + message=( + "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, " + "oci_compartment_id and at least one of oci_key or oci_key_file. " + "These can be supplied via optional_params or via OCI_USER, OCI_FINGERPRINT, " + "OCI_TENANCY, OCI_COMPARTMENT_ID, OCI_KEY_FILE environment variables. " + "Alternatively, provide an oci_signer object from the OCI SDK." + ), + ) + return validate_oci_environment(headers, optional_params, api_key) def get_complete_url( self, @@ -661,43 +407,63 @@ def get_complete_url( litellm_params: dict, stream: Optional[bool] = None, ) -> str: - oci_region = optional_params.get("oci_region", "us-ashburn-1") - return f"https://inference.generativeai.{oci_region}.oci.oraclecloud.com/20231130/actions/chat" + base = get_oci_base_url(optional_params, api_base or litellm.api_base) + return f"{base}/{OCI_API_VERSION}/actions/chat" + + def _get_optional_params( + self, vendor: OCIVendors, optional_params: dict, model: str = "" + ) -> Dict: + param_map = ( + self.openai_to_oci_cohere_param_map + if vendor == OCIVendors.COHERE + else self.openai_to_oci_generic_param_map + ) + selected_params: Dict = {} + + # OpenAI reasoning models on OCI (e.g. GPT-5 family) reject "maxTokens" + # and require "maxCompletionTokens" per OCI's /20231130/Chat schema. + # Driven by the supports_reasoning flag in the model catalog. Cohere's + # endpoint uses "maxTokens" regardless, so the override is GENERIC-only. + max_tokens_key = ( + "maxCompletionTokens" + if vendor != OCIVendors.COHERE + and model + and _model_uses_max_completion_tokens(model) + else "maxTokens" + ) - def _get_optional_params(self, vendor: OCIVendors, optional_params: dict) -> Dict: - selected_params = {} - if vendor == OCIVendors.COHERE: - open_ai_to_oci_param_map = self.openai_to_oci_cohere_param_map - # remove tool_choice from the map - open_ai_to_oci_param_map.pop("tool_choice") - # Add default values for Cohere API - selected_params = { - "maxTokens": 600, - "temperature": 1, - "topK": 0, - "topP": 0.75, - "frequencyPenalty": 0, - } - else: - open_ai_to_oci_param_map = self.openai_to_oci_generic_param_map - - # Map OpenAI params to OCI params - for openai_key, oci_key in open_ai_to_oci_param_map.items(): - if oci_key and openai_key in optional_params: - selected_params[oci_key] = optional_params[openai_key] # type: ignore[index] - - # Also check for already-mapped OCI params (for backward compatibility) - for oci_value in open_ai_to_oci_param_map.values(): - if ( - oci_value - and oci_value in optional_params - and oci_value not in selected_params - ): - selected_params[oci_value] = optional_params[oci_value] # type: ignore[index] + # ``map_openai_params`` runs before ``transform_request`` (and thus + # before this helper), so by the time we see ``optional_params`` the + # OpenAI keys have already been translated to their OCI aliases. + # We still accept the original OpenAI key as a fallback for callers + # that build ``optional_params`` directly, with OpenAI keys winning + # over OCI aliases when both happen to be present. The first OpenAI + # key reaching a given OCI target wins, so ``max_tokens`` / + # ``max_completion_tokens`` (both → ``maxTokens``) don't double-write. + for openai_key, oci_alias in param_map.items(): + if not oci_alias: + continue + target = max_tokens_key if oci_alias == "maxTokens" else oci_alias + if target in selected_params: + continue + if openai_key in optional_params: + selected_params[target] = optional_params[openai_key] # type: ignore[index] + elif oci_alias in optional_params: + selected_params[target] = optional_params[oci_alias] # type: ignore[index] + + # OCI expects uppercase reasoning levels (LOW/MEDIUM/HIGH/NONE); OpenAI + # clients send lowercase. OpenAI's "disable" maps to OCI's "NONE". + if "reasoningEffort" in selected_params: + effort = selected_params["reasoningEffort"] + if isinstance(effort, str): + normalized = effort.upper() + if normalized == "DISABLE": + normalized = "NONE" + selected_params["reasoningEffort"] = normalized if "tools" in selected_params: if vendor == OCIVendors.COHERE: - selected_params["tools"] = self.adapt_tool_definitions_to_cohere_standard( # type: ignore[assignment] + selected_params["tools"] = adapt_tool_definitions_to_cohere_standard( # type: ignore[assignment] selected_params["tools"] # type: ignore[arg-type] ) else: @@ -705,145 +471,14 @@ def _get_optional_params(self, vendor: OCIVendors, optional_params: dict) -> Dic selected_params["tools"], vendor # type: ignore[arg-type] ) - # Transform response_format type to OCI uppercase format - if "responseFormat" in selected_params: - rf = selected_params["responseFormat"] - if isinstance(rf, dict) and "type" in rf: - rf_payload = dict(rf) - selected_params["responseFormat"] = rf_payload - - response_type = rf_payload["type"] - schema_payload: Optional[Any] = None - - if "json_schema" in rf_payload: - raw_schema_payload = rf_payload.pop("json_schema") - if isinstance(raw_schema_payload, dict): - schema_payload = dict(raw_schema_payload) - else: - schema_payload = raw_schema_payload - - if schema_payload is not None: - rf_payload["jsonSchema"] = schema_payload - - if vendor == OCIVendors.COHERE: - # Cohere expects lower-case type values - rf_payload["type"] = response_type - else: - format_type = response_type.upper() - if format_type == "JSON": - format_type = "JSON_OBJECT" - rf_payload["type"] = format_type - - return selected_params - - def adapt_messages_to_cohere_standard( - self, messages: List[AllMessageValues] - ) -> List[CohereMessage]: - """Build chat history for Cohere models.""" - chat_history = [] - for msg in messages[:-1]: # All messages except the last one - role = msg.get("role") - content = msg.get("content") - - if isinstance(content, list): - # Extract text from content array - text_content = "" - for content_item in content: - if ( - isinstance(content_item, dict) - and content_item.get("type") == "text" - ): - text_content += content_item.get("text", "") - content = text_content - - # Ensure content is a string - if not isinstance(content, str): - content = str(content) if content is not None else "" - - # Handle tool calls - tool_calls: Optional[List[CohereToolCall]] = None - if role == "assistant" and "tool_calls" in msg and msg.get("tool_calls"): # type: ignore[union-attr,typeddict-item] - tool_calls = [] - for tool_call in msg["tool_calls"]: # type: ignore[union-attr,typeddict-item] - # Parse arguments if they're a JSON string - raw_arguments: Any = tool_call.get("function", {}).get( - "arguments", {} - ) - if isinstance(raw_arguments, str): - try: - arguments: Dict[str, Any] = json.loads(raw_arguments) - except json.JSONDecodeError: - arguments = {} - else: - arguments = raw_arguments - - tool_calls.append( - CohereToolCall( - name=str(tool_call.get("function", {}).get("name", "")), - parameters=arguments, - ) - ) - - if role == "user": - chat_history.append(CohereMessage(role="USER", message=content)) - elif role == "assistant": - chat_history.append( - CohereMessage(role="CHATBOT", message=content, toolCalls=tool_calls) - ) - elif role == "tool": - # Tool messages need special handling - chat_history.append( - CohereMessage( - role="TOOL", - message=content, - toolCalls=None, # Tool messages don't have tool calls - ) - ) + # Normalise tool_choice to OCI's flat uppercase dict form + # ({"type": "AUTO"|"NONE"|"REQUIRED"} or {"type": "FUNCTION", "name": ""}). + # OCI rejects both the OpenAI string and the nested OpenAI dict shape. + _normalize_tool_choice(selected_params) - return chat_history - - def adapt_tool_definitions_to_cohere_standard( - self, tools: List[Dict[str, Any]] - ) -> List[CohereTool]: - """Adapt tool definitions to Cohere format.""" - cohere_tools = [] - for tool in tools: - function_def = tool.get("function", {}) - parameters = function_def.get("parameters", {}).get("properties", {}) - required = function_def.get("parameters", {}).get("required", []) - - parameter_definitions = {} - for param_name, param_schema in parameters.items(): - parameter_definitions[param_name] = CohereParameterDefinition( - description=param_schema.get("description", ""), - type=param_schema.get("type", "string"), - isRequired=param_name in required, - ) + _normalize_response_format(selected_params, vendor) - cohere_tools.append( - CohereTool( - name=function_def.get("name", ""), - description=function_def.get("description", ""), - parameterDefinitions=parameter_definitions, - ) - ) - - return cohere_tools - - def _extract_text_content(self, content: Any) -> str: - """Extract text content from message content.""" - if isinstance(content, str): - return content - elif isinstance(content, list): - text_content = "" - for content_item in content: - if ( - isinstance(content_item, dict) - and content_item.get("type") == "text" - ): - text_content += content_item.get("text", "") - return text_content - return str(content) + return selected_params def transform_request( self, @@ -853,186 +488,78 @@ def transform_request( litellm_params: dict, headers: dict, ) -> dict: - oci_compartment_id = optional_params.get("oci_compartment_id", None) + creds = resolve_oci_credentials(optional_params) + oci_compartment_id = creds["oci_compartment_id"] if not oci_compartment_id: - raise Exception("kwarg `oci_compartment_id` is required for OCI requests") + raise OCIError( + status_code=400, + message=( + "oci_compartment_id is required for OCI chat requests. " + "Pass it as optional_params or set the OCI_COMPARTMENT_ID env var." + ), + ) vendor = get_vendor_from_model(model) oci_serving_mode = optional_params.get("oci_serving_mode", "ON_DEMAND") if oci_serving_mode not in ["ON_DEMAND", "DEDICATED"]: - raise Exception( - "kwarg `oci_serving_mode` must be either 'ON_DEMAND' or 'DEDICATED'" + raise OCIError( + status_code=400, + message="kwarg `oci_serving_mode` must be either 'ON_DEMAND' or 'DEDICATED'", ) if oci_serving_mode == "DEDICATED": - oci_endpoint_id = optional_params.get("oci_endpoint_id", model) - servingMode = OCIServingMode( + serving_mode = OCIServingMode( servingType="DEDICATED", - endpointId=oci_endpoint_id, + endpointId=optional_params.get("oci_endpoint_id", model), ) else: - servingMode = OCIServingMode( - servingType="ON_DEMAND", - modelId=model, - ) + serving_mode = OCIServingMode(servingType="ON_DEMAND", modelId=model) - # Build request based on vendor type if vendor == OCIVendors.COHERE: - # For Cohere, we need to use the specific Cohere format - # Extract the last user message as the main message - user_messages = [msg for msg in messages if msg.get("role") == "user"] + user_messages = [m for m in messages if m.get("role") == "user"] if not user_messages: - raise Exception("No user message found for Cohere model") + raise OCIError( + status_code=400, + message="No user message found — Cohere models require at least one user message", + ) - # Extract system messages into preambleOverride - system_messages = [msg for msg in messages if msg.get("role") == "system"] + system_messages = [m for m in messages if m.get("role") == "system"] preamble_override = None if system_messages: preamble = "\n".join( - self._extract_text_content(msg["content"]) - for msg in system_messages + _extract_text_content(m["content"]) for m in system_messages ) if preamble: preamble_override = preamble - # Create Cohere-specific chat request - optional_cohere_params = self._get_optional_params( - OCIVendors.COHERE, optional_params - ) chat_request = CohereChatRequest( apiFormat="COHERE", - message=self._extract_text_content(user_messages[-1]["content"]), - chatHistory=self.adapt_messages_to_cohere_standard(messages), + message=_extract_text_content(user_messages[-1]["content"]), + chatHistory=adapt_messages_to_cohere_standard( + [m for m in messages if m.get("role") != "system"] + ), preambleOverride=preamble_override, - **optional_cohere_params, + **self._get_optional_params(OCIVendors.COHERE, optional_params, model), ) - data = OCICompletionPayload( compartmentId=oci_compartment_id, - servingMode=servingMode, + servingMode=serving_mode, chatRequest=chat_request, ) else: - # Use generic format for other vendors data = OCICompletionPayload( compartmentId=oci_compartment_id, - servingMode=servingMode, + servingMode=serving_mode, chatRequest=OCIChatRequestPayload( apiFormat=vendor.value, messages=adapt_messages_to_generic_oci_standard(messages), - **self._get_optional_params(vendor, optional_params), + **self._get_optional_params(vendor, optional_params, model), ), ) return data.model_dump(exclude_none=True) - def _handle_cohere_response( - self, json_response: dict, model: str, model_response: ModelResponse - ) -> ModelResponse: - """Handle Cohere-specific response format.""" - cohere_response = CohereChatResult(**json_response) - # Cohere response format (uses camelCase) - model_id = model - - # Set basic response info - model_response.model = model_id - model_response.created = int(datetime.datetime.now().timestamp()) - - # Extract the response text - response_text = cohere_response.chatResponse.text - oci_finish_reason = cohere_response.chatResponse.finishReason - - # Map finish reason - if oci_finish_reason == "COMPLETE": - finish_reason = "stop" - elif oci_finish_reason == "MAX_TOKENS": - finish_reason = "length" - else: - finish_reason = "stop" - - # Handle tool calls - tool_calls: Optional[List[Dict[str, Any]]] = None - if cohere_response.chatResponse.toolCalls: - tool_calls = [] - for tool_call in cohere_response.chatResponse.toolCalls: - tool_calls.append( - { - "id": f"call_{len(tool_calls)}", # Generate a simple ID - "type": "function", - "function": { - "name": tool_call.name, - "arguments": json.dumps(tool_call.parameters), - }, - } - ) - - # Create choice - from litellm.types.utils import Choices - - choice = Choices( - index=0, - message={ - "role": "assistant", - "content": response_text, - "tool_calls": tool_calls, - }, - finish_reason=finish_reason, - ) - model_response.choices = [choice] - - # Extract usage info - usage_info = cohere_response.chatResponse.usage - from litellm.types.utils import Usage - - model_response.usage = Usage( # type: ignore[attr-defined] - prompt_tokens=usage_info.promptTokens, # type: ignore[union-attr] - completion_tokens=usage_info.completionTokens, # type: ignore[union-attr] - total_tokens=usage_info.totalTokens, # type: ignore[union-attr] - ) - - return model_response - - def _handle_generic_response( - self, - json: dict, - model: str, - model_response: ModelResponse, - raw_response: httpx.Response, - ) -> ModelResponse: - """Handle generic OCI response format.""" - try: - completion_response = OCICompletionResponse(**json) - except TypeError as e: - raise OCIError( - message=f"Response cannot be casted to OCICompletionResponse: {str(e)}", - status_code=raw_response.status_code, - ) - - iso_str = completion_response.chatResponse.timeCreated - dt = datetime.datetime.fromisoformat(iso_str.replace("Z", "+00:00")) - model_response.created = int(dt.timestamp()) - - model_response.model = completion_response.modelId - - message = model_response.choices[0].message # type: ignore - response_message = completion_response.chatResponse.choices[0].message - if response_message.content and response_message.content[0].type == "TEXT": - message.content = response_message.content[0].text - if response_message.toolCalls: - message.tool_calls = adapt_tools_to_openai_standard( - response_message.toolCalls - ) - - usage = Usage( - prompt_tokens=completion_response.chatResponse.usage.promptTokens, - completion_tokens=completion_response.chatResponse.usage.completionTokens, - total_tokens=completion_response.chatResponse.usage.totalTokens, - ) - model_response.usage = usage # type: ignore - - return model_response - def transform_response( self, model: str, @@ -1047,34 +574,31 @@ def transform_response( api_key: Optional[str] = None, json_mode: Optional[bool] = None, ) -> ModelResponse: - json = raw_response.json() # noqa: F811 + response_json = raw_response.json() - error = json.get("error") - - if error is not None: + if not isinstance(response_json, dict): raise OCIError( - message=str(json["error"]), + message="Invalid response format from OCI", status_code=raw_response.status_code, ) - if not isinstance(json, dict): + if response_json.get("error") is not None: raise OCIError( - message="Invalid response format from OCI", + message=str(response_json["error"]), status_code=raw_response.status_code, ) vendor = get_vendor_from_model(model) - - # Handle response based on vendor type if vendor == OCIVendors.COHERE: - model_response = self._handle_cohere_response(json, model, model_response) + model_response = handle_cohere_response( + response_json, model, model_response, raw_response + ) else: - model_response = self._handle_generic_response( - json, model, model_response, raw_response + model_response = handle_generic_response( + response_json, model, model_response, raw_response ) model_response._hidden_params["additional_headers"] = raw_response.headers - return model_response @track_llm_api_timing() @@ -1091,8 +615,6 @@ def get_sync_custom_stream_wrapper( json_mode: Optional[bool] = None, signed_json_body: Optional[bytes] = None, ) -> "OCIStreamWrapper": - if "stream" in data: - del data["stream"] if client is None or isinstance(client, AsyncHTTPHandler): client = _get_httpx_client(params={}) @@ -1100,7 +622,11 @@ def get_sync_custom_stream_wrapper( response = client.post( api_base, headers=headers, - data=json.dumps(data), + data=( + signed_json_body + if signed_json_body is not None + else json.dumps(data) + ), stream=True, logging_obj=logging_obj, timeout=STREAMING_TIMEOUT, @@ -1111,15 +637,12 @@ def get_sync_custom_stream_wrapper( if response.status_code != 200: raise OCIError(status_code=response.status_code, message=response.text) - completion_stream = response.iter_text() - - streaming_response = OCIStreamWrapper( - completion_stream=completion_stream, + return OCIStreamWrapper( + completion_stream=_iter_sse_events(response.iter_text()), model=model, custom_llm_provider=custom_llm_provider, logging_obj=logging_obj, ) - return streaming_response @track_llm_api_timing() async def get_async_custom_stream_wrapper( @@ -1135,17 +658,18 @@ async def get_async_custom_stream_wrapper( json_mode: Optional[bool] = None, signed_json_body: Optional[bytes] = None, ) -> "OCIStreamWrapper": - if "stream" in data: - del data["stream"] - if client is None or isinstance(client, HTTPHandler): - client = get_async_httpx_client(llm_provider=LlmProviders.BYTEZ, params={}) + client = get_async_httpx_client(llm_provider=LlmProviders.OCI, params={}) try: response = await client.post( api_base, headers=headers, - data=json.dumps(data), + data=( + signed_json_body + if signed_json_body is not None + else json.dumps(data) + ), stream=True, logging_obj=logging_obj, timeout=STREAMING_TIMEOUT, @@ -1156,22 +680,12 @@ async def get_async_custom_stream_wrapper( if response.status_code != 200: raise OCIError(status_code=response.status_code, message=response.text) - completion_stream = response.aiter_text() - - async def split_chunks(completion_stream: AsyncIterator[str]): - async for item in completion_stream: - for chunk in item.split("\n\n"): - if not chunk: - continue - yield chunk.strip() - - streaming_response = OCIStreamWrapper( - completion_stream=split_chunks(completion_stream), + return OCIStreamWrapper( + completion_stream=_aiter_sse_events(response.aiter_text()), model=model, custom_llm_provider=custom_llm_provider, logging_obj=logging_obj, ) - return streaming_response def get_error_class( self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] @@ -1179,332 +693,61 @@ def get_error_class( return OCIError(status_code=status_code, message=error_message) -open_ai_to_generic_oci_role_map: Dict[str, OCIRoles] = { - "system": "SYSTEM", - "user": "USER", - "assistant": "ASSISTANT", - "tool": "TOOL", -} - - -def adapt_messages_to_generic_oci_standard_content_message( - role: str, content: Union[str, list] -) -> OCIMessage: - new_content: List[OCIContentPartUnion] = [] - if isinstance(content, str): - return OCIMessage( - role=open_ai_to_generic_oci_role_map[role], - content=[OCITextContentPart(text=content)], - toolCalls=None, - toolCallId=None, - ) - - # content is a list of content items: - # [ - # {"type": "text", "text": "Hello"}, - # {"type": "image_url", "image_url": "https://example.com/image.png"} - # ] - for content_item in content: - if not isinstance(content_item, dict): - raise Exception("Each content item must be a dictionary") - - type = content_item.get("type") - if not isinstance(type, str): - raise Exception("Prop `type` is not a string") - - if type not in ["text", "image_url"]: - raise Exception(f"Prop `{type}` is not supported") - - if type == "text": - text = content_item.get("text") - if not isinstance(text, str): - raise Exception("Prop `text` is not a string") - new_content.append(OCITextContentPart(text=text)) - - elif type == "image_url": - image_url = content_item.get("image_url") - # Handle both OpenAI format (object with url) and string format - if isinstance(image_url, dict): - image_url = image_url.get("url") - if not isinstance(image_url, str): - raise Exception( - "Prop `image_url` must be a string or an object with a `url` property" - ) - new_content.append(OCIImageContentPart(imageUrl=OCIImageUrl(url=image_url))) - - return OCIMessage( - role=open_ai_to_generic_oci_role_map[role], - content=new_content, - toolCalls=None, - toolCallId=None, - ) - - -def adapt_messages_to_generic_oci_standard_tool_call( - role: str, tool_calls: list -) -> OCIMessage: - tool_calls_formated = [] - for tool_call in tool_calls: - if not isinstance(tool_call, dict): - raise Exception("Each tool call must be a dictionary") - - if tool_call.get("type") != "function": - raise Exception("OCI only supports function tools") - - tool_call_id = tool_call.get("id") - if not isinstance(tool_call_id, str): - raise Exception("Prop `id` is not a string") - - tool_function = tool_call.get("function") - if not isinstance(tool_function, dict): - raise Exception("Prop `function` is not a dictionary") - - function_name = tool_function.get("name") - if not isinstance(function_name, str): - raise Exception("Prop `name` is not a string") - - arguments = tool_call["function"].get("arguments", "{}") - if not isinstance(arguments, str): - raise Exception("Prop `arguments` is not a string") - - # tool_calls_formated.append(OCIToolCall( - # id=tool_call_id, - # type="FUNCTION", - # function=OCIFunction( - # name=function_name, - # arguments=arguments - # ) - # )) - - tool_calls_formated.append( - OCIToolCall( - id=tool_call_id, - type="FUNCTION", - name=function_name, - arguments=arguments, - ) - ) - - return OCIMessage( - role=open_ai_to_generic_oci_role_map[role], - content=None, - toolCalls=tool_calls_formated, - toolCallId=None, - ) - - -def adapt_messages_to_generic_oci_standard_tool_response( - role: str, tool_call_id: str, content: str -) -> OCIMessage: - return OCIMessage( - role=open_ai_to_generic_oci_role_map[role], - content=[OCITextContentPart(text=content)], - toolCalls=None, - toolCallId=tool_call_id, - ) - - -def adapt_messages_to_generic_oci_standard( - messages: List[AllMessageValues], -) -> List[OCIMessage]: - new_messages = [] - for message in messages: - role = message["role"] - content = message.get("content") - tool_calls = message.get("tool_calls") - tool_call_id = message.get("tool_call_id") - - if role == "assistant" and tool_calls is not None: - if not isinstance(tool_calls, list): - raise Exception("Prop `tool_calls` must be a list of tool calls") - new_messages.append( - adapt_messages_to_generic_oci_standard_tool_call(role, tool_calls) - ) - - elif role in ["system", "user", "assistant"] and content is not None: - if not isinstance(content, (str, list)): - raise Exception( - "Prop `content` must be a string or a list of content items" - ) - new_messages.append( - adapt_messages_to_generic_oci_standard_content_message(role, content) - ) - - elif role == "tool": - if not isinstance(tool_call_id, str): - raise Exception("Prop `tool_call_id` is required and must be a string") - if not isinstance(content, str): - raise Exception("Prop `content` is not a string") - new_messages.append( - adapt_messages_to_generic_oci_standard_tool_response( - role, tool_call_id, content - ) - ) - - return new_messages - - -def adapt_tool_definition_to_oci_standard(tools: List[Dict], vendor: OCIVendors): - new_tools = [] - for tool in tools: - if tool["type"] != "function": - raise Exception("OCI only supports function tools") - - tool_function = tool.get("function") - if not isinstance(tool_function, dict): - raise Exception("Prop `function` is not a dictionary") - - new_tool = OCIToolDefinition( - type="FUNCTION", - name=tool_function.get("name"), - description=tool_function.get("description", ""), - parameters=tool_function.get("parameters", {}), - ) - new_tools.append(new_tool) - - return new_tools - - -def adapt_tools_to_openai_standard( - tools: List[OCIToolCall], -) -> List[ChatCompletionMessageToolCall]: - new_tools = [] - for tool in tools: - new_tool = ChatCompletionMessageToolCall( - id=tool.id, - type="function", - function={ - "name": tool.name, - "arguments": tool.arguments, - }, - ) - new_tools.append(new_tool) - return new_tools - - class OCIStreamWrapper(CustomStreamWrapper): - """ - Custom stream wrapper for OCI responses. - This class is used to handle streaming responses from OCI's API. - """ + """Custom stream wrapper that dispatches OCI SSE chunks to the correct handler.""" - def __init__( - self, - **kwargs: Any, - ): + def __init__(self, **kwargs: Any): super().__init__(**kwargs) - - def chunk_creator(self, chunk: Any): + # Tracks whether any prior Cohere chunk in this stream has emitted + # tool calls. The Cohere handler uses this to decide whether the + # terminal consolidation chunk's tool calls are duplicates (suppress) + # or the only copy of the tool calls (pass through). + self._cohere_tool_calls_emitted = False + # Analogous flag for text content. Lets the Cohere handler distinguish + # the common case (prior deltas already streamed the text, so the + # terminal chunk's text is a duplicate to suppress) from the degenerate + # single-event case (terminal chunk carries the only copy of the text). + self._cohere_text_emitted = False + + def chunk_creator(self, chunk: Any) -> ModelResponseStream: if not isinstance(chunk, str): raise ValueError(f"Chunk is not a string: {chunk}") if not chunk.startswith("data:"): raise ValueError(f"Chunk does not start with 'data:': {chunk}") - dict_chunk = json.loads(chunk[5:]) # Remove 'data: ' prefix and parse JSON - - # Check if this is a Cohere stream chunk - if "apiFormat" in dict_chunk and dict_chunk.get("apiFormat") == "COHERE": - return self._handle_cohere_stream_chunk(dict_chunk) - else: - return self._handle_generic_stream_chunk(dict_chunk) - - def _handle_cohere_stream_chunk(self, dict_chunk: dict): - """Handle Cohere-specific streaming chunks.""" try: - typed_chunk = CohereStreamChunk(**dict_chunk) - except TypeError as e: - raise ValueError(f"Chunk cannot be casted to CohereStreamChunk: {str(e)}") - - if typed_chunk.index is None: - typed_chunk.index = 0 - - # Extract text content - text = typed_chunk.text or "" - - # Map finish reason to standard format - finish_reason = typed_chunk.finishReason - if finish_reason == "COMPLETE": - finish_reason = "stop" - elif finish_reason == "MAX_TOKENS": - finish_reason = "length" - elif finish_reason is None: - finish_reason = None - else: - finish_reason = "stop" - - # For Cohere, we don't have tool calls in the streaming format - tool_calls = None - - return ModelResponseStream( - choices=[ - StreamingChoices( - index=typed_chunk.index if typed_chunk.index else 0, - delta=Delta( - content=text, - tool_calls=tool_calls, - provider_specific_fields=None, - thinking_blocks=None, - reasoning_content=None, - ), - finish_reason=finish_reason, - ) - ] - ) - - def _handle_generic_stream_chunk(self, dict_chunk: dict): - """Handle generic OCI streaming chunks.""" - # Fix missing required fields in tool calls before Pydantic validation - # OCI streams tool calls progressively, so early chunks may be missing required fields - if dict_chunk.get("message") and dict_chunk["message"].get("toolCalls"): - for tool_call in dict_chunk["message"]["toolCalls"]: - if "arguments" not in tool_call: - tool_call["arguments"] = "" - if "id" not in tool_call: - tool_call["id"] = "" - if "name" not in tool_call: - tool_call["name"] = "" + dict_chunk = json.loads(chunk[5:]) + except json.JSONDecodeError as e: + raise OCIError( + status_code=500, + message=f"Chunk cannot be parsed as JSON: {str(e)}", + ) - try: - typed_chunk = OCIStreamChunk(**dict_chunk) - except TypeError as e: - raise ValueError(f"Chunk cannot be casted to OCIStreamChunk: {str(e)}") - - if typed_chunk.index is None: - typed_chunk.index = 0 - - text = "" - if typed_chunk.message and typed_chunk.message.content: - for item in typed_chunk.message.content: - if isinstance(item, OCITextContentPart): - text += item.text - elif isinstance(item, OCIImageContentPart): - raise ValueError( - "OCI does not support image content in streaming responses" - ) - else: - raise ValueError( - f"Unsupported content type in OCI response: {item.type}" - ) - - tool_calls = None - if typed_chunk.message and typed_chunk.message.toolCalls: - tool_calls = adapt_tools_to_openai_standard(typed_chunk.message.toolCalls) - - return ModelResponseStream( - choices=[ - StreamingChoices( - index=typed_chunk.index if typed_chunk.index else 0, - delta=Delta( - content=text, - tool_calls=( - [tool.model_dump() for tool in tool_calls] - if tool_calls - else None - ), - provider_specific_fields=None, # OCI does not have provider specific fields in the response - thinking_blocks=None, # OCI does not have thinking blocks in the response - reasoning_content=None, # OCI does not have reasoning content in the response - ), - finish_reason=typed_chunk.finishReason, - ) - ] - ) + if dict_chunk.get("apiFormat") == "COHERE": + result = handle_cohere_stream_chunk( + dict_chunk, + prior_tool_calls_emitted=self._cohere_tool_calls_emitted, + prior_text_emitted=self._cohere_text_emitted, + ) + if not self._cohere_tool_calls_emitted: + for choice in result.choices: + if getattr(choice.delta, "tool_calls", None) is not None: + self._cohere_tool_calls_emitted = True + break + if not self._cohere_text_emitted: + for choice in result.choices: + if getattr(choice.delta, "content", None): + self._cohere_text_emitted = True + break + return result + return handle_generic_stream_chunk(dict_chunk) + + +__all__ = [ + "OCIChatConfig", + "OCIStreamWrapper", + "OCIRequestWrapper", + "OCI_API_VERSION", + "STREAMING_TIMEOUT", + "get_vendor_from_model", + "version", +] diff --git a/litellm/llms/oci/common_utils.py b/litellm/llms/oci/common_utils.py index 661a6c89e4b..8785b1548a5 100644 --- a/litellm/llms/oci/common_utils.py +++ b/litellm/llms/oci/common_utils.py @@ -1,9 +1,42 @@ -from typing import Optional +import base64 +import hashlib +import json +import os +import re +from dataclasses import dataclass +from email.utils import formatdate +from typing import Any, Dict, Optional, Protocol, Tuple +from urllib.parse import urlparse import httpx from litellm.llms.base_llm.chat.transformation import BaseLLMException +try: + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import padding, rsa + + _CRYPTOGRAPHY_AVAILABLE = True +except ImportError: + _CRYPTOGRAPHY_AVAILABLE = False + +try: + from litellm._version import version as _litellm_version +except ImportError: + _litellm_version = "0.0.0" + + +# OCI GenAI REST API version — stable since service launch, unlikely to change +OCI_API_VERSION = "20231130" + + +def _require_cryptography() -> None: + if not _CRYPTOGRAPHY_AVAILABLE: + raise ImportError( + "cryptography package is required for OCI authentication. " + "Please install it with: pip install cryptography" + ) + class OCIError(BaseLLMException): def __init__( @@ -17,3 +50,520 @@ def __init__( message=message, headers=headers, ) + + +# --------------------------------------------------------------------------- +# OCI signing protocol and helpers +# --------------------------------------------------------------------------- + + +class OCISignerProtocol(Protocol): + """ + Protocol for OCI request signers (e.g., oci.signer.Signer). + + Compatible with the OCI Python SDK's Signer class. + See: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/signing.html + """ + + def do_request_sign( + self, request: Any, *, enforce_content_headers: bool = False + ) -> None: + pass + + +@dataclass +class OCIRequestWrapper: + """ + Wrapper for HTTP requests compatible with OCI signer interface. + + Wraps request data in the format expected by OCI SDK signers, which require + objects with method, url, headers, body, and path_url attributes. + """ + + method: str + url: str + headers: dict + body: bytes + + @property + def path_url(self) -> str: + """Returns the path + query string for OCI signing.""" + parsed = urlparse(self.url) + return parsed.path + ("?" + parsed.query if parsed.query else "") + + +def sha256_base64(data: bytes) -> str: + # SHA-256 is used here to compute the x-content-sha256 header required by the + # OCI HTTP signing specification (RSA-SHA256 request signing), not for password + # or secret hashing. This is the correct and mandated algorithm for this purpose. + # See: https://docs.oracle.com/en-us/iaas/Content/API/Concepts/signingrequests.htm + # + # ``usedforsecurity=False`` declares non-security intent to static analyzers + # (CodeQL ``py/weak-sensitive-data-hashing``) — without it the request body + # gets flagged as "password-like data" via taint tracking. + digest = hashlib.sha256(data, usedforsecurity=False).digest() # noqa: S324 + return base64.b64encode(digest).decode() + + +def build_signature_string( + method: str, path: str, headers: dict, signed_headers: list +) -> str: + lines = [] + for header in signed_headers: + if header == "(request-target)": + value = f"{method.lower()} {path}" + else: + value = headers[header] + lines.append(f"{header}: {value}") + return "\n".join(lines) + + +def load_private_key_from_str(key_str: str) -> Any: + _require_cryptography() + key = serialization.load_pem_private_key( # type: ignore[union-attr] + key_str.encode("utf-8"), + password=None, + ) + if not isinstance(key, rsa.RSAPrivateKey): # type: ignore[union-attr] + raise TypeError( + "The provided private key is not an RSA key, which is required for OCI signing." + ) + return key + + +def load_private_key_from_file(file_path: str) -> Any: + """Loads a private key from a file path.""" + try: + with open(file_path, "r", encoding="utf-8") as f: + key_str = f.read().strip() + except FileNotFoundError: + raise FileNotFoundError(f"Private key file not found: {file_path}") + except OSError as e: + raise OSError(f"Failed to read private key file '{file_path}': {e}") from e + + if not key_str: + raise ValueError(f"Private key file is empty: {file_path}") + + return load_private_key_from_str(key_str) + + +# --------------------------------------------------------------------------- +# Env-var credential resolution +# --------------------------------------------------------------------------- + +_OCI_REGION_ENV = "OCI_REGION" +_OCI_USER_ENV = "OCI_USER" +_OCI_FINGERPRINT_ENV = "OCI_FINGERPRINT" +_OCI_TENANCY_ENV = "OCI_TENANCY" +_OCI_KEY_FILE_ENV = "OCI_KEY_FILE" +_OCI_KEY_ENV = "OCI_KEY" +_OCI_COMPARTMENT_ID_ENV = "OCI_COMPARTMENT_ID" + + +def resolve_oci_credentials(optional_params: dict) -> dict: + """ + Merge OCI credentials from optional_params (explicit, always wins) and + environment variables (fallback). + + Returns a dict with resolved values for: + oci_region, oci_user, oci_fingerprint, oci_tenancy, + oci_key, oci_key_file, oci_compartment_id + """ + return { + "oci_region": optional_params.get("oci_region") + or os.environ.get(_OCI_REGION_ENV) + or "us-ashburn-1", + "oci_user": optional_params.get("oci_user") or os.environ.get(_OCI_USER_ENV), + "oci_fingerprint": optional_params.get("oci_fingerprint") + or os.environ.get(_OCI_FINGERPRINT_ENV), + "oci_tenancy": optional_params.get("oci_tenancy") + or os.environ.get(_OCI_TENANCY_ENV), + "oci_key": optional_params.get("oci_key") or os.environ.get(_OCI_KEY_ENV), + "oci_key_file": optional_params.get("oci_key_file") + or os.environ.get(_OCI_KEY_FILE_ENV), + "oci_compartment_id": optional_params.get("oci_compartment_id") + or os.environ.get(_OCI_COMPARTMENT_ID_ENV), + } + + +_OCI_REGION_RE = re.compile(r"^[a-z][a-z0-9-]{0,30}[a-z0-9]$") +_OCI_ACTION_PATH_RE = re.compile(rf"/{OCI_API_VERSION}/actions/[^/?#]+/?$") + + +def get_oci_base_url(optional_params: dict, api_base: Optional[str] = None) -> str: + """Return the OCI inference base URL, respecting any explicit api_base override. + + If ``api_base`` already ends with a fully-formed OCI action path + (``/{OCI_API_VERSION}/actions/``), that suffix is stripped so callers + can append their own action path without producing a doubled URL. + """ + if api_base: + return _OCI_ACTION_PATH_RE.sub("", api_base).rstrip("/") + creds = resolve_oci_credentials(optional_params) + region = creds["oci_region"] + if not isinstance(region, str) or not _OCI_REGION_RE.match(region): + raise OCIError( + status_code=400, + message=( + f"Invalid OCI region {region!r}: must match " + "^[a-z][a-z0-9-]{0,30}[a-z0-9]$ (e.g. 'us-ashburn-1')." + ), + ) + return f"https://inference.generativeai.{region}.oci.oraclecloud.com" + + +# --------------------------------------------------------------------------- +# Signing implementations (shared by chat, embed, and rerank configs) +# --------------------------------------------------------------------------- + + +def sign_with_oci_signer( + headers: dict, + optional_params: dict, + request_data: dict, + api_base: str, +) -> Tuple[dict, bytes]: + """Sign a request using an OCI SDK Signer object passed in optional_params.""" + oci_signer = optional_params.get("oci_signer") + body = json.dumps(request_data).encode("utf-8") + method = str(optional_params.get("method", "POST")).upper() + + if method not in {"POST", "GET", "PUT", "DELETE", "PATCH"}: + raise ValueError(f"Unsupported HTTP method: {method}") + + prepared_headers = {**headers} + prepared_headers.setdefault("content-type", "application/json") + prepared_headers.setdefault("content-length", str(len(body))) + + request_wrapper = OCIRequestWrapper( + method=method, url=api_base, headers=prepared_headers, body=body + ) + + if oci_signer is None: + raise ValueError("oci_signer cannot be None when calling sign_with_oci_signer") + + try: + oci_signer.do_request_sign(request_wrapper, enforce_content_headers=True) + except Exception as e: + raise OCIError( + status_code=500, + message=( + f"Failed to sign request with provided oci_signer: {str(e)}. " + "The signer must implement the OCI SDK Signer interface with a " + "do_request_sign(request, enforce_content_headers=True) method. " + "See: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/signing.html" + ), + ) from e + + headers.update(request_wrapper.headers) + return headers, body + + +def sign_with_manual_credentials( + headers: dict, + optional_params: dict, + request_data: dict, + api_base: str, +) -> Tuple[dict, bytes]: + """Sign a request using manually provided OCI credentials (user/fingerprint/tenancy/key).""" + creds = resolve_oci_credentials(optional_params) + oci_user = creds["oci_user"] + oci_fingerprint = creds["oci_fingerprint"] + oci_tenancy = creds["oci_tenancy"] + oci_key = creds["oci_key"] + oci_key_file = creds["oci_key_file"] + + if ( + not oci_user + or not oci_fingerprint + or not oci_tenancy + or not (oci_key or oci_key_file) + ): + raise OCIError( + status_code=401, + message=( + "Missing required OCI credentials: oci_user, oci_fingerprint, oci_tenancy, " + "and at least one of oci_key or oci_key_file. " + "These can also be supplied via environment variables: " + f"{_OCI_USER_ENV}, {_OCI_FINGERPRINT_ENV}, {_OCI_TENANCY_ENV}, {_OCI_KEY_ENV} (or {_OCI_KEY_FILE_ENV}). " + "Alternatively, provide an oci_signer object from the OCI SDK." + ), + ) + + method = str(optional_params.get("method", "POST")).upper() + body = json.dumps(request_data).encode("utf-8") + parsed = urlparse(api_base) + path = parsed.path or "/" + host = parsed.netloc + + date = formatdate(usegmt=True) + content_type = headers.get("content-type", "application/json") + content_length = str(len(body)) + x_content_sha256 = sha256_base64(body) + + headers_to_sign: Dict[str, str] = { + "date": date, + "host": host, + "content-type": content_type, + "content-length": content_length, + "x-content-sha256": x_content_sha256, + } + + signed_header_names = [ + "date", + "(request-target)", + "host", + "content-length", + "content-type", + "x-content-sha256", + ] + signing_string = build_signature_string( + method, path, headers_to_sign, signed_header_names + ) + + _require_cryptography() + + # Resolve the private key — prefer inline PEM content over file path + oci_key_content: Optional[str] = None + if oci_key: + if not isinstance(oci_key, str): + raise OCIError( + status_code=400, + message=( + f"oci_key must be a string containing the PEM private key content. " + f"Got type: {type(oci_key).__name__}" + ), + ) + oci_key_content = oci_key.replace("\\n", "\n").replace("\r\n", "\n") + + private_key = ( + load_private_key_from_str(oci_key_content) + if oci_key_content + else load_private_key_from_file(oci_key_file) if oci_key_file else None + ) + + if private_key is None: + raise OCIError( + status_code=400, + message="Private key is required for OCI authentication. Provide either oci_key or oci_key_file.", + ) + + signature = private_key.sign( + signing_string.encode("utf-8"), + padding.PKCS1v15(), # type: ignore[union-attr] + hashes.SHA256(), # type: ignore[union-attr] + ) + signature_b64 = base64.b64encode(signature).decode() + + key_id = f"{oci_tenancy}/{oci_user}/{oci_fingerprint}" + authorization = ( + 'Signature version="1",' + f'keyId="{key_id}",' + 'algorithm="rsa-sha256",' + f'headers="{" ".join(signed_header_names)}",' + f'signature="{signature_b64}"' + ) + + headers.update( + { + "authorization": authorization, + "date": date, + "host": host, + "content-type": content_type, + "content-length": content_length, + "x-content-sha256": x_content_sha256, + } + ) + return headers, body + + +def sign_oci_request( + headers: dict, + optional_params: dict, + request_data: dict, + api_base: str, + api_key: Optional[str] = None, + model: Optional[str] = None, + stream: Optional[bool] = None, + fake_stream: Optional[bool] = None, +) -> Tuple[dict, bytes]: + """ + Route to the appropriate OCI signing method based on what credentials are present. + + If ``oci_signer`` is in optional_params, use the OCI SDK signer object. + Otherwise use manual RSA-SHA256 signing with explicit credentials (which can + also be supplied via OCI_* environment variables). + + Returns: + Tuple of (signed_headers, signed_body_bytes) + """ + if optional_params.get("oci_signer") is not None: + return sign_with_oci_signer(headers, optional_params, request_data, api_base) + return sign_with_manual_credentials( + headers, optional_params, request_data, api_base + ) + + +def validate_oci_environment( + headers: dict, + optional_params: dict, + api_key: Optional[str] = None, +) -> dict: + """ + Populate common OCI request headers (content-type, user-agent). + + Full credential validation is deferred to signing time so that credentials + supplied via environment variables are resolved at call time rather than + at construction time. + """ + headers.setdefault("content-type", "application/json") + headers.setdefault("user-agent", f"litellm/{_litellm_version}") + return headers + + +# --------------------------------------------------------------------------- +# JSON schema utilities for OCI tool definitions +# +# OCI Generative AI does not support JSON Schema extensions ($ref, $defs, +# anyOf). Pydantic v2 emits all three for models with Optional fields or +# nested schemas. The helpers below are ported from the official +# langchain-oracle reference implementation so that tool schemas are always +# valid before they reach the OCI endpoint. +# --------------------------------------------------------------------------- + +# Mapping from JSON Schema type names to Python type names, as expected by +# the OCI Cohere API's CohereParameterDefinition.type field. +OCI_JSON_TO_PYTHON_TYPES: Dict[str, str] = { + "string": "str", + "number": "float", + "boolean": "bool", + "integer": "int", + "array": "List", + "object": "Dict", + "any": "any", +} + + +def resolve_oci_schema_refs(schema: Dict[str, Any]) -> Dict[str, Any]: + """Inline all ``$ref``/``$defs`` references — OCI does not support JSON Schema ``$ref``.""" + defs = schema.get("$defs", {}) + resolving_stack: set = set() + + def _resolve(obj: Any) -> Any: + if isinstance(obj, dict): + if "$ref" in obj: + ref = obj["$ref"] + if ref.startswith("#/$defs/"): + key = ref.split("/")[-1] + if key in resolving_stack: + return {"type": "object"} # break cycles + resolving_stack.add(key) + try: + return _resolve(defs.get(key, obj)) + finally: + resolving_stack.discard(key) + return obj # external $ref — leave unchanged + return {k: _resolve(v) for k, v in obj.items()} + if isinstance(obj, list): + return [_resolve(item) for item in obj] + return obj + + resolved = _resolve(schema) + if isinstance(resolved, dict): + resolved.pop("$defs", None) + return resolved + + +def resolve_oci_schema_anyof(obj: Any) -> Any: + """Resolve Pydantic v2 ``Optional[T]`` → ``anyOf`` patterns. + + Pydantic v2 emits ``{"anyOf": [{"type": "T"}, {"type": "null"}]}`` for + ``Optional[T]``. OCI models don't understand ``anyOf``, so we pick the + first non-null branch and merge top-level metadata into it. + """ + if isinstance(obj, dict): + if "anyOf" in obj and "type" not in obj: + non_null = [ + t + for t in obj["anyOf"] + if not (isinstance(t, dict) and t.get("type") == "null") + ] + if non_null: + resolved = {**obj, **non_null[0]} + resolved.pop("anyOf", None) + return resolve_oci_schema_anyof(resolved) + return {k: resolve_oci_schema_anyof(v) for k, v in obj.items()} + if isinstance(obj, list): + return [resolve_oci_schema_anyof(item) for item in obj] + return obj + + +def sanitize_oci_schema(schema: Any) -> Any: + """Recursively remove OCI-incompatible fields from a JSON schema. + + Strips ``title`` keys, removes ``None``-valued ``default`` entries, + normalises ``type: [T, "null"]`` list types, and ensures arrays carry an + ``items`` definition. + """ + if isinstance(schema, list): + return [sanitize_oci_schema(item) for item in schema] + if not isinstance(schema, dict): + return schema + + sanitized: Dict[str, Any] = {} + for key, value in schema.items(): + if key == "title": + continue + if key == "default" and value is None: + continue + if key == "type": + if value == "any": + sanitized[key] = "object" + continue + if isinstance(value, list): + non_null = [t for t in value if t != "null"] + sanitized[key] = non_null[0] if non_null else "string" + continue + sanitized[key] = sanitize_oci_schema(value) + + if sanitized.get("type") == "array" and "items" not in sanitized: + sanitized["items"] = {"type": "object"} + + required = sanitized.get("required") + properties = sanitized.get("properties") + if "required" in sanitized: + if isinstance(required, list) and isinstance(properties, dict): + sanitized["required"] = [ + f for f in required if isinstance(f, str) and f in properties + ] + elif not isinstance(required, list): + sanitized["required"] = [] + + return sanitized + + +def enrich_cohere_param_description( + description: str, param_schema: Dict[str, Any] +) -> str: + """Embed schema constraints into a Cohere parameter description. + + ``CohereParameterDefinition`` only has ``type``, ``description``, and + ``isRequired``. Rich constraints (``enum``, ``format``, ``minimum``, + ``maximum``, ``pattern``) are appended to the description string so the + model can still see and respect them. + """ + parts = [description] if description else [] + if "enum" in param_schema: + parts.append(f"Allowed values: {param_schema['enum']}") + if "format" in param_schema: + parts.append(f"Format: {param_schema['format']}") + if "minimum" in param_schema or "maximum" in param_schema: + range_parts = [] + if "minimum" in param_schema: + range_parts.append(f"min={param_schema['minimum']}") + if "maximum" in param_schema: + range_parts.append(f"max={param_schema['maximum']}") + parts.append(f"Range: {', '.join(range_parts)}") + if "pattern" in param_schema: + parts.append(f"Pattern: {param_schema['pattern']}") + return ". ".join(parts) if parts else "" diff --git a/litellm/llms/oci/embed/transformation.py b/litellm/llms/oci/embed/transformation.py index 1dcd8c5213c..6cfa85b4bc4 100644 --- a/litellm/llms/oci/embed/transformation.py +++ b/litellm/llms/oci/embed/transformation.py @@ -1,8 +1,14 @@ """ -OCI Generative AI Embedding Configuration +OCI Generative AI — Embedding transformation. -Supports embedding models available on Oracle Cloud Infrastructure Generative AI service. -Uses the same authentication mechanisms as OCI chat (manual signing or OCI SDK Signer). +Endpoint: POST /20231130/actions/embedText +Supported models: cohere.embed-english-v3.0, cohere.embed-multilingual-v3.0, +cohere.embed-v4.0, and all other Cohere embed variants available on OCI +(including dedicated endpoints). + +Authentication follows the same RSA-SHA256 / OCI SDK signer pattern as chat. +The base handler (base_llm_http_handler.embedding) calls sign_request after +building the body, so signing happens automatically. Supported models: - cohere.embed-english-v3.0 @@ -10,25 +16,45 @@ - cohere.embed-multilingual-v3.0 - cohere.embed-multilingual-light-v3.0 - cohere.embed-english-image-v3.0 -- cohere.embed-english-light-image-v3.0 -- cohere.embed-multilingual-light-image-v3.0 +- cohere.embed-multilingual-image-v3.0 - cohere.embed-v4.0 Reference: https://docs.oracle.com/en-us/iaas/api/#/en/generative-ai-inference/latest/EmbedTextResult/EmbedText """ -from typing import Any, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union import httpx -from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj +import litellm from litellm.llms.base_llm.chat.transformation import BaseLLMException from litellm.llms.base_llm.embedding.transformation import BaseEmbeddingConfig -from litellm.llms.oci.chat.transformation import OCIChatConfig -from litellm.llms.oci.common_utils import OCIError +from litellm.llms.oci.common_utils import ( + OCI_API_VERSION, + OCIError, + get_oci_base_url, + resolve_oci_credentials, + sign_oci_request, + validate_oci_environment, +) +from litellm.types.llms.oci import ( + OCIEmbedRequest, + OCIEmbedResponse, + OCIServingMode, +) from litellm.types.llms.openai import AllEmbeddingInputValues, AllMessageValues from litellm.types.utils import EmbeddingResponse, Usage +if TYPE_CHECKING: + from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj + + LiteLLMLoggingObj = _LiteLLMLoggingObj +else: + LiteLLMLoggingObj = Any + +# OCI sends up to 96 texts per embedText request (Cohere limit). +OCI_EMBED_BATCH_LIMIT = 96 + # Input type mapping from OpenAI conventions to OCI/Cohere conventions _INPUT_TYPE_MAP = { "search_document": "SEARCH_DOCUMENT", @@ -38,65 +64,43 @@ } -class OCIEmbeddingConfig(BaseEmbeddingConfig): - """ - Configuration for OCI Generative AI Embedding API. - - The OCI embedding endpoint uses the Cohere embed models hosted on OCI. - Authentication is handled via OCI request signing (manual credentials or OCI SDK Signer). - - Usage: - ```python - import litellm - - response = litellm.embedding( - model="oci/cohere.embed-english-v3.0", - input=["Hello world", "Goodbye world"], - oci_compartment_id="ocid1.compartment.oc1..xxx", - oci_region="us-ashburn-1", - oci_user="ocid1.user.oc1..xxx", - oci_fingerprint="xx:xx:xx:xx", - oci_tenancy="ocid1.tenancy.oc1..xxx", - oci_key_file="~/.oci/key.pem", - ) - ``` +class OCIEmbedConfig(BaseEmbeddingConfig): """ + Transformation config for OCI Generative AI embeddings. - def __init__(self) -> None: - # We reuse OCIChatConfig for signing logic - self._chat_config = OCIChatConfig() + Supports both text and (on cohere.embed-v4.0) multimodal inputs. - def get_complete_url( - self, - api_base: Optional[str], - api_key: Optional[str], - model: str, - optional_params: dict, - litellm_params: dict, - stream: Optional[bool] = None, - ) -> str: - if api_base: - return api_base + Authentication — same two modes as chat: + - **OCI SDK signer**: pass ``oci_signer`` in optional_params. + - **Manual RSA-SHA256**: pass ``oci_user``, ``oci_fingerprint``, ``oci_tenancy``, + and ``oci_key`` or ``oci_key_file``, or set the corresponding ``OCI_*`` env vars. - oci_region = optional_params.get("oci_region", "us-ashburn-1") - return f"https://inference.generativeai.{oci_region}.oci.oraclecloud.com/20231130/actions/embedText" + Required call-time params (via optional_params or env vars): + - ``oci_compartment_id`` / ``OCI_COMPARTMENT_ID`` + - ``oci_region`` / ``OCI_REGION`` (default: ``us-ashburn-1``) - def get_supported_openai_params(self, model: str) -> list: - return [ - "dimensions", - ] + Optional call-time params: + - ``oci_serving_mode``: ``"ON_DEMAND"`` (default) or ``"DEDICATED"`` + - ``oci_endpoint_id``: endpoint OCID for dedicated serving mode + - ``input_type``: ``SEARCH_DOCUMENT``, ``SEARCH_QUERY``, ``CLASSIFICATION``, ``CLUSTERING`` + - ``truncate``: ``NONE``, ``START``, or ``END`` (default ``END``) + - ``dimensions``: output embedding dimensions (cohere.embed-v4.0+) + """ + + def get_supported_openai_params(self, model: str) -> List[str]: + return ["dimensions"] def map_openai_params( self, non_default_params: dict, optional_params: dict, model: str, - drop_params: bool, + drop_params: bool = False, ) -> dict: - # Note: OCI Cohere embed does not support custom dimensions natively, - # but we pass it through in case future models support it - if "dimensions" in non_default_params: - optional_params["dimensions"] = non_default_params["dimensions"] + for key, value in non_default_params.items(): + if key == "dimensions": + # OCI API uses outputDimensions (cohere.embed-v4.0+) + optional_params["outputDimensions"] = value return optional_params def validate_environment( @@ -109,49 +113,42 @@ def validate_environment( api_key: Optional[str] = None, api_base: Optional[str] = None, ) -> dict: - """ - Validate OCI credentials for embedding requests. - Supports both OCI SDK Signer and manual credential signing. - """ - oci_signer = optional_params.get("oci_signer") - oci_region = optional_params.get("oci_region", "us-ashburn-1") - - api_base = ( - api_base - or f"https://inference.generativeai.{oci_region}.oci.oraclecloud.com" - ) - - if oci_signer is None: - oci_user = optional_params.get("oci_user") - oci_fingerprint = optional_params.get("oci_fingerprint") - oci_tenancy = optional_params.get("oci_tenancy") - oci_key = optional_params.get("oci_key") - oci_key_file = optional_params.get("oci_key_file") - oci_compartment_id = optional_params.get("oci_compartment_id") - - if ( - not oci_user - or not oci_fingerprint - or not oci_tenancy - or not (oci_key or oci_key_file) - or not oci_compartment_id - ): - raise Exception( - "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, oci_compartment_id " - "and at least one of oci_key or oci_key_file. " - "Alternatively, provide an oci_signer object from the OCI SDK." + if optional_params.get("oci_signer") is None: + creds = resolve_oci_credentials(optional_params) + missing = [ + k + for k in ( + "oci_user", + "oci_fingerprint", + "oci_tenancy", + "oci_compartment_id", ) + if not creds.get(k) + ] + if missing or not (creds.get("oci_key") or creds.get("oci_key_file")): + raise OCIError( + status_code=401, + message=( + "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, " + "oci_compartment_id and at least one of oci_key or oci_key_file. " + "These can be supplied via optional_params or via OCI_USER, OCI_FINGERPRINT, " + "OCI_TENANCY, OCI_COMPARTMENT_ID, OCI_KEY_FILE environment variables. " + "Alternatively, provide an oci_signer object from the OCI SDK." + ), + ) + return validate_oci_environment(headers, optional_params, api_key) - from litellm.llms.custom_httpx.http_handler import version - - headers.update( - { - "content-type": "application/json", - "user-agent": f"litellm/{version}", - } - ) - - return headers + def get_complete_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: dict, + litellm_params: dict, + stream: Optional[bool] = None, + ) -> str: + base = get_oci_base_url(optional_params, api_base or litellm.api_base) + return f"{base}/{OCI_API_VERSION}/actions/embedText" def sign_request( self, @@ -163,9 +160,8 @@ def sign_request( model: Optional[str] = None, stream: Optional[bool] = None, fake_stream: Optional[bool] = None, - ): - """Delegate to OCIChatConfig's signing logic.""" - return self._chat_config.sign_request( + ) -> Tuple[dict, bytes]: + return sign_oci_request( headers=headers, optional_params=optional_params, request_data=request_data, @@ -182,91 +178,74 @@ def transform_embedding_request( input: AllEmbeddingInputValues, optional_params: dict, headers: dict, - api_base: Optional[str] = None, ) -> dict: - """ - Transform the embedding request to OCI format. - - OCI embedText API expects: - { - "compartmentId": "...", - "servingMode": {"servingType": "ON_DEMAND", "modelId": "..."}, - "inputs": ["text1", "text2"], - "truncate": "END", - "inputType": "SEARCH_DOCUMENT" - } - """ - oci_compartment_id = optional_params.get("oci_compartment_id") - if not oci_compartment_id: - raise Exception( - "kwarg `oci_compartment_id` is required for OCI embedding requests" + creds = resolve_oci_credentials(optional_params) + compartment_id = creds["oci_compartment_id"] + if not compartment_id: + raise OCIError( + status_code=400, + message=( + "oci_compartment_id is required for OCI embedding requests. " + "Pass it as optional_params or set the OCI_COMPARTMENT_ID env var." + ), ) - # Build serving mode - oci_serving_mode = optional_params.get("oci_serving_mode", "ON_DEMAND") - if oci_serving_mode == "DEDICATED": - oci_endpoint_id = optional_params.get("oci_endpoint_id", model) - serving_mode = { - "servingType": "DEDICATED", - "endpointId": oci_endpoint_id, - } - else: - serving_mode = { - "servingType": "ON_DEMAND", - "modelId": model, - } - - # Normalize input to list of strings + # Normalise input to a flat list of strings if isinstance(input, str): - inputs = [input] + texts = [input] elif isinstance(input, list): - inputs = [] + texts = [] for item in input: - if isinstance(item, str): - inputs.append(item) - elif isinstance(item, list): - raise ValueError( - "OCI embedding does not support token-array inputs. " - "Please convert token lists to strings before calling embedding()." + if isinstance(item, list): + raise OCIError( + status_code=400, + message=( + "OCI embedText does not support token-array inputs. " + "Convert token lists to strings before calling embedding()." + ), ) - else: - inputs.append(str(item)) + texts.append(item if isinstance(item, str) else str(item)) else: - inputs = [str(input)] - - # Build request data — OCI embedText API expects inputs, truncate, - # and inputType at the top level alongside compartmentId and servingMode - request_data: Dict[str, Any] = { - "compartmentId": oci_compartment_id, - "servingMode": serving_mode, - "inputs": inputs, - "truncate": optional_params.get("truncate", "END"), - } - - # Map input_type if provided - input_type = optional_params.get("input_type") - if input_type: - mapped_type = _INPUT_TYPE_MAP.get(input_type.lower(), input_type.upper()) - request_data["inputType"] = mapped_type + texts = [str(input)] - # Sign the request using the same URL the HTTP handler will POST to - signing_url = self.get_complete_url( - api_base=api_base, - api_key=None, - model=model, - optional_params=optional_params, - litellm_params={}, - ) + if len(texts) > OCI_EMBED_BATCH_LIMIT: + raise OCIError( + status_code=400, + message=( + f"OCI embedText accepts at most {OCI_EMBED_BATCH_LIMIT} inputs per request " + f"(got {len(texts)}). Batch your requests." + ), + ) - signed_headers, body = self.sign_request( - headers=headers, - optional_params=optional_params, - request_data=request_data, - api_base=signing_url, - ) - headers.update(signed_headers) + serving_mode_type = optional_params.get("oci_serving_mode", "ON_DEMAND").upper() + if serving_mode_type not in {"ON_DEMAND", "DEDICATED"}: + raise OCIError( + status_code=400, + message="oci_serving_mode must be 'ON_DEMAND' or 'DEDICATED'.", + ) + + if serving_mode_type == "DEDICATED": + endpoint_id = optional_params.get("oci_endpoint_id", model) + serving_mode = OCIServingMode( + servingType="DEDICATED", endpointId=endpoint_id + ) + else: + serving_mode = OCIServingMode(servingType="ON_DEMAND", modelId=model) - return request_data + # Map input_type from OpenAI convention to OCI/Cohere convention + input_type = optional_params.get("input_type") + if input_type: + input_type = _INPUT_TYPE_MAP.get(input_type.lower(), input_type.upper()) + + request = OCIEmbedRequest( + compartmentId=compartment_id, + servingMode=serving_mode, + inputs=texts, + inputType=input_type, + truncate=optional_params.get("truncate", "END"), + outputDimensions=optional_params.get("outputDimensions"), + ) + return request.model_dump(exclude_none=True) def transform_embedding_response( self, @@ -274,63 +253,57 @@ def transform_embedding_response( raw_response: httpx.Response, model_response: EmbeddingResponse, logging_obj: LiteLLMLoggingObj, - api_key: Optional[str] = None, - request_data: dict = {}, - optional_params: dict = {}, - litellm_params: dict = {}, + api_key: Optional[str], + request_data: dict, + optional_params: dict, + litellm_params: dict, ) -> EmbeddingResponse: - """ - Transform OCI embedding response to standard EmbeddingResponse format. - - OCI response format: - { - "embeddings": [[0.1, 0.2, ...], [0.3, 0.4, ...]], - "modelId": "cohere.embed-english-v3.0", - "modelVersion": "3.0", - "inputTextTokenCounts": [5, 4] - } - """ if raw_response.status_code != 200: raise OCIError( - message=raw_response.text, status_code=raw_response.status_code, + message=raw_response.text, ) try: - raw_response_json = raw_response.json() - except Exception: + json_response = raw_response.json() + except Exception as e: raise OCIError( - message=raw_response.text, status_code=raw_response.status_code, + message=f"Failed to parse OCI embed response as JSON: {e}", ) - embeddings = raw_response_json.get("embeddings", []) - model_id = raw_response_json.get("modelId", model) - - # Build response data in OpenAI format - embedding_data = [] - for idx, embedding in enumerate(embeddings): - embedding_data.append( - { - "object": "embedding", - "index": idx, - "embedding": embedding, - } + try: + parsed = OCIEmbedResponse(**json_response) + except Exception as e: + raise OCIError( + status_code=500, + message=f"OCI embed response does not match expected schema: {e}", ) - model_response.model = model_id - model_response.data = embedding_data - model_response.object = "list" - - # Calculate token usage - input_token_counts = raw_response_json.get("inputTextTokenCounts", []) - total_tokens = sum(input_token_counts) if input_token_counts else 0 + model_response.model = parsed.modelId + model_response.data = [ + { + "object": "embedding", + "index": i, + "embedding": embedding, + } + for i, embedding in enumerate(parsed.embeddings) + ] - usage = Usage( - prompt_tokens=total_tokens, - total_tokens=total_tokens, - ) - model_response.usage = usage + if parsed.inputTextTokenCounts is not None: + # Actual OCI API returns per-input token counts — sum for total usage + total = sum(parsed.inputTextTokenCounts) + model_response.usage = Usage(prompt_tokens=total, total_tokens=total) + elif parsed.usage is not None: + # Some deployments may return a usage object directly + model_response.usage = Usage( + prompt_tokens=parsed.usage.promptTokens, + total_tokens=parsed.usage.totalTokens, + ) + else: + # Neither field returned — default to zero so downstream consumers + # can always rely on usage being populated. + model_response.usage = Usage(prompt_tokens=0, total_tokens=0) return model_response @@ -340,8 +313,8 @@ def get_error_class( status_code: int, headers: Union[dict, httpx.Headers], ) -> BaseLLMException: - return OCIError( - message=error_message, - status_code=status_code, - headers=headers if isinstance(headers, httpx.Headers) else None, - ) + return OCIError(status_code=status_code, message=error_message) + + +# Alias for backwards compatibility with any code that imports OCIEmbeddingConfig +OCIEmbeddingConfig = OCIEmbedConfig diff --git a/litellm/llms/openai/cost_calculation.py b/litellm/llms/openai/cost_calculation.py index 32b71a43afa..6935cafd0d9 100644 --- a/litellm/llms/openai/cost_calculation.py +++ b/litellm/llms/openai/cost_calculation.py @@ -19,7 +19,10 @@ def cost_router(call_type: CallTypes) -> Literal["cost_per_token", "cost_per_sec def cost_per_token( - model: str, usage: Usage, service_tier: Optional[str] = None + model: str, + usage: Usage, + service_tier: Optional[str] = None, + data_residency: Optional[str] = None, ) -> Tuple[float, float]: """ Calculates the cost per token for a given model, prompt tokens, and completion tokens. @@ -27,6 +30,9 @@ def cost_per_token( Input: - model: str, the model name without provider prefix - usage: LiteLLM Usage block, containing anthropic caching information + - data_residency: optional OpenAI data-residency region (e.g. "eu", "us"), + inferred from api_base. Applies the model's regional-processing + uplift multiplier when set. Returns: Tuple[float, float] - prompt_cost_in_usd, completion_cost_in_usd @@ -37,6 +43,7 @@ def cost_per_token( usage=usage, custom_llm_provider="openai", service_tier=service_tier, + data_residency=data_residency, ) # ### Non-cached text tokens # non_cached_text_tokens = usage.prompt_tokens diff --git a/litellm/llms/openai/data_residency.py b/litellm/llms/openai/data_residency.py new file mode 100644 index 00000000000..7162f70ca5f --- /dev/null +++ b/litellm/llms/openai/data_residency.py @@ -0,0 +1,41 @@ +""" +Helpers for resolving OpenAI data-residency (regional processing) from an +api_base URL. + +OpenAI enforces hostname-per-region for projects with geography restrictions +enabled and rejects requests sent to the wrong host, so the api_base hostname +is the authoritative signal of which region a request was processed in. +""" + +from typing import Dict, Optional +from urllib.parse import urlparse + +# Mapping of OpenAI regional hostnames to the corresponding data-residency +# value used by the cost calculator. See +# https://developers.openai.com/api/docs/pricing for the regional-processing +# uplift these hostnames trigger. +_OPENAI_REGIONAL_HOSTS: Dict[str, str] = { + "eu.api.openai.com": "eu", + "us.api.openai.com": "us", +} + + +def infer_openai_data_residency( + custom_llm_provider: Optional[str], api_base: Optional[str] +) -> Optional[str]: + """ + Derive the OpenAI data-residency region from an api_base URL. + + Returns ``"eu"`` for the EU regional host, ``"us"`` for the US regional + host, and ``None`` for the default global host, any non-OpenAI provider, + or any non-OpenAI URL. + """ + if custom_llm_provider != "openai" or not api_base: + return None + try: + host = urlparse(api_base).hostname + except (TypeError, ValueError): + return None + if not host: + return None + return _OPENAI_REGIONAL_HOSTS.get(host.lower()) diff --git a/litellm/llms/openai/videos/transformation.py b/litellm/llms/openai/videos/transformation.py index 2d165a7d7df..520a42e9dd1 100644 --- a/litellm/llms/openai/videos/transformation.py +++ b/litellm/llms/openai/videos/transformation.py @@ -534,6 +534,7 @@ def transform_video_edit_request( litellm_params: GenericLiteLLMParams, headers: dict, extra_body: Optional[Dict[str, Any]] = None, + prefetched_source_data: Optional[Dict[str, Any]] = None, ) -> Tuple[str, Dict]: original_video_id = extract_original_video_id(video_id) url = f"{api_base.rstrip('/')}/edits" @@ -547,6 +548,7 @@ def transform_video_edit_response( raw_response: httpx.Response, logging_obj: Any, custom_llm_provider: Optional[str] = None, + request_data: Optional[Dict] = None, ) -> VideoObject: video_obj = VideoObject(**raw_response.json()) if custom_llm_provider and video_obj.id: diff --git a/litellm/llms/runwayml/videos/transformation.py b/litellm/llms/runwayml/videos/transformation.py index 4f84816a2bc..b1723f494ec 100644 --- a/litellm/llms/runwayml/videos/transformation.py +++ b/litellm/llms/runwayml/videos/transformation.py @@ -623,12 +623,23 @@ def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for RunwayML") def transform_video_edit_request( - self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + self, + prompt, + video_id, + api_base, + litellm_params, + headers, + extra_body=None, + prefetched_source_data=None, ): raise NotImplementedError("video edit is not supported for RunwayML") def transform_video_edit_response( - self, raw_response, logging_obj, custom_llm_provider=None + self, + raw_response, + logging_obj, + custom_llm_provider=None, + request_data=None, ): raise NotImplementedError("video edit is not supported for RunwayML") diff --git a/litellm/llms/vertex_ai/realtime/transformation.py b/litellm/llms/vertex_ai/realtime/transformation.py index 2b4746b174e..ea4dbccc8c8 100644 --- a/litellm/llms/vertex_ai/realtime/transformation.py +++ b/litellm/llms/vertex_ai/realtime/transformation.py @@ -14,6 +14,7 @@ import json from typing import List, Optional +from litellm import verbose_logger from litellm.llms.gemini.realtime.transformation import GeminiRealtimeConfig @@ -26,6 +27,7 @@ class VertexAIRealtimeConfig(GeminiRealtimeConfig): """ def __init__(self, access_token: str, project: str, location: str) -> None: + super().__init__() self._access_token = access_token self._project = project self._location = location @@ -138,6 +140,62 @@ def session_configuration_request(self, model: str) -> str: # Request translation # ------------------------------------------------------------------ + def _vertex_model_path(self, model: str) -> str: + """Return the fully-qualified Vertex AI model resource path.""" + return ( + f"projects/{self._project}" + f"/locations/{self._location}" + f"/publishers/google/models/{model}" + ) + + def _build_vertex_ai_setup_config(self, model: str, session_params: dict) -> dict: + """Build Vertex AI setup configuration with proper model path and defaults.""" + # Normalize GA-remapped fields (``output_modalities``, nested + # ``audio.input.transcription``, ``audio.input.turn_detection``) back to + # their flat beta keys so ``map_openai_params`` picks them up. Without + # this, GA clients' explicit modality / transcription / turn-detection + # settings would be silently dropped because ``map_openai_params`` only + # recognises the flat OpenAI-beta key names. + session_params = self._normalize_session_payload_for_mapping(session_params) + setup_config = self.map_openai_params( + optional_params={}, non_default_params=session_params + ) + + # Use full Vertex AI model path + setup_config["model"] = self._vertex_model_path(model) + + # Add Vertex AI specific defaults if not provided + generation_config = setup_config.setdefault("generationConfig", {}) + generation_config.setdefault("responseModalities", ["AUDIO"]) + + # Ensure Vertex defaults for realtimeInputConfig apply even when + # the client provided a partial ``turn_detection`` (e.g. only + # ``silence_duration_ms``). ``map_automatic_turn_detection`` sets + # ``disabled=True`` whenever ``create_response`` is absent or + # ``False``. Force ``disabled=False`` only when the client did + # not explicitly request ``create_response: False`` — that path + # is how transcription guardrails suppress automatic responses, + # and overriding it here would silently bypass the guardrail. + # Vertex Live has no "VAD on, no auto-response" mode, so callers + # that need that behaviour must accept that VAD is off. + client_turn_detection = session_params.get("turn_detection") + client_disabled_auto_response = ( + isinstance(client_turn_detection, dict) + and client_turn_detection.get("create_response") is False + ) + realtime_input_config = setup_config.setdefault("realtimeInputConfig", {}) + automatic_detection = realtime_input_config.setdefault( + "automaticActivityDetection", {} + ) + if not client_disabled_auto_response: + automatic_detection["disabled"] = False + automatic_detection.setdefault("silenceDurationMs", 800) + + setup_config.setdefault("inputAudioTranscription", {}) + setup_config.setdefault("outputAudioTranscription", {}) + + return setup_config + def transform_realtime_request( self, message: str, @@ -147,16 +205,50 @@ def transform_realtime_request( """ Translate OpenAI realtime client messages to Vertex AI format. - ``session.update`` is intentionally ignored (returns []) because - Vertex AI only accepts a single ``setup`` message at the start of - the connection — sending a second one causes a 1007 close error. - The initial setup (sent automatically before bidirectional_forward) - already includes AUDIO modality and server VAD, so there is nothing - more to configure. + On the first ``session.update`` (when no setup has been sent yet) the + full ``BidiGenerateContentSetup`` is built with Vertex AI's model path + and forwarded. Any later ``session.update`` is dropped: Vertex AI + documents ``setup`` as the first-and-only client message, and a second + ``setup`` closes the connection with a 1007 policy error. """ json_message = json.loads(message) - if json_message.get("type") == "session.update": - # Do not forward as a second setup — Vertex AI rejects it. + msg_type = json_message.get("type") + + if msg_type == "session.update": + if session_configuration_request is None: + setup_config = self._build_vertex_ai_setup_config( + model, json_message.get("session") or {} + ) + gemini_setup_msg = json.dumps({"setup": setup_config}) + + verbose_logger.debug( + "Vertex AI Realtime: Sending initial setup with tools to backend" + ) + return [gemini_setup_msg] + + # A follow-up session.update can't be forwarded as a second setup + # (Vertex Live closes the WebSocket with 1007). If this drop is + # silencing the audio-transcription guardrail's create_response + # disable, surface a warning so operators know the model will + # auto-respond before the guardrail can gate it on Vertex AI. + client_turn_detection = GeminiRealtimeConfig._extract_turn_detection( + json_message.get("session") or {} + ) + if ( + isinstance(client_turn_detection, dict) + and client_turn_detection.get("create_response") is False + ): + verbose_logger.warning( + "Vertex AI Realtime: Dropping subsequent session.update " + "(turn_detection.create_response=False) — Vertex Live " + "rejects a second setup message. Audio-transcription " + "guardrails cannot suppress the model's auto-response on " + "Vertex AI in non-deferred mode." + ) + else: + verbose_logger.debug( + "Vertex AI Realtime: Ignoring session.update (setup already sent)" + ) return [] return super().transform_realtime_request( diff --git a/litellm/llms/vertex_ai/videos/transformation.py b/litellm/llms/vertex_ai/videos/transformation.py index ed6176cef05..b84966354b8 100644 --- a/litellm/llms/vertex_ai/videos/transformation.py +++ b/litellm/llms/vertex_ai/videos/transformation.py @@ -40,6 +40,29 @@ BaseLLMException = Any +def _build_vertex_video_usage_from_request_data( + request_data: Optional[Dict[str, Any]], +) -> Dict[str, Any]: + """Build usage metadata (duration, resolution) for video cost calculation.""" + usage_data: Dict[str, Any] = {} + if not request_data: + return usage_data + + parameters = request_data.get("parameters", {}) + duration = ( + parameters.get("durationSeconds") or DEFAULT_GOOGLE_VIDEO_DURATION_SECONDS + ) + if duration is not None: + try: + usage_data["duration_seconds"] = float(duration) + except (ValueError, TypeError): + pass + res = parameters.get("resolution") + if res is not None and str(res).strip() != "": + usage_data["video_resolution"] = str(res).strip().lower() + return usage_data + + def _convert_image_to_vertex_format(image_file) -> Dict[str, str]: """ Convert image file to Vertex AI format with base64 encoding and MIME type. @@ -363,23 +386,7 @@ def transform_video_create_response( id=video_id, object="video", status="processing", model=model ) - usage_data: Dict[str, Any] = {} - if request_data: - parameters = request_data.get("parameters", {}) - duration = ( - parameters.get("durationSeconds") - or DEFAULT_GOOGLE_VIDEO_DURATION_SECONDS - ) - if duration is not None: - try: - usage_data["duration_seconds"] = float(duration) - except (ValueError, TypeError): - pass - res = parameters.get("resolution") - if res is not None and str(res).strip() != "": - usage_data["video_resolution"] = str(res).strip().lower() - - video_obj.usage = usage_data + video_obj.usage = _build_vertex_video_usage_from_request_data(request_data) return video_obj def transform_video_status_retrieve_request( @@ -647,15 +654,123 @@ def transform_video_get_character_request( def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Vertex AI") + def get_video_edit_prefetch_params( + self, + video_id: str, + api_base: str, + litellm_params: GenericLiteLLMParams, + headers: dict, + ) -> Tuple[str, Dict]: + """Return the fetchPredictOperation URL and body needed to retrieve the source video.""" + return self.transform_video_status_retrieve_request( + video_id=video_id, + api_base=api_base, + litellm_params=litellm_params, + headers=headers, + ) + def transform_video_edit_request( - self, prompt, video_id, api_base, litellm_params, headers, extra_body=None - ): - raise NotImplementedError("video edit is not supported for Vertex AI") + self, + prompt: str, + video_id: str, + api_base: str, + litellm_params: GenericLiteLLMParams, + headers: dict, + extra_body: Optional[Dict[str, Any]] = None, + prefetched_source_data: Optional[Dict[str, Any]] = None, + ) -> Tuple[str, Dict]: + """ + Build a predictLongRunning edit request from the pre-fetched source video. + + The actual fetchPredictOperation HTTP call is hoisted into the handler so + it can use the shared async/sync httpx client instead of blocking the loop. + """ + if prefetched_source_data is None: + raise ValueError( + "prefetched_source_data is required for Vertex AI video edit. " + "Ensure get_video_edit_prefetch_params is called by the handler." + ) + + if not prefetched_source_data.get("done", False): + raise ValueError( + "Source video generation is not complete yet. " + "Check the video status before editing." + ) + + videos = prefetched_source_data.get("response", {}).get("videos", []) + if not videos: + raise ValueError("No videos found in the completed operation. Cannot edit.") + + source_video = videos[0] + video_input: Dict[str, Any] = {} + if "gcsUri" in source_video: + video_input["gcsUri"] = source_video["gcsUri"] + elif "bytesBase64Encoded" in source_video: + video_input["bytesBase64Encoded"] = source_video["bytesBase64Encoded"] + video_input["mimeType"] = source_video.get("mimeType", "video/mp4") + else: + raise ValueError( + "Source video has neither gcsUri nor bytesBase64Encoded. Cannot edit." + ) + + operation_name = extract_original_video_id(video_id) + model = self.extract_model_from_operation_name(operation_name) or "" + + instance_dict: Dict[str, Any] = {"prompt": prompt, "video": video_input} + request_data: Dict[str, Any] = {"instances": [instance_dict]} + + if extra_body: + extra_body_copy = dict(extra_body) + nested_params = extra_body_copy.pop("parameters", None) + vertex_params: Dict[str, Any] = {} + if isinstance(nested_params, dict): + vertex_params.update(nested_params) + vertex_params.update(extra_body_copy) + if vertex_params: + request_data["parameters"] = vertex_params + + edit_url = f"{api_base.rstrip('/')}/{model}:predictLongRunning" + return edit_url, request_data def transform_video_edit_response( - self, raw_response, logging_obj, custom_llm_provider=None - ): - raise NotImplementedError("video edit is not supported for Vertex AI") + self, + raw_response: httpx.Response, + logging_obj: LiteLLMLoggingObj, + custom_llm_provider: Optional[str] = None, + request_data: Optional[Dict] = None, + ) -> VideoObject: + """ + Transform the Veo video edit response. + + Veo returns the same operation response as video generation: + {"name": "projects/.../operations/OPERATION_ID"} + + usage includes duration_seconds and optional video_resolution from the + edit request parameters for cost calculation. + """ + response_data = raw_response.json() + + operation_name = response_data.get("name") + if not operation_name: + raise ValueError(f"No operation name in Veo edit response: {response_data}") + + model = self.extract_model_from_operation_name(operation_name) or "" + + if custom_llm_provider: + video_id = encode_video_id_with_provider( + operation_name, custom_llm_provider, model + ) + else: + video_id = operation_name + + video_obj = VideoObject( + id=video_id, + object="video", + status="processing", + model=model, + ) + video_obj.usage = _build_vertex_video_usage_from_request_data(request_data) + return video_obj def transform_video_extension_request( self, diff --git a/litellm/main.py b/litellm/main.py index e17a5ad9a48..09c70998cf7 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -5127,6 +5127,24 @@ def embedding( # noqa: PLR0915 client=client, aembedding=aembedding, ) + elif custom_llm_provider == "oci": + if headers is None: + headers = {} + response = base_llm_http_handler.embedding( + model=model, + input=input, + custom_llm_provider=custom_llm_provider, + api_base=api_base, + api_key=api_key, + logging_obj=logging, + timeout=timeout, + model_response=EmbeddingResponse(), + optional_params=optional_params, + client=client, + aembedding=aembedding, + litellm_params=litellm_params_dict, + headers=headers, + ) elif custom_llm_provider == "cohere" or custom_llm_provider == "cohere_chat": cohere_key = ( api_key @@ -5807,22 +5825,6 @@ def embedding( # noqa: PLR0915 aembedding=aembedding, litellm_params={}, ) - elif custom_llm_provider == "oci": - response = base_llm_http_handler.embedding( - model=model, - input=input, - custom_llm_provider=custom_llm_provider, - api_base=api_base, - api_key=api_key, - logging_obj=logging, - timeout=timeout, - model_response=EmbeddingResponse(), - optional_params=optional_params, - client=client, - aembedding=aembedding, - litellm_params=litellm_params_dict, - headers=headers, - ) elif custom_llm_provider in litellm._custom_providers: custom_handler: Optional[CustomLLM] = None for item in litellm.custom_provider_map: @@ -6613,8 +6615,7 @@ def transcription( api_key=api_key, ) # type: ignore - if dynamic_api_key is not None: - api_key = dynamic_api_key + api_key = dynamic_api_key if dynamic_api_key is not None else api_key optional_params = get_optional_params_transcription( model=model, @@ -6654,7 +6655,7 @@ def transcription( provider=LlmProviders(custom_llm_provider), ) - if custom_llm_provider == "azure": + if custom_llm_provider == "azure" and provider_config is None: # azure configs api_base = api_base or litellm.api_base or get_secret_str("AZURE_API_BASE") diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 6a4a5dd6a03..ce6d4ac824c 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -731,7 +731,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "anthropic.claude-haiku-4-5@20251001": { @@ -755,7 +754,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_streaming": true, "supports_native_structured_output": true }, @@ -926,8 +924,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "anthropic.claude-opus-4-20250514-v1:0": { "cache_creation_input_token_cost": 1.875e-05, @@ -952,8 +949,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "anthropic.claude-opus-4-5-20251101-v1:0": { "cache_creation_input_token_cost": 6.25e-06, @@ -977,12 +973,12 @@ "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_native_structured_output": true + "supports_native_structured_output": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "high" }, "anthropic.claude-opus-4-6-v1": { "cache_creation_input_token_cost": 6.25e-06, @@ -1009,10 +1005,10 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, + "supports_output_config": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "bedrock_output_config_effort_ceiling": "max" }, "global.anthropic.claude-opus-4-6-v1": { "cache_creation_input_token_cost": 6.25e-06, @@ -1039,10 +1035,10 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, + "supports_output_config": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "bedrock_output_config_effort_ceiling": "max" }, "us.anthropic.claude-opus-4-6-v1": { "cache_creation_input_token_cost": 6.875e-06, @@ -1069,10 +1065,10 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, + "supports_output_config": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "bedrock_output_config_effort_ceiling": "max" }, "eu.anthropic.claude-opus-4-6-v1": { "cache_creation_input_token_cost": 6.875e-06, @@ -1098,10 +1094,10 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, + "supports_output_config": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "bedrock_output_config_effort_ceiling": "max" }, "au.anthropic.claude-opus-4-6-v1": { "cache_creation_input_token_cost": 6.875e-06, @@ -1127,10 +1123,10 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, + "supports_output_config": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "bedrock_output_config_effort_ceiling": "max" }, "anthropic.claude-opus-4-7": { "cache_creation_input_token_cost": 6.25e-06, @@ -1158,10 +1154,10 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" }, "anthropic.claude-mythos-preview": { "input_cost_per_token": 0, @@ -1175,8 +1171,8 @@ "supports_vision": true, "supports_prompt_caching": false, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_output_config": true }, "global.anthropic.claude-opus-4-7": { "cache_creation_input_token_cost": 6.25e-06, @@ -1204,10 +1200,10 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" }, "us.anthropic.claude-opus-4-7": { "cache_creation_input_token_cost": 6.875e-06, @@ -1235,10 +1231,10 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" }, "eu.anthropic.claude-opus-4-7": { "cache_creation_input_token_cost": 6.875e-06, @@ -1265,10 +1261,10 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" }, "au.anthropic.claude-opus-4-7": { "cache_creation_input_token_cost": 6.875e-06, @@ -1295,10 +1291,165 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" + }, + "anthropic.claude-opus-4-8": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_native_structured_output": true, + "supports_max_reasoning_effort": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" + }, + "global.anthropic.claude-opus-4-8": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_native_structured_output": true, + "supports_max_reasoning_effort": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" + }, + "us.anthropic.claude-opus-4-8": { + "cache_creation_input_token_cost": 6.875e-06, + "cache_creation_input_token_cost_above_1hr": 1.1e-05, + "cache_read_input_token_cost": 5.5e-07, + "input_cost_per_token": 5.5e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.75e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_native_structured_output": true, + "supports_max_reasoning_effort": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" + }, + "eu.anthropic.claude-opus-4-8": { + "cache_creation_input_token_cost": 6.875e-06, + "cache_creation_input_token_cost_above_1hr": 1.1e-05, + "cache_read_input_token_cost": 5.5e-07, + "input_cost_per_token": 5.5e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.75e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_native_structured_output": true, + "supports_max_reasoning_effort": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" + }, + "au.anthropic.claude-opus-4-8": { + "cache_creation_input_token_cost": 6.875e-06, + "cache_creation_input_token_cost_above_1hr": 1.1e-05, + "cache_read_input_token_cost": 5.5e-07, + "input_cost_per_token": 5.5e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.75e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_native_structured_output": true, + "supports_max_reasoning_effort": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "xhigh" }, "anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 3.75e-06, @@ -1326,9 +1477,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "global.anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 3.75e-06, @@ -1356,9 +1506,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "us.anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 4.125e-06, @@ -1386,9 +1535,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "eu.anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 4.125e-06, @@ -1415,9 +1563,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "au.anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 4.125e-06, @@ -1444,9 +1591,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "jp.anthropic.claude-sonnet-4-6": { "cache_creation_input_token_cost": 4.125e-06, @@ -1473,9 +1619,8 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "anthropic.claude-sonnet-4-20250514-v1:0": { "cache_creation_input_token_cost": 3.75e-06, @@ -1504,8 +1649,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "anthropic.claude-sonnet-4-5-20250929-v1:0": { "cache_creation_input_token_cost": 3.75e-06, @@ -1537,7 +1681,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, "supports_native_structured_output": true }, "anthropic.claude-v1": { @@ -1788,7 +1931,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "apac.anthropic.claude-3-sonnet-20240229-v1:0": { @@ -1834,8 +1976,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "assemblyai/best": { "input_cost_per_second": 3.333e-05, @@ -1877,7 +2018,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "azure/ada": { @@ -1965,10 +2105,10 @@ "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_output_config": true }, "azure_ai/claude-opus-4-6": { "input_cost_per_token": 5e-06, @@ -1995,9 +2135,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "supports_max_reasoning_effort": true }, "azure_ai/claude-opus-4-7": { "input_cost_per_token": 5e-06, @@ -2025,9 +2164,35 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 159, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_max_reasoning_effort": true + }, + "azure_ai/claude-opus-4-8": { + "input_cost_per_token": 5e-06, + "output_cost_per_token": 2.5e-05, + "litellm_provider": "azure_ai", + "max_input_tokens": 200000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_max_reasoning_effort": true }, "azure_ai/claude-opus-4-1": { "cache_creation_input_token_cost": 1.875e-05, @@ -2092,8 +2257,7 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "azure/computer-use-preview": { "input_cost_per_token": 3e-06, @@ -6054,6 +6218,17 @@ "mode": "audio_speech", "source": "https://azure.microsoft.com/en-us/pricing/calculator/" }, + "azure/speech/azure-stt": { + "audio_transcription_config": "azure_speech", + "input_cost_per_second": 0.0002777778, + "litellm_provider": "azure", + "mode": "audio_transcription", + "output_cost_per_second": 0.0, + "source": "https://azure.microsoft.com/en-us/pricing/details/cognitive-services/speech-services/", + "supported_endpoints": [ + "/v1/audio/transcriptions" + ] + }, "azure/tts-1": { "input_cost_per_character": 1.5e-05, "litellm_provider": "azure", @@ -9456,8 +9631,7 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "supports_web_search": true, - "tool_use_system_prompt_tokens": 159 + "supports_web_search": true }, "claude-3-haiku-20240307": { "cache_creation_input_token_cost": 3e-07, @@ -9475,8 +9649,7 @@ "supports_prompt_caching": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 264 + "supports_vision": true }, "claude-3-opus-20240229": { "cache_creation_input_token_cost": 1.875e-05, @@ -9495,8 +9668,7 @@ "supports_prompt_caching": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 395 + "supports_vision": true }, "claude-4-opus-20250514": { "cache_creation_input_token_cost": 1.875e-05, @@ -9521,8 +9693,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "claude-4-sonnet-20250514": { "cache_creation_input_token_cost": 3.75e-06, @@ -9552,8 +9723,7 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "supports_web_search": true, - "tool_use_system_prompt_tokens": 159 + "supports_web_search": true }, "claude-sonnet-4-5": { "cache_creation_input_token_cost": 3.75e-06, @@ -9582,8 +9752,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 346 + "supports_vision": true }, "claude-sonnet-4-5-20250929": { "cache_creation_input_token_cost": 3.75e-06, @@ -9613,8 +9782,7 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "supports_web_search": true, - "tool_use_system_prompt_tokens": 346 + "supports_web_search": true }, "claude-sonnet-4-6": { "cache_creation_input_token_cost": 3.75e-06, @@ -9642,8 +9810,7 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "claude-sonnet-4-5-20250929-v1:0": { "cache_creation_input_token_cost": 3.75e-06, @@ -9667,8 +9834,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "claude-opus-4-1": { "cache_creation_input_token_cost": 1.875e-05, @@ -9694,8 +9860,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "claude-opus-4-1-20250805": { "cache_creation_input_token_cost": 1.875e-05, @@ -9722,8 +9887,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "claude-opus-4-20250514": { "cache_creation_input_token_cost": 1.875e-05, @@ -9750,8 +9914,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "claude-opus-4-5-20251101": { "cache_creation_input_token_cost": 6.25e-06, @@ -9775,11 +9938,10 @@ "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_output_config": true }, "claude-opus-4-5": { "cache_creation_input_token_cost": 6.25e-06, @@ -9803,11 +9965,10 @@ "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_output_config": true }, "claude-opus-4-6": { "cache_creation_input_token_cost": 6.25e-06, @@ -9835,13 +9996,12 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "provider_specific_entry": { "us": 1.1, "fast": 6.0 }, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "supports_max_reasoning_effort": true }, "claude-opus-4-6-20260205": { "cache_creation_input_token_cost": 6.25e-06, @@ -9869,13 +10029,12 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "provider_specific_entry": { "us": 1.1, "fast": 6.0 }, "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "claude-opus-4-7": { "cache_creation_input_token_cost": 6.25e-06, @@ -9905,12 +10064,11 @@ "supports_vision": true, "supports_xhigh_reasoning_effort": true, "supports_max_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "provider_specific_entry": { "us": 1.1, "fast": 6.0 }, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "claude-opus-4-7-20260416": { "cache_creation_input_token_cost": 6.25e-06, @@ -9940,12 +10098,45 @@ "supports_vision": true, "supports_xhigh_reasoning_effort": true, "supports_max_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, "provider_specific_entry": { "us": 1.1, "fast": 6.0 }, - "supports_minimal_reasoning_effort": true + "supports_output_config": true + }, + "claude-opus-4-8": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "anthropic", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_adaptive_thinking": true, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_max_reasoning_effort": true, + "provider_specific_entry": { + "us": 1.1, + "fast": 2.0 + }, + "supports_output_config": true }, "claude-sonnet-4-20250514": { "deprecation_date": "2026-05-14", @@ -9976,8 +10167,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "cloudflare/@cf/meta/llama-2-7b-chat-fp16": { "input_cost_per_token": 1.923e-06, @@ -11222,8 +11412,8 @@ "supports_assistant_prefill": true, "supports_function_calling": true, "supports_reasoning": true, - "supports_minimal_reasoning_effort": true, - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_output_config": true }, "databricks/databricks-claude-sonnet-4": { "input_cost_per_token": 2.9999900000000002e-06, @@ -13389,7 +13579,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "eu.anthropic.claude-3-5-sonnet-20240620-v1:0": { @@ -13517,8 +13706,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "eu.anthropic.claude-opus-4-20250514-v1:0": { "cache_creation_input_token_cost": 1.875e-05, @@ -13543,8 +13731,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "eu.anthropic.claude-sonnet-4-20250514-v1:0": { "cache_creation_input_token_cost": 3.75e-06, @@ -13573,8 +13760,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { "cache_creation_input_token_cost": 4.125e-06, @@ -13604,7 +13790,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "eu.meta.llama3-2-1b-instruct-v1:0": { @@ -14947,7 +15132,7 @@ "mode": "chat", "output_cost_per_reasoning_token": 1.5e-06, "output_cost_per_token": 1.5e-06, - "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing#gemini-models", + "source": "https://ai.google.dev/gemini-api/docs/models", "supported_endpoints": [ "/v1/chat/completions", "/v1/completions", @@ -17890,22 +18075,23 @@ }, "github_copilot/claude-haiku-4.5": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, - "max_output_tokens": 16000, - "max_tokens": 16000, + "max_input_tokens": 200000, + "max_output_tokens": 32000, + "max_tokens": 32000, "mode": "chat", "supported_endpoints": [ "/v1/chat/completions" ], "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supports_reasoning": true }, "github_copilot/claude-opus-4.5": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, - "max_output_tokens": 16000, - "max_tokens": 16000, + "max_input_tokens": 200000, + "max_output_tokens": 32000, + "max_tokens": 32000, "mode": "chat", "supported_endpoints": [ "/v1/chat/completions" @@ -17913,7 +18099,8 @@ "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_vision": true, - "supports_minimal_reasoning_effort": true + "supports_reasoning": true, + "supports_output_config": true }, "github_copilot/claude-opus-4.6-fast": { "litellm_provider": "github_copilot", @@ -17928,6 +18115,22 @@ "supports_parallel_function_calling": true, "supports_vision": true }, + "github_copilot/claude-opus-4.7": { + "litellm_provider": "github_copilot", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/messages" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true + }, "github_copilot/claude-opus-41": { "litellm_provider": "github_copilot", "max_input_tokens": 80000, @@ -17954,16 +18157,33 @@ }, "github_copilot/claude-sonnet-4.5": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, - "max_output_tokens": 16000, - "max_tokens": 16000, + "max_input_tokens": 200000, + "max_output_tokens": 32000, + "max_tokens": 32000, "mode": "chat", "supported_endpoints": [ "/v1/chat/completions" ], "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supports_reasoning": true + }, + "github_copilot/claude-sonnet-4.6": { + "litellm_provider": "github_copilot", + "max_input_tokens": 200000, + "max_output_tokens": 32000, + "max_tokens": 32000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/messages" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true }, "github_copilot/gemini-2.5-pro": { "litellm_provider": "github_copilot", @@ -17973,7 +18193,25 @@ "mode": "chat", "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ], + "supports_reasoning": true + }, + "github_copilot/gemini-3-flash-preview": { + "litellm_provider": "github_copilot", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_reasoning": true }, "github_copilot/gemini-3-pro-preview": { "litellm_provider": "github_copilot", @@ -17985,13 +18223,30 @@ "supports_parallel_function_calling": true, "supports_vision": true }, + "github_copilot/gemini-3.1-pro-preview": { + "litellm_provider": "github_copilot", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_reasoning": true + }, "github_copilot/gpt-3.5-turbo": { "litellm_provider": "github_copilot", "max_input_tokens": 16384, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "supports_function_calling": true + "supports_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-3.5-turbo-0613": { "litellm_provider": "github_copilot", @@ -17999,7 +18254,10 @@ "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "supports_function_calling": true + "supports_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4": { "litellm_provider": "github_copilot", @@ -18007,7 +18265,22 @@ "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "supports_function_calling": true + "supports_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] + }, + "github_copilot/gpt-4-0125-preview": { + "litellm_provider": "github_copilot", + "max_input_tokens": 128000, + "max_output_tokens": 4096, + "max_tokens": 4096, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true }, "github_copilot/gpt-4-0613": { "litellm_provider": "github_copilot", @@ -18015,16 +18288,22 @@ "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "supports_function_calling": true + "supports_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4-o-preview": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", "supports_function_calling": true, - "supports_parallel_function_calling": true + "supports_parallel_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4.1": { "litellm_provider": "github_copilot", @@ -18035,7 +18314,10 @@ "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_response_schema": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4.1-2025-04-14": { "litellm_provider": "github_copilot", @@ -18046,68 +18328,89 @@ "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_response_schema": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-41-copilot": { "litellm_provider": "github_copilot", - "mode": "completion" + "mode": "chat" }, "github_copilot/gpt-4o": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4o-2024-05-13": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4o-2024-08-06": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 16384, "max_tokens": 16384, "mode": "chat", "supports_function_calling": true, - "supports_parallel_function_calling": true + "supports_parallel_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4o-2024-11-20": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 16384, "max_tokens": 16384, "mode": "chat", "supports_function_calling": true, "supports_parallel_function_calling": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4o-mini": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", "supports_function_calling": true, - "supports_parallel_function_calling": true + "supports_parallel_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-4o-mini-2024-07-18": { "litellm_provider": "github_copilot", - "max_input_tokens": 64000, + "max_input_tokens": 128000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", "supports_function_calling": true, - "supports_parallel_function_calling": true + "supports_parallel_function_calling": true, + "supported_endpoints": [ + "/v1/chat/completions" + ] }, "github_copilot/gpt-5": { "litellm_provider": "github_copilot", @@ -18126,14 +18429,19 @@ }, "github_copilot/gpt-5-mini": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, + "max_input_tokens": 264000, "max_output_tokens": 64000, "max_tokens": 64000, "mode": "chat", "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_response_schema": true, - "supports_vision": true + "supports_vision": true, + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_reasoning": true }, "github_copilot/gpt-5.1": { "litellm_provider": "github_copilot", @@ -18166,7 +18474,7 @@ }, "github_copilot/gpt-5.2": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, + "max_input_tokens": 264000, "max_output_tokens": 64000, "max_tokens": 64000, "mode": "chat", @@ -18177,11 +18485,27 @@ "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_response_schema": true, - "supports_vision": true + "supports_vision": true, + "supports_reasoning": true + }, + "github_copilot/gpt-5.2-codex": { + "litellm_provider": "github_copilot", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true }, "github_copilot/gpt-5.3-codex": { "litellm_provider": "github_copilot", - "max_input_tokens": 128000, + "max_input_tokens": 400000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", @@ -18191,25 +18515,96 @@ "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_response_schema": true, - "supports_vision": true + "supports_vision": true, + "supports_reasoning": true + }, + "github_copilot/gpt-5.4": { + "litellm_provider": "github_copilot", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true + }, + "github_copilot/gpt-5.4-mini": { + "litellm_provider": "github_copilot", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true + }, + "github_copilot/gpt-5.5": { + "litellm_provider": "github_copilot", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_reasoning": true + }, + "github_copilot/oswe-vscode-prime": { + "litellm_provider": "github_copilot", + "max_input_tokens": 264000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_vision": true, + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true }, "github_copilot/text-embedding-3-small": { "litellm_provider": "github_copilot", "max_input_tokens": 8191, "max_tokens": 8191, - "mode": "embedding" + "mode": "embedding", + "supported_endpoints": [ + "/v1/embeddings" + ] }, "github_copilot/text-embedding-3-small-inference": { "litellm_provider": "github_copilot", "max_input_tokens": 8191, "max_tokens": 8191, - "mode": "embedding" + "mode": "embedding", + "supported_endpoints": [ + "/v1/embeddings" + ] }, "github_copilot/text-embedding-ada-002": { "litellm_provider": "github_copilot", "max_input_tokens": 8191, "max_tokens": 8191, - "mode": "embedding" + "mode": "embedding", + "supported_endpoints": [ + "/v1/embeddings" + ] }, "chatgpt/gpt-5.4": { "litellm_provider": "chatgpt", @@ -18427,7 +18822,7 @@ "output_cost_per_token": 2.5e-05, "supports_function_calling": true, "supports_vision": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "gmi/anthropic/claude-sonnet-4.5": { "input_cost_per_token": 3e-06, @@ -18727,7 +19122,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "global.anthropic.claude-sonnet-4-20250514-v1:0": { @@ -18757,8 +19151,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "global.anthropic.claude-haiku-4-5-20251001-v1:0": { "cache_creation_input_token_cost": 1.25e-06, @@ -18781,7 +19174,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "global.amazon.nova-2-lite-v1:0": { @@ -19003,6 +19395,8 @@ "output_cost_per_token": 8e-06, "output_cost_per_token_batches": 4e-06, "output_cost_per_token_priority": 1.4e-05, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -19076,6 +19470,8 @@ "output_cost_per_token": 1.6e-06, "output_cost_per_token_batches": 8e-07, "output_cost_per_token_priority": 2.8e-06, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -19149,6 +19545,8 @@ "output_cost_per_token": 4e-07, "output_cost_per_token_batches": 2e-07, "output_cost_per_token_priority": 8e-07, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -19220,6 +19618,8 @@ "output_cost_per_token": 1e-05, "output_cost_per_token_batches": 5e-06, "output_cost_per_token_priority": 1.7e-05, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_pdf_input": true, @@ -19261,6 +19661,8 @@ "mode": "chat", "output_cost_per_token": 1e-05, "output_cost_per_token_batches": 5e-06, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_pdf_input": true, @@ -19282,6 +19684,8 @@ "mode": "chat", "output_cost_per_token": 1e-05, "output_cost_per_token_batches": 5e-06, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_pdf_input": true, @@ -19570,6 +19974,8 @@ "output_cost_per_token": 6e-07, "output_cost_per_token_batches": 3e-07, "output_cost_per_token_priority": 1e-06, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supports_function_calling": true, "supports_parallel_function_calling": true, "supports_pdf_input": true, @@ -20273,6 +20679,8 @@ "output_cost_per_token": 1e-05, "output_cost_per_token_flex": 5e-06, "output_cost_per_token_priority": 2e-05, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21195,6 +21603,8 @@ "mode": "responses", "output_cost_per_token": 0.00012, "output_cost_per_token_batches": 6e-05, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/batch", "/v1/responses" @@ -21601,6 +22011,8 @@ "output_cost_per_token": 2e-06, "output_cost_per_token_flex": 1e-06, "output_cost_per_token_priority": 3.6e-06, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21682,6 +22094,8 @@ "max_input_tokens": 272000, "max_output_tokens": 128000, "max_tokens": 128000, + "regional_processing_uplift_multiplier_eu": 1.10, + "regional_processing_uplift_multiplier_us": 1.10, "mode": "chat", "output_cost_per_token": 4e-07, "output_cost_per_token_flex": 2e-07, @@ -22867,7 +23281,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "jp.anthropic.claude-haiku-4-5-20251001-v1:0": { @@ -22890,7 +23303,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "crusoe/deepseek-ai/DeepSeek-R1-0528": { @@ -26297,6 +26709,51 @@ "supports_function_calling": true, "supports_response_schema": false }, + "oci/openai.gpt-5": { + "input_cost_per_token": 1.25e-06, + "litellm_provider": "oci", + "max_input_tokens": 272000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 1e-05, + "source": "https://www.oracle.com/artificial-intelligence/generative-ai/generative-ai-service/pricing", + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_vision": true + }, + "oci/openai.gpt-5-mini": { + "input_cost_per_token": 2.5e-07, + "litellm_provider": "oci", + "max_input_tokens": 272000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2e-06, + "source": "https://www.oracle.com/artificial-intelligence/generative-ai/generative-ai-service/pricing", + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_vision": true + }, + "oci/openai.gpt-5-nano": { + "input_cost_per_token": 5e-08, + "litellm_provider": "oci", + "max_input_tokens": 272000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 4e-07, + "source": "https://www.oracle.com/artificial-intelligence/generative-ai/generative-ai-service/pricing", + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_vision": true + }, "oci/google.gemini-2.5-pro": { "input_cost_per_token": 1.25e-06, "litellm_provider": "oci", @@ -26787,8 +27244,7 @@ "supports_computer_use": true, "supports_function_calling": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-3.7-sonnet": { "input_cost_per_image": 0.0048, @@ -26804,8 +27260,7 @@ "supports_function_calling": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-opus-4": { "input_cost_per_image": 0.0048, @@ -26824,8 +27279,7 @@ "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-opus-4.1": { "input_cost_per_image": 0.0048, @@ -26845,8 +27299,7 @@ "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-sonnet-4": { "input_cost_per_image": 0.0048, @@ -26869,8 +27322,7 @@ "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-sonnet-4.6": { "cache_creation_input_token_cost": 3.75e-06, @@ -26894,9 +27346,7 @@ "supports_reasoning": true, "supports_max_reasoning_effort": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_minimal_reasoning_effort": true + "supports_vision": true }, "openrouter/anthropic/claude-opus-4.5": { "cache_creation_input_token_cost": 6.25e-06, @@ -26911,12 +27361,11 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_output_config": true }, "openrouter/anthropic/claude-opus-4.6": { "cache_creation_input_token_cost": 6.25e-06, @@ -26935,9 +27384,7 @@ "supports_reasoning": true, "supports_max_reasoning_effort": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 346, - "supports_minimal_reasoning_effort": true + "supports_vision": true }, "openrouter/anthropic/claude-sonnet-4.5": { "input_cost_per_image": 0.0048, @@ -26960,8 +27407,7 @@ "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "openrouter/anthropic/claude-haiku-4.5": { "cache_creation_input_token_cost": 1.25e-06, @@ -26979,8 +27425,7 @@ "supports_prompt_caching": true, "supports_reasoning": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 346 + "supports_vision": true }, "openrouter/anthropic/claude-opus-4.7": { "cache_creation_input_token_cost": 6.25e-06, @@ -27002,8 +27447,7 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346 + "supports_xhigh_reasoning_effort": true }, "openrouter/bytedance/ui-tars-1.5-7b": { "input_cost_per_token": 1e-07, @@ -28187,10 +28631,10 @@ "supports_tool_choice": true }, "openrouter/xiaomi/mimo-v2-flash": { - "input_cost_per_token": 9e-08, - "output_cost_per_token": 2.9e-07, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 3e-07, "cache_creation_input_token_cost": 0.0, - "cache_read_input_token_cost": 0.0, + "cache_read_input_token_cost": 1e-08, "litellm_provider": "openrouter", "max_input_tokens": 262144, "max_output_tokens": 16384, @@ -28200,7 +28644,43 @@ "supports_tool_choice": true, "supports_reasoning": true, "supports_vision": false, - "supports_prompt_caching": false + "supports_prompt_caching": true + }, + "openrouter/xiaomi/mimo-v2.5-pro": { + "input_cost_per_token": 1e-06, + "output_cost_per_token": 3e-06, + "cache_creation_input_token_cost": 0.0, + "cache_read_input_token_cost": 2e-07, + "litellm_provider": "openrouter", + "max_input_tokens": 1048576, + "max_output_tokens": 16384, + "max_tokens": 16384, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_reasoning": true, + "supports_vision": false, + "supports_response_schema": true, + "supports_prompt_caching": true + }, + "openrouter/xiaomi/mimo-v2.5": { + "input_cost_per_token": 4e-07, + "output_cost_per_token": 2e-06, + "cache_creation_input_token_cost": 0.0, + "cache_read_input_token_cost": 8e-08, + "litellm_provider": "openrouter", + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "max_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_reasoning": true, + "supports_vision": true, + "supports_audio_input": true, + "supports_video_input": true, + "supports_response_schema": true, + "supports_prompt_caching": true }, "openrouter/z-ai/glm-4.7": { "input_cost_per_token": 4e-07, @@ -28931,14 +29411,16 @@ "mode": "responses", "supports_web_search": true, "supports_reasoning": false, - "supports_function_calling": true + "supports_function_calling": true, + "supports_output_config": true }, "perplexity/anthropic/claude-opus-4-7": { "litellm_provider": "perplexity", "mode": "responses", "supports_web_search": true, "supports_reasoning": false, - "supports_function_calling": true + "supports_function_calling": true, + "supports_output_config": true }, "perplexity/anthropic/claude-opus-4-5": { "litellm_provider": "perplexity", @@ -28946,7 +29428,7 @@ "supports_web_search": true, "supports_reasoning": false, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "perplexity/anthropic/claude-sonnet-4-5": { "litellm_provider": "perplexity", @@ -31199,7 +31681,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "us.anthropic.claude-3-5-sonnet-20240620-v1:0": { @@ -31327,8 +31808,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { "cache_creation_input_token_cost": 4.125e-06, @@ -31360,7 +31840,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0": { @@ -31386,7 +31865,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "au.anthropic.claude-haiku-4-5-20251001-v1:0": { @@ -31408,7 +31886,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true }, "us.anthropic.claude-opus-4-20250514-v1:0": { @@ -31434,8 +31911,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "us.anthropic.claude-opus-4-5-20251101-v1:0": { "cache_creation_input_token_cost": 6.875e-06, @@ -31456,15 +31932,15 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_native_structured_output": true + "supports_native_structured_output": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "high" }, "global.anthropic.claude-opus-4-5-20251101-v1:0": { "cache_creation_input_token_cost": 6.25e-06, @@ -31485,15 +31961,15 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_native_structured_output": true + "supports_native_structured_output": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "high" }, "eu.anthropic.claude-opus-4-5-20251101-v1:0": { "cache_creation_input_token_cost": 6.25e-06, @@ -31513,15 +31989,15 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_native_structured_output": true + "supports_native_structured_output": true, + "supports_output_config": true, + "bedrock_output_config_effort_ceiling": "high" }, "us.anthropic.claude-sonnet-4-20250514-v1:0": { "cache_creation_input_token_cost": 3.75e-06, @@ -31550,8 +32026,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "us.deepseek.r1-v1:0": { "input_cost_per_token": 1.35e-06, @@ -32094,13 +32569,13 @@ "output_cost_per_token": 2.5e-05, "supports_assistant_prefill": true, "supports_computer_use": true, - "supports_minimal_reasoning_effort": true, "supports_function_calling": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_output_config": true }, "vercel_ai_gateway/anthropic/claude-opus-4.6": { "cache_creation_input_token_cost": 6.25e-06, @@ -32120,7 +32595,7 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "vercel_ai_gateway/anthropic/claude-sonnet-4": { "cache_creation_input_token_cost": 3.75e-06, @@ -33128,8 +33603,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "vertex_ai/claude-3-haiku": { "input_cost_per_token": 2.5e-07, @@ -33232,8 +33706,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "vertex_ai/claude-opus-4-1": { "cache_creation_input_token_cost": 1.875e-05, @@ -33287,14 +33760,13 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_output_config": true }, "vertex_ai/claude-opus-4-5@20251101": { "cache_creation_input_token_cost": 6.25e-06, @@ -33314,15 +33786,14 @@ "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, - "supports_minimal_reasoning_effort": true, "supports_pdf_input": true, "supports_prompt_caching": true, "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 159, - "supports_native_streaming": true + "supports_native_streaming": true, + "supports_output_config": true }, "vertex_ai/claude-opus-4-6": { "cache_creation_input_token_cost": 6.25e-06, @@ -33348,9 +33819,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "supports_max_reasoning_effort": true }, "vertex_ai/claude-opus-4-6@default": { "cache_creation_input_token_cost": 6.25e-06, @@ -33376,9 +33846,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_output_config": true, + "supports_max_reasoning_effort": true }, "vertex_ai/claude-opus-4-7": { "cache_creation_input_token_cost": 6.25e-06, @@ -33405,9 +33874,7 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_max_reasoning_effort": true }, "vertex_ai/claude-opus-4-7@default": { "cache_creation_input_token_cost": 6.25e-06, @@ -33434,9 +33901,63 @@ "supports_tool_choice": true, "supports_vision": true, "supports_xhigh_reasoning_effort": true, - "tool_use_system_prompt_tokens": 346, - "supports_max_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_max_reasoning_effort": true + }, + "vertex_ai/claude-opus-4-8": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "vertex_ai-anthropic_models", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_max_reasoning_effort": true + }, + "vertex_ai/claude-opus-4-8@default": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "vertex_ai-anthropic_models", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true, + "supports_max_reasoning_effort": true }, "vertex_ai/claude-sonnet-4-5": { "cache_creation_input_token_cost": 3.75e-06, @@ -33484,13 +34005,12 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "search_context_cost_per_query": { "search_context_size_high": 0.01, "search_context_size_low": 0.01, "search_context_size_medium": 0.01 }, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "vertex_ai/claude-sonnet-4-5@20250929": { "cache_creation_input_token_cost": 3.75e-06, @@ -33542,8 +34062,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "vertex_ai/claude-sonnet-4": { "cache_creation_input_token_cost": 3.75e-06, @@ -33572,8 +34091,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "vertex_ai/claude-sonnet-4@20250514": { "cache_creation_input_token_cost": 3.75e-06, @@ -33602,8 +34120,7 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true, - "tool_use_system_prompt_tokens": 159 + "supports_vision": true }, "vertex_ai/mistralai/codestral-2@001": { "input_cost_per_token": 3e-07, @@ -40596,13 +41113,12 @@ "supports_max_reasoning_effort": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "search_context_cost_per_query": { "search_context_size_high": 0.01, "search_context_size_low": 0.01, "search_context_size_medium": 0.01 }, - "supports_minimal_reasoning_effort": true + "supports_output_config": true }, "duckduckgo/search": { "litellm_provider": "duckduckgo", @@ -40918,7 +41434,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_pdf_input": true }, @@ -40941,7 +41456,6 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "tool_use_system_prompt_tokens": 346, "supports_native_structured_output": true, "supports_pdf_input": true } diff --git a/litellm/passthrough/utils.py b/litellm/passthrough/utils.py index d39a0dda152..9484922833a 100644 --- a/litellm/passthrough/utils.py +++ b/litellm/passthrough/utils.py @@ -71,6 +71,11 @@ def forward_headers_from_request( request_headers.pop("content-length", None) request_headers.pop("host", None) + custom_header_names = {header_name.lower() for header_name in headers} + for header_name in list(request_headers.keys()): + if header_name.lower() in custom_header_names: + request_headers.pop(header_name, None) + # Combine request headers with custom headers headers = {**request_headers, **headers} diff --git a/litellm/proxy/_experimental/mcp_server/CLAUDE.md b/litellm/proxy/_experimental/mcp_server/CLAUDE.md new file mode 100644 index 00000000000..0ba8f73315f --- /dev/null +++ b/litellm/proxy/_experimental/mcp_server/CLAUDE.md @@ -0,0 +1 @@ +MCP note: **`available_on_public_internet: false` with `delegate_auth_to_upstream: true` (oauth2, interactive - not `client_credentials`)** - LiteLLM still allows the anonymous upstream PKCE path (no proxy API key for `/authorize` and matching MCP routes). The internal-only flag mainly affects other surfaces (e.g. IP-based discovery). Rely on the upstream IdP and network policy; the dashboard shows a warning when both are set, and the proxy logs a warning when the server is loaded from config or the database diff --git a/litellm/proxy/_experimental/mcp_server/auth/litellm_auth_handler.py b/litellm/proxy/_experimental/mcp_server/auth/litellm_auth_handler.py index 75b75d3ba44..7122c64ec64 100644 --- a/litellm/proxy/_experimental/mcp_server/auth/litellm_auth_handler.py +++ b/litellm/proxy/_experimental/mcp_server/auth/litellm_auth_handler.py @@ -20,7 +20,7 @@ class MCPAuthenticatedUser(AuthenticatedUser): def __init__( self, - user_api_key_auth: UserAPIKeyAuth, + user_api_key_auth: Optional[UserAPIKeyAuth], mcp_auth_header: Optional[str] = None, mcp_servers: Optional[List[str]] = None, mcp_server_auth_headers: Optional[Dict[str, Dict[str, str]]] = None, diff --git a/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py b/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py index 708ec7f1176..2aacab80f57 100644 --- a/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py +++ b/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py @@ -118,15 +118,19 @@ async def mock_body(): return b"{}" request.body = mock_body # type: ignore + # Inline import — auth_utils participates in a proxy import cycle. + from litellm.proxy.auth.auth_utils import ( # noqa: PLC0415 + get_request_route, + ) + + request_route = get_request_route(request) # Only OAuth metadata routes registered under /.well-known/ are public. - # Match on request.url.path (path-only, exact prefix) so the substring - # cannot be smuggled via query string, hostname, or a deeper URL segment. - if request.url.path.startswith("/.well-known/"): + if request_route.startswith("/.well-known/"): validated_user_api_key_auth = UserAPIKeyAuth() elif ( not litellm_api_key and MCPRequestHandler._target_servers_delegate_auth_to_upstream( # noqa: E501 - path=request.url.path, mcp_servers=mcp_servers + path=request_route, mcp_servers=mcp_servers ) ): # Operator opted this oauth2 server into upstream-delegated auth @@ -174,7 +178,7 @@ async def mock_body(): "401", "403", ) and MCPRequestHandler._target_servers_use_oauth2( - path=request.url.path, mcp_servers=mcp_servers + path=request_route, mcp_servers=mcp_servers ): verbose_logger.debug( "MCP OAuth2: target server is OAuth2-mode, treating " @@ -562,25 +566,33 @@ async def get_allowed_mcp_servers( ) ) + key_access_group_grants = ( + await MCPRequestHandler._get_key_access_group_mcp_server_extras( + user_api_key_auth + ) + ) + ######################################################### # Calculate key/team allowed servers using inheritance and intersection logic ######################################################### - allowed_mcp_servers: List[str] = [] - has_lower_level_mcp_restrictions = ( - len(allowed_mcp_servers_for_key) > 0 - or len(allowed_mcp_servers_for_team) > 0 - ) - if len(allowed_mcp_servers_for_team) > 0: - if len(allowed_mcp_servers_for_key) > 0: - # Key has its own MCP permissions - use intersection with team permissions - for _mcp_server in allowed_mcp_servers_for_key: - if _mcp_server in allowed_mcp_servers_for_team: - allowed_mcp_servers.append(_mcp_server) - else: - # Key has no MCP permissions - inherit from team - allowed_mcp_servers = allowed_mcp_servers_for_team + key_set = set(allowed_mcp_servers_for_key) + team_set = set(allowed_mcp_servers_for_team) + grants_set = set(key_access_group_grants) + + has_lower_level_mcp_restrictions = bool(key_set or team_set or grants_set) + + # 1. Key/team ceiling. An empty set means "this level does not restrict". + if not team_set: + base = key_set # no team restriction + elif not key_set: + base = team_set # key has no own perms → inherits team else: - allowed_mcp_servers = allowed_mcp_servers_for_key + base = key_set & team_set # both restrict → intersect + + # 2. Add the key's access-group grants on top. These are additive: + # attaching a group to the key grants its servers regardless of the + # team ceiling. + allowed_mcp_servers: List[str] = list(base | grants_set) ######################################################### # Check end_user permissions if end_user_id is set @@ -873,43 +885,98 @@ def is_tool_allowed( return True return False + @staticmethod + async def _get_key_access_group_mcp_server_extras( + user_api_key_auth: Optional[UserAPIKeyAuth] = None, + ) -> List[str]: + """ + Resolve the key's unified `access_group_ids` (LiteLLM_AccessGroupTable) to + MCP server IDs as additive grants: a group attached to the key extends the + key's allowed servers on top of the key/team ceiling rather than being + capped by the team. Attaching the group to the key is itself the grant — + no `assigned_key_ids` / `assigned_team_ids` re-check. Tag-style + `mcp_access_groups` (per-server tags) live in the key's object_permission + scope, not here. + """ + if user_api_key_auth is None: + return [] + try: + from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( + global_mcp_server_manager, + ) + from litellm.proxy.auth.auth_checks import ( + _get_mcp_server_ids_from_access_groups, + ) + from litellm.proxy.proxy_server import ( + prisma_client, + proxy_logging_obj, + user_api_key_cache, + ) + + raw_server_ids = await _get_mcp_server_ids_from_access_groups( + access_group_ids=user_api_key_auth.access_group_ids or [], + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) + if not raw_server_ids: + return [] + # Permission entries may be server_ids OR names/aliases — expand to ids. + return global_mcp_server_manager.expand_permission_list(raw_server_ids) + except Exception as e: + verbose_logger.warning( + f"Failed to get key access group MCP server grants: {str(e)}" + ) + return [] + @staticmethod async def _get_allowed_mcp_servers_for_key( user_api_key_auth: Optional[UserAPIKeyAuth] = None, ) -> List[str]: + """ + Get the key's own MCP ceiling from its object_permission + (mcp_servers, tag-style mcp_access_groups, mcp_tool_permissions). + + Unified key.access_group_ids are NOT resolved here — they are additive + grants handled by _get_key_access_group_mcp_server_extras and unioned on + top of the key/team ceiling, so they must not enter this scope (which is + intersected against the team). + """ + if user_api_key_auth is None: + return [] try: + from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( + global_mcp_server_manager, + ) + from litellm.proxy.auth.auth_checks import ( + get_object_permission, + ) + from litellm.proxy.proxy_server import ( + prisma_client, + proxy_logging_obj, + user_api_key_cache, + ) + # Get key object permission (already loaded in main auth flow, or fetch from DB) key_object_permission = MCPRequestHandler._get_key_object_permission( user_api_key_auth ) if ( key_object_permission is None - and user_api_key_auth and user_api_key_auth.object_permission_id + and prisma_client is not None ): - from litellm.proxy.auth.auth_checks import get_object_permission - from litellm.proxy.proxy_server import ( - prisma_client, - proxy_logging_obj, - user_api_key_cache, + key_object_permission = await get_object_permission( + object_permission_id=user_api_key_auth.object_permission_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + parent_otel_span=user_api_key_auth.parent_otel_span, + proxy_logging_obj=proxy_logging_obj, ) - - if prisma_client is not None: - key_object_permission = await get_object_permission( - object_permission_id=user_api_key_auth.object_permission_id, - prisma_client=prisma_client, - user_api_key_cache=user_api_key_cache, - parent_otel_span=user_api_key_auth.parent_otel_span, - proxy_logging_obj=proxy_logging_obj, - ) if key_object_permission is None: return [] # Permission entries may be server_ids OR names/aliases — expand to ids. - from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( - global_mcp_server_manager, - ) - direct_mcp_servers = global_mcp_server_manager.expand_permission_list( key_object_permission.mcp_servers or [] ) @@ -944,42 +1011,78 @@ async def _get_allowed_mcp_servers_for_team( """ Get allowed MCP servers for a team. - Note: object_permission is automatically loaded by get_team_object() in main auth flow. + Unions two sources: + - Legacy team.object_permission (mcp_servers, mcp_access_groups, + mcp_tool_permissions). + - Unified team.access_group_ids → access_group.access_mcp_server_ids. + Mirrors the model-side pattern in can_team_access_model — the group + is already attached to the team, so the team relationship is itself + the gate (no assigned_team_ids check needed here). """ try: - # Get team object permission (already loaded in main auth flow) - object_permissions = await MCPRequestHandler._get_team_object_permission( - user_api_key_auth + from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( + global_mcp_server_manager, + ) + from litellm.proxy.auth.auth_checks import ( + _get_mcp_server_ids_from_access_groups, + get_team_object, + ) + from litellm.proxy.proxy_server import ( + prisma_client, + proxy_logging_obj, + user_api_key_cache, ) - if object_permissions is None: + if ( + user_api_key_auth is None + or not user_api_key_auth.team_id + or prisma_client is None + ): return [] - # Permission entries may be server_ids OR names/aliases — expand to ids. - from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( - global_mcp_server_manager, + team_obj: Optional[LiteLLM_TeamTable] = await get_team_object( + team_id=user_api_key_auth.team_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + parent_otel_span=user_api_key_auth.parent_otel_span, + proxy_logging_obj=proxy_logging_obj, ) + if team_obj is None: + return [] + + team_access_group_servers = await _get_mcp_server_ids_from_access_groups( + access_group_ids=team_obj.access_group_ids or [], + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) + + object_permissions = team_obj.object_permission + if object_permissions is None: + return list(set(team_access_group_servers)) direct_mcp_servers = global_mcp_server_manager.expand_permission_list( object_permissions.mcp_servers or [] ) - # Get MCP servers from access groups - access_group_servers = ( + legacy_access_group_servers = ( await MCPRequestHandler._get_mcp_servers_from_access_groups( object_permissions.mcp_access_groups or [] ) ) - # servers referenced in tool permissions should also be accessible tool_perm_servers = list( global_mcp_server_manager.expand_tool_permissions( object_permissions.mcp_tool_permissions ).keys() ) - # Combine all lists - all_servers = direct_mcp_servers + access_group_servers + tool_perm_servers + all_servers = ( + direct_mcp_servers + + legacy_access_group_servers + + tool_perm_servers + + team_access_group_servers + ) return list(set(all_servers)) except Exception as e: verbose_logger.warning( diff --git a/litellm/proxy/_experimental/mcp_server/db.py b/litellm/proxy/_experimental/mcp_server/db.py index a6f0d145e9b..e30667776c1 100644 --- a/litellm/proxy/_experimental/mcp_server/db.py +++ b/litellm/proxy/_experimental/mcp_server/db.py @@ -30,6 +30,8 @@ def _prepare_mcp_server_data( data: Union[NewMCPServerRequest, UpdateMCPServerRequest], + exclude_unset: bool = False, + fields_set: Optional[Set[str]] = None, ) -> Dict[str, Any]: """ Helper function to prepare MCP server data for database operations. @@ -37,17 +39,39 @@ def _prepare_mcp_server_data( Args: data: NewMCPServerRequest or UpdateMCPServerRequest object + exclude_unset: When True, only fields the caller explicitly provided are + included. Used for partial updates (PUT /v1/mcp/server) so omitted + fields keep their existing DB value instead of being silently reset + to a Pydantic schema default. ``exclude_none`` is not enough here: + non-Optional fields (e.g. ``transport=MCPTransport.sse``, + ``mcp_access_groups=[]``, ``allow_all_keys=False``) are backfilled + with their default when omitted, and a non-None default survives the + ``exclude_none`` filter and overwrites the row. Returns: Dict with properly serialized JSON fields """ from litellm.litellm_core_utils.safe_json_dumps import safe_dumps - # Convert model to dict - data_dict = data.model_dump(exclude_none=True) - # Ensure alias is always present in the dict (even if None) - if "alias" not in data_dict: - data_dict["alias"] = getattr(data, "alias", None) + # Convert model to dict. + # - Partial update (exclude_unset): only caller-provided keys are emitted, so + # omitted fields are never written and keep their existing DB value. + # - Create (exclude_none): drop None-valued fields and let DB defaults apply. + if exclude_unset: + if fields_set is None: + fields_set = data.fields_set() + data_dict = data.model_dump(exclude_unset=True) + # ``validate_and_normalize_mcp_server_payload`` always assigns ``alias`` + # on the payload, which marks it as set even when the caller omitted it. + # Drop it only when the original request omitted alias; an explicit + # ``alias=None`` is a valid request to clear the stored alias. + if data_dict.get("alias") is None and "alias" not in fields_set: + data_dict.pop("alias", None) + else: + data_dict = data.model_dump(exclude_none=True) + # Ensure alias is always present in the dict (even if None) + if "alias" not in data_dict: + data_dict["alias"] = getattr(data, "alias", None) # Handle credentials serialization credentials = data_dict.get("credentials") @@ -57,33 +81,33 @@ def _prepare_mcp_server_data( ) data_dict["credentials"] = safe_dumps(data_dict["credentials"]) - # Handle static_headers serialization - if data.static_headers is not None: - data_dict["static_headers"] = safe_dumps(data.static_headers) + # Serialize JSON fields from ``data_dict`` (not ``data``) so the + # exclude_unset filter is respected. Reading back from ``data`` would + # reintroduce defaults (e.g. ``env={}``) for fields the caller never set. + if data_dict.get("static_headers") is not None: + data_dict["static_headers"] = safe_dumps(data_dict["static_headers"]) - # Handle mcp_info serialization - if data.mcp_info is not None: - data_dict["mcp_info"] = safe_dumps(data.mcp_info) + if data_dict.get("mcp_info") is not None: + data_dict["mcp_info"] = safe_dumps(data_dict["mcp_info"]) - # Handle env serialization - if data.env is not None: - data_dict["env"] = safe_dumps(data.env) + if data_dict.get("env") is not None: + data_dict["env"] = safe_dumps(data_dict["env"]) - # Handle tool name override serialization - if data.tool_name_to_display_name is not None: + if data_dict.get("tool_name_to_display_name") is not None: data_dict["tool_name_to_display_name"] = safe_dumps( - data.tool_name_to_display_name + data_dict["tool_name_to_display_name"] ) - if data.tool_name_to_description is not None: + if data_dict.get("tool_name_to_description") is not None: data_dict["tool_name_to_description"] = safe_dumps( - data.tool_name_to_description + data_dict["tool_name_to_description"] ) # mcp_access_groups is already List[str], no serialization needed - # Force include is_byok even when False (exclude_none=True would not drop it, - # but be explicit to ensure a False value is always written to the DB). - data_dict["is_byok"] = getattr(data, "is_byok", False) + # On create, force is_byok so a False value is always written to the DB. On + # partial update, only write it when the caller explicitly provided it. + if not exclude_unset: + data_dict["is_byok"] = getattr(data, "is_byok", False) return data_dict @@ -398,7 +422,10 @@ async def create_mcp_server( async def update_mcp_server( - prisma_client: PrismaClient, data: UpdateMCPServerRequest, touched_by: str + prisma_client: PrismaClient, + data: UpdateMCPServerRequest, + touched_by: str, + fields_set: Optional[Set[str]] = None, ) -> LiteLLM_MCPServerTable: """ Update a new mcp server record in the db @@ -407,8 +434,13 @@ async def update_mcp_server( from litellm.litellm_core_utils.safe_json_dumps import safe_dumps - # Use helper to prepare data with proper JSON serialization - data_dict = _prepare_mcp_server_data(data) + # Use helper to prepare data with proper JSON serialization. + # exclude_unset=True makes this a true partial update: fields the caller did + # not provide are not written, so they keep their existing DB value instead + # of being reset to a schema default (transport=sse, allow_all_keys=False...). + data_dict = _prepare_mcp_server_data( + data, exclude_unset=True, fields_set=fields_set + ) # Pre-fetch existing record once if we need it for auth_type or credential logic existing = None diff --git a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py index 652e284ed49..8324ba641a4 100644 --- a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py @@ -1,3 +1,4 @@ +import html as _html import json from typing import Any, Dict, Optional from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse @@ -618,8 +619,105 @@ async def token_endpoint( ) +# Per RFC 6749 §4.1.2.1, an IdP that rejects an OAuth authorization request +# redirects back to the configured redirect URI with ``error`` / +# ``error_description`` / ``error_uri`` query params and no ``code``. The MCP +# loopback flow funnels that response through this /callback endpoint, so +# the endpoint must accept either a successful (``code``+``state``) or an +# error response. Declaring ``code``/``state`` as required would cause +# FastAPI to reject the error response with a 422 before the handler runs, +# which strands the MCP client waiting on the loopback (see LIT-2750). + + +def _render_oauth_error_html(error: str, description: Optional[str]) -> HTMLResponse: + """Render an actionable HTML page for an IdP-reported OAuth error. + + Used when we cannot propagate the error back to the registered + ``redirect_uri`` (state missing or undecryptable). Returned with a 400 + status so the failure is observable to operators while still being a + human-readable page for the end user. + """ + safe_error = _html.escape(error or "unknown_error") + safe_description = _html.escape(description) if description else "" + description_html = f"

{safe_description}

" if safe_description else "" + body = ( + "" + "

Authentication failed

" + f"

Error: {safe_error}

" + f"{description_html}" + "

You can close this window and try again.

" + "" + ) + return HTMLResponse(body, status_code=400) + + @router.get("/callback") -async def callback(request: Request, code: str, state: str): +async def callback( + request: Request, + code: Optional[str] = None, + state: Optional[str] = None, + error: Optional[str] = None, + error_description: Optional[str] = None, + error_uri: Optional[str] = None, +): + """OAuth 2.0 authorization response handler for MCP loopback clients. + + Accepts either: + + - A successful authorization response (``code`` + ``state``), which is + forwarded back to the validated client ``redirect_uri`` with the + original (un-wrapped) ``state``. + - An error response (``error``[+``error_description``/``error_uri``]), per + RFC 6749 §4.1.2.1. When ``state`` is present and decodes to a trusted + ``redirect_uri``, the error params are propagated back to the client so + its OAuth library can surface them. Otherwise we render an HTML error + page so the user is not left on an opaque 422 / blank screen. + """ + # 1. IdP-reported error path (e.g. ``?error=access_denied``). + if error: + verbose_logger.info( + "MCP /callback received IdP error: error=%s, error_description=%s", + error, + error_description, + ) + if state: + try: + state_data = decode_state_hash(state) + original_state = state_data.get("original_state") + redirect_uri = _get_validated_client_redirect_uri(request, state_data) + except HTTPException: + # Untrusted/invalid client redirect_uri — surface inline rather + # than blindly forwarding the error to an attacker-controlled URL. + return _render_oauth_error_html(error, error_description) + except Exception: + # State could not be decrypted (expired key, tampered, etc.). + return _render_oauth_error_html(error, error_description) + + params: Dict[str, str] = {"error": error} + if error_description: + params["error_description"] = error_description + if error_uri: + params["error_uri"] = error_uri + if original_state is not None: + params["state"] = original_state + complete_returned_url = _append_query_params(redirect_uri, params) + return RedirectResponse(url=complete_returned_url, status_code=302) + + # No state — nothing to round-trip to. Show the user the error. + return _render_oauth_error_html(error, error_description) + + # 2. Neither success nor error parameters present — most likely a stray + # GET / dropped SSO redirect chain. Surface a 400 instead of 422. + if not code or not state: + missing = [ + name for name, value in (("code", code), ("state", state)) if not value + ] + return _render_oauth_error_html( + "invalid_request", + f"Missing authorization {' and '.join(repr(m) for m in missing)} parameter(s).", + ) + + # 3. Successful authorization response. try: state_data = decode_state_hash(state) original_state = state_data["original_state"] diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index d0e9ad7b2a4..f35aa30a7c9 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -892,6 +892,7 @@ async def build_mcp_server_from_table( is_byok=bool(getattr(mcp_server, "is_byok", False)), byok_description=getattr(mcp_server, "byok_description", None) or [], byok_api_key_help_url=getattr(mcp_server, "byok_api_key_help_url", None), + source_url=getattr(mcp_server, "source_url", None), # AWS SigV4 fields aws_access_key_id=aws_creds.get("aws_access_key_id"), aws_secret_access_key=aws_creds.get("aws_secret_access_key"), @@ -3750,6 +3751,7 @@ def _build_mcp_server_table(self, server: MCPServer) -> LiteLLM_MCPServerTable: is_byok=server.is_byok, byok_description=server.byok_description, byok_api_key_help_url=server.byok_api_key_help_url, + source_url=server.source_url, instructions=server.instructions, ) diff --git a/litellm/proxy/_experimental/mcp_server/server.py b/litellm/proxy/_experimental/mcp_server/server.py index f31005be0cb..a05ce3f7417 100644 --- a/litellm/proxy/_experimental/mcp_server/server.py +++ b/litellm/proxy/_experimental/mcp_server/server.py @@ -6,6 +6,8 @@ import asyncio import contextlib +import hashlib +import json import time import types import traceback @@ -28,7 +30,7 @@ from pydantic import AnyUrl, ConfigDict from starlette.requests import Request as StarletteRequest from starlette.responses import JSONResponse -from starlette.types import Receive, Scope, Send +from starlette.types import Message, Receive, Scope, Send from litellm._logging import verbose_logger from litellm.constants import MAXIMUM_TRACEBACK_LINES_TO_LOG @@ -74,6 +76,19 @@ _byok_cred_cache: Dict[Tuple[str, str], Tuple[Optional[str], float]] = {} _BYOK_CRED_CACHE_TTL = 60 # seconds _BYOK_CRED_CACHE_MAX_SIZE = 4096 # cap to prevent unbounded growth +_STATEFUL_SESSION_IDLE_TIMEOUT_SECONDS = 30 * 60 +# Upper bound on concurrent stateful sessions a single caller may hold. Each +# `initialize` creates a session that survives until the idle timeout, so +# without a cap an authenticated client could spam `initialize` and exhaust +# memory. The caller's own oldest idle sessions are evicted to make room; if +# the cap is still hit (every session in flight), the new `initialize` is +# rejected with 429. +_MAX_STATEFUL_SESSIONS_PER_OWNER = 100 +# Maximum bytes to peek when sniffing the JSON-RPC method on a POST. +# An `initialize` envelope is a few hundred bytes; capping the peek +# prevents an authenticated client from forcing the proxy to buffer an +# arbitrarily large body just to make a routing decision. +_MCP_ROUTING_PEEK_MAX_BYTES = 4096 def _invalidate_byok_cred_cache(user_id: str, server_id: str) -> None: @@ -242,13 +257,45 @@ def _gateway_create_initialization_options( sse: SseServerTransport = SseServerTransport("/mcp/sse/messages") # Create session managers - session_manager = StreamableHTTPSessionManager( + session_manager_stateless = StreamableHTTPSessionManager( app=server, event_store=None, json_response=False, # enables SSE streaming stateless=True, ) + session_manager_stateful = StreamableHTTPSessionManager( + app=server, + event_store=None, # TODO: Add EventStore for reconnection/event replay if needed + json_response=False, # enables SSE streaming + stateless=False, + ) + _stateful_session_auth_contexts: Dict[str, MCPAuthenticatedUser] = {} + _stateful_session_auth_context_last_seen: Dict[str, float] = {} + # Maps session_id -> owner identifier (hashed API key/token) so we can + # reject requests that supply a session_id created by a different caller. + # Without this, a leaked mcp-session-id could be driven (or terminated) + # by any other authenticated proxy user. + _stateful_session_owners: Dict[str, str] = {} + # Per-session lock that serializes ``handle_request`` for the same + # mcp-session-id. The stored ``MCPAuthenticatedUser`` is mutated in place + # by ``_update_auth_context`` each request; without this lock, two + # concurrent requests on the same session would clobber each other's + # auth headers / mcp_servers / oauth state while in-flight callbacks are + # still reading the shared object. + _stateful_session_locks: Dict[str, asyncio.Lock] = {} + _stateful_session_active_request_counts: Dict[str, int] = {} + + def _remove_stateful_session_tracking(session_id: str) -> None: + _stateful_session_auth_contexts.pop(session_id, None) + _stateful_session_auth_context_last_seen.pop(session_id, None) + _stateful_session_owners.pop(session_id, None) + _stateful_session_locks.pop(session_id, None) + _stateful_session_active_request_counts.pop(session_id, None) + + # Keep this alias so existing references to session_manager still work + session_manager = session_manager_stateless + # Create SSE session manager sse_session_manager = StreamableHTTPSessionManager( app=server, @@ -259,11 +306,100 @@ def _gateway_create_initialization_options( # Context managers for proper lifecycle management _session_manager_cm = None + _session_manager_stateful_cm = None _sse_session_manager_cm = None + _stateful_auth_context_cleanup_task: Optional[asyncio.Task] = None + + async def _purge_expired_stateful_session_auth_contexts( + now: Optional[float] = None, + ) -> None: + """Terminate expired stateful sessions and drop their auth contexts.""" + now = time.monotonic() if now is None else now + server_instances = getattr(session_manager_stateful, "_server_instances", {}) + expired_session_ids = [] + for session_id, last_seen in _stateful_session_auth_context_last_seen.items(): + if _stateful_session_active_request_counts.get(session_id, 0) > 0: + continue + if ( + now - last_seen >= _STATEFUL_SESSION_IDLE_TIMEOUT_SECONDS + or session_id not in server_instances + ): + expired_session_ids.append(session_id) + + for session_id in expired_session_ids: + # Re-check the active-request count immediately before tearing + # the session down. ``await transport.terminate()`` yields to + # the event loop, so a request that started after the first + # collection pass could otherwise observe its transport being + # ripped out from under it mid-flight. + if _stateful_session_active_request_counts.get(session_id, 0) > 0: + continue + # Pop transport + terminate BEFORE removing owner/auth tracking. + # Reversing the order avoids a window where ``_stateful_session_owners`` + # is empty but ``server_instances`` still serves the session — a + # concurrent request in that window would observe ``expected_owner + # is None`` and bypass the owner-binding check. + transport = server_instances.pop(session_id, None) + if transport is not None: + await transport.terminate() + _remove_stateful_session_tracking(session_id) + + for session_id in list(_stateful_session_auth_context_last_seen): + if session_id not in _stateful_session_auth_contexts: + _remove_stateful_session_tracking(session_id) + + async def _enforce_stateful_session_cap_for_owner(owner: str) -> bool: + """ + Bound the number of concurrent stateful sessions a single caller holds + before routing a new ``initialize`` to the stateful manager. + + Evicts the caller's *own* oldest idle sessions (no in-flight requests) + to make room, so a busy-but-legitimate client keeps its newest sessions + and other callers are never affected. Returns ``True`` if the new + session may proceed, or ``False`` when the caller is already at the cap + with every session in flight (the new ``initialize`` should be rejected). + """ + server_instances = getattr(session_manager_stateful, "_server_instances", {}) + + def _owned_live_session_ids() -> List[str]: + return [ + session_id + for session_id, session_owner in _stateful_session_owners.items() + if session_owner == owner and session_id in server_instances + ] + + owned = _owned_live_session_ids() + if len(owned) < _MAX_STATEFUL_SESSIONS_PER_OWNER: + return True + + for session_id in sorted( + owned, + key=lambda sid: _stateful_session_auth_context_last_seen.get(sid, 0.0), + ): + if len(_owned_live_session_ids()) < _MAX_STATEFUL_SESSIONS_PER_OWNER: + break + if _stateful_session_active_request_counts.get(session_id, 0) > 0: + continue + transport = server_instances.pop(session_id, None) + if transport is not None: + await transport.terminate() + _remove_stateful_session_tracking(session_id) + + return len(_owned_live_session_ids()) < _MAX_STATEFUL_SESSIONS_PER_OWNER + + async def _cleanup_expired_stateful_session_auth_contexts() -> None: + while True: + await asyncio.sleep(_STATEFUL_SESSION_IDLE_TIMEOUT_SECONDS) + try: + await _purge_expired_stateful_session_auth_contexts() + except Exception as e: + verbose_logger.exception( + f"Error cleaning up expired MCP stateful sessions: {e}" + ) async def initialize_session_managers(): """Initialize the session managers. Can be called from main app lifespan.""" - global _SESSION_MANAGERS_INITIALIZED, _session_manager_cm, _sse_session_manager_cm + global _SESSION_MANAGERS_INITIALIZED, _session_manager_cm, _session_manager_stateful_cm, _sse_session_manager_cm, _stateful_auth_context_cleanup_task # Use async lock to prevent concurrent initialization async with _INITIALIZATION_LOCK: @@ -273,12 +409,17 @@ async def initialize_session_managers(): verbose_logger.info("Initializing MCP session managers...") # Start the session managers with context managers - _session_manager_cm = session_manager.run() + _session_manager_cm = session_manager_stateless.run() + _session_manager_stateful_cm = session_manager_stateful.run() _sse_session_manager_cm = sse_session_manager.run() # Enter the context managers await _session_manager_cm.__aenter__() + await _session_manager_stateful_cm.__aenter__() await _sse_session_manager_cm.__aenter__() + _stateful_auth_context_cleanup_task = asyncio.create_task( + _cleanup_expired_stateful_session_auth_contexts() + ) _SESSION_MANAGERS_INITIALIZED = True verbose_logger.info( @@ -287,21 +428,29 @@ async def initialize_session_managers(): async def shutdown_session_managers(): """Shutdown the session managers.""" - global _SESSION_MANAGERS_INITIALIZED, _session_manager_cm, _sse_session_manager_cm + global _SESSION_MANAGERS_INITIALIZED, _session_manager_cm, _session_manager_stateful_cm, _sse_session_manager_cm, _stateful_auth_context_cleanup_task if _SESSION_MANAGERS_INITIALIZED: verbose_logger.info("Shutting down MCP session managers...") try: + if _stateful_auth_context_cleanup_task: + _stateful_auth_context_cleanup_task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await _stateful_auth_context_cleanup_task if _session_manager_cm: await _session_manager_cm.__aexit__(None, None, None) + if _session_manager_stateful_cm: + await _session_manager_stateful_cm.__aexit__(None, None, None) if _sse_session_manager_cm: await _sse_session_manager_cm.__aexit__(None, None, None) except Exception as e: verbose_logger.exception(f"Error during session manager shutdown: {e}") _session_manager_cm = None + _session_manager_stateful_cm = None _sse_session_manager_cm = None + _stateful_auth_context_cleanup_task = None _SESSION_MANAGERS_INITIALIZED = False @contextlib.asynccontextmanager @@ -366,7 +515,7 @@ async def list_tools() -> List[MCPTool]: @server.call_tool() async def mcp_server_tool_call( - name: str, arguments: Dict[str, Any] | None + name: str, arguments: Optional[Dict[str, Any]] ) -> CallToolResult: """ Call a specific tool with the provided arguments @@ -409,7 +558,7 @@ async def mcp_server_tool_call( if host_token and hasattr(host_ctx, "session") and host_ctx.session: host_session = host_ctx.session - async def forward_progress(progress: float, total: float | None): + async def forward_progress(progress: float, total: Optional[float]): """Forward progress notifications from external MCP to Host""" try: await host_session.send_progress_notification( @@ -551,7 +700,7 @@ async def list_prompts() -> List[Prompt]: @server.get_prompt() async def get_prompt( - name: str, arguments: dict[str, str] | None + name: str, arguments: Optional[Dict[str, str]] ) -> GetPromptResult: """ Get a specific prompt with the provided arguments @@ -2697,6 +2846,144 @@ async def extract_mcp_auth_context(scope, path): raw_headers, ) + def _get_session_id_from_scope(scope: Scope) -> Optional[str]: + """ + Extract mcp-session-id from ASGI scope headers. + Returns None if not present. + """ + for header_name, header_value in scope.get("headers", []): + name = ( + header_name if isinstance(header_name, bytes) else header_name.encode() + ) + if name.lower() == b"mcp-session-id": + return ( + header_value.decode() + if isinstance(header_value, bytes) + else str(header_value) + ) + return None + + def _owner_fingerprint_for( + user_api_key_auth: Optional[UserAPIKeyAuth], + oauth2_headers: Optional[Dict[str, str]] = None, + client_ip: Optional[str] = None, + ) -> str: + """ + Stable, non-reversible identifier for the caller used to bind an + mcp-session-id to its creator. Hash the resolved credential before + using it so custom key formats are never stored in cleartext. + + For OAuth2 passthrough (``UserAPIKeyAuth()`` with no key/user_id), + the caller's identity is the upstream OAuth bearer; hash it so two + OAuth callers with different tokens don't both fingerprint to + ``anonymous`` and end up sharing a session. + + When no caller-identifying credentials are available at all + (e.g. proxy running without master key, or an unauthenticated + passthrough path), fall back to the client IP so two unrelated + anonymous callers from different sources do not collapse to a + single ``anonymous`` owner and end up able to drive each other's + stateful sessions. Note: when even client IP is unavailable + (exotic deployments without trusted X-Forwarded-For and direct + socket info), the fingerprint degrades to the ``anonymous`` + sentinel and cannot meaningfully protect against another + unauthenticated caller who learns the session id — owner-binding + is best-effort in that mode. + """ + + def _bytes_for_hash(value: Any) -> Optional[bytes]: + """Only hash str/bytes secrets; skip mocks and other unexpected types.""" + if value is None: + return None + if isinstance(value, (bytes, bytearray)): + return bytes(value) + if isinstance(value, str): + return value.encode("utf-8") + return None + + if user_api_key_auth is not None: + key_material = _bytes_for_hash(getattr(user_api_key_auth, "api_key", None)) + if key_material: + api_key_hash = hashlib.sha256(key_material).hexdigest() + return f"key:{api_key_hash}" + uid_material = _bytes_for_hash(getattr(user_api_key_auth, "user_id", None)) + if uid_material: + user_id_hash = hashlib.sha256(uid_material).hexdigest() + return f"user:{user_id_hash}" + if oauth2_headers: + authz = oauth2_headers.get("Authorization") or oauth2_headers.get( + "authorization" + ) + authz_bytes = _bytes_for_hash(authz) + if authz_bytes: + return f"oauth:{hashlib.sha256(authz_bytes).hexdigest()}" + if client_ip and isinstance(client_ip, str): + return f"ip:{hashlib.sha256(client_ip.encode('utf-8')).hexdigest()}" + return "anonymous" + + def _is_initialize_request(body: bytes) -> bool: + """ + Check if the request body is a JSON-RPC initialize method. + Returns True if method is "initialize", False otherwise or on parse error. + """ + if not body: + return False + try: + data = json.loads(body) + return isinstance(data, dict) and data.get("method") == "initialize" + except (json.JSONDecodeError, TypeError): + return False + + async def _read_request_body_for_routing( + receive: Receive, + ) -> Tuple[List[Message], bytes]: + """ + Read just enough of the request body to decide whether this is a + JSON-RPC ``initialize`` call. Returns the consumed ASGI messages so + the caller can replay them faithfully to the downstream handler, and + the peeked body bytes (capped at ``_MCP_ROUTING_PEEK_MAX_BYTES``). + + Stops reading from the wire as soon as either (a) we have peeked + ``_MCP_ROUTING_PEEK_MAX_BYTES`` of body, or (b) the body is complete. + The remainder of an oversized body is streamed lazily through + ``wrapped_receive`` in the caller — so an authenticated client cannot + force the proxy to buffer an arbitrarily large payload just to make a + routing decision. + """ + consumed_messages: List[Message] = [] + body_chunks: List[bytes] = [] + peeked_bytes = 0 + + while True: + message = await receive() + consumed_messages.append(message) + + if message.get("type") != "http.request": + break + + body = message.get("body", b"") or b"" + if body: + # Only retain up to the remaining peek budget for sniffing. + # The full ``message`` is already in memory (delivered by + # the ASGI server) and must round-trip to the downstream + # handler via ``consumed_messages``, but ``body_chunks`` is + # purely for the JSON-RPC method check — there is no reason + # to copy a large body frame into a second buffer. + remaining = _MCP_ROUTING_PEEK_MAX_BYTES - peeked_bytes + if remaining > 0: + body_chunks.append(body[:remaining]) + peeked_bytes += min(len(body), remaining) + + if not message.get("more_body", False): + break + + if peeked_bytes >= _MCP_ROUTING_PEEK_MAX_BYTES: + # Stop draining; downstream replay will pull remaining chunks + # directly from the original `receive` via wrapped_receive. + break + + return consumed_messages, b"".join(body_chunks) + async def _handle_stale_mcp_session( scope: Scope, receive: Receive, @@ -2760,6 +3047,7 @@ def _normalize_header_name(header_name: Any) -> Optional[bytes]: method = scope.get("method", "").upper() if method == "DELETE": + _remove_stateful_session_tracking(_session_id) verbose_logger.info( "DELETE request for non-existent MCP session '%s'. " "Returning success (idempotent DELETE).", @@ -2993,7 +3281,7 @@ async def _check_passthrough_upstream_auth( detail="Forbidden", ) - async def handle_streamable_http_mcp( + async def handle_streamable_http_mcp( # noqa: PLR0915 scope: Scope, receive: Receive, send: Send ) -> None: """Handle MCP requests through StreamableHTTP.""" @@ -3086,38 +3374,215 @@ async def handle_streamable_http_mcp( if _debug_headers: send = MCPDebug.wrap_send_with_debug_headers(send, _debug_headers) - # Set the auth context variable for easy access in MCP functions - set_auth_context( - user_api_key_auth=user_api_key_auth, - mcp_auth_header=mcp_auth_header, - mcp_servers=mcp_servers, - mcp_server_auth_headers=mcp_server_auth_headers, - oauth2_headers=oauth2_headers, - raw_headers=raw_headers, - client_ip=_client_ip, - ) - # Ensure session managers are initialized if not _SESSION_MANAGERS_INITIALIZED: await initialize_session_managers() # Give it a moment to start up await asyncio.sleep(0.1) - # Handle stale session IDs - either strip them for reconnection - # or return success for idempotent DELETE operations - handled = await _handle_stale_mcp_session( - scope, receive, send, session_manager + # Route based on mcp-session-id and request method: + # - Has session ID → stateful (Claude Code, Cursor, VSCode) + # - No session ID + initialize → stateful (so client gets mcp-session-id) + # - No session ID + other → stateless (curl, Inspector, Notion) + session_id = _get_session_id_from_scope(scope) + is_initialize = False + consumed_messages: List[Message] = [] + + # Owner-binding: a live stateful session may only be driven by the + # caller that created it. Reject mismatches with 403 so a leaked + # mcp-session-id cannot be hijacked by another authenticated user. + # + # Run before ``_handle_stale_mcp_session`` so a non-owner cannot + # force-clean another caller's residual tracking entries via a + # stale DELETE, and before peeking the request body so the 403 + # response sees a pristine ``receive`` channel. + if session_id: + expected_owner = _stateful_session_owners.get(session_id) + request_owner = _owner_fingerprint_for( + user_api_key_auth, oauth2_headers, _client_ip + ) + if expected_owner is not None and expected_owner != request_owner: + verbose_logger.warning( + "Rejecting MCP request: session '%s' owner mismatch.", + session_id, + ) + forbidden_response = JSONResponse( + status_code=403, + content={ + "error": "Forbidden", + "details": "mcp-session-id is bound to a different caller.", + }, + ) + await forbidden_response(scope, receive, send) + return + + # Handle stale session IDs before choosing a target manager. Stale + # non-DELETE requests have their session header stripped and should + # be routed as no-session requests. + if session_id: + handled = await _handle_stale_mcp_session( + scope, receive, send, session_manager_stateful + ) + if handled: + # Request was fully handled (e.g., DELETE on non-existent session) + return + session_id = _get_session_id_from_scope(scope) + + if scope.get("method") == "POST": + consumed_messages, body = await _read_request_body_for_routing(receive) + is_initialize = _is_initialize_request(body) + + use_stateful = bool(session_id or is_initialize) + target_manager = ( + session_manager_stateful if use_stateful else session_manager_stateless ) - if handled: - # Request was fully handled (e.g., DELETE on non-existent session) - return - async with _gateway_initialize_instructions_request_scope( - user_api_key_auth, - mcp_servers, - _client_ip, - ): - await session_manager.handle_request(scope, receive, send) + verbose_logger.debug( + f"MCP routing to {'stateful' if use_stateful else 'stateless'} manager" + + (f" (session={session_id[:8]}...)" if session_id else "") + + (" (initialize)" if is_initialize else "") + ) + + # A new `initialize` (no session id) is about to create a stateful + # session. Cap how many a single caller can hold so an authenticated + # client cannot spam `initialize` and exhaust memory. + if is_initialize and not session_id: + request_owner = _owner_fingerprint_for( + user_api_key_auth, oauth2_headers, _client_ip + ) + if not await _enforce_stateful_session_cap_for_owner(request_owner): + verbose_logger.warning( + "Rejecting MCP initialize: caller already holds the maximum " + "number of active stateful sessions." + ) + too_many_response = JSONResponse( + status_code=429, + content={ + "error": "Too Many Requests", + "details": "Too many active MCP sessions for this caller.", + }, + ) + await too_many_response(scope, receive, send) + return + + # Replay body messages if we consumed them for peeking + original_receive = receive + if consumed_messages: + + async def wrapped_receive(): + if consumed_messages: + return consumed_messages.pop(0) + return await original_receive() + + receive = wrapped_receive + + # Serialize requests on the same stateful session so concurrent + # callers don't clobber each other's auth context mid-flight. + # + # Skip the lock for streaming GETs (SSE channels held open for the + # life of the session): holding a per-session lock for a long-lived + # stream would block every subsequent POST on the same session. + # POST/DELETE are the methods that actually mutate the shared + # auth context, so serializing those is sufficient for the + # clobbering race between concurrent JSON-RPC calls. + session_lock: Optional[asyncio.Lock] = None + request_method = (scope.get("method") or "").upper() + if use_stateful and session_id and request_method in ("POST", "DELETE"): + session_lock = _stateful_session_locks.setdefault( + session_id, asyncio.Lock() + ) + + active_request_session_ids: List[str] = [] + + def _increment_active_request_session(session_id_to_track: str) -> None: + if session_id_to_track in active_request_session_ids: + return + active_request_session_ids.append(session_id_to_track) + _stateful_session_active_request_counts[session_id_to_track] = ( + _stateful_session_active_request_counts.get(session_id_to_track, 0) + + 1 + ) + + if use_stateful and session_id: + _increment_active_request_session(session_id) + + def _track_initialized_stateful_session( + initialized_session_id: str, + ) -> None: + _increment_active_request_session(initialized_session_id) + + async def _dispatch() -> None: + auth_user = _set_or_update_auth_context( + user_api_key_auth=user_api_key_auth, + mcp_auth_header=mcp_auth_header, + mcp_servers=mcp_servers, + mcp_server_auth_headers=mcp_server_auth_headers, + oauth2_headers=oauth2_headers, + raw_headers=raw_headers, + client_ip=_client_ip, + session_id=session_id if use_stateful else None, + touch_last_seen=(scope.get("method") or "").upper() != "DELETE", + copy_existing_session_auth_context=is_initialize, + ) + local_send = send + if use_stateful and is_initialize: + local_send = _wrap_send_with_stateful_session_auth_context( + local_send, + auth_user, + _owner_fingerprint_for( + user_api_key_auth, oauth2_headers, _client_ip + ), + _track_initialized_stateful_session, + ) + + async with _gateway_initialize_instructions_request_scope( + user_api_key_auth, + mcp_servers, + _client_ip, + ): + await target_manager.handle_request(scope, receive, local_send) + if use_stateful and session_id and scope.get("method") == "DELETE": + _remove_stateful_session_tracking(session_id) + + try: + if session_lock is not None: + async with session_lock: + await _dispatch() + else: + await _dispatch() + finally: + for active_request_session_id in active_request_session_ids: + active_request_count = ( + _stateful_session_active_request_counts.get( + active_request_session_id, 0 + ) + - 1 + ) + if active_request_count > 0: + _stateful_session_active_request_counts[ + active_request_session_id + ] = active_request_count + else: + _stateful_session_active_request_counts.pop( + active_request_session_id, None + ) + + if ( + scope.get("method") != "DELETE" + and active_request_session_id in _stateful_session_auth_contexts + ): + _stateful_session_auth_context_last_seen[ + active_request_session_id + ] = time.monotonic() + + # Periodic cleanup iterates _stateful_session_auth_context_last_seen, + # so locks for untracked sessions must be dropped here. + if ( + active_request_count <= 0 + and active_request_session_id + not in _stateful_session_auth_contexts + ): + _stateful_session_locks.pop(active_request_session_id, None) except HTTPException: # Re-raise HTTP exceptions to preserve status codes and details raise @@ -3125,7 +3590,6 @@ async def handle_streamable_http_mcp( verbose_logger.exception(f"Error handling MCP request: {e}") # Try to send a graceful error response for non-HTTP exceptions try: - from starlette.responses import JSONResponse from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR error_response = JSONResponse( @@ -3231,8 +3695,9 @@ def get_mcp_server_enabled() -> Dict[str, bool]: ############ Auth Context Functions #################### ######################################################## - def set_auth_context( - user_api_key_auth: UserAPIKeyAuth, + def _update_auth_context( + auth_user: MCPAuthenticatedUser, + user_api_key_auth: Optional[UserAPIKeyAuth], mcp_auth_header: Optional[str] = None, mcp_servers: Optional[List[str]] = None, mcp_server_auth_headers: Optional[Dict[str, Dict[str, str]]] = None, @@ -3240,6 +3705,23 @@ def set_auth_context( raw_headers: Optional[Dict[str, str]] = None, client_ip: Optional[str] = None, ) -> None: + auth_user.user_api_key_auth = user_api_key_auth + auth_user.mcp_auth_header = mcp_auth_header + auth_user.mcp_servers = mcp_servers + auth_user.mcp_server_auth_headers = mcp_server_auth_headers or {} + auth_user.oauth2_headers = oauth2_headers + auth_user.raw_headers = raw_headers + auth_user.client_ip = client_ip + + def set_auth_context( + user_api_key_auth: Optional[UserAPIKeyAuth], + mcp_auth_header: Optional[str] = None, + mcp_servers: Optional[List[str]] = None, + mcp_server_auth_headers: Optional[Dict[str, Dict[str, str]]] = None, + oauth2_headers: Optional[Dict[str, str]] = None, + raw_headers: Optional[Dict[str, str]] = None, + client_ip: Optional[str] = None, + ) -> MCPAuthenticatedUser: """ Set the UserAPIKeyAuth in the auth context variable. @@ -3260,6 +3742,84 @@ def set_auth_context( client_ip=client_ip, ) auth_context_var.set(auth_user) + return auth_user + + def _set_or_update_auth_context( + user_api_key_auth: Optional[UserAPIKeyAuth], + mcp_auth_header: Optional[str] = None, + mcp_servers: Optional[List[str]] = None, + mcp_server_auth_headers: Optional[Dict[str, Dict[str, str]]] = None, + oauth2_headers: Optional[Dict[str, str]] = None, + raw_headers: Optional[Dict[str, str]] = None, + client_ip: Optional[str] = None, + session_id: Optional[str] = None, + touch_last_seen: bool = True, + copy_existing_session_auth_context: bool = False, + ) -> MCPAuthenticatedUser: + auth_user = ( + _stateful_session_auth_contexts.get(session_id) if session_id else None + ) + if auth_user is not None and session_id is not None: + if touch_last_seen: + _stateful_session_auth_context_last_seen[session_id] = time.monotonic() + if copy_existing_session_auth_context: + return set_auth_context( + user_api_key_auth=user_api_key_auth, + mcp_auth_header=mcp_auth_header, + mcp_servers=mcp_servers, + mcp_server_auth_headers=mcp_server_auth_headers, + oauth2_headers=oauth2_headers, + raw_headers=raw_headers, + client_ip=client_ip, + ) + _update_auth_context( + auth_user=auth_user, + user_api_key_auth=user_api_key_auth, + mcp_auth_header=mcp_auth_header, + mcp_servers=mcp_servers, + mcp_server_auth_headers=mcp_server_auth_headers, + oauth2_headers=oauth2_headers, + raw_headers=raw_headers, + client_ip=client_ip, + ) + auth_context_var.set(auth_user) + return auth_user + return set_auth_context( + user_api_key_auth=user_api_key_auth, + mcp_auth_header=mcp_auth_header, + mcp_servers=mcp_servers, + mcp_server_auth_headers=mcp_server_auth_headers, + oauth2_headers=oauth2_headers, + raw_headers=raw_headers, + client_ip=client_ip, + ) + + def _wrap_send_with_stateful_session_auth_context( + send: Send, + auth_user: MCPAuthenticatedUser, + owner_fingerprint: str, + on_session_registered: Optional[Callable[[str], None]] = None, + ) -> Send: + async def wrapped_send(message: Message) -> None: + if message.get("type") == "http.response.start": + for key, value in message.get("headers", []): + header_name = key if isinstance(key, bytes) else str(key).encode() + if header_name.lower() == b"mcp-session-id": + session_id = ( + value.decode() if isinstance(value, bytes) else str(value) + ) + if on_session_registered is not None: + on_session_registered(session_id) + auth_context_var.set(auth_user) + _stateful_session_auth_contexts[session_id] = auth_user + _stateful_session_auth_context_last_seen[session_id] = ( + time.monotonic() + ) + _stateful_session_owners[session_id] = owner_fingerprint + break + await send(message) + + return wrapped_send def get_auth_context() -> Tuple[ Optional[UserAPIKeyAuth], diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html new file mode 100644 index 00000000000..f27612ff54e --- /dev/null +++ b/litellm/proxy/_experimental/out/404.html @@ -0,0 +1 @@ +404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/404/index.html b/litellm/proxy/_experimental/out/404/index.html index 46e13ca9931..f27612ff54e 100644 --- a/litellm/proxy/_experimental/out/404/index.html +++ b/litellm/proxy/_experimental/out/404/index.html @@ -1 +1 @@ -404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file +404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/__next.__PAGE__.txt b/litellm/proxy/_experimental/out/__next.__PAGE__.txt index 29fe3567502..c024136e8dc 100644 --- a/litellm/proxy/_experimental/out/__next.__PAGE__.txt +++ b/litellm/proxy/_experimental/out/__next.__PAGE__.txt @@ -1,30 +1,10 @@ 1:"$Sreact.fragment" 2:I[347257,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ClientPageRoot"] -3:I[952683,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js","/litellm-asset-prefix/_next/static/chunks/0493aafc4891dd29.js","/litellm-asset-prefix/_next/static/chunks/f7e1d08418645368.js","/litellm-asset-prefix/_next/static/chunks/b3d198d6c56a21b8.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/ee5f9a39a526e423.js","/litellm-asset-prefix/_next/static/chunks/adb8beb738574863.js","/litellm-asset-prefix/_next/static/chunks/0549bc9afa7d4888.js","/litellm-asset-prefix/_next/static/chunks/0b470ffc60999bf4.js","/litellm-asset-prefix/_next/static/chunks/0b3d09ff6c6e4335.js","/litellm-asset-prefix/_next/static/chunks/e099566e8bd4ee4e.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/b1c98cc932a0ab19.js","/litellm-asset-prefix/_next/static/chunks/4e17b625d75327a7.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/a06cc76a774dd182.js","/litellm-asset-prefix/_next/static/chunks/ca5fbafaf3826374.js","/litellm-asset-prefix/_next/static/chunks/e7e5bfdf70ba79ab.js","/litellm-asset-prefix/_next/static/chunks/10dc4591ef08a91f.js","/litellm-asset-prefix/_next/static/chunks/7a9066dcd4a390ff.js","/litellm-asset-prefix/_next/static/chunks/baadbd26839e7b66.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/679dbd657c8b5aef.js","/litellm-asset-prefix/_next/static/chunks/94f7208f5087e27c.js","/litellm-asset-prefix/_next/static/chunks/43f6fc3c2ab9cf23.js","/litellm-asset-prefix/_next/static/chunks/4e06277331e725da.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/908828a91f602d8b.js","/litellm-asset-prefix/_next/static/chunks/da1c7742cc6fe8b4.js","/litellm-asset-prefix/_next/static/chunks/bd02f158353d9cea.js","/litellm-asset-prefix/_next/static/chunks/a09028cd611c08ef.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/ad02f56c287539eb.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/a8f7c8c5eeb6e042.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/6188170a32c9a3c3.js","/litellm-asset-prefix/_next/static/chunks/1bc2898be56acd1b.js","/litellm-asset-prefix/_next/static/chunks/20acf4fa815c638e.js","/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","/litellm-asset-prefix/_next/static/chunks/e1a670efcb966aaa.js","/litellm-asset-prefix/_next/static/chunks/3c0e9dc19dbbd4ed.js","/litellm-asset-prefix/_next/static/chunks/e1f23fd814ac3500.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/ca7a3fdb635fb7dc.js","/litellm-asset-prefix/_next/static/chunks/659ce28f2cb74401.js","/litellm-asset-prefix/_next/static/chunks/934dbc43f8c1abde.js","/litellm-asset-prefix/_next/static/chunks/d6ab357d1bbb53f0.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/4a0ccb5ed3d0c33f.js"],"default"] -1a:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] -1b:"$Sreact.suspense" +3:I[952683,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js","/litellm-asset-prefix/_next/static/chunks/52c4ecc57f72065e.js","/litellm-asset-prefix/_next/static/chunks/4bb663ff806dc32f.js","/litellm-asset-prefix/_next/static/chunks/ee8f89c672745c59.js","/litellm-asset-prefix/_next/static/chunks/2954392b7a60a6a1.js","/litellm-asset-prefix/_next/static/chunks/04711b0f8ffa7bbd.js","/litellm-asset-prefix/_next/static/chunks/9710770c6333a72f.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d734cb3d5659b0da.js","/litellm-asset-prefix/_next/static/chunks/a1ef280b7ad5ae6a.js","/litellm-asset-prefix/_next/static/chunks/09c1f51da7e82268.js","/litellm-asset-prefix/_next/static/chunks/542a1a209eb732c6.js","/litellm-asset-prefix/_next/static/chunks/d028f8c28935d281.js","/litellm-asset-prefix/_next/static/chunks/61aa637257592262.js","/litellm-asset-prefix/_next/static/chunks/bf962cd5264be987.js","/litellm-asset-prefix/_next/static/chunks/37f229ef9335f8c3.js","/litellm-asset-prefix/_next/static/chunks/36d1c027ba991a4f.js","/litellm-asset-prefix/_next/static/chunks/786e88f4abdd5c58.js","/litellm-asset-prefix/_next/static/chunks/43c3db1352241a8b.js","/litellm-asset-prefix/_next/static/chunks/31275eb5c6f6332f.js","/litellm-asset-prefix/_next/static/chunks/0ac09b227f50edb4.js","/litellm-asset-prefix/_next/static/chunks/4c848b12d4ecda3d.js","/litellm-asset-prefix/_next/static/chunks/91c828abd7c0aff5.js","/litellm-asset-prefix/_next/static/chunks/08c348f8e09a5cb0.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/b323e0ef008e6348.js","/litellm-asset-prefix/_next/static/chunks/4ac3235460262f36.js","/litellm-asset-prefix/_next/static/chunks/51494a4a4b6fc437.js","/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","/litellm-asset-prefix/_next/static/chunks/9f1486622270556b.js"],"default"] +6:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] +7:"$Sreact.suspense" :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"buildId":"LpD6ruZoEpvYpT5IvMEoa","rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/0493aafc4891dd29.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/f7e1d08418645368.js","async":true}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/b3d198d6c56a21b8.js","async":true}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/ee5f9a39a526e423.js","async":true}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/adb8beb738574863.js","async":true}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/0549bc9afa7d4888.js","async":true}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/0b470ffc60999bf4.js","async":true}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/0b3d09ff6c6e4335.js","async":true}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/e099566e8bd4ee4e.js","async":true}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/b1c98cc932a0ab19.js","async":true}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/4e17b625d75327a7.js","async":true}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/a06cc76a774dd182.js","async":true}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/ca5fbafaf3826374.js","async":true}],["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/e7e5bfdf70ba79ab.js","async":true}],["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/10dc4591ef08a91f.js","async":true}],["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/7a9066dcd4a390ff.js","async":true}],["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/baadbd26839e7b66.js","async":true}],["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","async":true}],["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","async":true}],["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/679dbd657c8b5aef.js","async":true}],["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/94f7208f5087e27c.js","async":true}],["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/43f6fc3c2ab9cf23.js","async":true}],["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/4e06277331e725da.js","async":true}],["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true}],["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/908828a91f602d8b.js","async":true}],["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/da1c7742cc6fe8b4.js","async":true}],["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/bd02f158353d9cea.js","async":true}],["$","script","script-30",{"src":"/litellm-asset-prefix/_next/static/chunks/a09028cd611c08ef.js","async":true}],["$","script","script-31",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true}],["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/ad02f56c287539eb.js","async":true}],["$","script","script-33",{"src":"/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","async":true}],"$L6","$L7","$L8","$L9","$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17","$L18"],"$L19"]}],"loading":null,"isPartial":false} +0:{"buildId":"TrcGiQpTupSbDYFFfkFHY","rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/52c4ecc57f72065e.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/4bb663ff806dc32f.js","async":true}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/ee8f89c672745c59.js","async":true}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/2954392b7a60a6a1.js","async":true}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/04711b0f8ffa7bbd.js","async":true}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/9710770c6333a72f.js","async":true}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/d734cb3d5659b0da.js","async":true}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/a1ef280b7ad5ae6a.js","async":true}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/09c1f51da7e82268.js","async":true}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/542a1a209eb732c6.js","async":true}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/d028f8c28935d281.js","async":true}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/61aa637257592262.js","async":true}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/bf962cd5264be987.js","async":true}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/37f229ef9335f8c3.js","async":true}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/36d1c027ba991a4f.js","async":true}],["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/786e88f4abdd5c58.js","async":true}],["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/43c3db1352241a8b.js","async":true}],["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/31275eb5c6f6332f.js","async":true}],["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/0ac09b227f50edb4.js","async":true}],["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/4c848b12d4ecda3d.js","async":true}],["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/91c828abd7c0aff5.js","async":true}],["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/08c348f8e09a5cb0.js","async":true}],["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true}],["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/b323e0ef008e6348.js","async":true}],["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/4ac3235460262f36.js","async":true}],["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/51494a4a4b6fc437.js","async":true}],["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","async":true}],["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/9f1486622270556b.js","async":true}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],"loading":null,"isPartial":false} 4:{} 5:"$0:rsc:props:children:0:props:serverProvidedParams:params" -6:["$","script","script-34",{"src":"/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","async":true}] -7:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","async":true}] -8:["$","script","script-36",{"src":"/litellm-asset-prefix/_next/static/chunks/a8f7c8c5eeb6e042.js","async":true}] -9:["$","script","script-37",{"src":"/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","async":true}] -a:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","async":true}] -b:["$","script","script-39",{"src":"/litellm-asset-prefix/_next/static/chunks/6188170a32c9a3c3.js","async":true}] -c:["$","script","script-40",{"src":"/litellm-asset-prefix/_next/static/chunks/1bc2898be56acd1b.js","async":true}] -d:["$","script","script-41",{"src":"/litellm-asset-prefix/_next/static/chunks/20acf4fa815c638e.js","async":true}] -e:["$","script","script-42",{"src":"/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","async":true}] -f:["$","script","script-43",{"src":"/litellm-asset-prefix/_next/static/chunks/e1a670efcb966aaa.js","async":true}] -10:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/3c0e9dc19dbbd4ed.js","async":true}] -11:["$","script","script-45",{"src":"/litellm-asset-prefix/_next/static/chunks/e1f23fd814ac3500.js","async":true}] -12:["$","script","script-46",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true}] -13:["$","script","script-47",{"src":"/litellm-asset-prefix/_next/static/chunks/ca7a3fdb635fb7dc.js","async":true}] -14:["$","script","script-48",{"src":"/litellm-asset-prefix/_next/static/chunks/659ce28f2cb74401.js","async":true}] -15:["$","script","script-49",{"src":"/litellm-asset-prefix/_next/static/chunks/934dbc43f8c1abde.js","async":true}] -16:["$","script","script-50",{"src":"/litellm-asset-prefix/_next/static/chunks/d6ab357d1bbb53f0.js","async":true}] -17:["$","script","script-51",{"src":"/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","async":true}] -18:["$","script","script-52",{"src":"/litellm-asset-prefix/_next/static/chunks/4a0ccb5ed3d0c33f.js","async":true}] -19:["$","$L1a",null,{"children":["$","$1b",null,{"name":"Next.MetadataOutlet","children":"$@1c"}]}] -1c:null +8:null diff --git a/litellm/proxy/_experimental/out/__next._full.txt b/litellm/proxy/_experimental/out/__next._full.txt index 33e1ef61e1f..0c119086b9e 100644 --- a/litellm/proxy/_experimental/out/__next._full.txt +++ b/litellm/proxy/_experimental/out/__next._full.txt @@ -1,62 +1,39 @@ 1:"$Sreact.fragment" -2:I[867271,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js"],"default"] -3:I[71195,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js"],"default"] -4:I[339756,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] -5:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] -6:I[347257,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ClientPageRoot"] -7:I[952683,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js","/litellm-asset-prefix/_next/static/chunks/0493aafc4891dd29.js","/litellm-asset-prefix/_next/static/chunks/f7e1d08418645368.js","/litellm-asset-prefix/_next/static/chunks/b3d198d6c56a21b8.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/ee5f9a39a526e423.js","/litellm-asset-prefix/_next/static/chunks/adb8beb738574863.js","/litellm-asset-prefix/_next/static/chunks/0549bc9afa7d4888.js","/litellm-asset-prefix/_next/static/chunks/0b470ffc60999bf4.js","/litellm-asset-prefix/_next/static/chunks/0b3d09ff6c6e4335.js","/litellm-asset-prefix/_next/static/chunks/e099566e8bd4ee4e.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/b1c98cc932a0ab19.js","/litellm-asset-prefix/_next/static/chunks/4e17b625d75327a7.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/a06cc76a774dd182.js","/litellm-asset-prefix/_next/static/chunks/ca5fbafaf3826374.js","/litellm-asset-prefix/_next/static/chunks/e7e5bfdf70ba79ab.js","/litellm-asset-prefix/_next/static/chunks/10dc4591ef08a91f.js","/litellm-asset-prefix/_next/static/chunks/7a9066dcd4a390ff.js","/litellm-asset-prefix/_next/static/chunks/baadbd26839e7b66.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/679dbd657c8b5aef.js","/litellm-asset-prefix/_next/static/chunks/94f7208f5087e27c.js","/litellm-asset-prefix/_next/static/chunks/43f6fc3c2ab9cf23.js","/litellm-asset-prefix/_next/static/chunks/4e06277331e725da.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/908828a91f602d8b.js","/litellm-asset-prefix/_next/static/chunks/da1c7742cc6fe8b4.js","/litellm-asset-prefix/_next/static/chunks/bd02f158353d9cea.js","/litellm-asset-prefix/_next/static/chunks/a09028cd611c08ef.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/ad02f56c287539eb.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/a8f7c8c5eeb6e042.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/6188170a32c9a3c3.js","/litellm-asset-prefix/_next/static/chunks/1bc2898be56acd1b.js","/litellm-asset-prefix/_next/static/chunks/20acf4fa815c638e.js","/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","/litellm-asset-prefix/_next/static/chunks/e1a670efcb966aaa.js","/litellm-asset-prefix/_next/static/chunks/3c0e9dc19dbbd4ed.js","/litellm-asset-prefix/_next/static/chunks/e1f23fd814ac3500.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/ca7a3fdb635fb7dc.js","/litellm-asset-prefix/_next/static/chunks/659ce28f2cb74401.js","/litellm-asset-prefix/_next/static/chunks/934dbc43f8c1abde.js","/litellm-asset-prefix/_next/static/chunks/d6ab357d1bbb53f0.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/4a0ccb5ed3d0c33f.js"],"default"] -31:I[168027,[],"default"] +2:I[867271,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"default"] +3:I[71195,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"default"] +4:I[557951,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"AuthProvider"] +5:I[339756,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] +6:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] +7:I[347257,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ClientPageRoot"] +8:I[952683,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js","/litellm-asset-prefix/_next/static/chunks/52c4ecc57f72065e.js","/litellm-asset-prefix/_next/static/chunks/4bb663ff806dc32f.js","/litellm-asset-prefix/_next/static/chunks/ee8f89c672745c59.js","/litellm-asset-prefix/_next/static/chunks/2954392b7a60a6a1.js","/litellm-asset-prefix/_next/static/chunks/04711b0f8ffa7bbd.js","/litellm-asset-prefix/_next/static/chunks/9710770c6333a72f.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d734cb3d5659b0da.js","/litellm-asset-prefix/_next/static/chunks/a1ef280b7ad5ae6a.js","/litellm-asset-prefix/_next/static/chunks/09c1f51da7e82268.js","/litellm-asset-prefix/_next/static/chunks/542a1a209eb732c6.js","/litellm-asset-prefix/_next/static/chunks/d028f8c28935d281.js","/litellm-asset-prefix/_next/static/chunks/61aa637257592262.js","/litellm-asset-prefix/_next/static/chunks/bf962cd5264be987.js","/litellm-asset-prefix/_next/static/chunks/37f229ef9335f8c3.js","/litellm-asset-prefix/_next/static/chunks/36d1c027ba991a4f.js","/litellm-asset-prefix/_next/static/chunks/786e88f4abdd5c58.js","/litellm-asset-prefix/_next/static/chunks/43c3db1352241a8b.js","/litellm-asset-prefix/_next/static/chunks/31275eb5c6f6332f.js","/litellm-asset-prefix/_next/static/chunks/0ac09b227f50edb4.js","/litellm-asset-prefix/_next/static/chunks/4c848b12d4ecda3d.js","/litellm-asset-prefix/_next/static/chunks/91c828abd7c0aff5.js","/litellm-asset-prefix/_next/static/chunks/08c348f8e09a5cb0.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/b323e0ef008e6348.js","/litellm-asset-prefix/_next/static/chunks/4ac3235460262f36.js","/litellm-asset-prefix/_next/static/chunks/51494a4a4b6fc437.js","/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","/litellm-asset-prefix/_next/static/chunks/9f1486622270556b.js"],"default"] +1a:I[168027,[],"default"] :HL["/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","style"] -:HL["/litellm-asset-prefix/_next/static/chunks/91037395c95e366d.css","style"] +:HL["/litellm-asset-prefix/_next/static/chunks/1bcca3c38c9deb02.css","style"] :HL["/litellm-asset-prefix/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"P":null,"b":"LpD6ruZoEpvYpT5IvMEoa","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/91037395c95e366d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@8","$@9"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/0493aafc4891dd29.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/f7e1d08418645368.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/b3d198d6c56a21b8.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/ee5f9a39a526e423.js","async":true,"nonce":"$undefined"}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/adb8beb738574863.js","async":true,"nonce":"$undefined"}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/0549bc9afa7d4888.js","async":true,"nonce":"$undefined"}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/0b470ffc60999bf4.js","async":true,"nonce":"$undefined"}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/0b3d09ff6c6e4335.js","async":true,"nonce":"$undefined"}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/e099566e8bd4ee4e.js","async":true,"nonce":"$undefined"}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true,"nonce":"$undefined"}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/b1c98cc932a0ab19.js","async":true,"nonce":"$undefined"}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/4e17b625d75327a7.js","async":true,"nonce":"$undefined"}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true,"nonce":"$undefined"}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/a06cc76a774dd182.js","async":true,"nonce":"$undefined"}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/ca5fbafaf3826374.js","async":true,"nonce":"$undefined"}],"$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17","$L18","$L19","$L1a","$L1b","$L1c","$L1d","$L1e","$L1f","$L20","$L21","$L22","$L23","$L24","$L25","$L26","$L27","$L28","$L29","$L2a","$L2b","$L2c","$L2d","$L2e"],"$L2f"]}],{},null,false,false]},null,false,false],"$L30",false]],"m":"$undefined","G":["$31",[]],"S":true} -32:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] -33:"$Sreact.suspense" -35:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ViewportBoundary"] -37:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"MetadataBoundary"] -a:["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/e7e5bfdf70ba79ab.js","async":true,"nonce":"$undefined"}] -b:["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/10dc4591ef08a91f.js","async":true,"nonce":"$undefined"}] -c:["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/7a9066dcd4a390ff.js","async":true,"nonce":"$undefined"}] -d:["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/baadbd26839e7b66.js","async":true,"nonce":"$undefined"}] -e:["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","async":true,"nonce":"$undefined"}] -f:["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","async":true,"nonce":"$undefined"}] -10:["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/679dbd657c8b5aef.js","async":true,"nonce":"$undefined"}] -11:["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/94f7208f5087e27c.js","async":true,"nonce":"$undefined"}] -12:["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/43f6fc3c2ab9cf23.js","async":true,"nonce":"$undefined"}] -13:["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/4e06277331e725da.js","async":true,"nonce":"$undefined"}] -14:["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true,"nonce":"$undefined"}] -15:["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/908828a91f602d8b.js","async":true,"nonce":"$undefined"}] -16:["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/da1c7742cc6fe8b4.js","async":true,"nonce":"$undefined"}] -17:["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/bd02f158353d9cea.js","async":true,"nonce":"$undefined"}] -18:["$","script","script-30",{"src":"/litellm-asset-prefix/_next/static/chunks/a09028cd611c08ef.js","async":true,"nonce":"$undefined"}] -19:["$","script","script-31",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true,"nonce":"$undefined"}] -1a:["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/ad02f56c287539eb.js","async":true,"nonce":"$undefined"}] -1b:["$","script","script-33",{"src":"/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","async":true,"nonce":"$undefined"}] -1c:["$","script","script-34",{"src":"/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","async":true,"nonce":"$undefined"}] -1d:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","async":true,"nonce":"$undefined"}] -1e:["$","script","script-36",{"src":"/litellm-asset-prefix/_next/static/chunks/a8f7c8c5eeb6e042.js","async":true,"nonce":"$undefined"}] -1f:["$","script","script-37",{"src":"/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","async":true,"nonce":"$undefined"}] -20:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","async":true,"nonce":"$undefined"}] -21:["$","script","script-39",{"src":"/litellm-asset-prefix/_next/static/chunks/6188170a32c9a3c3.js","async":true,"nonce":"$undefined"}] -22:["$","script","script-40",{"src":"/litellm-asset-prefix/_next/static/chunks/1bc2898be56acd1b.js","async":true,"nonce":"$undefined"}] -23:["$","script","script-41",{"src":"/litellm-asset-prefix/_next/static/chunks/20acf4fa815c638e.js","async":true,"nonce":"$undefined"}] -24:["$","script","script-42",{"src":"/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","async":true,"nonce":"$undefined"}] -25:["$","script","script-43",{"src":"/litellm-asset-prefix/_next/static/chunks/e1a670efcb966aaa.js","async":true,"nonce":"$undefined"}] -26:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/3c0e9dc19dbbd4ed.js","async":true,"nonce":"$undefined"}] -27:["$","script","script-45",{"src":"/litellm-asset-prefix/_next/static/chunks/e1f23fd814ac3500.js","async":true,"nonce":"$undefined"}] -28:["$","script","script-46",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true,"nonce":"$undefined"}] -29:["$","script","script-47",{"src":"/litellm-asset-prefix/_next/static/chunks/ca7a3fdb635fb7dc.js","async":true,"nonce":"$undefined"}] -2a:["$","script","script-48",{"src":"/litellm-asset-prefix/_next/static/chunks/659ce28f2cb74401.js","async":true,"nonce":"$undefined"}] -2b:["$","script","script-49",{"src":"/litellm-asset-prefix/_next/static/chunks/934dbc43f8c1abde.js","async":true,"nonce":"$undefined"}] -2c:["$","script","script-50",{"src":"/litellm-asset-prefix/_next/static/chunks/d6ab357d1bbb53f0.js","async":true,"nonce":"$undefined"}] -2d:["$","script","script-51",{"src":"/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","async":true,"nonce":"$undefined"}] -2e:["$","script","script-52",{"src":"/litellm-asset-prefix/_next/static/chunks/4a0ccb5ed3d0c33f.js","async":true,"nonce":"$undefined"}] -2f:["$","$L32",null,{"children":["$","$33",null,{"name":"Next.MetadataOutlet","children":"$@34"}]}] -30:["$","$1","h",{"children":[null,["$","$L35",null,{"children":"$L36"}],["$","div",null,{"hidden":true,"children":["$","$L37",null,{"children":["$","$33",null,{"name":"Next.Metadata","children":"$L38"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}] -8:{} -9:"$0:f:0:1:1:children:0:props:children:0:props:serverProvidedParams:params" -36:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]] -39:I[27201,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"IconMark"] -34:null -38:[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L39","4",{}]] +0:{"P":null,"b":"TrcGiQpTupSbDYFFfkFHY","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/1bcca3c38c9deb02.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L7",null,{"Component":"$8","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@9","$@a"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/52c4ecc57f72065e.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/4bb663ff806dc32f.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/ee8f89c672745c59.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/2954392b7a60a6a1.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/04711b0f8ffa7bbd.js","async":true,"nonce":"$undefined"}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/9710770c6333a72f.js","async":true,"nonce":"$undefined"}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true,"nonce":"$undefined"}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/d734cb3d5659b0da.js","async":true,"nonce":"$undefined"}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/a1ef280b7ad5ae6a.js","async":true,"nonce":"$undefined"}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/09c1f51da7e82268.js","async":true,"nonce":"$undefined"}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/542a1a209eb732c6.js","async":true,"nonce":"$undefined"}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/d028f8c28935d281.js","async":true,"nonce":"$undefined"}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/61aa637257592262.js","async":true,"nonce":"$undefined"}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/bf962cd5264be987.js","async":true,"nonce":"$undefined"}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/37f229ef9335f8c3.js","async":true,"nonce":"$undefined"}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/36d1c027ba991a4f.js","async":true,"nonce":"$undefined"}],"$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17"],"$L18"]}],{},null,false,false]},null,false,false],"$L19",false]],"m":"$undefined","G":["$1a",[]],"S":true} +1b:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] +1c:"$Sreact.suspense" +1e:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ViewportBoundary"] +20:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"MetadataBoundary"] +b:["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/786e88f4abdd5c58.js","async":true,"nonce":"$undefined"}] +c:["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/43c3db1352241a8b.js","async":true,"nonce":"$undefined"}] +d:["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/31275eb5c6f6332f.js","async":true,"nonce":"$undefined"}] +e:["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/0ac09b227f50edb4.js","async":true,"nonce":"$undefined"}] +f:["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/4c848b12d4ecda3d.js","async":true,"nonce":"$undefined"}] +10:["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/91c828abd7c0aff5.js","async":true,"nonce":"$undefined"}] +11:["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/08c348f8e09a5cb0.js","async":true,"nonce":"$undefined"}] +12:["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true,"nonce":"$undefined"}] +13:["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/b323e0ef008e6348.js","async":true,"nonce":"$undefined"}] +14:["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/4ac3235460262f36.js","async":true,"nonce":"$undefined"}] +15:["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/51494a4a4b6fc437.js","async":true,"nonce":"$undefined"}] +16:["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/878832edb30e99a4.js","async":true,"nonce":"$undefined"}] +17:["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/9f1486622270556b.js","async":true,"nonce":"$undefined"}] +18:["$","$L1b",null,{"children":["$","$1c",null,{"name":"Next.MetadataOutlet","children":"$@1d"}]}] +19:["$","$1","h",{"children":[null,["$","$L1e",null,{"children":"$L1f"}],["$","div",null,{"hidden":true,"children":["$","$L20",null,{"children":["$","$1c",null,{"name":"Next.Metadata","children":"$L21"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}] +9:{} +a:"$0:f:0:1:1:children:0:props:children:0:props:serverProvidedParams:params" +1f:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]] +22:I[27201,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"IconMark"] +1d:null +21:[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L22","4",{}]] diff --git a/litellm/proxy/_experimental/out/__next._head.txt b/litellm/proxy/_experimental/out/__next._head.txt index 52cb2daa038..ea6e5095458 100644 --- a/litellm/proxy/_experimental/out/__next._head.txt +++ b/litellm/proxy/_experimental/out/__next._head.txt @@ -3,4 +3,4 @@ 3:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"MetadataBoundary"] 4:"$Sreact.suspense" 5:I[27201,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"IconMark"] -0:{"buildId":"LpD6ruZoEpvYpT5IvMEoa","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L5","4",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false} +0:{"buildId":"TrcGiQpTupSbDYFFfkFHY","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L5","4",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false} diff --git a/litellm/proxy/_experimental/out/__next._index.txt b/litellm/proxy/_experimental/out/__next._index.txt index 24ed6776f93..ebf6d8fec08 100644 --- a/litellm/proxy/_experimental/out/__next._index.txt +++ b/litellm/proxy/_experimental/out/__next._index.txt @@ -1,8 +1,9 @@ 1:"$Sreact.fragment" -2:I[867271,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js"],"default"] -3:I[71195,["/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js"],"default"] -4:I[339756,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] -5:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] +2:I[867271,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"default"] +3:I[71195,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"default"] +4:I[557951,["/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js"],"AuthProvider"] +5:I[339756,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] +6:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] :HL["/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","style"] -:HL["/litellm-asset-prefix/_next/static/chunks/91037395c95e366d.css","style"] -0:{"buildId":"LpD6ruZoEpvYpT5IvMEoa","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/91037395c95e366d.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/9e09de50158b3159.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/7e5fe5584502da06.js","async":true}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","template":["$","$L5",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]}]}]}]]}],"loading":null,"isPartial":false} +:HL["/litellm-asset-prefix/_next/static/chunks/1bcca3c38c9deb02.css","style"] +0:{"buildId":"TrcGiQpTupSbDYFFfkFHY","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/1bcca3c38c9deb02.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/aefca6f40ea185cd.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/632b4c8e836bd956.js","async":true}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","template":["$","$L6",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]}]}]}]}]]}],"loading":null,"isPartial":false} diff --git a/litellm/proxy/_experimental/out/__next._tree.txt b/litellm/proxy/_experimental/out/__next._tree.txt index 78aafc1b3f5..4a08f4f9e11 100644 --- a/litellm/proxy/_experimental/out/__next._tree.txt +++ b/litellm/proxy/_experimental/out/__next._tree.txt @@ -1,5 +1,5 @@ :HL["/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","style"] -:HL["/litellm-asset-prefix/_next/static/chunks/91037395c95e366d.css","style"] +:HL["/litellm-asset-prefix/_next/static/chunks/1bcca3c38c9deb02.css","style"] :HL["/litellm-asset-prefix/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"buildId":"LpD6ruZoEpvYpT5IvMEoa","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":true},"staleTime":300} +0:{"buildId":"TrcGiQpTupSbDYFFfkFHY","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":true},"staleTime":300} diff --git a/litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_buildManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_buildManifest.js rename to litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_buildManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_clientMiddlewareManifest.json b/litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_clientMiddlewareManifest.json similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_clientMiddlewareManifest.json rename to litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_clientMiddlewareManifest.json diff --git a/litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_ssgManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/LpD6ruZoEpvYpT5IvMEoa/_ssgManifest.js rename to litellm/proxy/_experimental/out/_next/static/TrcGiQpTupSbDYFFfkFHY/_ssgManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/00ff280cdb7d7ee5.js b/litellm/proxy/_experimental/out/_next/static/chunks/00ff280cdb7d7ee5.js deleted file mode 100644 index ef84e7aadbe..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/00ff280cdb7d7ee5.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,829087,397126,229315,343084,953760,e=>{"use strict";e.i(247167);var t=e.i(271645);new WeakMap,new WeakMap;var n='input:not([inert]):not([inert] *),select:not([inert]):not([inert] *),textarea:not([inert]):not([inert] *),a[href]:not([inert]):not([inert] *),button:not([inert]):not([inert] *),[tabindex]:not(slot):not([inert]):not([inert] *),audio[controls]:not([inert]):not([inert] *),video[controls]:not([inert]):not([inert] *),[contenteditable]:not([contenteditable="false"]):not([inert]):not([inert] *),details>summary:first-of-type:not([inert]):not([inert] *),details:not([inert]):not([inert] *)',r="u"typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var o=h(t,e.form);return!o||o===e},v=function(e){return m(e)&&"radio"===e.type&&!g(e)},y=function(e){var t,n,r,o,l,u,a,c=e&&i(e),s=null==(t=c)?void 0:t.host,f=!1;if(c&&c!==e)for(f=!!(null!=(n=s)&&null!=(r=n.ownerDocument)&&r.contains(s)||null!=e&&null!=(o=e.ownerDocument)&&o.contains(e));!f&&s;)f=!!(null!=(u=s=null==(l=c=i(s))?void 0:l.host)&&null!=(a=u.ownerDocument)&&a.contains(s));return f},w=function(e){var t=e.getBoundingClientRect(),n=t.width,r=t.height;return 0===n&&0===r},b=function(e,t){var n=t.displayCheck,r=t.getShadowRoot;if("full-native"===n&&"checkVisibility"in e)return!e.checkVisibility({checkOpacity:!1,opacityProperty:!1,contentVisibilityAuto:!0,visibilityProperty:!0,checkVisibilityCSS:!0});if("hidden"===getComputedStyle(e).visibility)return!0;var l=o.call(e,"details>summary:first-of-type")?e.parentElement:e;if(o.call(l,"details:not([open]) *"))return!0;if(n&&"full"!==n&&"full-native"!==n&&"legacy-full"!==n){if("non-zero-area"===n)return w(e)}else{if("function"==typeof r){for(var u=e;e;){var a=e.parentElement,c=i(e);if(a&&!a.shadowRoot&&!0===r(a))return w(e);e=e.assignedSlot?e.assignedSlot:a||c===e.ownerDocument?a:c.host}e=u}if(y(e))return!e.getClientRects().length;if("legacy-full"!==n)return!0}return!1},x=function(e){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(e.tagName))for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;nf(t))&&!!E(e,t)},S=function(e){var t=parseInt(e.getAttribute("tabindex"),10);return!!isNaN(t)||!!(t>=0)},T=function(e){var t=[],n=[];return e.forEach(function(e,r){var o=!!e.scopeParent,i=o?e.scopeParent:e,l=d(i,o),u=o?T(e.candidates):i;0===l?o?t.push.apply(t,u):t.push(i):n.push({documentOrder:r,tabIndex:l,item:e,isScope:o,content:u})}),n.sort(p).reduce(function(e,t){return t.isScope?e.push.apply(e,t.content):e.push(t.content),e},[]).concat(t)},L=function(e,t){return T((t=t||{}).getShadowRoot?c([e],t.includeContainer,{filter:R.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot,shadowRootFilter:S}):a(e,t.includeContainer,R.bind(null,t)))},A=function(e,t){if(t=t||{},!e)throw Error("No node provided");return!1!==o.call(e,n)&&R(t,e)};e.s(["isTabbable",()=>A,"tabbable",()=>L],397126);var C=e.i(174080);function P(){return"u">typeof window}function O(e){return M(e)?(e.nodeName||"").toLowerCase():"#document"}function k(e){var t;return(null==e||null==(t=e.ownerDocument)?void 0:t.defaultView)||window}function D(e){var t;return null==(t=(M(e)?e.ownerDocument:e.document)||window.document)?void 0:t.documentElement}function M(e){return!!P()&&(e instanceof Node||e instanceof k(e).Node)}function N(e){return!!P()&&(e instanceof Element||e instanceof k(e).Element)}function F(e){return!!P()&&(e instanceof HTMLElement||e instanceof k(e).HTMLElement)}function I(e){return!(!P()||"u"{try{return e.matches(t)}catch(e){return!1}})}let z=["transform","translate","scale","rotate","perspective"],K=["transform","translate","scale","rotate","perspective","filter"],U=["paint","layout","strict","content"];function X(e){let t=$(),n=N(e)?J(e):e;return z.some(e=>!!n[e]&&"none"!==n[e])||!!n.containerType&&"normal"!==n.containerType||!t&&!!n.backdropFilter&&"none"!==n.backdropFilter||!t&&!!n.filter&&"none"!==n.filter||K.some(e=>(n.willChange||"").includes(e))||U.some(e=>(n.contain||"").includes(e))}function Y(e){let t=Z(e);for(;F(t)&&!G(t);){if(X(t))return t;if(j(t))break;t=Z(t)}return null}function $(){return!("u"J,"getContainingBlock",()=>Y,"getDocumentElement",()=>D,"getFrameElement",()=>et,"getNodeName",()=>O,"getNodeScroll",()=>Q,"getOverflowAncestors",()=>ee,"getParentNode",()=>Z,"getWindow",()=>k,"isContainingBlock",()=>X,"isElement",()=>N,"isHTMLElement",()=>F,"isLastTraversableNode",()=>G,"isOverflowElement",()=>W,"isShadowRoot",()=>I,"isTableElement",()=>V,"isTopLayer",()=>j,"isWebKit",()=>$],229315);let en=["top","right","bottom","left"],er=en.reduce((e,t)=>e.concat(t,t+"-start",t+"-end"),[]),eo=Math.min,ei=Math.max,el=Math.round,eu=Math.floor,ea=e=>({x:e,y:e}),ec={left:"right",right:"left",bottom:"top",top:"bottom"},es={start:"end",end:"start"};function ef(e,t,n){return ei(e,eo(t,n))}function ed(e,t){return"function"==typeof e?e(t):e}function ep(e){return e.split("-")[0]}function em(e){return e.split("-")[1]}function eh(e){return"x"===e?"y":"x"}function eg(e){return"y"===e?"height":"width"}let ev=new Set(["top","bottom"]);function ey(e){return ev.has(ep(e))?"y":"x"}function ew(e){return eh(ey(e))}function eb(e,t,n){void 0===n&&(n=!1);let r=em(e),o=ew(e),i=eg(o),l="x"===o?r===(n?"end":"start")?"right":"left":"start"===r?"bottom":"top";return t.reference[i]>t.floating[i]&&(l=eC(l)),[l,eC(l)]}function ex(e){let t=eC(e);return[eE(e),t,eE(t)]}function eE(e){return e.replace(/start|end/g,e=>es[e])}let eR=["left","right"],eS=["right","left"],eT=["top","bottom"],eL=["bottom","top"];function eA(e,t,n,r){let o=em(e),i=function(e,t,n){switch(e){case"top":case"bottom":if(n)return t?eS:eR;return t?eR:eS;case"left":case"right":return t?eT:eL;default:return[]}}(ep(e),"start"===n,r);return o&&(i=i.map(e=>e+"-"+o),t&&(i=i.concat(i.map(eE)))),i}function eC(e){return e.replace(/left|right|bottom|top/g,e=>ec[e])}function eP(e){return"number"!=typeof e?{top:0,right:0,bottom:0,left:0,...e}:{top:e,right:e,bottom:e,left:e}}function eO(e){let{x:t,y:n,width:r,height:o}=e;return{width:r,height:o,top:n,left:t,right:t+r,bottom:n+o,x:t,y:n}}function ek(e,t,n){let r,{reference:o,floating:i}=e,l=ey(t),u=ew(t),a=eg(u),c=ep(t),s="y"===l,f=o.x+o.width/2-i.width/2,d=o.y+o.height/2-i.height/2,p=o[a]/2-i[a]/2;switch(c){case"top":r={x:f,y:o.y-i.height};break;case"bottom":r={x:f,y:o.y+o.height};break;case"right":r={x:o.x+o.width,y:d};break;case"left":r={x:o.x-i.width,y:d};break;default:r={x:o.x,y:o.y}}switch(em(t)){case"start":r[u]-=p*(n&&s?-1:1);break;case"end":r[u]+=p*(n&&s?-1:1)}return r}async function eD(e,t){var n;void 0===t&&(t={});let{x:r,y:o,platform:i,rects:l,elements:u,strategy:a}=e,{boundary:c="clippingAncestors",rootBoundary:s="viewport",elementContext:f="floating",altBoundary:d=!1,padding:p=0}=ed(t,e),m=eP(p),h=u[d?"floating"===f?"reference":"floating":f],g=eO(await i.getClippingRect({element:null==(n=await (null==i.isElement?void 0:i.isElement(h)))||n?h:h.contextElement||await (null==i.getDocumentElement?void 0:i.getDocumentElement(u.floating)),boundary:c,rootBoundary:s,strategy:a})),v="floating"===f?{x:r,y:o,width:l.floating.width,height:l.floating.height}:l.reference,y=await (null==i.getOffsetParent?void 0:i.getOffsetParent(u.floating)),w=await (null==i.isElement?void 0:i.isElement(y))&&await (null==i.getScale?void 0:i.getScale(y))||{x:1,y:1},b=eO(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:u,rect:v,offsetParent:y,strategy:a}):v);return{top:(g.top-b.top+m.top)/w.y,bottom:(b.bottom-g.bottom+m.bottom)/w.y,left:(g.left-b.left+m.left)/w.x,right:(b.right-g.right+m.right)/w.x}}e.s(["clamp",()=>ef,"createCoords",()=>ea,"evaluate",()=>ed,"floor",()=>eu,"getAlignment",()=>em,"getAlignmentAxis",()=>ew,"getAlignmentSides",()=>eb,"getAxisLength",()=>eg,"getExpandedPlacements",()=>ex,"getOppositeAlignmentPlacement",()=>eE,"getOppositeAxis",()=>eh,"getOppositeAxisPlacements",()=>eA,"getOppositePlacement",()=>eC,"getPaddingObject",()=>eP,"getSide",()=>ep,"getSideAxis",()=>ey,"max",()=>ei,"min",()=>eo,"placements",()=>er,"rectToClientRect",()=>eO,"round",()=>el,"sides",()=>en],343084);let eM=async(e,t,n)=>{let{placement:r="bottom",strategy:o="absolute",middleware:i=[],platform:l}=n,u=i.filter(Boolean),a=await (null==l.isRTL?void 0:l.isRTL(t)),c=await l.getElementRects({reference:e,floating:t,strategy:o}),{x:s,y:f}=ek(c,r,a),d=r,p={},m=0;for(let n=0;ne[t]>=0)}function eI(e){let t=eo(...e.map(e=>e.left)),n=eo(...e.map(e=>e.top));return{x:t,y:n,width:ei(...e.map(e=>e.right))-t,height:ei(...e.map(e=>e.bottom))-n}}let eB=new Set(["left","top"]);async function eW(e,t){let{placement:n,platform:r,elements:o}=e,i=await (null==r.isRTL?void 0:r.isRTL(o.floating)),l=ep(n),u=em(n),a="y"===ey(n),c=eB.has(l)?-1:1,s=i&&a?-1:1,f=ed(t,e),{mainAxis:d,crossAxis:p,alignmentAxis:m}="number"==typeof f?{mainAxis:f,crossAxis:0,alignmentAxis:null}:{mainAxis:f.mainAxis||0,crossAxis:f.crossAxis||0,alignmentAxis:f.alignmentAxis};return u&&"number"==typeof m&&(p="end"===u?-1*m:m),a?{x:p*s,y:d*c}:{x:d*c,y:p*s}}function eH(e){let t=J(e),n=parseFloat(t.width)||0,r=parseFloat(t.height)||0,o=F(e),i=o?e.offsetWidth:n,l=o?e.offsetHeight:r,u=el(n)!==i||el(r)!==l;return u&&(n=i,r=l),{width:n,height:r,$:u}}function eV(e){return N(e)?e:e.contextElement}function e_(e){let t=eV(e);if(!F(t))return ea(1);let n=t.getBoundingClientRect(),{width:r,height:o,$:i}=eH(t),l=(i?el(n.width):n.width)/r,u=(i?el(n.height):n.height)/o;return l&&Number.isFinite(l)||(l=1),u&&Number.isFinite(u)||(u=1),{x:l,y:u}}let ej=ea(0);function ez(e){let t=k(e);return $()&&t.visualViewport?{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}:ej}function eK(e,t,n,r){var o;void 0===t&&(t=!1),void 0===n&&(n=!1);let i=e.getBoundingClientRect(),l=eV(e),u=ea(1);t&&(r?N(r)&&(u=e_(r)):u=e_(e));let a=(void 0===(o=n)&&(o=!1),r&&(!o||r===k(l))&&o)?ez(l):ea(0),c=(i.left+a.x)/u.x,s=(i.top+a.y)/u.y,f=i.width/u.x,d=i.height/u.y;if(l){let e=k(l),t=r&&N(r)?k(r):r,n=e,o=et(n);for(;o&&r&&t!==n;){let e=e_(o),t=o.getBoundingClientRect(),r=J(o),i=t.left+(o.clientLeft+parseFloat(r.paddingLeft))*e.x,l=t.top+(o.clientTop+parseFloat(r.paddingTop))*e.y;c*=e.x,s*=e.y,f*=e.x,d*=e.y,c+=i,s+=l,o=et(n=k(o))}}return eO({width:f,height:d,x:c,y:s})}function eU(e,t){let n=Q(e).scrollLeft;return t?t.left+n:eK(D(e)).left+n}function eX(e,t){let n=e.getBoundingClientRect();return{x:n.left+t.scrollLeft-eU(e,n),y:n.top+t.scrollTop}}let eY=new Set(["absolute","fixed"]);function e$(e,t,n){var r;let o;if("viewport"===t)o=function(e,t){let n=k(e),r=D(e),o=n.visualViewport,i=r.clientWidth,l=r.clientHeight,u=0,a=0;if(o){i=o.width,l=o.height;let e=$();(!e||e&&"fixed"===t)&&(u=o.offsetLeft,a=o.offsetTop)}let c=eU(r);if(c<=0){let e=r.ownerDocument,t=e.body,n=getComputedStyle(t),o="CSS1Compat"===e.compatMode&&parseFloat(n.marginLeft)+parseFloat(n.marginRight)||0,l=Math.abs(r.clientWidth-t.clientWidth-o);l<=25&&(i-=l)}else c<=25&&(i+=c);return{width:i,height:l,x:u,y:a}}(e,n);else if("document"===t){let t,n,i,l,u,a,c;r=D(e),t=D(r),n=Q(r),i=r.ownerDocument.body,l=ei(t.scrollWidth,t.clientWidth,i.scrollWidth,i.clientWidth),u=ei(t.scrollHeight,t.clientHeight,i.scrollHeight,i.clientHeight),a=-n.scrollLeft+eU(r),c=-n.scrollTop,"rtl"===J(i).direction&&(a+=ei(t.clientWidth,i.clientWidth)-l),o={width:l,height:u,x:a,y:c}}else if(N(t)){let e,r,i,l,u,a;r=(e=eK(t,!0,"fixed"===n)).top+t.clientTop,i=e.left+t.clientLeft,l=F(t)?e_(t):ea(1),u=t.clientWidth*l.x,a=t.clientHeight*l.y,o={width:u,height:a,x:i*l.x,y:r*l.y}}else{let n=ez(e);o={x:t.x-n.x,y:t.y-n.y,width:t.width,height:t.height}}return eO(o)}function eq(e){return"static"===J(e).position}function eG(e,t){if(!F(e)||"fixed"===J(e).position)return null;if(t)return t(e);let n=e.offsetParent;return D(e)===n&&(n=n.ownerDocument.body),n}function eJ(e,t){let n=k(e);if(j(e))return n;if(!F(e)){let t=Z(e);for(;t&&!G(t);){if(N(t)&&!eq(t))return t;t=Z(t)}return n}let r=eG(e,t);for(;r&&V(r)&&eq(r);)r=eG(r,t);return r&&G(r)&&eq(r)&&!X(r)?n:r||Y(e)||n}let eQ=async function(e){let t=this.getOffsetParent||eJ,n=this.getDimensions,r=await n(e.floating);return{reference:function(e,t,n){let r=F(t),o=D(t),i="fixed"===n,l=eK(e,!0,i,t),u={scrollLeft:0,scrollTop:0},a=ea(0);if(r||!r&&!i)if(("body"!==O(t)||W(o))&&(u=Q(t)),r){let e=eK(t,!0,i,t);a.x=e.x+t.clientLeft,a.y=e.y+t.clientTop}else o&&(a.x=eU(o));i&&!r&&o&&(a.x=eU(o));let c=!o||r||i?ea(0):eX(o,u);return{x:l.left+u.scrollLeft-a.x-c.x,y:l.top+u.scrollTop-a.y-c.y,width:l.width,height:l.height}}(e.reference,await t(e.floating),e.strategy),floating:{x:0,y:0,width:r.width,height:r.height}}},eZ={convertOffsetParentRelativeRectToViewportRelativeRect:function(e){let{elements:t,rect:n,offsetParent:r,strategy:o}=e,i="fixed"===o,l=D(r),u=!!t&&j(t.floating);if(r===l||u&&i)return n;let a={scrollLeft:0,scrollTop:0},c=ea(1),s=ea(0),f=F(r);if((f||!f&&!i)&&(("body"!==O(r)||W(l))&&(a=Q(r)),F(r))){let e=eK(r);c=e_(r),s.x=e.x+r.clientLeft,s.y=e.y+r.clientTop}let d=!l||f||i?ea(0):eX(l,a);return{width:n.width*c.x,height:n.height*c.y,x:n.x*c.x-a.scrollLeft*c.x+s.x+d.x,y:n.y*c.y-a.scrollTop*c.y+s.y+d.y}},getDocumentElement:D,getClippingRect:function(e){let{element:t,boundary:n,rootBoundary:r,strategy:o}=e,i=[..."clippingAncestors"===n?j(t)?[]:function(e,t){let n=t.get(e);if(n)return n;let r=ee(e,[],!1).filter(e=>N(e)&&"body"!==O(e)),o=null,i="fixed"===J(e).position,l=i?Z(e):e;for(;N(l)&&!G(l);){let t=J(l),n=X(l);n||"fixed"!==t.position||(o=null),(i?!n&&!o:!n&&"static"===t.position&&!!o&&eY.has(o.position)||W(l)&&!n&&function e(t,n){let r=Z(t);return!(r===n||!N(r)||G(r))&&("fixed"===J(r).position||e(r,n))}(e,l))?r=r.filter(e=>e!==l):o=t,l=Z(l)}return t.set(e,r),r}(t,this._c):[].concat(n),r],l=i[0],u=i.reduce((e,n)=>{let r=e$(t,n,o);return e.top=ei(r.top,e.top),e.right=eo(r.right,e.right),e.bottom=eo(r.bottom,e.bottom),e.left=ei(r.left,e.left),e},e$(t,l,o));return{width:u.right-u.left,height:u.bottom-u.top,x:u.left,y:u.top}},getOffsetParent:eJ,getElementRects:eQ,getClientRects:function(e){return Array.from(e.getClientRects())},getDimensions:function(e){let{width:t,height:n}=eH(e);return{width:t,height:n}},getScale:e_,isElement:N,isRTL:function(e){return"rtl"===J(e).direction}};function e0(e,t){return e.x===t.x&&e.y===t.y&&e.width===t.width&&e.height===t.height}function e1(e,t,n,r){let o;void 0===r&&(r={});let{ancestorScroll:i=!0,ancestorResize:l=!0,elementResize:u="function"==typeof ResizeObserver,layoutShift:a="function"==typeof IntersectionObserver,animationFrame:c=!1}=r,s=eV(e),f=i||l?[...s?ee(s):[],...ee(t)]:[];f.forEach(e=>{i&&e.addEventListener("scroll",n,{passive:!0}),l&&e.addEventListener("resize",n)});let d=s&&a?function(e,t){let n,r=null,o=D(e);function i(){var e;clearTimeout(n),null==(e=r)||e.disconnect(),r=null}return!function l(u,a){void 0===u&&(u=!1),void 0===a&&(a=1),i();let c=e.getBoundingClientRect(),{left:s,top:f,width:d,height:p}=c;if(u||t(),!d||!p)return;let m={rootMargin:-eu(f)+"px "+-eu(o.clientWidth-(s+d))+"px "+-eu(o.clientHeight-(f+p))+"px "+-eu(s)+"px",threshold:ei(0,eo(1,a))||1},h=!0;function g(t){let r=t[0].intersectionRatio;if(r!==a){if(!h)return l();r?l(!1,r):n=setTimeout(()=>{l(!1,1e-7)},1e3)}1!==r||e0(c,e.getBoundingClientRect())||l(),h=!1}try{r=new IntersectionObserver(g,{...m,root:o.ownerDocument})}catch(e){r=new IntersectionObserver(g,m)}r.observe(e)}(!0),i}(s,n):null,p=-1,m=null;u&&(m=new ResizeObserver(e=>{let[r]=e;r&&r.target===s&&m&&(m.unobserve(t),cancelAnimationFrame(p),p=requestAnimationFrame(()=>{var e;null==(e=m)||e.observe(t)})),n()}),s&&!c&&m.observe(s),m.observe(t));let h=c?eK(e):null;return c&&function t(){let r=eK(e);h&&!e0(h,r)&&n(),h=r,o=requestAnimationFrame(t)}(),n(),()=>{var e;f.forEach(e=>{i&&e.removeEventListener("scroll",n),l&&e.removeEventListener("resize",n)}),null==d||d(),null==(e=m)||e.disconnect(),m=null,c&&cancelAnimationFrame(o)}}let e2=function(e){return void 0===e&&(e=0),{name:"offset",options:e,async fn(t){var n,r;let{x:o,y:i,placement:l,middlewareData:u}=t,a=await eW(t,e);return l===(null==(n=u.offset)?void 0:n.placement)&&null!=(r=u.arrow)&&r.alignmentOffset?{}:{x:o+a.x,y:i+a.y,data:{...a,placement:l}}}}},e3=function(e){return void 0===e&&(e={}),{name:"autoPlacement",options:e,async fn(t){var n,r,o,i;let{rects:l,middlewareData:u,placement:a,platform:c,elements:s}=t,{crossAxis:f=!1,alignment:d,allowedPlacements:p=er,autoAlignment:m=!0,...h}=ed(e,t),g=void 0!==d||p===er?((i=d||null)?[...p.filter(e=>em(e)===i),...p.filter(e=>em(e)!==i)]:p.filter(e=>ep(e)===e)).filter(e=>!i||em(e)===i||!!m&&eE(e)!==e):p,v=await c.detectOverflow(t,h),y=(null==(n=u.autoPlacement)?void 0:n.index)||0,w=g[y];if(null==w)return{};let b=eb(w,l,await (null==c.isRTL?void 0:c.isRTL(s.floating)));if(a!==w)return{reset:{placement:g[0]}};let x=[v[ep(w)],v[b[0]],v[b[1]]],E=[...(null==(r=u.autoPlacement)?void 0:r.overflows)||[],{placement:w,overflows:x}],R=g[y+1];if(R)return{data:{index:y+1,overflows:E},reset:{placement:R}};let S=E.map(e=>{let t=em(e.placement);return[e.placement,t&&f?e.overflows.slice(0,2).reduce((e,t)=>e+t,0):e.overflows[0],e.overflows]}).sort((e,t)=>e[1]-t[1]),T=(null==(o=S.filter(e=>e[2].slice(0,em(e[0])?2:3).every(e=>e<=0))[0])?void 0:o[0])||S[0][0];return T!==a?{data:{index:y+1,overflows:E},reset:{placement:T}}:{}}}},e5=function(e){return void 0===e&&(e={}),{name:"shift",options:e,async fn(t){let{x:n,y:r,placement:o,platform:i}=t,{mainAxis:l=!0,crossAxis:u=!1,limiter:a={fn:e=>{let{x:t,y:n}=e;return{x:t,y:n}}},...c}=ed(e,t),s={x:n,y:r},f=await i.detectOverflow(t,c),d=ey(ep(o)),p=eh(d),m=s[p],h=s[d];if(l){let e="y"===p?"top":"left",t="y"===p?"bottom":"right",n=m+f[e],r=m-f[t];m=ef(n,m,r)}if(u){let e="y"===d?"top":"left",t="y"===d?"bottom":"right",n=h+f[e],r=h-f[t];h=ef(n,h,r)}let g=a.fn({...t,[p]:m,[d]:h});return{...g,data:{x:g.x-n,y:g.y-r,enabled:{[p]:l,[d]:u}}}}}},e7=function(e){return void 0===e&&(e={}),{name:"flip",options:e,async fn(t){var n,r,o,i,l;let{placement:u,middlewareData:a,rects:c,initialPlacement:s,platform:f,elements:d}=t,{mainAxis:p=!0,crossAxis:m=!0,fallbackPlacements:h,fallbackStrategy:g="bestFit",fallbackAxisSideDirection:v="none",flipAlignment:y=!0,...w}=ed(e,t);if(null!=(n=a.arrow)&&n.alignmentOffset)return{};let b=ep(u),x=ey(s),E=ep(s)===s,R=await (null==f.isRTL?void 0:f.isRTL(d.floating)),S=h||(E||!y?[eC(s)]:ex(s)),T="none"!==v;!h&&T&&S.push(...eA(s,y,v,R));let L=[s,...S],A=await f.detectOverflow(t,w),C=[],P=(null==(r=a.flip)?void 0:r.overflows)||[];if(p&&C.push(A[b]),m){let e=eb(u,c,R);C.push(A[e[0]],A[e[1]])}if(P=[...P,{placement:u,overflows:C}],!C.every(e=>e<=0)){let e=((null==(o=a.flip)?void 0:o.index)||0)+1,t=L[e];if(t&&("alignment"!==m||x===ey(t)||P.every(e=>ey(e.placement)!==x||e.overflows[0]>0)))return{data:{index:e,overflows:P},reset:{placement:t}};let n=null==(i=P.filter(e=>e.overflows[0]<=0).sort((e,t)=>e.overflows[1]-t.overflows[1])[0])?void 0:i.placement;if(!n)switch(g){case"bestFit":{let e=null==(l=P.filter(e=>{if(T){let t=ey(e.placement);return t===x||"y"===t}return!0}).map(e=>[e.placement,e.overflows.filter(e=>e>0).reduce((e,t)=>e+t,0)]).sort((e,t)=>e[1]-t[1])[0])?void 0:l[0];e&&(n=e);break}case"initialPlacement":n=s}if(u!==n)return{reset:{placement:n}}}return{}}}},e4=function(e){return void 0===e&&(e={}),{name:"size",options:e,async fn(t){var n,r;let o,i,{placement:l,rects:u,platform:a,elements:c}=t,{apply:s=()=>{},...f}=ed(e,t),d=await a.detectOverflow(t,f),p=ep(l),m=em(l),h="y"===ey(l),{width:g,height:v}=u.floating;"top"===p||"bottom"===p?(o=p,i=m===(await (null==a.isRTL?void 0:a.isRTL(c.floating))?"start":"end")?"left":"right"):(i=p,o="end"===m?"top":"bottom");let y=v-d.top-d.bottom,w=g-d.left-d.right,b=eo(v-d[o],y),x=eo(g-d[i],w),E=!t.middlewareData.shift,R=b,S=x;if(null!=(n=t.middlewareData.shift)&&n.enabled.x&&(S=w),null!=(r=t.middlewareData.shift)&&r.enabled.y&&(R=y),E&&!m){let e=ei(d.left,0),t=ei(d.right,0),n=ei(d.top,0),r=ei(d.bottom,0);h?S=g-2*(0!==e||0!==t?e+t:ei(d.left,d.right)):R=v-2*(0!==n||0!==r?n+r:ei(d.top,d.bottom))}await s({...t,availableWidth:S,availableHeight:R});let T=await a.getDimensions(c.floating);return g!==T.width||v!==T.height?{reset:{rects:!0}}:{}}}},e9=function(e){return void 0===e&&(e={}),{name:"hide",options:e,async fn(t){let{rects:n,platform:r}=t,{strategy:o="referenceHidden",...i}=ed(e,t);switch(o){case"referenceHidden":{let e=eN(await r.detectOverflow(t,{...i,elementContext:"reference"}),n.reference);return{data:{referenceHiddenOffsets:e,referenceHidden:eF(e)}}}case"escaped":{let e=eN(await r.detectOverflow(t,{...i,altBoundary:!0}),n.floating);return{data:{escapedOffsets:e,escaped:eF(e)}}}default:return{}}}}},e8=e=>({name:"arrow",options:e,async fn(t){let{x:n,y:r,placement:o,rects:i,platform:l,elements:u,middlewareData:a}=t,{element:c,padding:s=0}=ed(e,t)||{};if(null==c)return{};let f=eP(s),d={x:n,y:r},p=ew(o),m=eg(p),h=await l.getDimensions(c),g="y"===p,v=g?"clientHeight":"clientWidth",y=i.reference[m]+i.reference[p]-d[p]-i.floating[m],w=d[p]-i.reference[p],b=await (null==l.getOffsetParent?void 0:l.getOffsetParent(c)),x=b?b[v]:0;x&&await (null==l.isElement?void 0:l.isElement(b))||(x=u.floating[v]||i.floating[m]);let E=x/2-h[m]/2-1,R=eo(f[g?"top":"left"],E),S=eo(f[g?"bottom":"right"],E),T=x-h[m]-S,L=x/2-h[m]/2+(y/2-w/2),A=ef(R,L,T),C=!a.arrow&&null!=em(o)&&L!==A&&i.reference[m]/2-(Le.y-t.y),n=[],r=null;for(let e=0;er.height/2?n.push([o]):n[n.length-1].push(o),r=o}return n.map(e=>eO(eI(e)))}(s),d=eO(eI(s)),p=eP(u),m=await i.getElementRects({reference:{getBoundingClientRect:function(){if(2===f.length&&f[0].left>f[1].right&&null!=a&&null!=c)return f.find(e=>a>e.left-p.left&&ae.top-p.top&&c=2){if("y"===ey(n)){let e=f[0],t=f[f.length-1],r="top"===ep(n),o=e.top,i=t.bottom,l=r?e.left:t.left,u=r?e.right:t.right;return{top:o,bottom:i,left:l,right:u,width:u-l,height:i-o,x:l,y:o}}let e="left"===ep(n),t=ei(...f.map(e=>e.right)),r=eo(...f.map(e=>e.left)),o=f.filter(n=>e?n.left===r:n.right===t),i=o[0].top,l=o[o.length-1].bottom;return{top:i,bottom:l,left:r,right:t,width:t-r,height:l-i,x:r,y:i}}return d}},floating:r.floating,strategy:l});return o.reference.x!==m.reference.x||o.reference.y!==m.reference.y||o.reference.width!==m.reference.width||o.reference.height!==m.reference.height?{reset:{rects:m}}:{}}}},te=function(e){return void 0===e&&(e={}),{options:e,fn(t){let{x:n,y:r,placement:o,rects:i,middlewareData:l}=t,{offset:u=0,mainAxis:a=!0,crossAxis:c=!0}=ed(e,t),s={x:n,y:r},f=ey(o),d=eh(f),p=s[d],m=s[f],h=ed(u,t),g="number"==typeof h?{mainAxis:h,crossAxis:0}:{mainAxis:0,crossAxis:0,...h};if(a){let e="y"===d?"height":"width",t=i.reference[d]-i.floating[e]+g.mainAxis,n=i.reference[d]+i.reference[e]-g.mainAxis;pn&&(p=n)}if(c){var v,y;let e="y"===d?"width":"height",t=eB.has(ep(o)),n=i.reference[f]-i.floating[e]+(t&&(null==(v=l.offset)?void 0:v[f])||0)+(t?0:g.crossAxis),r=i.reference[f]+i.reference[e]+(t?0:(null==(y=l.offset)?void 0:y[f])||0)-(t?g.crossAxis:0);mr&&(m=r)}return{[d]:p,[f]:m}}}},tt=(e,t,n)=>{let r=new Map,o={platform:eZ,...n},i={...o.platform,_c:r};return eM(e,t,{...o,platform:i})};e.s(["arrow",()=>e8,"autoPlacement",()=>e3,"autoUpdate",()=>e1,"computePosition",()=>tt,"detectOverflow",()=>eD,"flip",()=>e7,"hide",()=>e9,"inline",()=>e6,"limitShift",()=>te,"offset",()=>e2,"shift",()=>e5,"size",()=>e4],953760);var tn="u">typeof document?t.useLayoutEffect:t.useEffect;function tr(e,t){let n,r,o;if(e===t)return!0;if(typeof e!=typeof t)return!1;if("function"==typeof e&&e.toString()===t.toString())return!0;if(e&&t&&"object"==typeof e){if(Array.isArray(e)){if((n=e.length)!=t.length)return!1;for(r=n;0!=r--;)if(!tr(e[r],t[r]))return!1;return!0}if((n=(o=Object.keys(e)).length)!==Object.keys(t).length)return!1;for(r=n;0!=r--;)if(!Object.prototype.hasOwnProperty.call(t,o[r]))return!1;for(r=n;0!=r--;){let n=o[r];if(("_owner"!==n||!e.$$typeof)&&!tr(e[n],t[n]))return!1}return!0}return e!=e&&t!=t}function to(e){let n=t.useRef(e);return tn(()=>{n.current=e}),n}var ti="u">typeof document?t.useLayoutEffect:t.useEffect;let tl=!1,tu=0,ta=()=>"floating-ui-"+tu++,tc=t["useId".toString()]||function(){let[e,n]=t.useState(()=>tl?ta():void 0);return ti(()=>{null==e&&n(ta())},[]),t.useEffect(()=>{tl||(tl=!0)},[]),e},ts=t.createContext(null),tf=t.createContext(null),td=()=>{var e;return(null==(e=t.useContext(ts))?void 0:e.id)||null};function tp(e){return(null==e?void 0:e.ownerDocument)||document}function tm(e){return tp(e).defaultView||window}function th(e){return!!e&&e instanceof tm(e).Element}function tg(e){return!!e&&e instanceof tm(e).HTMLElement}function tv(e,t){let n=["mouse","pen"];return t||n.push("",void 0),n.includes(e)}function ty(e){let n=(0,t.useRef)(e);return ti(()=>{n.current=e}),n}let tw="data-floating-ui-safe-polygon";function tb(e,t,n){return n&&!tv(n)?0:"number"==typeof e?e:null==e?void 0:e[t]}let tx=function(e,n){let{enabled:r=!0,delay:o=0,handleClose:i=null,mouseOnly:l=!1,restMs:u=0,move:a=!0}=void 0===n?{}:n,{open:c,onOpenChange:s,dataRef:f,events:d,elements:{domReference:p,floating:m},refs:h}=e,g=t.useContext(tf),v=td(),y=ty(i),w=ty(o),b=t.useRef(),x=t.useRef(),E=t.useRef(),R=t.useRef(),S=t.useRef(!0),T=t.useRef(!1),L=t.useRef(()=>{}),A=t.useCallback(()=>{var e;let t=null==(e=f.current.openEvent)?void 0:e.type;return(null==t?void 0:t.includes("mouse"))&&"mousedown"!==t},[f]);t.useEffect(()=>{if(r)return d.on("dismiss",e),()=>{d.off("dismiss",e)};function e(){clearTimeout(x.current),clearTimeout(R.current),S.current=!0}},[r,d]),t.useEffect(()=>{if(!r||!y.current||!c)return;function e(){A()&&s(!1)}let t=tp(m).documentElement;return t.addEventListener("mouseleave",e),()=>{t.removeEventListener("mouseleave",e)}},[m,c,s,r,y,f,A]);let C=t.useCallback(function(e){void 0===e&&(e=!0);let t=tb(w.current,"close",b.current);t&&!E.current?(clearTimeout(x.current),x.current=setTimeout(()=>s(!1),t)):e&&(clearTimeout(x.current),s(!1))},[w,s]),P=t.useCallback(()=>{L.current(),E.current=void 0},[]),O=t.useCallback(()=>{if(T.current){let e=tp(h.floating.current).body;e.style.pointerEvents="",e.removeAttribute(tw),T.current=!1}},[h]);return t.useEffect(()=>{if(r&&th(p))return c&&p.addEventListener("mouseleave",i),null==m||m.addEventListener("mouseleave",i),a&&p.addEventListener("mousemove",n,{once:!0}),p.addEventListener("mouseenter",n),p.addEventListener("mouseleave",o),()=>{c&&p.removeEventListener("mouseleave",i),null==m||m.removeEventListener("mouseleave",i),a&&p.removeEventListener("mousemove",n),p.removeEventListener("mouseenter",n),p.removeEventListener("mouseleave",o)};function t(){return!!f.current.openEvent&&["click","mousedown"].includes(f.current.openEvent.type)}function n(e){if(clearTimeout(x.current),S.current=!1,l&&!tv(b.current)||u>0&&0===tb(w.current,"open"))return;f.current.openEvent=e;let t=tb(w.current,"open",b.current);t?x.current=setTimeout(()=>{s(!0)},t):s(!0)}function o(n){if(t())return;L.current();let r=tp(m);if(clearTimeout(R.current),y.current){c||clearTimeout(x.current),E.current=y.current({...e,tree:g,x:n.clientX,y:n.clientY,onClose(){O(),P(),C()}});let t=E.current;r.addEventListener("mousemove",t),L.current=()=>{r.removeEventListener("mousemove",t)};return}C()}function i(n){t()||null==y.current||y.current({...e,tree:g,x:n.clientX,y:n.clientY,onClose(){O(),P(),C()}})(n)}},[p,m,r,e,l,u,a,C,P,O,s,c,g,w,y,f]),ti(()=>{var e,t,n;if(r&&c&&null!=(e=y.current)&&e.__options.blockPointerEvents&&A()){let e=tp(m).body;if(e.setAttribute(tw,""),e.style.pointerEvents="none",T.current=!0,th(p)&&m){let e=null==g||null==(t=g.nodesRef.current.find(e=>e.id===v))||null==(n=t.context)?void 0:n.elements.floating;return e&&(e.style.pointerEvents=""),p.style.pointerEvents="auto",m.style.pointerEvents="auto",()=>{p.style.pointerEvents="",m.style.pointerEvents=""}}}},[r,c,v,m,p,g,y,f,A]),ti(()=>{c||(b.current=void 0,P(),O())},[c,P,O]),t.useEffect(()=>()=>{P(),clearTimeout(x.current),clearTimeout(R.current),O()},[r,P,O]),t.useMemo(()=>{if(!r)return{};function e(e){b.current=e.pointerType}return{reference:{onPointerDown:e,onPointerEnter:e,onMouseMove(){c||0===u||(clearTimeout(R.current),R.current=setTimeout(()=>{S.current||s(!0)},u))}},floating:{onMouseEnter(){clearTimeout(x.current)},onMouseLeave(){d.emit("dismiss",{type:"mouseLeave",data:{returnFocus:!1}}),C(!1)}}}},[d,r,u,c,s,C])};function tE(e,t){if(!e||!t)return!1;let n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&function(e){if("u"{var n;return e.parentId===t&&(null==(n=e.context)?void 0:n.open)})||[],r=n;for(;r.length;)r=e.filter(e=>{var t;return null==(t=r)?void 0:t.some(t=>{var n;return e.parentId===t.id&&(null==(n=e.context)?void 0:n.open)})})||[],n=n.concat(r);return n}let tS=t["useInsertionEffect".toString()]||(e=>e());function tT(e){let n=t.useRef(()=>{});return tS(()=>{n.current=e}),t.useCallback(function(){for(var e=arguments.length,t=Array(e),r=0;r!1),E="function"==typeof p?x:p,R=t.useRef(!1),{escapeKeyBubbles:S,outsidePressBubbles:T}=tP(y);return t.useEffect(()=>{if(!r||!f)return;function e(e){if("Escape"===e.key){let e=w?tR(w.nodesRef.current,l):[];if(e.length>0){let t=!0;if(e.forEach(e=>{var n;if(null!=(n=e.context)&&n.open&&!e.context.dataRef.current.__escapeKeyBubbles){t=!1;return}}),!t)return}i.emit("dismiss",{type:"escapeKey",data:{returnFocus:{preventScroll:!1}}}),o(!1)}}function t(e){var t;let n=R.current;if(R.current=!1,n||"function"==typeof E&&!E(e))return;let r="composedPath"in e?e.composedPath()[0]:e.target;if(tg(r)&&c){let t=c.ownerDocument.defaultView||window,n=r.scrollWidth>r.clientWidth,o=r.scrollHeight>r.clientHeight,i=o&&e.offsetX>r.clientWidth;if(o&&"rtl"===t.getComputedStyle(r).direction&&(i=e.offsetX<=r.offsetWidth-r.clientWidth),i||n&&e.offsetY>r.clientHeight)return}let u=w&&tR(w.nodesRef.current,l).some(t=>{var n;return tL(e,null==(n=t.context)?void 0:n.elements.floating)});if(tL(e,c)||tL(e,a)||u)return;let s=w?tR(w.nodesRef.current,l):[];if(s.length>0){let e=!0;if(s.forEach(t=>{var n;if(null!=(n=t.context)&&n.open&&!t.context.dataRef.current.__outsidePressBubbles){e=!1;return}}),!e)return}i.emit("dismiss",{type:"outsidePress",data:{returnFocus:b?{preventScroll:!0}:function(e){let t,n;if(0===e.mozInputSource&&e.isTrusted)return!0;let r=/Android/i;return(r.test(null!=(n=navigator.userAgentData)&&n.platform?n.platform:navigator.platform)||r.test((t=navigator.userAgentData)&&Array.isArray(t.brands)?t.brands.map(e=>{let{brand:t,version:n}=e;return t+"/"+n}).join(" "):navigator.userAgent))&&e.pointerType?"click"===e.type&&1===e.buttons:0===e.detail&&!e.pointerType}(e)||0===(t=e).width&&0===t.height||1===t.width&&1===t.height&&0===t.pressure&&0===t.detail&&"mouse"!==t.pointerType||t.width<1&&t.height<1&&0===t.pressure&&0===t.detail}}),o(!1)}function n(){o(!1)}s.current.__escapeKeyBubbles=S,s.current.__outsidePressBubbles=T;let p=tp(c);d&&p.addEventListener("keydown",e),E&&p.addEventListener(m,t);let h=[];return v&&(th(a)&&(h=ee(a)),th(c)&&(h=h.concat(ee(c))),!th(u)&&u&&u.contextElement&&(h=h.concat(ee(u.contextElement)))),(h=h.filter(e=>{var t;return e!==(null==(t=p.defaultView)?void 0:t.visualViewport)})).forEach(e=>{e.addEventListener("scroll",n,{passive:!0})}),()=>{d&&p.removeEventListener("keydown",e),E&&p.removeEventListener(m,t),h.forEach(e=>{e.removeEventListener("scroll",n)})}},[s,c,a,u,d,E,m,i,w,l,r,o,v,f,S,T,b]),t.useEffect(()=>{R.current=!1},[E,m]),t.useMemo(()=>f?{reference:{[tA[g]]:()=>{h&&(i.emit("dismiss",{type:"referencePress",data:{returnFocus:!1}}),o(!1))}},floating:{[tC[m]]:()=>{R.current=!0}}}:{},[f,i,h,m,g,o])},tk=function(e,n){let{open:r,onOpenChange:o,dataRef:i,events:l,refs:u,elements:{floating:a,domReference:c}}=e,{enabled:s=!0,keyboardOnly:f=!0}=void 0===n?{}:n,d=t.useRef(""),p=t.useRef(!1),m=t.useRef();return t.useEffect(()=>{if(!s)return;let e=tp(a).defaultView||window;function t(){!r&&tg(c)&&c===function(e){let t=e.activeElement;for(;(null==(n=t)||null==(r=n.shadowRoot)?void 0:r.activeElement)!=null;){var n,r;t=t.shadowRoot.activeElement}return t}(tp(c))&&(p.current=!0)}return e.addEventListener("blur",t),()=>{e.removeEventListener("blur",t)}},[a,c,r,s]),t.useEffect(()=>{if(s)return l.on("dismiss",e),()=>{l.off("dismiss",e)};function e(e){("referencePress"===e.type||"escapeKey"===e.type)&&(p.current=!0)}},[l,s]),t.useEffect(()=>()=>{clearTimeout(m.current)},[]),t.useMemo(()=>s?{reference:{onPointerDown(e){let{pointerType:t}=e;d.current=t,p.current=!!(t&&f)},onMouseLeave(){p.current=!1},onFocus(e){var t;p.current||"focus"===e.type&&(null==(t=i.current.openEvent)?void 0:t.type)==="mousedown"&&i.current.openEvent&&tL(i.current.openEvent,c)||(i.current.openEvent=e.nativeEvent,o(!0))},onBlur(e){p.current=!1;let t=e.relatedTarget,n=th(t)&&t.hasAttribute("data-floating-ui-focus-guard")&&"outside"===t.getAttribute("data-type");m.current=setTimeout(()=>{tE(u.floating.current,t)||tE(c,t)||n||o(!1)})}}}:{},[s,f,c,u,i,o])},tD=function(e,n){let{open:r}=e,{enabled:o=!0,role:i="dialog"}=void 0===n?{}:n,l=tc(),u=tc();return t.useMemo(()=>{let e={id:l,role:i};return o?"tooltip"===i?{reference:{"aria-describedby":r?l:void 0},floating:e}:{reference:{"aria-expanded":r?"true":"false","aria-haspopup":"alertdialog"===i?"dialog":i,"aria-controls":r?l:void 0,..."listbox"===i&&{role:"combobox"},..."menu"===i&&{id:u}},floating:{...e,..."menu"===i&&{"aria-labelledby":u}}}:{}},[o,i,r,l,u])};function tM(e,t,n){let r=new Map;return{..."floating"===n&&{tabIndex:-1},...e,...t.map(e=>e?e[n]:null).concat(e).reduce((e,t)=>(t&&Object.entries(t).forEach(t=>{let[n,o]=t;if(0===n.indexOf("on")){if(r.has(n)||r.set(n,[]),"function"==typeof o){var i;null==(i=r.get(n))||i.push(o),e[n]=function(){for(var e,t=arguments.length,o=Array(t),i=0;ie(...o))}}}else e[n]=o}),e),{})}}let tN=function(e){void 0===e&&(e=[]);let n=e,r=t.useCallback(t=>tM(t,e,"reference"),n),o=t.useCallback(t=>tM(t,e,"floating"),n),i=t.useCallback(t=>tM(t,e,"item"),e.map(e=>null==e?void 0:e.item));return t.useMemo(()=>({getReferenceProps:r,getFloatingProps:o,getItemProps:i}),[r,o,i])};var tF=e.i(444755);let tI=e=>{let[n,r]=(0,t.useState)(!1),[o,i]=(0,t.useState)(),{x:l,y:u,refs:a,strategy:c,context:s}=function(e){void 0===e&&(e={});let{open:n=!1,onOpenChange:r,nodeId:o}=e,i=function(e){void 0===e&&(e={});let{placement:n="bottom",strategy:r="absolute",middleware:o=[],platform:i,whileElementsMounted:l,open:u}=e,[a,c]=t.useState({x:null,y:null,strategy:r,placement:n,middlewareData:{},isPositioned:!1}),[s,f]=t.useState(o);tr(s,o)||f(o);let d=t.useRef(null),p=t.useRef(null),m=t.useRef(a),h=to(l),g=to(i),[v,y]=t.useState(null),[w,b]=t.useState(null),x=t.useCallback(e=>{d.current!==e&&(d.current=e,y(e))},[]),E=t.useCallback(e=>{p.current!==e&&(p.current=e,b(e))},[]),R=t.useCallback(()=>{if(!d.current||!p.current)return;let e={placement:n,strategy:r,middleware:s};g.current&&(e.platform=g.current),tt(d.current,p.current,e).then(e=>{let t={...e,isPositioned:!0};S.current&&!tr(m.current,t)&&(m.current=t,C.flushSync(()=>{c(t)}))})},[s,n,r,g]);tn(()=>{!1===u&&m.current.isPositioned&&(m.current.isPositioned=!1,c(e=>({...e,isPositioned:!1})))},[u]);let S=t.useRef(!1);tn(()=>(S.current=!0,()=>{S.current=!1}),[]),tn(()=>{if(v&&w)if(h.current)return h.current(v,w,R);else R()},[v,w,R,h]);let T=t.useMemo(()=>({reference:d,floating:p,setReference:x,setFloating:E}),[x,E]),L=t.useMemo(()=>({reference:v,floating:w}),[v,w]);return t.useMemo(()=>({...a,update:R,refs:T,elements:L,reference:x,floating:E}),[a,R,T,L,x,E])}(e),l=t.useContext(tf),u=t.useRef(null),a=t.useRef({}),c=t.useState(()=>{let e;return e=new Map,{emit(t,n){var r;null==(r=e.get(t))||r.forEach(e=>e(n))},on(t,n){e.set(t,[...e.get(t)||[],n])},off(t,n){e.set(t,(e.get(t)||[]).filter(e=>e!==n))}}})[0],[s,f]=t.useState(null),d=t.useCallback(e=>{let t=th(e)?{getBoundingClientRect:()=>e.getBoundingClientRect(),contextElement:e}:e;i.refs.setReference(t)},[i.refs]),p=t.useCallback(e=>{(th(e)||null===e)&&(u.current=e,f(e)),(th(i.refs.reference.current)||null===i.refs.reference.current||null!==e&&!th(e))&&i.refs.setReference(e)},[i.refs]),m=t.useMemo(()=>({...i.refs,setReference:p,setPositionReference:d,domReference:u}),[i.refs,p,d]),h=t.useMemo(()=>({...i.elements,domReference:s}),[i.elements,s]),g=tT(r),v=t.useMemo(()=>({...i,refs:m,elements:h,dataRef:a,nodeId:o,events:c,open:n,onOpenChange:g}),[i,o,c,n,g,m,h]);return ti(()=>{let e=null==l?void 0:l.nodesRef.current.find(e=>e.id===o);e&&(e.context=v)}),t.useMemo(()=>({...i,context:v,refs:m,reference:p,positionReference:d}),[i,m,v,p,d])}({open:n,onOpenChange:t=>{t&&e?i(setTimeout(()=>{r(t)},e)):(clearTimeout(o),r(t))},placement:"top",whileElementsMounted:e1,middleware:[e2(5),e7({fallbackAxisSideDirection:"start"}),e5()]}),{getReferenceProps:f,getFloatingProps:d}=tN([tx(s,{move:!1}),tk(s),tO(s),tD(s,{role:"tooltip"})]);return{tooltipProps:{open:n,x:l,y:u,refs:a,strategy:c,getFloatingProps:d},getReferenceProps:f}},tB=({text:e,open:n,x:r,y:o,refs:i,strategy:l,getFloatingProps:u})=>n&&e?t.default.createElement("div",Object.assign({className:(0,tF.tremorTwMerge)("max-w-xs text-sm z-20 rounded-tremor-default opacity-100 px-2.5 py-1","text-white bg-tremor-background-emphasis","dark:text-tremor-content-emphasis dark:bg-white"),ref:i.setFloating,style:{position:l,top:null!=o?o:0,left:null!=r?r:0}},u()),e):null;tB.displayName="Tooltip",e.s(["default",()=>tB,"useTooltip",()=>tI],829087)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/018293fccad2eeda.js b/litellm/proxy/_experimental/out/_next/static/chunks/018293fccad2eeda.js new file mode 100644 index 00000000000..6ef0d01f2bd --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/018293fccad2eeda.js @@ -0,0 +1 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,482725,244451,e=>{"use strict";let t;e.i(247167);var n=e.i(271645),r=e.i(343794),i=e.i(242064),o=e.i(763731),s=e.i(174428);let a=80*Math.PI,l=e=>{let{dotClassName:t,style:i,hasCircleCls:o}=e;return n.createElement("circle",{className:(0,r.default)(`${t}-circle`,{[`${t}-circle-bg`]:o}),r:40,cx:50,cy:50,strokeWidth:20,style:i})},c=({percent:e,prefixCls:t})=>{let i=`${t}-dot`,o=`${i}-holder`,c=`${o}-hidden`,[u,d]=n.useState(!1);(0,s.default)(()=>{0!==e&&d(!0)},[0!==e]);let f=Math.max(Math.min(e,100),0);if(!u)return null;let h={strokeDashoffset:`${a/4}`,strokeDasharray:`${a*f/100} ${a*(100-f)/100}`};return n.createElement("span",{className:(0,r.default)(o,`${i}-progress`,f<=0&&c)},n.createElement("svg",{viewBox:"0 0 100 100",role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":f},n.createElement(l,{dotClassName:i,hasCircleCls:!0}),n.createElement(l,{dotClassName:i,style:h})))};function u(e){let{prefixCls:t,percent:i=0}=e,o=`${t}-dot`,s=`${o}-holder`,a=`${s}-hidden`;return n.createElement(n.Fragment,null,n.createElement("span",{className:(0,r.default)(s,i>0&&a)},n.createElement("span",{className:(0,r.default)(o,`${t}-dot-spin`)},[1,2,3,4].map(e=>n.createElement("i",{className:`${t}-dot-item`,key:e})))),n.createElement(c,{prefixCls:t,percent:i}))}function d(e){var t;let{prefixCls:i,indicator:s,percent:a}=e,l=`${i}-dot`;return s&&n.isValidElement(s)?(0,o.cloneElement)(s,{className:(0,r.default)(null==(t=s.props)?void 0:t.className,l),percent:a}):n.createElement(u,{prefixCls:i,percent:a})}e.i(296059);var f=e.i(694758),h=e.i(183293),m=e.i(246422),p=e.i(838378);let v=new f.Keyframes("antSpinMove",{to:{opacity:1}}),g=new f.Keyframes("antRotate",{to:{transform:"rotate(405deg)"}}),y=(0,m.genStyleHooks)("Spin",e=>(e=>{let{componentCls:t,calc:n}=e;return{[t]:Object.assign(Object.assign({},(0,h.resetComponent)(e)),{position:"absolute",display:"none",color:e.colorPrimary,fontSize:0,textAlign:"center",verticalAlign:"middle",opacity:0,transition:`transform ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`,"&-spinning":{position:"relative",display:"inline-block",opacity:1},[`${t}-text`]:{fontSize:e.fontSize,paddingTop:n(n(e.dotSize).sub(e.fontSize)).div(2).add(2).equal()},"&-fullscreen":{position:"fixed",width:"100vw",height:"100vh",backgroundColor:e.colorBgMask,zIndex:e.zIndexPopupBase,inset:0,display:"flex",alignItems:"center",flexDirection:"column",justifyContent:"center",opacity:0,visibility:"hidden",transition:`all ${e.motionDurationMid}`,"&-show":{opacity:1,visibility:"visible"},[t]:{[`${t}-dot-holder`]:{color:e.colorWhite},[`${t}-text`]:{color:e.colorTextLightSolid}}},"&-nested-loading":{position:"relative",[`> div > ${t}`]:{position:"absolute",top:0,insetInlineStart:0,zIndex:4,display:"block",width:"100%",height:"100%",maxHeight:e.contentHeight,[`${t}-dot`]:{position:"absolute",top:"50%",insetInlineStart:"50%",margin:n(e.dotSize).mul(-1).div(2).equal()},[`${t}-text`]:{position:"absolute",top:"50%",width:"100%",textShadow:`0 1px 2px ${e.colorBgContainer}`},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSize).div(2).mul(-1).sub(10).equal()},"&-sm":{[`${t}-dot`]:{margin:n(e.dotSizeSM).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeSM).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeSM).div(2).mul(-1).sub(10).equal()}},"&-lg":{[`${t}-dot`]:{margin:n(e.dotSizeLG).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeLG).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeLG).div(2).mul(-1).sub(10).equal()}}},[`${t}-container`]:{position:"relative",transition:`opacity ${e.motionDurationSlow}`,"&::after":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:10,width:"100%",height:"100%",background:e.colorBgContainer,opacity:0,transition:`all ${e.motionDurationSlow}`,content:'""',pointerEvents:"none"}},[`${t}-blur`]:{clear:"both",opacity:.5,userSelect:"none",pointerEvents:"none","&::after":{opacity:.4,pointerEvents:"auto"}}},"&-tip":{color:e.spinDotDefault},[`${t}-dot-holder`]:{width:"1em",height:"1em",fontSize:e.dotSize,display:"inline-block",transition:`transform ${e.motionDurationSlow} ease, opacity ${e.motionDurationSlow} ease`,transformOrigin:"50% 50%",lineHeight:1,color:e.colorPrimary,"&-hidden":{transform:"scale(0.3)",opacity:0}},[`${t}-dot-progress`]:{position:"absolute",inset:0},[`${t}-dot`]:{position:"relative",display:"inline-block",fontSize:e.dotSize,width:"1em",height:"1em","&-item":{position:"absolute",display:"block",width:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),height:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),background:"currentColor",borderRadius:"100%",transform:"scale(0.75)",transformOrigin:"50% 50%",opacity:.3,animationName:v,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear",animationDirection:"alternate","&:nth-child(1)":{top:0,insetInlineStart:0,animationDelay:"0s"},"&:nth-child(2)":{top:0,insetInlineEnd:0,animationDelay:"0.4s"},"&:nth-child(3)":{insetInlineEnd:0,bottom:0,animationDelay:"0.8s"},"&:nth-child(4)":{bottom:0,insetInlineStart:0,animationDelay:"1.2s"}},"&-spin":{transform:"rotate(45deg)",animationName:g,animationDuration:"1.2s",animationIterationCount:"infinite",animationTimingFunction:"linear"},"&-circle":{strokeLinecap:"round",transition:["stroke-dashoffset","stroke-dasharray","stroke","stroke-width","opacity"].map(t=>`${t} ${e.motionDurationSlow} ease`).join(","),fillOpacity:0,stroke:"currentcolor"},"&-circle-bg":{stroke:e.colorFillSecondary}},[`&-sm ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeSM}},[`&-sm ${t}-dot-holder`]:{i:{width:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal(),height:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal()}},[`&-lg ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeLG}},[`&-lg ${t}-dot-holder`]:{i:{width:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal(),height:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal()}},[`&${t}-show-text ${t}-text`]:{display:"block"}})}})((0,p.mergeToken)(e,{spinDotDefault:e.colorTextDescription})),e=>{let{controlHeightLG:t,controlHeight:n}=e;return{contentHeight:400,dotSize:t/2,dotSizeSM:.35*t,dotSizeLG:n}}),S=[[30,.05],[70,.03],[96,.01]];var b=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let $=e=>{var o;let{prefixCls:s,spinning:a=!0,delay:l=0,className:c,rootClassName:u,size:f="default",tip:h,wrapperClassName:m,style:p,children:v,fullscreen:g=!1,indicator:$,percent:_}=e,w=b(e,["prefixCls","spinning","delay","className","rootClassName","size","tip","wrapperClassName","style","children","fullscreen","indicator","percent"]),{getPrefixCls:O,direction:C,className:x,style:z,indicator:E}=(0,i.useComponentConfig)("spin"),M=O("spin",s),[j,D,T]=y(M),[k,N]=n.useState(()=>a&&(!a||!l||!!Number.isNaN(Number(l)))),R=function(e,t){let[r,i]=n.useState(0),o=n.useRef(null),s="auto"===t;return n.useEffect(()=>(s&&e&&(i(0),o.current=setInterval(()=>{i(e=>{let t=100-e;for(let n=0;n{o.current&&(clearInterval(o.current),o.current=null)}),[s,e]),s?r:t}(k,_);n.useEffect(()=>{if(a){let e=function(e,t,n){var r,i=n||{},o=i.noTrailing,s=void 0!==o&&o,a=i.noLeading,l=void 0!==a&&a,c=i.debounceMode,u=void 0===c?void 0:c,d=!1,f=0;function h(){r&&clearTimeout(r)}function m(){for(var n=arguments.length,i=Array(n),o=0;oe?l?(f=Date.now(),s||(r=setTimeout(u?p:m,e))):m():!0!==s&&(r=setTimeout(u?p:m,void 0===u?e-c:e)))}return m.cancel=function(e){var t=(e||{}).upcomingOnly;h(),d=!(void 0!==t&&t)},m}(l,()=>{N(!0)},{debounceMode:false});return e(),()=>{var t;null==(t=null==e?void 0:e.cancel)||t.call(e)}}N(!1)},[l,a]);let I=n.useMemo(()=>void 0!==v&&!g,[v,g]),A=(0,r.default)(M,x,{[`${M}-sm`]:"small"===f,[`${M}-lg`]:"large"===f,[`${M}-spinning`]:k,[`${M}-show-text`]:!!h,[`${M}-rtl`]:"rtl"===C},c,!g&&u,D,T),F=(0,r.default)(`${M}-container`,{[`${M}-blur`]:k}),P=null!=(o=null!=$?$:E)?o:t,H=Object.assign(Object.assign({},z),p),L=n.createElement("div",Object.assign({},w,{style:H,className:A,"aria-live":"polite","aria-busy":k}),n.createElement(d,{prefixCls:M,indicator:P,percent:R}),h&&(I||g)?n.createElement("div",{className:`${M}-text`},h):null);return j(I?n.createElement("div",Object.assign({},w,{className:(0,r.default)(`${M}-nested-loading`,m,D,T)}),k&&n.createElement("div",{key:"loading"},L),n.createElement("div",{className:F,key:"container"},v)):g?n.createElement("div",{className:(0,r.default)(`${M}-fullscreen`,{[`${M}-fullscreen-show`]:k},u,D,T)},L):L)};$.setDefaultIndicator=e=>{t=e},e.s(["default",0,$],244451),e.s(["Spin",0,$],482725)},597440,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"}}]},name:"delete",theme:"outlined"};var i=e.i(9583),o=n.forwardRef(function(e,o){return n.createElement(i.default,(0,t.default)({},e,{ref:o,icon:r}))});e.s(["default",0,o],597440)},955135,e=>{"use strict";var t=e.i(597440);e.s(["DeleteOutlined",()=>t.default])},689020,e=>{"use strict";var t=e.i(764205);let n=async e=>{try{let n=await (0,t.modelHubCall)(e);if(console.log("model_info:",n),n?.data.length>0){let e=n.data.map(e=>({model_group:e.model_group,mode:e?.mode}));return e.sort((e,t)=>e.model_group.localeCompare(t.model_group)),e}return[]}catch(e){throw console.error("Error fetching model info:",e),e}};e.s(["fetchAvailableModels",0,n])},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},751904,883552,e=>{"use strict";var t=e.i(401361);e.s(["EditOutlined",()=>t.default],751904),e.i(247167);var n=e.i(271645),r=e.i(562901),i=e.i(343794),o=e.i(914949),s=e.i(529681),a=e.i(242064),l=e.i(829672),c=e.i(285781),u=e.i(836938),d=e.i(920228),f=e.i(62405),h=e.i(408850),m=e.i(87414),p=e.i(310730);let v=(0,e.i(246422).genStyleHooks)("Popconfirm",e=>(e=>{let{componentCls:t,iconCls:n,antCls:r,zIndexPopup:i,colorText:o,colorWarning:s,marginXXS:a,marginXS:l,fontSize:c,fontWeightStrong:u,colorTextHeading:d}=e;return{[t]:{zIndex:i,[`&${r}-popover`]:{fontSize:c},[`${t}-message`]:{marginBottom:l,display:"flex",flexWrap:"nowrap",alignItems:"start",[`> ${t}-message-icon ${n}`]:{color:s,fontSize:c,lineHeight:1,marginInlineEnd:l},[`${t}-title`]:{fontWeight:u,color:d,"&:only-child":{fontWeight:"normal"}},[`${t}-description`]:{marginTop:a,color:o}},[`${t}-buttons`]:{textAlign:"end",whiteSpace:"nowrap",button:{marginInlineStart:l}}}}})(e),e=>{let{zIndexPopupBase:t}=e;return{zIndexPopup:t+60}},{resetStyle:!1});var g=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let y=e=>{let{prefixCls:t,okButtonProps:i,cancelButtonProps:o,title:s,description:l,cancelText:p,okText:v,okType:g="primary",icon:y=n.createElement(r.default,null),showCancel:S=!0,close:b,onConfirm:$,onCancel:_,onPopupClick:w}=e,{getPrefixCls:O}=n.useContext(a.ConfigContext),[C]=(0,h.useLocale)("Popconfirm",m.default.Popconfirm),x=(0,u.getRenderPropValue)(s),z=(0,u.getRenderPropValue)(l);return n.createElement("div",{className:`${t}-inner-content`,onClick:w},n.createElement("div",{className:`${t}-message`},y&&n.createElement("span",{className:`${t}-message-icon`},y),n.createElement("div",{className:`${t}-message-text`},x&&n.createElement("div",{className:`${t}-title`},x),z&&n.createElement("div",{className:`${t}-description`},z))),n.createElement("div",{className:`${t}-buttons`},S&&n.createElement(d.default,Object.assign({onClick:_,size:"small"},o),p||(null==C?void 0:C.cancelText)),n.createElement(c.default,{buttonProps:Object.assign(Object.assign({size:"small"},(0,f.convertLegacyProps)(g)),i),actionFn:$,close:b,prefixCls:O("btn"),quitOnNullishReturnValue:!0,emitEvent:!0},v||(null==C?void 0:C.okText))))};var S=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let b=n.forwardRef((e,t)=>{var c,u;let{prefixCls:d,placement:f="top",trigger:h="click",okType:m="primary",icon:p=n.createElement(r.default,null),children:g,overlayClassName:b,onOpenChange:$,onVisibleChange:_,overlayStyle:w,styles:O,classNames:C}=e,x=S(e,["prefixCls","placement","trigger","okType","icon","children","overlayClassName","onOpenChange","onVisibleChange","overlayStyle","styles","classNames"]),{getPrefixCls:z,className:E,style:M,classNames:j,styles:D}=(0,a.useComponentConfig)("popconfirm"),[T,k]=(0,o.default)(!1,{value:null!=(c=e.open)?c:e.visible,defaultValue:null!=(u=e.defaultOpen)?u:e.defaultVisible}),N=(e,t)=>{k(e,!0),null==_||_(e),null==$||$(e,t)},R=z("popconfirm",d),I=(0,i.default)(R,E,b,j.root,null==C?void 0:C.root),A=(0,i.default)(j.body,null==C?void 0:C.body),[F]=v(R);return F(n.createElement(l.default,Object.assign({},(0,s.default)(x,["title"]),{trigger:h,placement:f,onOpenChange:(t,n)=>{let{disabled:r=!1}=e;r||N(t,n)},open:T,ref:t,classNames:{root:I,body:A},styles:{root:Object.assign(Object.assign(Object.assign(Object.assign({},D.root),M),w),null==O?void 0:O.root),body:Object.assign(Object.assign({},D.body),null==O?void 0:O.body)},content:n.createElement(y,Object.assign({okType:m,icon:p},e,{prefixCls:R,close:e=>{N(!1,e)},onConfirm:t=>{var n;return null==(n=e.onConfirm)?void 0:n.call(void 0,t)},onCancel:t=>{var n;N(!1,t),null==(n=e.onCancel)||n.call(void 0,t)}})),"data-popover-inject":!0}),g))});b._InternalPanelDoNotUseOrYouWillBeFired=e=>{let{prefixCls:t,placement:r,className:o,style:s}=e,l=g(e,["prefixCls","placement","className","style"]),{getPrefixCls:c}=n.useContext(a.ConfigContext),u=c("popconfirm",t),[d]=v(u);return d(n.createElement(p.default,{placement:r,className:(0,i.default)(u,o),style:s,content:n.createElement(y,Object.assign({prefixCls:u},l))}))},e.s(["Popconfirm",0,b],883552)},822315,(e,t,n)=>{e.e,t.exports=function(){"use strict";var e="millisecond",t="second",n="minute",r="hour",i="week",o="month",s="quarter",a="year",l="date",c="Invalid Date",u=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,d=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,f=function(e,t,n){var r=String(e);return!r||r.length>=t?e:""+Array(t+1-r.length).join(n)+e},h="en",m={};m[h]={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(e){var t=["th","st","nd","rd"],n=e%100;return"["+e+(t[(n-20)%10]||t[n]||t[0])+"]"}};var p="$isDayjsObject",v=function(e){return e instanceof b||!(!e||!e[p])},g=function e(t,n,r){var i;if(!t)return h;if("string"==typeof t){var o=t.toLowerCase();m[o]&&(i=o),n&&(m[o]=n,i=o);var s=t.split("-");if(!i&&s.length>1)return e(s[0])}else{var a=t.name;m[a]=t,i=a}return!r&&i&&(h=i),i||!r&&h},y=function(e,t){if(v(e))return e.clone();var n="object"==typeof t?t:{};return n.date=e,n.args=arguments,new b(n)},S={s:f,z:function(e){var t=-e.utcOffset(),n=Math.abs(t);return(t<=0?"+":"-")+f(Math.floor(n/60),2,"0")+":"+f(n%60,2,"0")},m:function e(t,n){if(t.date(){"use strict";var t=e.i(959013);e.s(["PlusOutlined",()=>t.default])},313603,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"}}]},name:"setting",theme:"outlined"};var i=e.i(9583),o=n.forwardRef(function(e,o){return n.createElement(i.default,(0,t.default)({},e,{ref:o,icon:r}))});e.s(["SettingOutlined",0,o],313603)},362024,e=>{"use strict";var t=e.i(988122);e.s(["Collapse",()=>t.default])},240647,e=>{"use strict";var t=e.i(286612);e.s(["RightOutlined",()=>t.default])},516015,(e,t,n)=>{},898547,(e,t,n)=>{var r=e.i(247167);e.r(516015);var i=e.r(271645),o=i&&"object"==typeof i&&"default"in i?i:{default:i},s=void 0!==r.default&&r.default.env&&!0,a=function(e){return"[object String]"===Object.prototype.toString.call(e)},l=function(){function e(e){var t=void 0===e?{}:e,n=t.name,r=void 0===n?"stylesheet":n,i=t.optimizeForSpeed,o=void 0===i?s:i;c(a(r),"`name` must be a string"),this._name=r,this._deletedRulePlaceholder="#"+r+"-deleted-rule____{}",c("boolean"==typeof o,"`optimizeForSpeed` must be a boolean"),this._optimizeForSpeed=o,this._serverSheet=void 0,this._tags=[],this._injected=!1,this._rulesCount=0;var l="u">typeof window&&document.querySelector('meta[property="csp-nonce"]');this._nonce=l?l.getAttribute("content"):null}var t,n=e.prototype;return n.setOptimizeForSpeed=function(e){c("boolean"==typeof e,"`setOptimizeForSpeed` accepts a boolean"),c(0===this._rulesCount,"optimizeForSpeed cannot be when rules have already been inserted"),this.flush(),this._optimizeForSpeed=e,this.inject()},n.isOptimizeForSpeed=function(){return this._optimizeForSpeed},n.inject=function(){var e=this;if(c(!this._injected,"sheet already injected"),this._injected=!0,"u">typeof window&&this._optimizeForSpeed){this._tags[0]=this.makeStyleTag(this._name),this._optimizeForSpeed="insertRule"in this.getSheet(),this._optimizeForSpeed||(s||console.warn("StyleSheet: optimizeForSpeed mode not supported falling back to standard mode."),this.flush(),this._injected=!0);return}this._serverSheet={cssRules:[],insertRule:function(t,n){return"number"==typeof n?e._serverSheet.cssRules[n]={cssText:t}:e._serverSheet.cssRules.push({cssText:t}),n},deleteRule:function(t){e._serverSheet.cssRules[t]=null}}},n.getSheetForTag=function(e){if(e.sheet)return e.sheet;for(var t=0;ttypeof window?this.getSheet():this._serverSheet;if(t.trim()||(t=this._deletedRulePlaceholder),!n.cssRules[e])return e;n.deleteRule(e);try{n.insertRule(t,e)}catch(r){s||console.warn("StyleSheet: illegal rule: \n\n"+t+"\n\nSee https://stackoverflow.com/q/20007992 for more info"),n.insertRule(this._deletedRulePlaceholder,e)}}else{var r=this._tags[e];c(r,"old rule at index `"+e+"` not found"),r.textContent=t}return e},n.deleteRule=function(e){if("u"typeof window?(this._tags.forEach(function(e){return e&&e.parentNode.removeChild(e)}),this._tags=[]):this._serverSheet.cssRules=[]},n.cssRules=function(){var e=this;return"u">>0},d={};function f(e,t){if(!t)return"jsx-"+e;var n=String(t),r=e+n;return d[r]||(d[r]="jsx-"+u(e+"-"+n)),d[r]}function h(e,t){"u"typeof window&&!this._fromServer&&(this._fromServer=this.selectFromServer(),this._instancesCounts=Object.keys(this._fromServer).reduce(function(e,t){return e[t]=0,e},{}));var n=this.getIdAndRules(e),r=n.styleId,i=n.rules;if(r in this._instancesCounts){this._instancesCounts[r]+=1;return}var o=i.map(function(e){return t._sheet.insertRule(e)}).filter(function(e){return -1!==e});this._indices[r]=o,this._instancesCounts[r]=1},t.remove=function(e){var t=this,n=this.getIdAndRules(e).styleId;if(function(e,t){if(!e)throw Error("StyleSheetRegistry: "+t+".")}(n in this._instancesCounts,"styleId: `"+n+"` not found"),this._instancesCounts[n]-=1,this._instancesCounts[n]<1){var r=this._fromServer&&this._fromServer[n];r?(r.parentNode.removeChild(r),delete this._fromServer[n]):(this._indices[n].forEach(function(e){return t._sheet.deleteRule(e)}),delete this._indices[n]),delete this._instancesCounts[n]}},t.update=function(e,t){this.add(t),this.remove(e)},t.flush=function(){this._sheet.flush(),this._sheet.inject(),this._fromServer=void 0,this._indices={},this._instancesCounts={}},t.cssRules=function(){var e=this,t=this._fromServer?Object.keys(this._fromServer).map(function(t){return[t,e._fromServer[t]]}):[],n=this._sheet.cssRules();return t.concat(Object.keys(this._indices).map(function(t){return[t,e._indices[t].map(function(e){return n[e].cssText}).join(e._optimizeForSpeed?"":"\n")]}).filter(function(e){return!!e[1]}))},t.styles=function(e){var t,n;return t=this.cssRules(),void 0===(n=e)&&(n={}),t.map(function(e){var t=e[0],r=e[1];return o.default.createElement("style",{id:"__"+t,key:"__"+t,nonce:n.nonce?n.nonce:void 0,dangerouslySetInnerHTML:{__html:r}})})},t.getIdAndRules=function(e){var t=e.children,n=e.dynamic,r=e.id;if(n){var i=f(r,n);return{styleId:i,rules:Array.isArray(t)?t.map(function(e){return h(i,e)}):[h(i,t)]}}return{styleId:f(r),rules:Array.isArray(t)?t:[t]}},t.selectFromServer=function(){return Array.prototype.slice.call(document.querySelectorAll('[id^="__jsx-"]')).reduce(function(e,t){return e[t.id.slice(2)]=t,e},{})},e}(),p=i.createContext(null);function v(){return new m}function g(){return i.useContext(p)}p.displayName="StyleSheetContext";var y=o.default.useInsertionEffect||o.default.useLayoutEffect,S="u">typeof window?v():void 0;function b(e){var t=S||g();return t&&("u"{t.exports=e.r(898547).style},434166,e=>{"use strict";function t(e,t){window.sessionStorage.setItem(e,btoa(encodeURIComponent(t).replace(/%([0-9A-F]{2})/g,(e,t)=>String.fromCharCode(parseInt(t,16)))))}function n(e){try{let t=window.sessionStorage.getItem(e);if(null===t)return null;return decodeURIComponent(atob(t).split("").map(e=>"%"+e.charCodeAt(0).toString(16).padStart(2,"0")).join(""))}catch{return null}}e.s(["getSecureItem",()=>n,"setSecureItem",()=>t])},438957,366308,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M608 112c-167.9 0-304 136.1-304 304 0 70.3 23.9 135 63.9 186.5l-41.1 41.1-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-44.9 44.9-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-65.3 65.3a8.03 8.03 0 000 11.3l42.3 42.3c3.1 3.1 8.2 3.1 11.3 0l253.6-253.6A304.06 304.06 0 00608 720c167.9 0 304-136.1 304-304S775.9 112 608 112zm161.2 465.2C726.2 620.3 668.9 644 608 644c-60.9 0-118.2-23.7-161.2-66.8-43.1-43-66.8-100.3-66.8-161.2 0-60.9 23.7-118.2 66.8-161.2 43-43.1 100.3-66.8 161.2-66.8 60.9 0 118.2 23.7 161.2 66.8 43.1 43 66.8 100.3 66.8 161.2 0 60.9-23.7 118.2-66.8 161.2z"}}]},name:"key",theme:"outlined"};var i=e.i(9583),o=n.forwardRef(function(e,o){return n.createElement(i.default,(0,t.default)({},e,{ref:o,icon:r}))});e.s(["KeyOutlined",0,o],438957);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M876.6 239.5c-.5-.9-1.2-1.8-2-2.5-5-5-13.1-5-18.1 0L684.2 409.3l-67.9-67.9L788.7 169c.8-.8 1.4-1.6 2-2.5 3.6-6.1 1.6-13.9-4.5-17.5-98.2-58-226.8-44.7-311.3 39.7-67 67-89.2 162-66.5 247.4l-293 293c-3 3-2.8 7.9.3 11l169.7 169.7c3.1 3.1 8.1 3.3 11 .3l292.9-292.9c85.5 22.8 180.5.7 247.6-66.4 84.4-84.5 97.7-213.1 39.7-311.3zM786 499.8c-58.1 58.1-145.3 69.3-214.6 33.6l-8.8 8.8-.1-.1-274 274.1-79.2-79.2 230.1-230.1s0 .1.1.1l52.8-52.8c-35.7-69.3-24.5-156.5 33.6-214.6a184.2 184.2 0 01144-53.5L537 318.9a32.05 32.05 0 000 45.3l124.5 124.5a32.05 32.05 0 0045.3 0l132.8-132.8c3.7 51.8-14.4 104.8-53.6 143.9z"}}]},name:"tool",theme:"outlined"};var a=n.forwardRef(function(e,r){return n.createElement(i.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["ToolOutlined",0,a],366308)},477189,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"};var i=e.i(9583),o=n.forwardRef(function(e,o){return n.createElement(i.default,(0,t.default)({},e,{ref:o,icon:r}))});e.s(["AppstoreOutlined",0,o],477189)},264843,292335,122520,165615,779129,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 512a48 48 0 1096 0 48 48 0 10-96 0zm200 0a48 48 0 1096 0 48 48 0 10-96 0zm-400 0a48 48 0 1096 0 48 48 0 10-96 0zm661.2-173.6c-22.6-53.7-55-101.9-96.3-143.3a444.35 444.35 0 00-143.3-96.3C630.6 75.7 572.2 64 512 64h-2c-60.6.3-119.3 12.3-174.5 35.9a445.35 445.35 0 00-142 96.5c-40.9 41.3-73 89.3-95.2 142.8-23 55.4-34.6 114.3-34.3 174.9A449.4 449.4 0 00112 714v152a46 46 0 0046 46h152.1A449.4 449.4 0 00510 960h2.1c59.9 0 118-11.6 172.7-34.3a444.48 444.48 0 00142.8-95.2c41.3-40.9 73.8-88.7 96.5-142 23.6-55.2 35.6-113.9 35.9-174.5.3-60.9-11.5-120-34.8-175.6zm-151.1 438C704 845.8 611 884 512 884h-1.7c-60.3-.3-120.2-15.3-173.1-43.5l-8.4-4.5H188V695.2l-4.5-8.4C155.3 633.9 140.3 574 140 513.7c-.4-99.7 37.7-193.3 107.6-263.8 69.8-70.5 163.1-109.5 262.8-109.9h1.7c50 0 98.5 9.7 144.2 28.9 44.6 18.7 84.6 45.6 119 80 34.3 34.3 61.3 74.4 80 119 19.4 46.2 29.1 95.2 28.9 145.8-.6 99.6-39.7 192.9-110.1 262.7z"}}]},name:"message",theme:"outlined"};var i=e.i(9583),o=n.forwardRef(function(e,o){return n.createElement(i.default,(0,t.default)({},e,{ref:o,icon:r}))});e.s(["MessageOutlined",0,o],264843);let s={NONE:"none",API_KEY:"api_key",BEARER_TOKEN:"bearer_token",TOKEN:"token",BASIC:"basic",OAUTH2:"oauth2",AWS_SIGV4:"aws_sigv4"},a={SSE:"sse",HTTP:"http",STDIO:"stdio",OPENAPI:"openapi"};function l(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){let t=e.detail;return"string"==typeof t?t:Array.isArray(t)?t.map(e=>e&&"object"==typeof e?"string"==typeof e.msg?e.msg:JSON.stringify(e):String(e)).join("; "):t&&"object"==typeof t&&"string"==typeof t.error?t.error:"string"==typeof e.message?e.message:JSON.stringify(e)}return String(e)}e.s(["AUTH_TYPE",0,s,"OAUTH_FLOW",0,{INTERACTIVE:"interactive",M2M:"m2m"},"TRANSPORT",0,a,"handleAuth",0,e=>null==e?s.NONE:e,"handleTransport",0,(e,t)=>null==e?a.SSE:t&&e!==a.STDIO?a.OPENAPI:e],292335),e.s(["extractErrorMessage",()=>l],122520);let c=e=>{let t=new Uint8Array(e),n="";return t.forEach(e=>n+=String.fromCharCode(e)),btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},u=async e=>{let t=new TextEncoder().encode(e);return c(await window.crypto.subtle.digest("SHA-256",t))};e.s(["generateCodeChallenge",0,u,"generateCodeVerifier",0,()=>{let e=new Uint8Array(32);return window.crypto.getRandomValues(e),c(e.buffer)}],165615),e.i(764205),e.s(["buildCallbackUrl",0,()=>{{let e=window.location.pathname||"",t=e.indexOf("/ui"),n=t>=0?e.slice(0,t+3).replace(/\/+$/,""):"";return`${window.location.origin}${n}/mcp/oauth/callback`}},"clearStorage",0,(...e)=>{e.forEach(e=>{try{window.sessionStorage.removeItem(e)}catch(e){}})}],779129)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/01a2d4575f32b1b4.js b/litellm/proxy/_experimental/out/_next/static/chunks/01a2d4575f32b1b4.js new file mode 100644 index 00000000000..1a3f4b3b3c9 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/01a2d4575f32b1b4.js @@ -0,0 +1,8 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,282786,836938,310730,829672,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),i=e.i(914949),n=e.i(404948);let s=e=>e?"function"==typeof e?e():e:null;e.s(["getRenderPropValue",0,s],836938);var a=e.i(613541),l=e.i(763731),o=e.i(242064),u=e.i(491816);e.i(793154);var c=e.i(880476),d=e.i(183293),h=e.i(717356),p=e.i(320560),f=e.i(307358),g=e.i(246422),m=e.i(838378),b=e.i(617933);let y=(0,g.genStyleHooks)("Popover",e=>{let{colorBgElevated:t,colorText:r}=e,i=(0,m.mergeToken)(e,{popoverBg:t,popoverColor:r});return[(e=>{let{componentCls:t,popoverColor:r,titleMinWidth:i,fontWeightStrong:n,innerPadding:s,boxShadowSecondary:a,colorTextHeading:l,borderRadiusLG:o,zIndexPopup:u,titleMarginBottom:c,colorBgElevated:h,popoverBg:f,titleBorderBottom:g,innerContentPadding:m,titlePadding:b}=e;return[{[t]:Object.assign(Object.assign({},(0,d.resetComponent)(e)),{position:"absolute",top:0,left:{_skip_check_:!0,value:0},zIndex:u,fontWeight:"normal",whiteSpace:"normal",textAlign:"start",cursor:"auto",userSelect:"text","--valid-offset-x":"var(--arrow-offset-horizontal, var(--arrow-x))",transformOrigin:"var(--valid-offset-x, 50%) var(--arrow-y, 50%)","--antd-arrow-background-color":h,width:"max-content",maxWidth:"100vw","&-rtl":{direction:"rtl"},"&-hidden":{display:"none"},[`${t}-content`]:{position:"relative"},[`${t}-inner`]:{backgroundColor:f,backgroundClip:"padding-box",borderRadius:o,boxShadow:a,padding:s},[`${t}-title`]:{minWidth:i,marginBottom:c,color:l,fontWeight:n,borderBottom:g,padding:b},[`${t}-inner-content`]:{color:r,padding:m}})},(0,p.default)(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow,display:"inline-block",[`${t}-content`]:{display:"inline-block"}}}]})(i),(e=>{let{componentCls:t}=e;return{[t]:b.PresetColors.map(r=>{let i=e[`${r}6`];return{[`&${t}-${r}`]:{"--antd-arrow-background-color":i,[`${t}-inner`]:{backgroundColor:i},[`${t}-arrow`]:{background:"transparent"}}}})}})(i),(0,h.initZoomMotion)(i,"zoom-big")]},e=>{let{lineWidth:t,controlHeight:r,fontHeight:i,padding:n,wireframe:s,zIndexPopupBase:a,borderRadiusLG:l,marginXS:o,lineType:u,colorSplit:c,paddingSM:d}=e,h=r-i;return Object.assign(Object.assign(Object.assign({titleMinWidth:177,zIndexPopup:a+30},(0,f.getArrowToken)(e)),(0,p.getArrowOffsetToken)({contentRadius:l,limitVerticalRadius:!0})),{innerPadding:12*!s,titleMarginBottom:s?0:o,titlePadding:s?`${h/2}px ${n}px ${h/2-t}px`:0,titleBorderBottom:s?`${t}px ${u} ${c}`:"none",innerContentPadding:s?`${d}px ${n}px`:0})},{resetStyle:!1,deprecatedTokens:[["width","titleMinWidth"],["minWidth","titleMinWidth"]]});var v=function(e,t){var r={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&0>t.indexOf(i)&&(r[i]=e[i]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,i=Object.getOwnPropertySymbols(e);nt.indexOf(i[n])&&Object.prototype.propertyIsEnumerable.call(e,i[n])&&(r[i[n]]=e[i[n]]);return r};let O=({title:e,content:r,prefixCls:i})=>e||r?t.createElement(t.Fragment,null,e&&t.createElement("div",{className:`${i}-title`},e),r&&t.createElement("div",{className:`${i}-inner-content`},r)):null,$=e=>{let{hashId:i,prefixCls:n,className:a,style:l,placement:o="top",title:u,content:d,children:h}=e,p=s(u),f=s(d),g=(0,r.default)(i,n,`${n}-pure`,`${n}-placement-${o}`,a);return t.createElement("div",{className:g,style:l},t.createElement("div",{className:`${n}-arrow`}),t.createElement(c.Popup,Object.assign({},e,{className:i,prefixCls:n}),h||t.createElement(O,{prefixCls:n,title:p,content:f})))},R=e=>{let{prefixCls:i,className:n}=e,s=v(e,["prefixCls","className"]),{getPrefixCls:a}=t.useContext(o.ConfigContext),l=a("popover",i),[u,c,d]=y(l);return u(t.createElement($,Object.assign({},s,{prefixCls:l,hashId:c,className:(0,r.default)(n,d)})))};e.s(["Overlay",0,O,"default",0,R],310730);var C=function(e,t){var r={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&0>t.indexOf(i)&&(r[i]=e[i]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,i=Object.getOwnPropertySymbols(e);nt.indexOf(i[n])&&Object.prototype.propertyIsEnumerable.call(e,i[n])&&(r[i[n]]=e[i[n]]);return r};let w=t.forwardRef((e,c)=>{var d,h;let{prefixCls:p,title:f,content:g,overlayClassName:m,placement:b="top",trigger:v="hover",children:$,mouseEnterDelay:R=.1,mouseLeaveDelay:w=.1,onOpenChange:x,overlayStyle:E={},styles:k,classNames:j}=e,S=C(e,["prefixCls","title","content","overlayClassName","placement","trigger","children","mouseEnterDelay","mouseLeaveDelay","onOpenChange","overlayStyle","styles","classNames"]),{getPrefixCls:I,className:T,style:Q,classNames:q,styles:U}=(0,o.useComponentConfig)("popover"),P=I("popover",p),[N,M,D]=y(P),F=I(),W=(0,r.default)(m,M,D,T,q.root,null==j?void 0:j.root),L=(0,r.default)(q.body,null==j?void 0:j.body),[A,B]=(0,i.default)(!1,{value:null!=(d=e.open)?d:e.visible,defaultValue:null!=(h=e.defaultOpen)?h:e.defaultVisible}),z=(e,t)=>{B(e,!0),null==x||x(e,t)},_=s(f),H=s(g);return N(t.createElement(u.default,Object.assign({placement:b,trigger:v,mouseEnterDelay:R,mouseLeaveDelay:w},S,{prefixCls:P,classNames:{root:W,body:L},styles:{root:Object.assign(Object.assign(Object.assign(Object.assign({},U.root),Q),E),null==k?void 0:k.root),body:Object.assign(Object.assign({},U.body),null==k?void 0:k.body)},ref:c,open:A,onOpenChange:e=>{z(e)},overlay:_||H?t.createElement(O,{prefixCls:P,title:_,content:H}):null,transitionName:(0,a.getTransitionName)(F,"zoom-big",S.transitionName),"data-popover-inject":!0}),(0,l.cloneElement)($,{onKeyDown:e=>{var r,i;(0,t.isValidElement)($)&&(null==(i=null==$?void 0:(r=$.props).onKeyDown)||i.call(r,e)),e.keyCode===n.default.ESC&&z(!1,e)}})))});w._InternalPanelDoNotUseOrYouWillBeFired=R,e.s(["default",0,w],829672),e.s(["Popover",0,w],282786)},618566,(e,t,r)=>{t.exports=e.r(976562)},612256,869230,469637,266027,243652,e=>{"use strict";let t;var r=e.i(764205),i=e.i(175555),n=e.i(540143),s=e.i(286491),a=e.i(915823),l=e.i(793803),o=e.i(619273),u=e.i(180166),c=class extends a.Subscribable{constructor(e,t){super(),this.options=t,this.#e=e,this.#t=null,this.#r=(0,l.pendingThenable)(),this.bindMethods(),this.setOptions(t)}#e;#i=void 0;#n=void 0;#s=void 0;#a;#l;#r;#t;#o;#u;#c;#d;#h;#p;#f=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){1===this.listeners.size&&(this.#i.addObserver(this),d(this.#i,this.options)?this.#g():this.updateResult(),this.#m())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return h(this.#i,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return h(this.#i,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#b(),this.#y(),this.#i.removeObserver(this)}setOptions(e){let t=this.options,r=this.#i;if(this.options=this.#e.defaultQueryOptions(e),void 0!==this.options.enabled&&"boolean"!=typeof this.options.enabled&&"function"!=typeof this.options.enabled&&"boolean"!=typeof(0,o.resolveEnabled)(this.options.enabled,this.#i))throw Error("Expected enabled to be a boolean or a callback that returns a boolean");this.#v(),this.#i.setOptions(this.options),t._defaulted&&!(0,o.shallowEqualObjects)(this.options,t)&&this.#e.getQueryCache().notify({type:"observerOptionsUpdated",query:this.#i,observer:this});let i=this.hasListeners();i&&p(this.#i,r,this.options,t)&&this.#g(),this.updateResult(),i&&(this.#i!==r||(0,o.resolveEnabled)(this.options.enabled,this.#i)!==(0,o.resolveEnabled)(t.enabled,this.#i)||(0,o.resolveStaleTime)(this.options.staleTime,this.#i)!==(0,o.resolveStaleTime)(t.staleTime,this.#i))&&this.#O();let n=this.#$();i&&(this.#i!==r||(0,o.resolveEnabled)(this.options.enabled,this.#i)!==(0,o.resolveEnabled)(t.enabled,this.#i)||n!==this.#p)&&this.#R(n)}getOptimisticResult(e){var t,r;let i=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(i,e);return t=this,r=n,(0,o.shallowEqualObjects)(t.getCurrentResult(),r)||(this.#s=n,this.#l=this.options,this.#a=this.#i.state),n}getCurrentResult(){return this.#s}trackResult(e,t){return new Proxy(e,{get:(e,r)=>(this.trackProp(r),t?.(r),"promise"===r&&(this.trackProp("data"),this.options.experimental_prefetchInRender||"pending"!==this.#r.status||this.#r.reject(Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(e,r))})}trackProp(e){this.#f.add(e)}getCurrentQuery(){return this.#i}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),r=this.#e.getQueryCache().build(this.#e,t);return r.fetch().then(()=>this.createResult(r,t))}fetch(e){return this.#g({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#s))}#g(e){this.#v();let t=this.#i.fetch(this.options,e);return e?.throwOnError||(t=t.catch(o.noop)),t}#O(){this.#b();let e=(0,o.resolveStaleTime)(this.options.staleTime,this.#i);if(o.isServer||this.#s.isStale||!(0,o.isValidTimeout)(e))return;let t=(0,o.timeUntilStale)(this.#s.dataUpdatedAt,e);this.#d=u.timeoutManager.setTimeout(()=>{this.#s.isStale||this.updateResult()},t+1)}#$(){return("function"==typeof this.options.refetchInterval?this.options.refetchInterval(this.#i):this.options.refetchInterval)??!1}#R(e){this.#y(),this.#p=e,!o.isServer&&!1!==(0,o.resolveEnabled)(this.options.enabled,this.#i)&&(0,o.isValidTimeout)(this.#p)&&0!==this.#p&&(this.#h=u.timeoutManager.setInterval(()=>{(this.options.refetchIntervalInBackground||i.focusManager.isFocused())&&this.#g()},this.#p))}#m(){this.#O(),this.#R(this.#$())}#b(){this.#d&&(u.timeoutManager.clearTimeout(this.#d),this.#d=void 0)}#y(){this.#h&&(u.timeoutManager.clearInterval(this.#h),this.#h=void 0)}createResult(e,t){let r,i=this.#i,n=this.options,a=this.#s,u=this.#a,c=this.#l,h=e!==i?e.state:this.#n,{state:g}=e,m={...g},b=!1;if(t._optimisticResults){let r=this.hasListeners(),a=!r&&d(e,t),l=r&&p(e,i,t,n);(a||l)&&(m={...m,...(0,s.fetchState)(g.data,e.options)}),"isRestoring"===t._optimisticResults&&(m.fetchStatus="idle")}let{error:y,errorUpdatedAt:v,status:O}=m;r=m.data;let $=!1;if(void 0!==t.placeholderData&&void 0===r&&"pending"===O){let e;a?.isPlaceholderData&&t.placeholderData===c?.placeholderData?(e=a.data,$=!0):e="function"==typeof t.placeholderData?t.placeholderData(this.#c?.state.data,this.#c):t.placeholderData,void 0!==e&&(O="success",r=(0,o.replaceData)(a?.data,e,t),b=!0)}if(t.select&&void 0!==r&&!$)if(a&&r===u?.data&&t.select===this.#o)r=this.#u;else try{this.#o=t.select,r=t.select(r),r=(0,o.replaceData)(a?.data,r,t),this.#u=r,this.#t=null}catch(e){this.#t=e}this.#t&&(y=this.#t,r=this.#u,v=Date.now(),O="error");let R="fetching"===m.fetchStatus,C="pending"===O,w="error"===O,x=C&&R,E=void 0!==r,k={status:O,fetchStatus:m.fetchStatus,isPending:C,isSuccess:"success"===O,isError:w,isInitialLoading:x,isLoading:x,data:r,dataUpdatedAt:m.dataUpdatedAt,error:y,errorUpdatedAt:v,failureCount:m.fetchFailureCount,failureReason:m.fetchFailureReason,errorUpdateCount:m.errorUpdateCount,isFetched:m.dataUpdateCount>0||m.errorUpdateCount>0,isFetchedAfterMount:m.dataUpdateCount>h.dataUpdateCount||m.errorUpdateCount>h.errorUpdateCount,isFetching:R,isRefetching:R&&!C,isLoadingError:w&&!E,isPaused:"paused"===m.fetchStatus,isPlaceholderData:b,isRefetchError:w&&E,isStale:f(e,t),refetch:this.refetch,promise:this.#r,isEnabled:!1!==(0,o.resolveEnabled)(t.enabled,e)};if(this.options.experimental_prefetchInRender){let t=void 0!==k.data,r="error"===k.status&&!t,n=e=>{r?e.reject(k.error):t&&e.resolve(k.data)},s=()=>{n(this.#r=k.promise=(0,l.pendingThenable)())},a=this.#r;switch(a.status){case"pending":e.queryHash===i.queryHash&&n(a);break;case"fulfilled":(r||k.data!==a.value)&&s();break;case"rejected":r&&k.error===a.reason||s()}}return k}updateResult(){let e=this.#s,t=this.createResult(this.#i,this.options);if(this.#a=this.#i.state,this.#l=this.options,void 0!==this.#a.data&&(this.#c=this.#i),(0,o.shallowEqualObjects)(t,e))return;this.#s=t;let r=()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,r="function"==typeof t?t():t;if("all"===r||!r&&!this.#f.size)return!0;let i=new Set(r??this.#f);return this.options.throwOnError&&i.add("error"),Object.keys(this.#s).some(t=>this.#s[t]!==e[t]&&i.has(t))};this.#C({listeners:r()})}#v(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#i)return;let t=this.#i;this.#i=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#m()}#C(e){n.notifyManager.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#s)}),this.#e.getQueryCache().notify({query:this.#i,type:"observerResultsUpdated"})})}};function d(e,t){return!1!==(0,o.resolveEnabled)(t.enabled,e)&&void 0===e.state.data&&("error"!==e.state.status||!1!==t.retryOnMount)||void 0!==e.state.data&&h(e,t,t.refetchOnMount)}function h(e,t,r){if(!1!==(0,o.resolveEnabled)(t.enabled,e)&&"static"!==(0,o.resolveStaleTime)(t.staleTime,e)){let i="function"==typeof r?r(e):r;return"always"===i||!1!==i&&f(e,t)}return!1}function p(e,t,r,i){return(e!==t||!1===(0,o.resolveEnabled)(i.enabled,e))&&(!r.suspense||"error"!==e.state.status)&&f(e,r)}function f(e,t){return!1!==(0,o.resolveEnabled)(t.enabled,e)&&e.isStaleByTime((0,o.resolveStaleTime)(t.staleTime,e))}e.s(["QueryObserver",()=>c],869230),e.i(247167);var g=e.i(271645),m=e.i(912598);e.i(843476);var b=g.createContext((t=!1,{clearReset:()=>{t=!1},reset:()=>{t=!0},isReset:()=>t})),y=g.createContext(!1);y.Provider;var v=(e,t,r)=>t.fetchOptimistic(e).catch(()=>{r.clearReset()});function O(e,t,r){let i,s=g.useContext(y),a=g.useContext(b),l=(0,m.useQueryClient)(r),u=l.defaultQueryOptions(e);l.getDefaultOptions().queries?._experimental_beforeQuery?.(u);let c=l.getQueryCache().get(u.queryHash);if(u._optimisticResults=s?"isRestoring":"optimistic",u.suspense){let e=e=>"static"===e?e:Math.max(e??1e3,1e3),t=u.staleTime;u.staleTime="function"==typeof t?(...r)=>e(t(...r)):e(t),"number"==typeof u.gcTime&&(u.gcTime=Math.max(u.gcTime,1e3))}i=c?.state.error&&"function"==typeof u.throwOnError?(0,o.shouldThrowError)(u.throwOnError,[c.state.error,c]):u.throwOnError,(u.suspense||u.experimental_prefetchInRender||i)&&!a.isReset()&&(u.retryOnMount=!1),g.useEffect(()=>{a.clearReset()},[a]);let d=!l.getQueryCache().get(u.queryHash),[h]=g.useState(()=>new t(l,u)),p=h.getOptimisticResult(u),f=!s&&!1!==e.subscribed;if(g.useSyncExternalStore(g.useCallback(e=>{let t=f?h.subscribe(n.notifyManager.batchCalls(e)):o.noop;return h.updateResult(),t},[h,f]),()=>h.getCurrentResult(),()=>h.getCurrentResult()),g.useEffect(()=>{h.setOptions(u)},[u,h]),u?.suspense&&p.isPending)throw v(u,h,a);if((({result:e,errorResetBoundary:t,throwOnError:r,query:i,suspense:n})=>e.isError&&!t.isReset()&&!e.isFetching&&i&&(n&&void 0===e.data||(0,o.shouldThrowError)(r,[e.error,i])))({result:p,errorResetBoundary:a,throwOnError:u.throwOnError,query:c,suspense:u.suspense}))throw p.error;if(l.getDefaultOptions().queries?._experimental_afterQuery?.(u,p),u.experimental_prefetchInRender&&!o.isServer&&p.isLoading&&p.isFetching&&!s){let e=d?v(u,h,a):c?.promise;e?.catch(o.noop).finally(()=>{h.updateResult()})}return u.notifyOnChangeProps?p:h.trackResult(p)}function $(e,t){return O(e,c,t)}function R(e){let t=[e];return{all:t,lists:()=>[...t,"list"],list:e=>[...t,"list",{params:e}],details:()=>[...t,"detail"],detail:e=>[...t,"detail",e]}}e.s(["useBaseQuery",()=>O],469637),e.s(["useQuery",()=>$],266027),e.s(["createQueryKeys",()=>R],243652);let C=R("uiConfig");e.s(["useUIConfig",0,()=>$({queryKey:C.list({}),queryFn:async()=>await (0,r.getUiConfig)(),staleTime:864e5,gcTime:864e5})],612256)},321836,e=>{"use strict";let t="litellm_return_url",r="redirect_to";function i(){return window.location.href}function n(){let e=i();e&&function(e,t,r=300){if("u"typeof document&&(document.cookie=`${t}=; path=/; max-age=0`)}catch(e){console.error("Failed to clear return URL cookie:",e)}}function l(){return new URLSearchParams(window.location.search).get(r)}function o(e,t){let n=t||i();if(!n||n.includes("/login"))return e;let s=e.includes("?")?"&":"?";return`${e}${s}${r}=${encodeURIComponent(n)}`}function u(){let e=l();if(e)return e;let t=s();return t||null}function c(){let e=window.location.hostname;return"localhost"===e||"127.0.0.1"===e||"::1"===e||e.startsWith("127.")||e.endsWith(".local")}function d(e){if(!e)return!1;if(e.startsWith("/")&&!e.startsWith("//"))return!0;try{let t=new URL(e),r=window.location.hostname;if(t.hostname!==r)return!1;if(c())return!0;return t.origin===window.location.origin}catch{return!1}}function h(e){try{let t=new URL(e,window.location.origin),r=t.pathname;r.length>1&&r.endsWith("/")&&(r=r.slice(0,-1));let i=new URLSearchParams(t.search),n=new URLSearchParams;Array.from(i.entries()).sort(([e],[t])=>e.localeCompare(t)).forEach(([e,t])=>{n.append(e,t)});let s=n.toString(),a=t.hash||"";return`${t.origin}${r}${s?`?${s}`:""}${a}`}catch{return e}}function p(){let e=l();if(e){if(d(e))return a(),e;c()&&console.warn("[returnUrlUtils] Invalid return URL in params rejected:",e)}let t=s();if(t){if(d(t))return a(),t;c()&&console.warn("[returnUrlUtils] Invalid return URL in cookie rejected:",t)}return null}e.s(["buildLoginUrlWithReturn",()=>o,"clearStoredReturnUrl",()=>a,"consumeReturnUrl",()=>p,"getReturnUrl",()=>u,"isValidReturnUrl",()=>d,"normalizeUrlForCompare",()=>h,"storeReturnUrl",()=>n])},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),i=e.i(242064),n=e.i(529681);let s=e=>{let{prefixCls:i,className:n,style:s,size:a,shape:l}=e,o=(0,r.default)({[`${i}-lg`]:"large"===a,[`${i}-sm`]:"small"===a}),u=(0,r.default)({[`${i}-circle`]:"circle"===l,[`${i}-square`]:"square"===l,[`${i}-round`]:"round"===l}),c=t.useMemo(()=>"number"==typeof a?{width:a,height:a,lineHeight:`${a}px`}:{},[a]);return t.createElement("span",{className:(0,r.default)(i,o,u,n),style:Object.assign(Object.assign({},c),s)})};e.i(296059);var a=e.i(694758),l=e.i(915654),o=e.i(246422),u=e.i(838378);let c=new a.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),d=e=>({height:e,lineHeight:(0,l.unit)(e)}),h=e=>Object.assign({width:e},d(e)),p=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},d(e)),f=e=>Object.assign({width:e},d(e)),g=(e,t,r)=>{let{skeletonButtonCls:i}=e;return{[`${r}${i}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${r}${i}-round`]:{borderRadius:t}}},m=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},d(e)),b=(0,o.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:r}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:r,skeletonTitleCls:i,skeletonParagraphCls:n,skeletonButtonCls:s,skeletonInputCls:a,skeletonImageCls:l,controlHeight:o,controlHeightLG:u,controlHeightSM:d,gradientFromColor:b,padding:y,marginSM:v,borderRadius:O,titleHeight:$,blockRadius:R,paragraphLiHeight:C,controlHeightXS:w,paragraphMarginTop:x}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:y,verticalAlign:"top",[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:b},h(o)),[`${r}-circle`]:{borderRadius:"50%"},[`${r}-lg`]:Object.assign({},h(u)),[`${r}-sm`]:Object.assign({},h(d))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[i]:{width:"100%",height:$,background:b,borderRadius:R,[`+ ${n}`]:{marginBlockStart:d}},[n]:{padding:0,"> li":{width:"100%",height:C,listStyle:"none",background:b,borderRadius:R,"+ li":{marginBlockStart:w}}},[`${n}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${i}, ${n} > li`]:{borderRadius:O}}},[`${t}-with-avatar ${t}-content`]:{[i]:{marginBlockStart:v,[`+ ${n}`]:{marginBlockStart:x}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:r,controlHeight:i,controlHeightLG:n,controlHeightSM:s,gradientFromColor:a,calc:l}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:t,width:l(i).mul(2).equal(),minWidth:l(i).mul(2).equal()},m(i,l))},g(e,i,r)),{[`${r}-lg`]:Object.assign({},m(n,l))}),g(e,n,`${r}-lg`)),{[`${r}-sm`]:Object.assign({},m(s,l))}),g(e,s,`${r}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:r,controlHeight:i,controlHeightLG:n,controlHeightSM:s}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:r},h(i)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},h(n)),[`${t}${t}-sm`]:Object.assign({},h(s))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:r,skeletonInputCls:i,controlHeightLG:n,controlHeightSM:s,gradientFromColor:a,calc:l}=e;return{[i]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:r},p(t,l)),[`${i}-lg`]:Object.assign({},p(n,l)),[`${i}-sm`]:Object.assign({},p(s,l))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:r,gradientFromColor:i,borderRadiusSM:n,calc:s}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:i,borderRadius:n},f(s(r).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},f(r)),{maxWidth:s(r).mul(4).equal(),maxHeight:s(r).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[s]:{width:"100%"},[a]:{width:"100%"}},[`${t}${t}-active`]:{[` + ${i}, + ${n} > li, + ${r}, + ${s}, + ${a}, + ${l} + `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,u.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:r(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:r}=e;return{color:t,colorGradientEnd:r,gradientFromColor:t,gradientToColor:r,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),y=e=>{let{prefixCls:i,className:n,style:s,rows:a=0}=e,l=Array.from({length:a}).map((r,i)=>t.createElement("li",{key:i,style:{width:((e,t)=>{let{width:r,rows:i=2}=t;return Array.isArray(r)?r[e]:i-1===e?r:void 0})(i,e)}}));return t.createElement("ul",{className:(0,r.default)(i,n),style:s},l)},v=({prefixCls:e,className:i,width:n,style:s})=>t.createElement("h3",{className:(0,r.default)(e,i),style:Object.assign({width:n},s)});function O(e){return e&&"object"==typeof e?e:{}}let $=e=>{let{prefixCls:n,loading:a,className:l,rootClassName:o,style:u,children:c,avatar:d=!1,title:h=!0,paragraph:p=!0,active:f,round:g}=e,{getPrefixCls:m,direction:$,className:R,style:C}=(0,i.useComponentConfig)("skeleton"),w=m("skeleton",n),[x,E,k]=b(w);if(a||!("loading"in e)){let e,i,n=!!d,a=!!h,c=!!p;if(n){let r=Object.assign(Object.assign({prefixCls:`${w}-avatar`},a&&!c?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),O(d));e=t.createElement("div",{className:`${w}-header`},t.createElement(s,Object.assign({},r)))}if(a||c){let e,r;if(a){let r=Object.assign(Object.assign({prefixCls:`${w}-title`},!n&&c?{width:"38%"}:n&&c?{width:"50%"}:{}),O(h));e=t.createElement(v,Object.assign({},r))}if(c){let e,i=Object.assign(Object.assign({prefixCls:`${w}-paragraph`},(e={},n&&a||(e.width="61%"),!n&&a?e.rows=3:e.rows=2,e)),O(p));r=t.createElement(y,Object.assign({},i))}i=t.createElement("div",{className:`${w}-content`},e,r)}let m=(0,r.default)(w,{[`${w}-with-avatar`]:n,[`${w}-active`]:f,[`${w}-rtl`]:"rtl"===$,[`${w}-round`]:g},R,l,o,E,k);return x(t.createElement("div",{className:m,style:Object.assign(Object.assign({},C),u)},e,i))}return null!=c?c:null};$.Button=e=>{let{prefixCls:a,className:l,rootClassName:o,active:u,block:c=!1,size:d="default"}=e,{getPrefixCls:h}=t.useContext(i.ConfigContext),p=h("skeleton",a),[f,g,m]=b(p),y=(0,n.default)(e,["prefixCls"]),v=(0,r.default)(p,`${p}-element`,{[`${p}-active`]:u,[`${p}-block`]:c},l,o,g,m);return f(t.createElement("div",{className:v},t.createElement(s,Object.assign({prefixCls:`${p}-button`,size:d},y))))},$.Avatar=e=>{let{prefixCls:a,className:l,rootClassName:o,active:u,shape:c="circle",size:d="default"}=e,{getPrefixCls:h}=t.useContext(i.ConfigContext),p=h("skeleton",a),[f,g,m]=b(p),y=(0,n.default)(e,["prefixCls","className"]),v=(0,r.default)(p,`${p}-element`,{[`${p}-active`]:u},l,o,g,m);return f(t.createElement("div",{className:v},t.createElement(s,Object.assign({prefixCls:`${p}-avatar`,shape:c,size:d},y))))},$.Input=e=>{let{prefixCls:a,className:l,rootClassName:o,active:u,block:c,size:d="default"}=e,{getPrefixCls:h}=t.useContext(i.ConfigContext),p=h("skeleton",a),[f,g,m]=b(p),y=(0,n.default)(e,["prefixCls"]),v=(0,r.default)(p,`${p}-element`,{[`${p}-active`]:u,[`${p}-block`]:c},l,o,g,m);return f(t.createElement("div",{className:v},t.createElement(s,Object.assign({prefixCls:`${p}-input`,size:d},y))))},$.Image=e=>{let{prefixCls:n,className:s,rootClassName:a,style:l,active:o}=e,{getPrefixCls:u}=t.useContext(i.ConfigContext),c=u("skeleton",n),[d,h,p]=b(c),f=(0,r.default)(c,`${c}-element`,{[`${c}-active`]:o},s,a,h,p);return d(t.createElement("div",{className:f},t.createElement("div",{className:(0,r.default)(`${c}-image`,s),style:l},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${c}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${c}-image-path`})))))},$.Node=e=>{let{prefixCls:n,className:s,rootClassName:a,style:l,active:o,children:u}=e,{getPrefixCls:c}=t.useContext(i.ConfigContext),d=c("skeleton",n),[h,p,f]=b(d),g=(0,r.default)(d,`${d}-element`,{[`${d}-active`]:o},p,s,a,f);return h(t.createElement("div",{className:g},t.createElement("div",{className:(0,r.default)(`${d}-image`,s),style:l},u)))},e.s(["default",0,$],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var n=e.i(9583),s=r.forwardRef(function(e,s){return r.createElement(n.default,(0,t.default)({},e,{ref:s,icon:i}))});e.s(["default",0,s],959013)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/030fbd1b8bfd0d5f.js b/litellm/proxy/_experimental/out/_next/static/chunks/030fbd1b8bfd0d5f.js deleted file mode 100644 index 2897712de1d..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/030fbd1b8bfd0d5f.js +++ /dev/null @@ -1,98 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,290571,e=>{"use strict";function t(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r}"function"==typeof SuppressedError&&SuppressedError,e.s(["__rest",()=>t])},444755,e=>{"use strict";let t=(e,r)=>{if(0===e.length)return r.classGroupId;let o=e[0],n=r.nextPart.get(o),a=n?t(e.slice(1),n):void 0;if(a)return a;if(0===r.validators.length)return;let i=e.join("-");return r.validators.find(({validator:e})=>e(i))?.classGroupId},r=/^\[(.+)\]$/,o=(e,t,r,i)=>{e.forEach(e=>{if("string"==typeof e){(""===e?t:n(t,e)).classGroupId=r;return}"function"==typeof e?a(e)?o(e(i),t,r,i):t.validators.push({validator:e,classGroupId:r}):Object.entries(e).forEach(([e,a])=>{o(a,n(t,e),r,i)})})},n=(e,t)=>{let r=e;return t.split("-").forEach(e=>{r.nextPart.has(e)||r.nextPart.set(e,{nextPart:new Map,validators:[]}),r=r.nextPart.get(e)}),r},a=e=>e.isThemeGetter,i=(e,t)=>t?e.map(([e,r])=>[e,r.map(e=>"string"==typeof e?t+e:"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,r])=>[t+e,r])):e)]):e,l=e=>{if(e.length<=1)return e;let t=[],r=[];return e.forEach(e=>{"["===e[0]?(t.push(...r.sort(),e),r=[]):r.push(e)}),t.push(...r.sort()),t},s=/\s+/;function c(){let e,t,r=0,o="";for(;r{let t;if("string"==typeof e)return e;let r="";for(let o=0;o{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,r=new Map,o=new Map,n=(n,a)=>{r.set(n,a),++t>e&&(t=0,o=r,r=new Map)};return{get(e){let t=r.get(e);return void 0!==t?t:void 0!==(t=o.get(e))?(n(e,t),t):void 0},set(e,t){r.has(e)?r.set(e,t):n(e,t)}}})((s=n.reduce((e,t)=>t(e),e())).cacheSize),parseClassName:(e=>{let{separator:t,experimentalParseClassName:r}=e,o=1===t.length,n=t[0],a=t.length,i=e=>{let r,i=[],l=0,s=0;for(let c=0;cs?r-s:void 0}};return r?e=>r({className:e,parseClassName:i}):i})(s),...(e=>{let n=(e=>{let{theme:t,prefix:r}=e,n={nextPart:new Map,validators:[]};return i(Object.entries(e.classGroups),r).forEach(([e,r])=>{o(r,n,e,t)}),n})(e),{conflictingClassGroups:a,conflictingClassGroupModifiers:l}=e;return{getClassGroupId:e=>{let o=e.split("-");return""===o[0]&&1!==o.length&&o.shift(),t(o,n)||(e=>{if(r.test(e)){let t=r.exec(e)[1],o=t?.substring(0,t.indexOf(":"));if(o)return"arbitrary.."+o}})(e)},getConflictingClassGroupIds:(e,t)=>{let r=a[e]||[];return t&&l[e]?[...r,...l[e]]:r}}})(s)}).cache.get,f=a.cache.set,p=h,h(l)};function h(e){let t=u(e);if(t)return t;let r=((e,t)=>{let{parseClassName:r,getClassGroupId:o,getConflictingClassGroupIds:n}=t,a=[],i=e.trim().split(s),c="";for(let e=i.length-1;e>=0;e-=1){let t=i[e],{modifiers:s,hasImportantModifier:u,baseClassName:d,maybePostfixModifierPosition:f}=r(t),p=!!f,h=o(p?d.substring(0,f):d);if(!h){if(!p||!(h=o(d))){c=t+(c.length>0?" "+c:c);continue}p=!1}let m=l(s).join(":"),g=u?m+"!":m,v=g+h;if(a.includes(v))continue;a.push(v);let y=n(h,p);for(let e=0;e0?" "+c:c)}return c})(e,a);return f(e,r),r}return function(){return p(c.apply(null,arguments))}}let f=e=>{let t=t=>t[e]||[];return t.isThemeGetter=!0,t},p=/^\[(?:([a-z-]+):)?(.+)\]$/i,h=/^\d+\/\d+$/,m=new Set(["px","full","screen"]),g=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,v=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,y=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,b=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,w=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,$=e=>x(e)||m.has(e)||h.test(e),C=e=>M(e,"length",B),x=e=>!!e&&!Number.isNaN(Number(e)),E=e=>M(e,"number",x),S=e=>!!e&&Number.isInteger(Number(e)),k=e=>e.endsWith("%")&&x(e.slice(0,-1)),j=e=>p.test(e),O=e=>g.test(e),T=new Set(["length","size","percentage"]),I=e=>M(e,T,A),_=e=>M(e,"position",A),F=new Set(["image","url"]),P=e=>M(e,F,L),R=e=>M(e,"",z),N=()=>!0,M=(e,t,r)=>{let o=p.exec(e);return!!o&&(o[1]?"string"==typeof t?o[1]===t:t.has(o[1]):r(o[2]))},B=e=>v.test(e)&&!y.test(e),A=()=>!1,z=e=>b.test(e),L=e=>w.test(e),D=()=>{let e=f("colors"),t=f("spacing"),r=f("blur"),o=f("brightness"),n=f("borderColor"),a=f("borderRadius"),i=f("borderSpacing"),l=f("borderWidth"),s=f("contrast"),c=f("grayscale"),u=f("hueRotate"),d=f("invert"),p=f("gap"),h=f("gradientColorStops"),m=f("gradientColorStopPositions"),g=f("inset"),v=f("margin"),y=f("opacity"),b=f("padding"),w=f("saturate"),T=f("scale"),F=f("sepia"),M=f("skew"),B=f("space"),A=f("translate"),z=()=>["auto","contain","none"],L=()=>["auto","hidden","clip","visible","scroll"],D=()=>["auto",j,t],H=()=>[j,t],V=()=>["",$,C],W=()=>["auto",x,j],U=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],G=()=>["solid","dashed","dotted","double","none"],q=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],J=()=>["start","end","center","between","around","evenly","stretch"],K=()=>["","0",j],X=()=>["auto","avoid","all","avoid-page","page","left","right","column"],Y=()=>[x,j];return{cacheSize:500,separator:":",theme:{colors:[N],spacing:[$,C],blur:["none","",O,j],brightness:Y(),borderColor:[e],borderRadius:["none","","full",O,j],borderSpacing:H(),borderWidth:V(),contrast:Y(),grayscale:K(),hueRotate:Y(),invert:K(),gap:H(),gradientColorStops:[e],gradientColorStopPositions:[k,C],inset:D(),margin:D(),opacity:Y(),padding:H(),saturate:Y(),scale:Y(),sepia:K(),skew:Y(),space:H(),translate:H()},classGroups:{aspect:[{aspect:["auto","square","video",j]}],container:["container"],columns:[{columns:[O]}],"break-after":[{"break-after":X()}],"break-before":[{"break-before":X()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...U(),j]}],overflow:[{overflow:L()}],"overflow-x":[{"overflow-x":L()}],"overflow-y":[{"overflow-y":L()}],overscroll:[{overscroll:z()}],"overscroll-x":[{"overscroll-x":z()}],"overscroll-y":[{"overscroll-y":z()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[g]}],"inset-x":[{"inset-x":[g]}],"inset-y":[{"inset-y":[g]}],start:[{start:[g]}],end:[{end:[g]}],top:[{top:[g]}],right:[{right:[g]}],bottom:[{bottom:[g]}],left:[{left:[g]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",S,j]}],basis:[{basis:D()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",j]}],grow:[{grow:K()}],shrink:[{shrink:K()}],order:[{order:["first","last","none",S,j]}],"grid-cols":[{"grid-cols":[N]}],"col-start-end":[{col:["auto",{span:["full",S,j]},j]}],"col-start":[{"col-start":W()}],"col-end":[{"col-end":W()}],"grid-rows":[{"grid-rows":[N]}],"row-start-end":[{row:["auto",{span:[S,j]},j]}],"row-start":[{"row-start":W()}],"row-end":[{"row-end":W()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",j]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",j]}],gap:[{gap:[p]}],"gap-x":[{"gap-x":[p]}],"gap-y":[{"gap-y":[p]}],"justify-content":[{justify:["normal",...J()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...J(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...J(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[b]}],px:[{px:[b]}],py:[{py:[b]}],ps:[{ps:[b]}],pe:[{pe:[b]}],pt:[{pt:[b]}],pr:[{pr:[b]}],pb:[{pb:[b]}],pl:[{pl:[b]}],m:[{m:[v]}],mx:[{mx:[v]}],my:[{my:[v]}],ms:[{ms:[v]}],me:[{me:[v]}],mt:[{mt:[v]}],mr:[{mr:[v]}],mb:[{mb:[v]}],ml:[{ml:[v]}],"space-x":[{"space-x":[B]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[B]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",j,t]}],"min-w":[{"min-w":[j,t,"min","max","fit"]}],"max-w":[{"max-w":[j,t,"none","full","min","max","fit","prose",{screen:[O]},O]}],h:[{h:[j,t,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[j,t,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[j,t,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[j,t,"auto","min","max","fit"]}],"font-size":[{text:["base",O,C]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",E]}],"font-family":[{font:[N]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",j]}],"line-clamp":[{"line-clamp":["none",x,E]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",$,j]}],"list-image":[{"list-image":["none",j]}],"list-style-type":[{list:["none","disc","decimal",j]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[e]}],"placeholder-opacity":[{"placeholder-opacity":[y]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[e]}],"text-opacity":[{"text-opacity":[y]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...G(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",$,C]}],"underline-offset":[{"underline-offset":["auto",$,j]}],"text-decoration-color":[{decoration:[e]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:H()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",j]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",j]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[y]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...U(),_]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",I]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},P]}],"bg-color":[{bg:[e]}],"gradient-from-pos":[{from:[m]}],"gradient-via-pos":[{via:[m]}],"gradient-to-pos":[{to:[m]}],"gradient-from":[{from:[h]}],"gradient-via":[{via:[h]}],"gradient-to":[{to:[h]}],rounded:[{rounded:[a]}],"rounded-s":[{"rounded-s":[a]}],"rounded-e":[{"rounded-e":[a]}],"rounded-t":[{"rounded-t":[a]}],"rounded-r":[{"rounded-r":[a]}],"rounded-b":[{"rounded-b":[a]}],"rounded-l":[{"rounded-l":[a]}],"rounded-ss":[{"rounded-ss":[a]}],"rounded-se":[{"rounded-se":[a]}],"rounded-ee":[{"rounded-ee":[a]}],"rounded-es":[{"rounded-es":[a]}],"rounded-tl":[{"rounded-tl":[a]}],"rounded-tr":[{"rounded-tr":[a]}],"rounded-br":[{"rounded-br":[a]}],"rounded-bl":[{"rounded-bl":[a]}],"border-w":[{border:[l]}],"border-w-x":[{"border-x":[l]}],"border-w-y":[{"border-y":[l]}],"border-w-s":[{"border-s":[l]}],"border-w-e":[{"border-e":[l]}],"border-w-t":[{"border-t":[l]}],"border-w-r":[{"border-r":[l]}],"border-w-b":[{"border-b":[l]}],"border-w-l":[{"border-l":[l]}],"border-opacity":[{"border-opacity":[y]}],"border-style":[{border:[...G(),"hidden"]}],"divide-x":[{"divide-x":[l]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[l]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[y]}],"divide-style":[{divide:G()}],"border-color":[{border:[n]}],"border-color-x":[{"border-x":[n]}],"border-color-y":[{"border-y":[n]}],"border-color-s":[{"border-s":[n]}],"border-color-e":[{"border-e":[n]}],"border-color-t":[{"border-t":[n]}],"border-color-r":[{"border-r":[n]}],"border-color-b":[{"border-b":[n]}],"border-color-l":[{"border-l":[n]}],"divide-color":[{divide:[n]}],"outline-style":[{outline:["",...G()]}],"outline-offset":[{"outline-offset":[$,j]}],"outline-w":[{outline:[$,C]}],"outline-color":[{outline:[e]}],"ring-w":[{ring:V()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[e]}],"ring-opacity":[{"ring-opacity":[y]}],"ring-offset-w":[{"ring-offset":[$,C]}],"ring-offset-color":[{"ring-offset":[e]}],shadow:[{shadow:["","inner","none",O,R]}],"shadow-color":[{shadow:[N]}],opacity:[{opacity:[y]}],"mix-blend":[{"mix-blend":[...q(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":q()}],filter:[{filter:["","none"]}],blur:[{blur:[r]}],brightness:[{brightness:[o]}],contrast:[{contrast:[s]}],"drop-shadow":[{"drop-shadow":["","none",O,j]}],grayscale:[{grayscale:[c]}],"hue-rotate":[{"hue-rotate":[u]}],invert:[{invert:[d]}],saturate:[{saturate:[w]}],sepia:[{sepia:[F]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[r]}],"backdrop-brightness":[{"backdrop-brightness":[o]}],"backdrop-contrast":[{"backdrop-contrast":[s]}],"backdrop-grayscale":[{"backdrop-grayscale":[c]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[u]}],"backdrop-invert":[{"backdrop-invert":[d]}],"backdrop-opacity":[{"backdrop-opacity":[y]}],"backdrop-saturate":[{"backdrop-saturate":[w]}],"backdrop-sepia":[{"backdrop-sepia":[F]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[i]}],"border-spacing-x":[{"border-spacing-x":[i]}],"border-spacing-y":[{"border-spacing-y":[i]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",j]}],duration:[{duration:Y()}],ease:[{ease:["linear","in","out","in-out",j]}],delay:[{delay:Y()}],animate:[{animate:["none","spin","ping","pulse","bounce",j]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[T]}],"scale-x":[{"scale-x":[T]}],"scale-y":[{"scale-y":[T]}],rotate:[{rotate:[S,j]}],"translate-x":[{"translate-x":[A]}],"translate-y":[{"translate-y":[A]}],"skew-x":[{"skew-x":[M]}],"skew-y":[{"skew-y":[M]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",j]}],accent:[{accent:["auto",e]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",j]}],"caret-color":[{caret:[e]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":H()}],"scroll-mx":[{"scroll-mx":H()}],"scroll-my":[{"scroll-my":H()}],"scroll-ms":[{"scroll-ms":H()}],"scroll-me":[{"scroll-me":H()}],"scroll-mt":[{"scroll-mt":H()}],"scroll-mr":[{"scroll-mr":H()}],"scroll-mb":[{"scroll-mb":H()}],"scroll-ml":[{"scroll-ml":H()}],"scroll-p":[{"scroll-p":H()}],"scroll-px":[{"scroll-px":H()}],"scroll-py":[{"scroll-py":H()}],"scroll-ps":[{"scroll-ps":H()}],"scroll-pe":[{"scroll-pe":H()}],"scroll-pt":[{"scroll-pt":H()}],"scroll-pr":[{"scroll-pr":H()}],"scroll-pb":[{"scroll-pb":H()}],"scroll-pl":[{"scroll-pl":H()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",j]}],fill:[{fill:[e,"none"]}],"stroke-w":[{stroke:[$,C,E]}],stroke:[{stroke:[e,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},H=(e,t,r)=>{void 0!==r&&(e[t]=r)},V=(e,t)=>{if(t)for(let r in t)H(e,r,t[r])},W=(e,t)=>{if(t)for(let r in t){let o=t[r];void 0!==o&&(e[r]=(e[r]||[]).concat(o))}},U=((e,...t)=>"function"==typeof e?d(D,e,...t):d(()=>((e,{cacheSize:t,prefix:r,separator:o,experimentalParseClassName:n,extend:a={},override:i={}})=>{for(let a in H(e,"cacheSize",t),H(e,"prefix",r),H(e,"separator",o),H(e,"experimentalParseClassName",n),i)V(e[a],i[a]);for(let t in a)W(e[t],a[t]);return e})(D(),e),...t))({extend:{classGroups:{shadow:[{shadow:[{tremor:["input","card","dropdown"],"dark-tremor":["input","card","dropdown"]}]}],rounded:[{rounded:[{tremor:["small","default","full"],"dark-tremor":["small","default","full"]}]}],"font-size":[{text:[{tremor:["default","title","metric"],"dark-tremor":["default","title","metric"]}]}]}}});e.s(["tremorTwMerge",()=>U],444755)},480731,e=>{"use strict";let t={Increase:"increase",ModerateIncrease:"moderateIncrease",Decrease:"decrease",ModerateDecrease:"moderateDecrease",Unchanged:"unchanged"},r={Slate:"slate",Gray:"gray",Zinc:"zinc",Neutral:"neutral",Stone:"stone",Red:"red",Orange:"orange",Amber:"amber",Yellow:"yellow",Lime:"lime",Green:"green",Emerald:"emerald",Teal:"teal",Cyan:"cyan",Sky:"sky",Blue:"blue",Indigo:"indigo",Violet:"violet",Purple:"purple",Fuchsia:"fuchsia",Pink:"pink",Rose:"rose"},o={XS:"xs",SM:"sm",MD:"md",LG:"lg",XL:"xl"},n={Left:"left",Right:"right"},a={Top:"top",Bottom:"bottom"};e.s(["BaseColors",()=>r,"DeltaTypes",()=>t,"HorizontalPositions",()=>n,"Sizes",()=>o,"VerticalPositions",()=>a])},673706,e=>{"use strict";e.i(480731);let t=["slate","gray","zinc","neutral","stone","red","orange","amber","yellow","lime","green","emerald","teal","cyan","sky","blue","indigo","violet","purple","fuchsia","pink","rose"],r=e=>e.toString(),o=e=>e.reduce((e,t)=>e+t,0),n=(e,t)=>{for(let r=0;r{e.forEach(e=>{"function"==typeof e?e(t):null!=e&&(e.current=t)})}}function i(e){return t=>`tremor-${e}-${t}`}function l(e,r){let o=t.includes(e);if("white"===e||"black"===e||"transparent"===e||!r||!o){let t=e.includes("#")||e.includes("--")||e.includes("rgb")?`[${e}]`:e;return{bgColor:`bg-${t} dark:bg-${t}`,hoverBgColor:`hover:bg-${t} dark:hover:bg-${t}`,selectBgColor:`data-[selected]:bg-${t} dark:data-[selected]:bg-${t}`,textColor:`text-${t} dark:text-${t}`,selectTextColor:`data-[selected]:text-${t} dark:data-[selected]:text-${t}`,hoverTextColor:`hover:text-${t} dark:hover:text-${t}`,borderColor:`border-${t} dark:border-${t}`,selectBorderColor:`data-[selected]:border-${t} dark:data-[selected]:border-${t}`,hoverBorderColor:`hover:border-${t} dark:hover:border-${t}`,ringColor:`ring-${t} dark:ring-${t}`,strokeColor:`stroke-${t} dark:stroke-${t}`,fillColor:`fill-${t} dark:fill-${t}`}}return{bgColor:`bg-${e}-${r} dark:bg-${e}-${r}`,selectBgColor:`data-[selected]:bg-${e}-${r} dark:data-[selected]:bg-${e}-${r}`,hoverBgColor:`hover:bg-${e}-${r} dark:hover:bg-${e}-${r}`,textColor:`text-${e}-${r} dark:text-${e}-${r}`,selectTextColor:`data-[selected]:text-${e}-${r} dark:data-[selected]:text-${e}-${r}`,hoverTextColor:`hover:text-${e}-${r} dark:hover:text-${e}-${r}`,borderColor:`border-${e}-${r} dark:border-${e}-${r}`,selectBorderColor:`data-[selected]:border-${e}-${r} dark:data-[selected]:border-${e}-${r}`,hoverBorderColor:`hover:border-${e}-${r} dark:hover:border-${e}-${r}`,ringColor:`ring-${e}-${r} dark:ring-${e}-${r}`,strokeColor:`stroke-${e}-${r} dark:stroke-${e}-${r}`,fillColor:`fill-${e}-${r} dark:fill-${e}-${r}`}}e.s(["defaultValueFormatter",()=>r,"getColorClassNames",()=>l,"isValueInArray",()=>n,"makeClassName",()=>i,"mergeRefs",()=>a,"sumNumericArray",()=>o],673706)},552821,e=>{"use strict";var t=e.i(343794),r=e.i(271645);function o(e){var o=e.children,n=e.prefixCls,a=e.id,i=e.overlayInnerStyle,l=e.bodyClassName,s=e.className,c=e.style;return r.createElement("div",{className:(0,t.default)("".concat(n,"-content"),s),style:c},r.createElement("div",{className:(0,t.default)("".concat(n,"-inner"),l),id:a,role:"tooltip",style:i},"function"==typeof o?o():o))}e.s(["default",()=>o])},951160,815289,e=>{"use strict";e.i(247167);var t,r=e.i(392221),o=e.i(271645),n=e.i(174080),a=e.i(654310);e.i(883110);var i=e.i(611935),l=o.createContext(null),s=e.i(8211),c=e.i(174428),u=[],d=e.i(575943);function f(e){var t,r,o="rc-scrollbar-measure-".concat(Math.random().toString(36).substring(7)),n=document.createElement("div");n.id=o;var a=n.style;if(a.position="absolute",a.left="0",a.top="0",a.width="100px",a.height="100px",a.overflow="scroll",e){var i=getComputedStyle(e);a.scrollbarColor=i.scrollbarColor,a.scrollbarWidth=i.scrollbarWidth;var l=getComputedStyle(e,"::-webkit-scrollbar"),s=parseInt(l.width,10),c=parseInt(l.height,10);try{var u=s?"width: ".concat(l.width,";"):"",f=c?"height: ".concat(l.height,";"):"";(0,d.updateCSS)("\n#".concat(o,"::-webkit-scrollbar {\n").concat(u,"\n").concat(f,"\n}"),o)}catch(e){console.error(e),t=s,r=c}}document.body.appendChild(n);var p=e&&t&&!isNaN(t)?t:n.offsetWidth-n.clientWidth,h=e&&r&&!isNaN(r)?r:n.offsetHeight-n.clientHeight;return document.body.removeChild(n),(0,d.removeCSS)(o),{width:p,height:h}}function p(e){return"u"p,"getTargetScrollBarSize",()=>h],815289);var m="rc-util-locker-".concat(Date.now()),g=0,v=function(e){return!1!==e&&((0,a.default)()&&e?"string"==typeof e?document.querySelector(e):"function"==typeof e?e():e:null)},y=o.forwardRef(function(e,t){var f,p,y,b=e.open,w=e.autoLock,$=e.getContainer,C=(e.debug,e.autoDestroy),x=void 0===C||C,E=e.children,S=o.useState(b),k=(0,r.default)(S,2),j=k[0],O=k[1],T=j||b;o.useEffect(function(){(x||b)&&O(b)},[b,x]);var I=o.useState(function(){return v($)}),_=(0,r.default)(I,2),F=_[0],P=_[1];o.useEffect(function(){var e=v($);P(null!=e?e:null)});var R=function(e,t){var n=o.useState(function(){return(0,a.default)()?document.createElement("div"):null}),i=(0,r.default)(n,1)[0],d=o.useRef(!1),f=o.useContext(l),p=o.useState(u),h=(0,r.default)(p,2),m=h[0],g=h[1],v=f||(d.current?void 0:function(e){g(function(t){return[e].concat((0,s.default)(t))})});function y(){i.parentElement||document.body.appendChild(i),d.current=!0}function b(){var e;null==(e=i.parentElement)||e.removeChild(i),d.current=!1}return(0,c.default)(function(){return e?f?f(y):y():b(),b},[e]),(0,c.default)(function(){m.length&&(m.forEach(function(e){return e()}),g(u))},[m]),[i,v]}(T&&!F,0),N=(0,r.default)(R,2),M=N[0],B=N[1],A=null!=F?F:M;f=!!(w&&b&&(0,a.default)()&&(A===M||A===document.body)),p=o.useState(function(){return g+=1,"".concat(m,"_").concat(g)}),y=(0,r.default)(p,1)[0],(0,c.default)(function(){if(f){var e=h(document.body).width,t=document.body.scrollHeight>(window.innerHeight||document.documentElement.clientHeight)&&window.innerWidth>document.body.offsetWidth;(0,d.updateCSS)("\nhtml body {\n overflow-y: hidden;\n ".concat(t?"width: calc(100% - ".concat(e,"px);"):"","\n}"),y)}else(0,d.removeCSS)(y);return function(){(0,d.removeCSS)(y)}},[f,y]);var z=null;E&&(0,i.supportRef)(E)&&t&&(z=E.ref);var L=(0,i.useComposeRef)(z,t);if(!T||!(0,a.default)()||void 0===F)return null;var D=!1===A,H=E;return t&&(H=o.cloneElement(E,{ref:L})),o.createElement(l.Provider,{value:B},D?H:(0,n.createPortal)(H,A))});e.s(["default",0,y],951160)},876556,e=>{"use strict";var t=e.i(565924),r=e.i(271645);e.s(["default",()=>function e(o){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=[];return r.default.Children.forEach(o,function(r){(null!=r||n.keepEmpty)&&(Array.isArray(r)?a=a.concat(e(r)):(0,t.default)(r)&&r.props?a=a.concat(e(r.props.children,n)):a.push(r))}),a}])},430073,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645),o=e.i(876556);e.i(883110);var n=e.i(209428),a=e.i(410160),i=e.i(279697),l=e.i(611935),s=r.createContext(null),c=function(){if("u">typeof Map)return Map;function e(e,t){var r=-1;return e.some(function(e,o){return e[0]===t&&(r=o,!0)}),r}function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var r=e(this.__entries__,t),o=this.__entries__[r];return o&&o[1]},t.prototype.set=function(t,r){var o=e(this.__entries__,t);~o?this.__entries__[o][1]=r:this.__entries__.push([t,r])},t.prototype.delete=function(t){var r=this.__entries__,o=e(r,t);~o&&r.splice(o,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var r=0,o=this.__entries__;rtypeof window&&"u">typeof document&&window.document===document,d=e.g.Math===Math?e.g:"u">typeof self&&self.Math===Math?self:"u">typeof window&&window.Math===Math?window:Function("return this")(),f="function"==typeof requestAnimationFrame?requestAnimationFrame.bind(d):function(e){return setTimeout(function(){return e(Date.now())},1e3/60)},p=["top","right","bottom","left","width","height","size","weight"],h="u">typeof MutationObserver,m=function(){function e(){this.connected_=!1,this.mutationEventsAdded_=!1,this.mutationsObserver_=null,this.observers_=[],this.onTransitionEnd_=this.onTransitionEnd_.bind(this),this.refresh=function(e,t){var r=!1,o=!1,n=0;function a(){r&&(r=!1,e()),o&&l()}function i(){f(a)}function l(){var e=Date.now();if(r){if(e-n<2)return;o=!0}else r=!0,o=!1,setTimeout(i,20);n=e}return l}(this.refresh.bind(this),0)}return e.prototype.addObserver=function(e){~this.observers_.indexOf(e)||this.observers_.push(e),this.connected_||this.connect_()},e.prototype.removeObserver=function(e){var t=this.observers_,r=t.indexOf(e);~r&&t.splice(r,1),!t.length&&this.connected_&&this.disconnect_()},e.prototype.refresh=function(){this.updateObservers_()&&this.refresh()},e.prototype.updateObservers_=function(){var e=this.observers_.filter(function(e){return e.gatherActive(),e.hasActive()});return e.forEach(function(e){return e.broadcastActive()}),e.length>0},e.prototype.connect_=function(){u&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),h?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){u&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,r=void 0===t?"":t;p.some(function(e){return!!~r.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),g=function(e,t){for(var r=0,o=Object.keys(t);rtypeof SVGGraphicsElement?function(e){return e instanceof v(e).SVGGraphicsElement}:function(e){return e instanceof v(e).SVGElement&&"function"==typeof e.getBBox};function C(e,t,r,o){return{x:e,y:t,width:r,height:o}}var x=function(){function e(e){this.broadcastWidth=0,this.broadcastHeight=0,this.contentRect_=C(0,0,0,0),this.target=e}return e.prototype.isActive=function(){var e=function(e){if(!u)return y;if($(e)){var t;return C(0,0,(t=e.getBBox()).width,t.height)}return function(e){var t,r=e.clientWidth,o=e.clientHeight;if(!r&&!o)return y;var n=v(e).getComputedStyle(e),a=function(e){for(var t={},r=0,o=["top","right","bottom","left"];rtypeof DOMRectReadOnly?DOMRectReadOnly:Object).prototype),{x:r,y:o,width:n,height:a,top:o,right:r+n,bottom:a+o,left:r}),i);g(this,{target:e,contentRect:l})},S=function(){function e(e,t,r){if(this.activeObservations_=[],this.observations_=new c,"function"!=typeof e)throw TypeError("The callback provided as parameter 1 is not a function.");this.callback_=e,this.controller_=t,this.callbackCtx_=r}return e.prototype.observe=function(e){if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");if(!("u"0},e}(),k="u">typeof WeakMap?new WeakMap:new c,j=function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var r=new S(t,m.getInstance(),this);k.set(this,r)};["observe","unobserve","disconnect"].forEach(function(e){j.prototype[e]=function(){var t;return(t=k.get(this))[e].apply(t,arguments)}});var O=void 0!==d.ResizeObserver?d.ResizeObserver:j,T=new Map,I=new O(function(e){e.forEach(function(e){var t,r=e.target;null==(t=T.get(r))||t.forEach(function(e){return e(r)})})}),_=e.i(278409),F=e.i(233848),P=e.i(868917),R=e.i(674813),N=function(e){(0,P.default)(r,e);var t=(0,R.default)(r);function r(){return(0,_.default)(this,r),t.apply(this,arguments)}return(0,F.default)(r,[{key:"render",value:function(){return this.props.children}}]),r}(r.Component),M=r.forwardRef(function(e,t){var o=e.children,c=e.disabled,u=r.useRef(null),d=r.useRef(null),f=r.useContext(s),p="function"==typeof o,h=p?o(u):o,m=r.useRef({width:-1,height:-1,offsetWidth:-1,offsetHeight:-1}),g=!p&&r.isValidElement(h)&&(0,l.supportRef)(h),v=g?(0,l.getNodeRef)(h):null,y=(0,l.useComposeRef)(v,u),b=function(){var e;return(0,i.default)(u.current)||(u.current&&"object"===(0,a.default)(u.current)?(0,i.default)(null==(e=u.current)?void 0:e.nativeElement):null)||(0,i.default)(d.current)};r.useImperativeHandle(t,function(){return b()});var w=r.useRef(e);w.current=e;var $=r.useCallback(function(e){var t=w.current,r=t.onResize,o=t.data,a=e.getBoundingClientRect(),i=a.width,l=a.height,s=e.offsetWidth,c=e.offsetHeight,u=Math.floor(i),d=Math.floor(l);if(m.current.width!==u||m.current.height!==d||m.current.offsetWidth!==s||m.current.offsetHeight!==c){var p={width:u,height:d,offsetWidth:s,offsetHeight:c};m.current=p;var h=s===Math.round(i)?i:s,g=c===Math.round(l)?l:c,v=(0,n.default)((0,n.default)({},p),{},{offsetWidth:h,offsetHeight:g});null==f||f(v,e,o),r&&Promise.resolve().then(function(){r(v,e)})}},[]);return r.useEffect(function(){var e=b();return e&&!c&&(T.has(e)||(T.set(e,new Set),I.observe(e)),T.get(e).add($)),function(){T.has(e)&&(T.get(e).delete($),!T.get(e).size&&(I.unobserve(e),T.delete(e)))}},[u.current,c]),r.createElement(N,{ref:d},g?r.cloneElement(h,{ref:y}):h)}),B=r.forwardRef(function(e,n){var a=e.children;return("function"==typeof a?[a]:(0,o.default)(a)).map(function(o,a){var i=(null==o?void 0:o.key)||"".concat("rc-observer-key","-").concat(a);return r.createElement(M,(0,t.default)({},e,{key:i,ref:0===a?n:void 0}),o)})});B.Collection=function(e){var t=e.children,o=e.onBatchResize,n=r.useRef(0),a=r.useRef([]),i=r.useContext(s),l=r.useCallback(function(e,t,r){n.current+=1;var l=n.current;a.current.push({size:e,element:t,data:r}),Promise.resolve().then(function(){l===n.current&&(null==o||o(a.current),a.current=[])}),null==i||i(e,t,r)},[o,i]);return r.createElement(s.Provider,{value:l},t)},e.s(["default",0,B],430073)},981444,e=>{"use strict";var t=e.i(392221),r=e.i(209428),o=e.i(271645),n=0,a=(0,r.default)({},o).useId;let i=a?function(e){var t=a();return e||t}:function(e){var r=o.useState("ssr-id"),a=(0,t.default)(r,2),i=a[0],l=a[1];return(o.useEffect(function(){var e=n;n+=1,l("rc_unique_".concat(e))},[]),e)?e:i};e.s(["default",0,i])},614761,e=>{"use strict";e.s(["default",0,function(){if("u"{"use strict";e.i(247167);var t=e.i(931067),r=e.i(209428),o=e.i(392221),n=e.i(343794),a=e.i(361275),i=e.i(430073),l=e.i(174428),s=e.i(611935),c=e.i(271645);function u(e){var t=e.prefixCls,r=e.align,o=e.arrow,a=e.arrowPos,i=o||{},l=i.className,s=i.content,u=a.x,d=a.y,f=c.useRef();if(!r||!r.points)return null;var p={position:"absolute"};if(!1!==r.autoArrow){var h=r.points[0],m=r.points[1],g=h[0],v=h[1],y=m[0],b=m[1];g!==y&&["t","b"].includes(g)?"t"===g?p.top=0:p.bottom=0:p.top=void 0===d?0:d,v!==b&&["l","r"].includes(v)?"l"===v?p.left=0:p.right=0:p.left=void 0===u?0:u}return c.createElement("div",{ref:f,className:(0,n.default)("".concat(t,"-arrow"),l),style:p},s)}function d(e){var r=e.prefixCls,o=e.open,i=e.zIndex,l=e.mask,s=e.motion;return l?c.createElement(a.default,(0,t.default)({},s,{motionAppear:!0,visible:o,removeOnLeave:!0}),function(e){var t=e.className;return c.createElement("div",{style:{zIndex:i},className:(0,n.default)("".concat(r,"-mask"),t)})}):null}var f=c.memo(function(e){return e.children},function(e,t){return t.cache}),p=c.forwardRef(function(e,p){var h=e.popup,m=e.className,g=e.prefixCls,v=e.style,y=e.target,b=e.onVisibleChanged,w=e.open,$=e.keepDom,C=e.fresh,x=e.onClick,E=e.mask,S=e.arrow,k=e.arrowPos,j=e.align,O=e.motion,T=e.maskMotion,I=e.forceRender,_=e.getPopupContainer,F=e.autoDestroy,P=e.portal,R=e.zIndex,N=e.onMouseEnter,M=e.onMouseLeave,B=e.onPointerEnter,A=e.onPointerDownCapture,z=e.ready,L=e.offsetX,D=e.offsetY,H=e.offsetR,V=e.offsetB,W=e.onAlign,U=e.onPrepare,G=e.stretch,q=e.targetWidth,J=e.targetHeight,K="function"==typeof h?h():h,X=w||$,Y=(null==_?void 0:_.length)>0,Q=c.useState(!_||!Y),Z=(0,o.default)(Q,2),ee=Z[0],et=Z[1];if((0,l.default)(function(){!ee&&Y&&y&&et(!0)},[ee,Y,y]),!ee)return null;var er="auto",eo={left:"-1000vw",top:"-1000vh",right:er,bottom:er};if(z||!w){var en,ea=j.points,ei=j.dynamicInset||(null==(en=j._experimental)?void 0:en.dynamicInset),el=ei&&"r"===ea[0][1],es=ei&&"b"===ea[0][0];el?(eo.right=H,eo.left=er):(eo.left=L,eo.right=er),es?(eo.bottom=V,eo.top=er):(eo.top=D,eo.bottom=er)}var ec={};return G&&(G.includes("height")&&J?ec.height=J:G.includes("minHeight")&&J&&(ec.minHeight=J),G.includes("width")&&q?ec.width=q:G.includes("minWidth")&&q&&(ec.minWidth=q)),w||(ec.pointerEvents="none"),c.createElement(P,{open:I||X,getContainer:_&&function(){return _(y)},autoDestroy:F},c.createElement(d,{prefixCls:g,open:w,zIndex:R,mask:E,motion:T}),c.createElement(i.default,{onResize:W,disabled:!w},function(e){return c.createElement(a.default,(0,t.default)({motionAppear:!0,motionEnter:!0,motionLeave:!0,removeOnLeave:!1,forceRender:I,leavedClassName:"".concat(g,"-hidden")},O,{onAppearPrepare:U,onEnterPrepare:U,visible:w,onVisibleChanged:function(e){var t;null==O||null==(t=O.onVisibleChanged)||t.call(O,e),b(e)}}),function(t,o){var a=t.className,i=t.style,l=(0,n.default)(g,a,m);return c.createElement("div",{ref:(0,s.composeRef)(e,p,o),className:l,style:(0,r.default)((0,r.default)((0,r.default)((0,r.default)({"--arrow-x":"".concat(k.x||0,"px"),"--arrow-y":"".concat(k.y||0,"px")},eo),ec),i),{},{boxSizing:"border-box",zIndex:R},v),onMouseEnter:N,onMouseLeave:M,onPointerEnter:B,onClick:x,onPointerDownCapture:A},S&&c.createElement(u,{prefixCls:g,arrow:S,arrowPos:k,align:j}),c.createElement(f,{cache:!w&&!C},K))})}))});e.s(["default",0,p],546004);var h=c.forwardRef(function(e,t){var r=e.children,o=e.getTriggerDOMNode,n=(0,s.supportRef)(r),a=c.useCallback(function(e){(0,s.fillRef)(t,o?o(e):e)},[o]),i=(0,s.useComposeRef)(a,(0,s.getNodeRef)(r));return n?c.cloneElement(r,{ref:i}):r});e.s(["default",0,h],508811);var m=c.createContext(null);function g(e){return e?Array.isArray(e)?e:[e]:[]}function v(e,t,r,o){return c.useMemo(function(){var n=g(null!=r?r:t),a=g(null!=o?o:t),i=new Set(n),l=new Set(a);return e&&(i.has("hover")&&(i.delete("hover"),i.add("click")),l.has("hover")&&(l.delete("hover"),l.add("click"))),[i,l]},[e,t,r,o])}e.s(["default",0,m],976637),e.s(["default",()=>v],920)},606262,e=>{"use strict";e.s(["default",0,function(e){if(!e)return!1;if(e instanceof Element){if(e.offsetParent)return!0;if(e.getBBox){var t=e.getBBox(),r=t.width,o=t.height;if(r||o)return!0}if(e.getBoundingClientRect){var n=e.getBoundingClientRect(),a=n.width,i=n.height;if(a||i)return!0}}return!1}])},707067,e=>{"use strict";e.i(247167);var t=e.i(209428),r=e.i(392221),o=e.i(703923),n=e.i(951160),a=e.i(343794),i=e.i(430073),l=e.i(279697),s=e.i(909887),c=e.i(175066),u=e.i(981444),d=e.i(174428),f=e.i(614761),p=e.i(271645),h=e.i(546004),m=e.i(508811),g=e.i(976637),v=e.i(920),y=e.i(606262);function b(e,t,r,o){return t||(r?{motionName:"".concat(e,"-").concat(r)}:o?{motionName:o}:null)}function w(e){return e.ownerDocument.defaultView}function $(e){for(var t=[],r=null==e?void 0:e.parentElement,o=["hidden","scroll","clip","auto"];r;){var n=w(r).getComputedStyle(r);[n.overflowX,n.overflowY,n.overflow].some(function(e){return o.includes(e)})&&t.push(r),r=r.parentElement}return t}function C(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return Number.isNaN(e)?t:e}function x(e){return C(parseFloat(e),0)}function E(e,r){var o=(0,t.default)({},e);return(r||[]).forEach(function(e){if(!(e instanceof HTMLBodyElement||e instanceof HTMLHtmlElement)){var t=w(e).getComputedStyle(e),r=t.overflow,n=t.overflowClipMargin,a=t.borderTopWidth,i=t.borderBottomWidth,l=t.borderLeftWidth,s=t.borderRightWidth,c=e.getBoundingClientRect(),u=e.offsetHeight,d=e.clientHeight,f=e.offsetWidth,p=e.clientWidth,h=x(a),m=x(i),g=x(l),v=x(s),y=C(Math.round(c.width/f*1e3)/1e3),b=C(Math.round(c.height/u*1e3)/1e3),$=h*b,E=g*y,S=0,k=0;if("clip"===r){var j=x(n);S=j*y,k=j*b}var O=c.x+E-S,T=c.y+$-k,I=O+c.width+2*S-E-v*y-(f-p-g-v)*y,_=T+c.height+2*k-$-m*b-(u-d-h-m)*b;o.left=Math.max(o.left,O),o.top=Math.max(o.top,T),o.right=Math.min(o.right,I),o.bottom=Math.min(o.bottom,_)}}),o}function S(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,r="".concat(t),o=r.match(/^(.*)\%$/);return o?e*(parseFloat(o[1])/100):parseFloat(r)}function k(e,t){var o=(0,r.default)(t||[],2),n=o[0],a=o[1];return[S(e.width,n),S(e.height,a)]}function j(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return[e[0],e[1]]}function O(e,t){var r,o=t[0],n=t[1];return r="t"===o?e.y:"b"===o?e.y+e.height:e.y+e.height/2,{x:"l"===n?e.x:"r"===n?e.x+e.width:e.x+e.width/2,y:r}}function T(e,t){var r={t:"b",b:"t",l:"r",r:"l"};return e.map(function(e,o){return o===t?r[e]||"c":e}).join("")}var I=e.i(8211);e.i(883110);var _=["prefixCls","children","action","showAction","hideAction","popupVisible","defaultPopupVisible","onPopupVisibleChange","afterPopupVisibleChange","mouseEnterDelay","mouseLeaveDelay","focusDelay","blurDelay","mask","maskClosable","getPopupContainer","forceRender","autoDestroy","destroyPopupOnHide","popup","popupClassName","popupStyle","popupPlacement","builtinPlacements","popupAlign","zIndex","stretch","getPopupClassNameFromAlign","fresh","alignPoint","onPopupClick","onPopupAlign","arrow","popupMotion","maskMotion","popupTransitionName","popupAnimation","maskTransitionName","maskAnimation","className","getTriggerDOMNode"];let F=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:n.default;return p.forwardRef(function(n,x){var S,F,P,R,N,M,B,A,z,L,D,H,V,W,U,G,q=n.prefixCls,J=void 0===q?"rc-trigger-popup":q,K=n.children,X=n.action,Y=n.showAction,Q=n.hideAction,Z=n.popupVisible,ee=n.defaultPopupVisible,et=n.onPopupVisibleChange,er=n.afterPopupVisibleChange,eo=n.mouseEnterDelay,en=n.mouseLeaveDelay,ea=void 0===en?.1:en,ei=n.focusDelay,el=n.blurDelay,es=n.mask,ec=n.maskClosable,eu=n.getPopupContainer,ed=n.forceRender,ef=n.autoDestroy,ep=n.destroyPopupOnHide,eh=n.popup,em=n.popupClassName,eg=n.popupStyle,ev=n.popupPlacement,ey=n.builtinPlacements,eb=void 0===ey?{}:ey,ew=n.popupAlign,e$=n.zIndex,eC=n.stretch,ex=n.getPopupClassNameFromAlign,eE=n.fresh,eS=n.alignPoint,ek=n.onPopupClick,ej=n.onPopupAlign,eO=n.arrow,eT=n.popupMotion,eI=n.maskMotion,e_=n.popupTransitionName,eF=n.popupAnimation,eP=n.maskTransitionName,eR=n.maskAnimation,eN=n.className,eM=n.getTriggerDOMNode,eB=(0,o.default)(n,_),eA=p.useState(!1),ez=(0,r.default)(eA,2),eL=ez[0],eD=ez[1];(0,d.default)(function(){eD((0,f.default)())},[]);var eH=p.useRef({}),eV=p.useContext(g.default),eW=p.useMemo(function(){return{registerSubPopup:function(e,t){eH.current[e]=t,null==eV||eV.registerSubPopup(e,t)}}},[eV]),eU=(0,u.default)(),eG=p.useState(null),eq=(0,r.default)(eG,2),eJ=eq[0],eK=eq[1],eX=p.useRef(null),eY=(0,c.default)(function(e){eX.current=e,(0,l.isDOM)(e)&&eJ!==e&&eK(e),null==eV||eV.registerSubPopup(eU,e)}),eQ=p.useState(null),eZ=(0,r.default)(eQ,2),e0=eZ[0],e1=eZ[1],e2=p.useRef(null),e4=(0,c.default)(function(e){(0,l.isDOM)(e)&&e0!==e&&(e1(e),e2.current=e)}),e6=p.Children.only(K),e3=(null==e6?void 0:e6.props)||{},e7={},e5=(0,c.default)(function(e){var t,r;return(null==e0?void 0:e0.contains(e))||(null==(t=(0,s.getShadowRoot)(e0))?void 0:t.host)===e||e===e0||(null==eJ?void 0:eJ.contains(e))||(null==(r=(0,s.getShadowRoot)(eJ))?void 0:r.host)===e||e===eJ||Object.values(eH.current).some(function(t){return(null==t?void 0:t.contains(e))||e===t})}),e9=b(J,eT,eF,e_),e8=b(J,eI,eR,eP),te=p.useState(ee||!1),tt=(0,r.default)(te,2),tr=tt[0],to=tt[1],tn=null!=Z?Z:tr,ta=(0,c.default)(function(e){void 0===Z&&to(e)});(0,d.default)(function(){to(Z||!1)},[Z]);var ti=p.useRef(tn);ti.current=tn;var tl=p.useRef([]);tl.current=[];var ts=(0,c.default)(function(e){var t;ta(e),(null!=(t=tl.current[tl.current.length-1])?t:tn)!==e&&(tl.current.push(e),null==et||et(e))}),tc=p.useRef(),tu=function(){clearTimeout(tc.current)},td=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;tu(),0===t?ts(e):tc.current=setTimeout(function(){ts(e)},1e3*t)};p.useEffect(function(){return tu},[]);var tf=p.useState(!1),tp=(0,r.default)(tf,2),th=tp[0],tm=tp[1];(0,d.default)(function(e){(!e||tn)&&tm(!0)},[tn]);var tg=p.useState(null),tv=(0,r.default)(tg,2),ty=tv[0],tb=tv[1],tw=p.useState(null),t$=(0,r.default)(tw,2),tC=t$[0],tx=t$[1],tE=function(e){tx([e.clientX,e.clientY])},tS=(S=eS&&null!==tC?tC:e0,F=p.useState({ready:!1,offsetX:0,offsetY:0,offsetR:0,offsetB:0,arrowX:0,arrowY:0,scaleX:1,scaleY:1,align:eb[ev]||{}}),R=(P=(0,r.default)(F,2))[0],N=P[1],M=p.useRef(0),B=p.useMemo(function(){return eJ?$(eJ):[]},[eJ]),A=p.useRef({}),tn||(A.current={}),z=(0,c.default)(function(){if(eJ&&S&&tn){var e=eJ.ownerDocument,o=w(eJ),n=o.getComputedStyle(eJ).position,a=eJ.style.left,i=eJ.style.top,s=eJ.style.right,c=eJ.style.bottom,u=eJ.style.overflow,d=(0,t.default)((0,t.default)({},eb[ev]),ew),f=e.createElement("div");if(null==(v=eJ.parentElement)||v.appendChild(f),f.style.left="".concat(eJ.offsetLeft,"px"),f.style.top="".concat(eJ.offsetTop,"px"),f.style.position=n,f.style.height="".concat(eJ.offsetHeight,"px"),f.style.width="".concat(eJ.offsetWidth,"px"),eJ.style.left="0",eJ.style.top="0",eJ.style.right="auto",eJ.style.bottom="auto",eJ.style.overflow="hidden",Array.isArray(S))I={x:S[0],y:S[1],width:0,height:0};else{var p,h,m,g,v,b,$,x,I,_,F,P=S.getBoundingClientRect();P.x=null!=(_=P.x)?_:P.left,P.y=null!=(F=P.y)?F:P.top,I={x:P.x,y:P.y,width:P.width,height:P.height}}var R=eJ.getBoundingClientRect(),M=o.getComputedStyle(eJ),z=M.height,L=M.width;R.x=null!=(b=R.x)?b:R.left,R.y=null!=($=R.y)?$:R.top;var D=e.documentElement,H=D.clientWidth,V=D.clientHeight,W=D.scrollWidth,U=D.scrollHeight,G=D.scrollTop,q=D.scrollLeft,J=R.height,K=R.width,X=I.height,Y=I.width,Q=d.htmlRegion,Z="visible",ee="visibleFirst";"scroll"!==Q&&Q!==ee&&(Q=Z);var et=Q===ee,er=E({left:-q,top:-G,right:W-q,bottom:U-G},B),eo=E({left:0,top:0,right:H,bottom:V},B),en=Q===Z?eo:er,ea=et?eo:en;eJ.style.left="auto",eJ.style.top="auto",eJ.style.right="0",eJ.style.bottom="0";var ei=eJ.getBoundingClientRect();eJ.style.left=a,eJ.style.top=i,eJ.style.right=s,eJ.style.bottom=c,eJ.style.overflow=u,null==(x=eJ.parentElement)||x.removeChild(f);var el=C(Math.round(K/parseFloat(L)*1e3)/1e3),es=C(Math.round(J/parseFloat(z)*1e3)/1e3);if(!(0===el||0===es||(0,l.isDOM)(S)&&!(0,y.default)(S))){var ec=d.offset,eu=d.targetOffset,ed=k(R,ec),ef=(0,r.default)(ed,2),ep=ef[0],eh=ef[1],em=k(I,eu),eg=(0,r.default)(em,2),ey=eg[0],e$=eg[1];I.x-=ey,I.y-=e$;var eC=d.points||[],ex=(0,r.default)(eC,2),eE=ex[0],eS=j(ex[1]),ek=j(eE),eO=O(I,eS),eT=O(R,ek),eI=(0,t.default)({},d),e_=eO.x-eT.x+ep,eF=eO.y-eT.y+eh,eP=td(e_,eF),eR=td(e_,eF,eo),eN=O(I,["t","l"]),eM=O(R,["t","l"]),eB=O(I,["b","r"]),eA=O(R,["b","r"]),ez=d.overflow||{},eL=ez.adjustX,eD=ez.adjustY,eH=ez.shiftX,eV=ez.shiftY,eW=function(e){return"boolean"==typeof e?e:e>=0};tf();var eU=eW(eD),eG=ek[0]===eS[0];if(eU&&"t"===ek[0]&&(h>ea.bottom||A.current.bt)){var eq=eF;eG?eq-=J-X:eq=eN.y-eA.y-eh;var eK=td(e_,eq),eX=td(e_,eq,eo);eK>eP||eK===eP&&(!et||eX>=eR)?(A.current.bt=!0,eF=eq,eh=-eh,eI.points=[T(ek,0),T(eS,0)]):A.current.bt=!1}if(eU&&"b"===ek[0]&&(peP||eQ===eP&&(!et||eZ>=eR)?(A.current.tb=!0,eF=eY,eh=-eh,eI.points=[T(ek,0),T(eS,0)]):A.current.tb=!1}var e0=eW(eL),e1=ek[1]===eS[1];if(e0&&"l"===ek[1]&&(g>ea.right||A.current.rl)){var e2=e_;e1?e2-=K-Y:e2=eN.x-eA.x-ep;var e4=td(e2,eF),e6=td(e2,eF,eo);e4>eP||e4===eP&&(!et||e6>=eR)?(A.current.rl=!0,e_=e2,ep=-ep,eI.points=[T(ek,1),T(eS,1)]):A.current.rl=!1}if(e0&&"r"===ek[1]&&(meP||e7===eP&&(!et||e5>=eR)?(A.current.lr=!0,e_=e3,ep=-ep,eI.points=[T(ek,1),T(eS,1)]):A.current.lr=!1}tf();var e9=!0===eH?0:eH;"number"==typeof e9&&(meo.right&&(e_-=g-eo.right-ep,I.x>eo.right-e9&&(e_+=I.x-eo.right+e9)));var e8=!0===eV?0:eV;"number"==typeof e8&&(peo.bottom&&(eF-=h-eo.bottom-eh,I.y>eo.bottom-e8&&(eF+=I.y-eo.bottom+e8)));var te=R.x+e_,tt=R.y+eF,tr=I.x,to=I.y,ta=Math.max(te,tr),ti=Math.min(te+K,tr+Y),tl=Math.max(tt,to),ts=Math.min(tt+J,to+X);null==ej||ej(eJ,eI);var tc=ei.right-R.x-(e_+R.width),tu=ei.bottom-R.y-(eF+R.height);1===el&&(e_=Math.floor(e_),tc=Math.floor(tc)),1===es&&(eF=Math.floor(eF),tu=Math.floor(tu)),N({ready:!0,offsetX:e_/el,offsetY:eF/es,offsetR:tc/el,offsetB:tu/es,arrowX:((ta+ti)/2-te)/el,arrowY:((tl+ts)/2-tt)/es,scaleX:el,scaleY:es,align:eI})}function td(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:en,o=R.x+e,n=R.y+t,a=Math.max(o,r.left),i=Math.max(n,r.top);return Math.max(0,(Math.min(o+K,r.right)-a)*(Math.min(n+J,r.bottom)-i))}function tf(){h=(p=R.y+eF)+J,g=(m=R.x+e_)+K}}}),L=function(){N(function(e){return(0,t.default)((0,t.default)({},e),{},{ready:!1})})},(0,d.default)(L,[ev]),(0,d.default)(function(){tn||L()},[tn]),[R.ready,R.offsetX,R.offsetY,R.offsetR,R.offsetB,R.arrowX,R.arrowY,R.scaleX,R.scaleY,R.align,function(){M.current+=1;var e=M.current;Promise.resolve().then(function(){M.current===e&&z()})}]),tk=(0,r.default)(tS,11),tj=tk[0],tO=tk[1],tT=tk[2],tI=tk[3],t_=tk[4],tF=tk[5],tP=tk[6],tR=tk[7],tN=tk[8],tM=tk[9],tB=tk[10],tA=(0,v.default)(eL,void 0===X?"hover":X,Y,Q),tz=(0,r.default)(tA,2),tL=tz[0],tD=tz[1],tH=tL.has("click"),tV=tD.has("click")||tD.has("contextMenu"),tW=(0,c.default)(function(){th||tB()});D=function(){ti.current&&eS&&tV&&td(!1)},(0,d.default)(function(){if(tn&&e0&&eJ){var e=$(e0),t=$(eJ),r=w(eJ),o=new Set([r].concat((0,I.default)(e),(0,I.default)(t)));function n(){tW(),D()}return o.forEach(function(e){e.addEventListener("scroll",n,{passive:!0})}),r.addEventListener("resize",n,{passive:!0}),tW(),function(){o.forEach(function(e){e.removeEventListener("scroll",n),r.removeEventListener("resize",n)})}}},[tn,e0,eJ]),(0,d.default)(function(){tW()},[tC,ev]),(0,d.default)(function(){tn&&!(null!=eb&&eb[ev])&&tW()},[JSON.stringify(ew)]);var tU=p.useMemo(function(){var e=function(e,t,r,o){for(var n=r.points,a=Object.keys(e),i=0;i0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2?arguments[2]:void 0;return r?e[0]===t[0]:e[0]===t[0]&&e[1]===t[1]}(null==(l=e[s])?void 0:l.points,n,o))return"".concat(t,"-placement-").concat(s)}return""}(eb,J,tM,eS);return(0,a.default)(e,null==ex?void 0:ex(tM))},[tM,ex,eb,J,eS]);p.useImperativeHandle(x,function(){return{nativeElement:e2.current,popupElement:eX.current,forceAlign:tW}});var tG=p.useState(0),tq=(0,r.default)(tG,2),tJ=tq[0],tK=tq[1],tX=p.useState(0),tY=(0,r.default)(tX,2),tQ=tY[0],tZ=tY[1],t0=function(){if(eC&&e0){var e=e0.getBoundingClientRect();tK(e.width),tZ(e.height)}};function t1(e,t,r,o){e7[e]=function(n){var a;null==o||o(n),td(t,r);for(var i=arguments.length,l=Array(i>1?i-1:0),s=1;s1?r-1:0),n=1;n1?r-1:0),n=1;n{"use strict";var t=e.i(552821),r=e.i(931067),o=e.i(209428),n=e.i(703923),a=e.i(707067),i=e.i(343794),l=e.i(271645),s={shiftX:64,adjustY:1},c={adjustX:1,shiftY:!0},u=[0,0],d={left:{points:["cr","cl"],overflow:c,offset:[-4,0],targetOffset:u},right:{points:["cl","cr"],overflow:c,offset:[4,0],targetOffset:u},top:{points:["bc","tc"],overflow:s,offset:[0,-4],targetOffset:u},bottom:{points:["tc","bc"],overflow:s,offset:[0,4],targetOffset:u},topLeft:{points:["bl","tl"],overflow:s,offset:[0,-4],targetOffset:u},leftTop:{points:["tr","tl"],overflow:c,offset:[-4,0],targetOffset:u},topRight:{points:["br","tr"],overflow:s,offset:[0,-4],targetOffset:u},rightTop:{points:["tl","tr"],overflow:c,offset:[4,0],targetOffset:u},bottomRight:{points:["tr","br"],overflow:s,offset:[0,4],targetOffset:u},rightBottom:{points:["bl","br"],overflow:c,offset:[4,0],targetOffset:u},bottomLeft:{points:["tl","bl"],overflow:s,offset:[0,4],targetOffset:u},leftBottom:{points:["br","bl"],overflow:c,offset:[-4,0],targetOffset:u}},f=e.i(981444),p=["overlayClassName","trigger","mouseEnterDelay","mouseLeaveDelay","overlayStyle","prefixCls","children","onVisibleChange","afterVisibleChange","transitionName","animation","motion","placement","align","destroyTooltipOnHide","defaultVisible","getTooltipContainer","overlayInnerStyle","arrowContent","overlay","id","showArrow","classNames","styles"];let h=(0,l.forwardRef)(function(e,s){var c,u,h,m=e.overlayClassName,g=e.trigger,v=e.mouseEnterDelay,y=e.mouseLeaveDelay,b=e.overlayStyle,w=e.prefixCls,$=void 0===w?"rc-tooltip":w,C=e.children,x=e.onVisibleChange,E=e.afterVisibleChange,S=e.transitionName,k=e.animation,j=e.motion,O=e.placement,T=e.align,I=e.destroyTooltipOnHide,_=e.defaultVisible,F=e.getTooltipContainer,P=e.overlayInnerStyle,R=(e.arrowContent,e.overlay),N=e.id,M=e.showArrow,B=e.classNames,A=e.styles,z=(0,n.default)(e,p),L=(0,f.default)(N),D=(0,l.useRef)(null);(0,l.useImperativeHandle)(s,function(){return D.current});var H=(0,o.default)({},z);return"visible"in e&&(H.popupVisible=e.visible),l.createElement(a.default,(0,r.default)({popupClassName:(0,i.default)(m,null==B?void 0:B.root),prefixCls:$,popup:function(){return l.createElement(t.default,{key:"content",prefixCls:$,id:L,bodyClassName:null==B?void 0:B.body,overlayInnerStyle:(0,o.default)((0,o.default)({},P),null==A?void 0:A.body)},R)},action:void 0===g?["hover"]:g,builtinPlacements:d,popupPlacement:void 0===O?"right":O,ref:D,popupAlign:void 0===T?{}:T,getPopupContainer:F,onPopupVisibleChange:x,afterPopupVisibleChange:E,popupTransitionName:S,popupAnimation:k,popupMotion:j,defaultPopupVisible:_,autoDestroy:void 0!==I&&I,mouseLeaveDelay:void 0===y?.1:y,popupStyle:(0,o.default)((0,o.default)({},b),null==A?void 0:A.root),mouseEnterDelay:void 0===v?0:v,arrow:void 0===M||M},H),(u=(null==(c=l.Children.only(C))?void 0:c.props)||{},h=(0,o.default)((0,o.default)({},u),{},{"aria-describedby":R?L:null}),l.cloneElement(C,h)))});e.s(["default",0,h],793154)},495347,177886,786944,162129,197091,787894,696752,621796,e=>{"use strict";var t,r=e.i(271645);e.i(247167);var o=e.i(931067),n=e.i(703923),a=e.i(31575),i=e.i(33968),l=e.i(209428),s=e.i(8211),c=e.i(278409),u=e.i(233848),d=e.i(971151),f=e.i(868917),p=e.i(674813),h=e.i(211577),m=e.i(876556),g=e.i(929123),v=e.i(883110),y="RC_FORM_INTERNAL_HOOKS",b=function(){(0,v.default)(!1,"Can not find FormContext. Please make sure you wrap Field under Form.")},w=r.createContext({getFieldValue:b,getFieldsValue:b,getFieldError:b,getFieldWarning:b,getFieldsError:b,isFieldsTouched:b,isFieldTouched:b,isFieldValidating:b,isFieldsValidating:b,resetFields:b,setFields:b,setFieldValue:b,setFieldsValue:b,validateFields:b,submit:b,getInternalHooks:function(){return b(),{dispatch:b,initEntityValue:b,registerField:b,useSubscribe:b,setInitialValues:b,destroyForm:b,setCallbacks:b,registerWatch:b,getFields:b,setValidateMessages:b,setPreserve:b,getInitialValue:b}}});e.s(["HOOK_MARK",()=>y,"default",0,w],177886);var $=r.createContext(null);function C(e){return null==e?[]:Array.isArray(e)?e:[e]}e.s(["default",0,$],786944);var x=e.i(410160);function E(){return{default:"Validation error on field %s",required:"%s is required",enum:"%s must be one of %s",whitespace:"%s cannot be empty",date:{format:"%s date %s is invalid for format %s",parse:"%s date could not be parsed, %s is invalid ",invalid:"%s date %s is invalid"},types:{string:"%s is not a %s",method:"%s is not a %s (function)",array:"%s is not an %s",object:"%s is not an %s",number:"%s is not a %s",date:"%s is not a %s",boolean:"%s is not a %s",integer:"%s is not an %s",float:"%s is not a %s",regexp:"%s is not a valid %s",email:"%s is not a valid %s",tel:"%s is not a valid %s",url:"%s is not a valid %s",hex:"%s is not a valid %s"},string:{len:"%s must be exactly %s characters",min:"%s must be at least %s characters",max:"%s cannot be longer than %s characters",range:"%s must be between %s and %s characters"},number:{len:"%s must equal %s",min:"%s cannot be less than %s",max:"%s cannot be greater than %s",range:"%s must be between %s and %s"},array:{len:"%s must be exactly %s in length",min:"%s cannot be less than %s in length",max:"%s cannot be greater than %s in length",range:"%s must be between %s and %s in length"},pattern:{mismatch:"%s value %s does not match pattern %s"},clone:function(){var e=JSON.parse(JSON.stringify(this));return e.clone=this.clone,e}}}var S=E(),k=e.i(487806),j=e.i(885963),O=e.i(479671);function T(e){var t="function"==typeof Map?new Map:void 0;return(T=function(e){if(null===e||!function(e){try{return -1!==Function.toString.call(e).indexOf("[native code]")}catch(t){return"function"==typeof e}}(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,r)}function r(){return function(e,t,r){if((0,O.default)())return Reflect.construct.apply(null,arguments);var o=[null];o.push.apply(o,t);var n=new(e.bind.apply(e,o));return r&&(0,j.default)(n,r.prototype),n}(e,arguments,(0,k.default)(this).constructor)}return r.prototype=Object.create(e.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),(0,j.default)(r,e)})(e)}var I=/%[sdj%]/g;function _(e){if(!e||!e.length)return null;var t={};return e.forEach(function(e){var r=e.field;t[r]=t[r]||[],t[r].push(e)}),t}function F(e){for(var t=arguments.length,r=Array(t>1?t-1:0),o=1;o=a)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}}):e}function P(e,t){return!!(null==e||"array"===t&&Array.isArray(e)&&!e.length)||("string"===t||"url"===t||"hex"===t||"email"===t||"date"===t||"pattern"===t||"tel"===t)&&"string"==typeof e&&!e||!1}function R(e,t,r){var o=0,n=e.length;!function a(i){if(i&&i.length)return void r(i);var l=o;o+=1,l()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,H=/^(\+[0-9]{1,3}[-\s\u2011]?)?(\([0-9]{1,4}\)[-\s\u2011]?)?([0-9]+[-\s\u2011]?)*[0-9]+$/,V=/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i,W={integer:function(e){return W.number(e)&&parseInt(e,10)===e},float:function(e){return W.number(e)&&!W.integer(e)},array:function(e){return Array.isArray(e)},regexp:function(e){if(e instanceof RegExp)return!0;try{return new RegExp(e),!0}catch(e){return!1}},date:function(e){return"function"==typeof e.getTime&&"function"==typeof e.getMonth&&"function"==typeof e.getYear&&!isNaN(e.getTime())},number:function(e){return!isNaN(e)&&"number"==typeof e},object:function(e){return"object"===(0,x.default)(e)&&!W.array(e)},method:function(e){return"function"==typeof e},email:function(e){return"string"==typeof e&&e.length<=320&&!!e.match(D)},tel:function(e){return"string"==typeof e&&e.length<=32&&!!e.match(H)},url:function(e){return"string"==typeof e&&e.length<=2048&&!!e.match(L())},hex:function(e){return"string"==typeof e&&!!e.match(V)}};let U=z,G=function(e,t,r,o,n){(/^\s+$/.test(t)||""===t)&&o.push(F(n.messages.whitespace,e.fullField))},q=function(e,t,r,o,n){if(e.required&&void 0===t)return void z(e,t,r,o,n);var a=e.type;["integer","float","array","regexp","object","method","email","tel","number","date","url","hex"].indexOf(a)>-1?W[a](t)||o.push(F(n.messages.types[a],e.fullField,e.type)):a&&(0,x.default)(t)!==e.type&&o.push(F(n.messages.types[a],e.fullField,e.type))},J=function(e,t,r,o,n){var a="number"==typeof e.len,i="number"==typeof e.min,l="number"==typeof e.max,s=t,c=null,u="number"==typeof t,d="string"==typeof t,f=Array.isArray(t);if(u?c="number":d?c="string":f&&(c="array"),!c)return!1;f&&(s=t.length),d&&(s=t.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"_").length),a?s!==e.len&&o.push(F(n.messages[c].len,e.fullField,e.len)):i&&!l&&se.max?o.push(F(n.messages[c].max,e.fullField,e.max)):i&&l&&(se.max)&&o.push(F(n.messages[c].range,e.fullField,e.min,e.max))},K=function(e,t,r,o,n){e[A]=Array.isArray(e[A])?e[A]:[],-1===e[A].indexOf(t)&&o.push(F(n.messages[A],e.fullField,e[A].join(", ")))},X=function(e,t,r,o,n){e.pattern&&(e.pattern instanceof RegExp?(e.pattern.lastIndex=0,e.pattern.test(t)||o.push(F(n.messages.pattern.mismatch,e.fullField,t,e.pattern))):"string"==typeof e.pattern&&(new RegExp(e.pattern).test(t)||o.push(F(n.messages.pattern.mismatch,e.fullField,t,e.pattern))))},Y=function(e,t,r,o,n){var a=e.type,i=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t,a)&&!e.required)return r();U(e,t,o,i,n,a),P(t,a)||q(e,t,o,i,n)}r(i)},Q={string:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t,"string")&&!e.required)return r();U(e,t,o,a,n,"string"),P(t,"string")||(q(e,t,o,a,n),J(e,t,o,a,n),X(e,t,o,a,n),!0===e.whitespace&&G(e,t,o,a,n))}r(a)},method:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&q(e,t,o,a,n)}r(a)},number:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(""===t&&(t=void 0),P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&(q(e,t,o,a,n),J(e,t,o,a,n))}r(a)},boolean:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&q(e,t,o,a,n)}r(a)},regexp:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),P(t)||q(e,t,o,a,n)}r(a)},integer:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&(q(e,t,o,a,n),J(e,t,o,a,n))}r(a)},float:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&(q(e,t,o,a,n),J(e,t,o,a,n))}r(a)},array:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(null==t&&!e.required)return r();U(e,t,o,a,n,"array"),null!=t&&(q(e,t,o,a,n),J(e,t,o,a,n))}r(a)},object:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&q(e,t,o,a,n)}r(a)},enum:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n),void 0!==t&&K(e,t,o,a,n)}r(a)},pattern:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t,"string")&&!e.required)return r();U(e,t,o,a,n),P(t,"string")||X(e,t,o,a,n)}r(a)},date:function(e,t,r,o,n){var a,i=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t,"date")&&!e.required)return r();U(e,t,o,i,n),!P(t,"date")&&(a=t instanceof Date?t:new Date(t),q(e,a,o,i,n),a&&J(e,a.getTime(),o,i,n))}r(i)},url:Y,hex:Y,email:Y,tel:Y,required:function(e,t,r,o,n){var a=[],i=Array.isArray(t)?"array":(0,x.default)(t);U(e,t,o,a,n,i),r(a)},any:function(e,t,r,o,n){var a=[];if(e.required||!e.required&&o.hasOwnProperty(e.field)){if(P(t)&&!e.required)return r();U(e,t,o,a,n)}r(a)}};var Z=function(){function e(t){(0,c.default)(this,e),(0,h.default)(this,"rules",null),(0,h.default)(this,"_messages",S),this.define(t)}return(0,u.default)(e,[{key:"define",value:function(e){var t=this;if(!e)throw Error("Cannot configure a schema with no rules");if("object"!==(0,x.default)(e)||Array.isArray(e))throw Error("Rules must be an object");this.rules={},Object.keys(e).forEach(function(r){var o=e[r];t.rules[r]=Array.isArray(o)?o:[o]})}},{key:"messages",value:function(e){return e&&(this._messages=B(E(),e)),this._messages}},{key:"validate",value:function(t){var r=this,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},a=t,i=o,c=n;if("function"==typeof i&&(c=i,i={}),!this.rules||0===Object.keys(this.rules).length)return c&&c(null,a),Promise.resolve(a);if(i.messages){var u=this.messages();u===S&&(u=E()),B(u,i.messages),i.messages=u}else i.messages=this.messages();var d={};(i.keys||Object.keys(this.rules)).forEach(function(e){var o=r.rules[e],n=a[e];o.forEach(function(o){var i=o;"function"==typeof i.transform&&(a===t&&(a=(0,l.default)({},a)),null!=(n=a[e]=i.transform(n))&&(i.type=i.type||(Array.isArray(n)?"array":(0,x.default)(n)))),(i="function"==typeof i?{validator:i}:(0,l.default)({},i)).validator=r.getValidationMethod(i),i.validator&&(i.field=e,i.fullField=i.fullField||e,i.type=r.getType(i),d[e]=d[e]||[],d[e].push({rule:i,value:n,source:a,field:e}))})});var f={};return function(e,t,r,o,n){if(t.first){var a=new Promise(function(t,a){var i;R((i=[],Object.keys(e).forEach(function(t){i.push.apply(i,(0,s.default)(e[t]||[]))}),i),r,function(e){return o(e),e.length?a(new N(e,_(e))):t(n)})});return a.catch(function(e){return e}),a}var i=!0===t.firstFields?Object.keys(e):t.firstFields||[],l=Object.keys(e),c=l.length,u=0,d=[],f=new Promise(function(t,a){var f=function(e){if(d.push.apply(d,e),++u===c)return o(d),d.length?a(new N(d,_(d))):t(n)};l.length||(o(d),t(n)),l.forEach(function(t){var o=e[t];if(-1!==i.indexOf(t))R(o,r,f);else{var n=[],a=0,l=o.length;function c(e){n.push.apply(n,(0,s.default)(e||[])),++a===l&&f(n)}o.forEach(function(e){r(e,c)})}})});return f.catch(function(e){return e}),f}(d,i,function(t,r){var o,n,c,u=t.rule,d=("object"===u.type||"array"===u.type)&&("object"===(0,x.default)(u.fields)||"object"===(0,x.default)(u.defaultField));function p(e,t){return(0,l.default)((0,l.default)({},t),{},{fullField:"".concat(u.fullField,".").concat(e),fullFields:u.fullFields?[].concat((0,s.default)(u.fullFields),[e]):[e]})}function h(){var o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=Array.isArray(o)?o:[o];!i.suppressWarning&&n.length&&e.warning("async-validator:",n),n.length&&void 0!==u.message&&null!==u.message&&(n=[].concat(u.message));var c=n.map(M(u,a));if(i.first&&c.length)return f[u.field]=1,r(c);if(d){if(u.required&&!t.value)return void 0!==u.message?c=[].concat(u.message).map(M(u,a)):i.error&&(c=[i.error(u,F(i.messages.required,u.field))]),r(c);var h={};u.defaultField&&Object.keys(t.value).map(function(e){h[e]=u.defaultField});var m={};Object.keys(h=(0,l.default)((0,l.default)({},h),t.rule.fields)).forEach(function(e){var t=h[e],r=Array.isArray(t)?t:[t];m[e]=r.map(p.bind(null,e))});var g=new e(m);g.messages(i.messages),t.rule.options&&(t.rule.options.messages=i.messages,t.rule.options.error=i.error),g.validate(t.value,t.rule.options||i,function(e){var t=[];c&&c.length&&t.push.apply(t,(0,s.default)(c)),e&&e.length&&t.push.apply(t,(0,s.default)(e)),r(t.length?t:null)})}else r(c)}if(d=d&&(u.required||!u.required&&t.value),u.field=t.field,u.asyncValidator)o=u.asyncValidator(u,t.value,h,t.source,i);else if(u.validator){try{o=u.validator(u,t.value,h,t.source,i)}catch(e){null==(n=(c=console).error)||n.call(c,e),i.suppressValidatorError||setTimeout(function(){throw e},0),h(e.message)}!0===o?h():!1===o?h("function"==typeof u.message?u.message(u.fullField||u.field):u.message||"".concat(u.fullField||u.field," fails")):o instanceof Array?h(o):o instanceof Error&&h(o.message)}o&&o.then&&o.then(function(){return h()},function(e){return h(e)})},function(e){for(var t=[],r={},o=0;o0)){e.next=23;break}return e.next=21,Promise.all(o.map(function(e,r){return en("".concat(t,".").concat(r),e,f,i,c)}));case 21:return v=e.sent,e.abrupt("return",v.reduce(function(e,t){return[].concat((0,s.default)(e),(0,s.default)(t))},[]));case 23:return y=(0,l.default)((0,l.default)({},n),{},{name:t,enum:(n.enum||[]).join(", ")},c),b=g.map(function(e){return"string"==typeof e?function(e,t){return e.replace(/\\?\$\{\w+\}/g,function(e){return e.startsWith("\\")?e.slice(1):t[e.slice(2,-1)]})}(e,y):e}),e.abrupt("return",b);case 26:case"end":return e.stop()}},e,null,[[10,15]])}))).apply(this,arguments)}function ei(){return(ei=(0,i.default)((0,a.default)().mark(function e(t){return(0,a.default)().wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",Promise.all(t).then(function(e){var t;return(t=[]).concat.apply(t,(0,s.default)(e))}));case 1:case"end":return e.stop()}},e)}))).apply(this,arguments)}function el(){return(el=(0,i.default)((0,a.default)().mark(function e(t){var r;return(0,a.default)().wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return r=0,e.abrupt("return",new Promise(function(e){t.forEach(function(o){o.then(function(o){o.errors.length&&e([o]),(r+=1)===t.length&&e([])})})}));case 2:case"end":return e.stop()}},e)}))).apply(this,arguments)}var es=e.i(657791);function ec(e){return C(e)}function eu(e,t){var r={};return t.forEach(function(t){var o=(0,es.default)(e,t);r=(0,er.default)(r,t,o)}),r}function ed(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return e&&e.some(function(e){return ef(t,e,r)})}function ef(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return!!e&&!!t&&(!!r||e.length===t.length)&&t.every(function(t,r){return e[r]===t})}function ep(e){var t=arguments.length<=1?void 0:arguments[1];return t&&t.target&&"object"===(0,x.default)(t.target)&&e in t.target?t.target[e]:t}function eh(e,t,r){var o=e.length;if(t<0||t>=o||r<0||r>=o)return e;var n=e[t],a=t-r;return a>0?[].concat((0,s.default)(e.slice(0,r)),[n],(0,s.default)(e.slice(r,t)),(0,s.default)(e.slice(t+1,o))):a<0?[].concat((0,s.default)(e.slice(0,t)),(0,s.default)(e.slice(t+1,r+1)),[n],(0,s.default)(e.slice(r+1,o))):e}var em=es,eg=["name"],ev=[];function ey(e,t,r,o,n,a){return"function"==typeof e?e(t,r,"source"in a?{source:a.source}:{}):o!==n}var eb=function(e){(0,f.default)(o,e);var t=(0,p.default)(o);function o(e){var n;return(0,c.default)(this,o),n=t.call(this,e),(0,h.default)((0,d.default)(n),"state",{resetCount:0}),(0,h.default)((0,d.default)(n),"cancelRegisterFunc",null),(0,h.default)((0,d.default)(n),"mounted",!1),(0,h.default)((0,d.default)(n),"touched",!1),(0,h.default)((0,d.default)(n),"dirty",!1),(0,h.default)((0,d.default)(n),"validatePromise",void 0),(0,h.default)((0,d.default)(n),"prevValidating",void 0),(0,h.default)((0,d.default)(n),"errors",ev),(0,h.default)((0,d.default)(n),"warnings",ev),(0,h.default)((0,d.default)(n),"cancelRegister",function(){var e=n.props,t=e.preserve,r=e.isListField,o=e.name;n.cancelRegisterFunc&&n.cancelRegisterFunc(r,t,ec(o)),n.cancelRegisterFunc=null}),(0,h.default)((0,d.default)(n),"getNamePath",function(){var e=n.props,t=e.name,r=e.fieldContext.prefixName;return void 0!==t?[].concat((0,s.default)(void 0===r?[]:r),(0,s.default)(t)):[]}),(0,h.default)((0,d.default)(n),"getRules",function(){var e=n.props,t=e.rules,r=e.fieldContext;return(void 0===t?[]:t).map(function(e){return"function"==typeof e?e(r):e})}),(0,h.default)((0,d.default)(n),"refresh",function(){n.mounted&&n.setState(function(e){return{resetCount:e.resetCount+1}})}),(0,h.default)((0,d.default)(n),"metaCache",null),(0,h.default)((0,d.default)(n),"triggerMetaEvent",function(e){var t=n.props.onMetaChange;if(t){var r=(0,l.default)((0,l.default)({},n.getMeta()),{},{destroy:e});(0,g.default)(n.metaCache,r)||t(r),n.metaCache=r}else n.metaCache=null}),(0,h.default)((0,d.default)(n),"onStoreChange",function(e,t,r){var o=n.props,a=o.shouldUpdate,i=o.dependencies,l=void 0===i?[]:i,s=o.onReset,c=r.store,u=n.getNamePath(),d=n.getValue(e),f=n.getValue(c),p=t&&ed(t,u);switch("valueUpdate"===r.type&&"external"===r.source&&!(0,g.default)(d,f)&&(n.touched=!0,n.dirty=!0,n.validatePromise=null,n.errors=ev,n.warnings=ev,n.triggerMetaEvent()),r.type){case"reset":if(!t||p){n.touched=!1,n.dirty=!1,n.validatePromise=void 0,n.errors=ev,n.warnings=ev,n.triggerMetaEvent(),null==s||s(),n.refresh();return}break;case"remove":if(a&&ey(a,e,c,d,f,r))return void n.reRender();break;case"setField":var h=r.data;if(p){"touched"in h&&(n.touched=h.touched),"validating"in h&&!("originRCField"in h)&&(n.validatePromise=h.validating?Promise.resolve([]):null),"errors"in h&&(n.errors=h.errors||ev),"warnings"in h&&(n.warnings=h.warnings||ev),n.dirty=!0,n.triggerMetaEvent(),n.reRender();return}if("value"in h&&ed(t,u,!0)||a&&!u.length&&ey(a,e,c,d,f,r))return void n.reRender();break;case"dependenciesUpdate":if(l.map(ec).some(function(e){return ed(r.relatedFields,e)}))return void n.reRender();break;default:if(p||(!l.length||u.length||a)&&ey(a,e,c,d,f,r))return void n.reRender()}!0===a&&n.reRender()}),(0,h.default)((0,d.default)(n),"validateRules",function(e){var t=n.getNamePath(),r=n.getValue(),o=e||{},c=o.triggerName,u=o.validateOnly,d=Promise.resolve().then((0,i.default)((0,a.default)().mark(function o(){var u,f,p,h,m,g,y;return(0,a.default)().wrap(function(o){for(;;)switch(o.prev=o.next){case 0:if(n.mounted){o.next=2;break}return o.abrupt("return",[]);case 2:if(p=void 0!==(f=(u=n.props).validateFirst)&&f,h=u.messageVariables,m=u.validateDebounce,g=n.getRules(),c&&(g=g.filter(function(e){return e}).filter(function(e){var t=e.validateTrigger;return!t||C(t).includes(c)})),!(m&&c)){o.next=10;break}return o.next=8,new Promise(function(e){setTimeout(e,m)});case 8:if(n.validatePromise===d){o.next=10;break}return o.abrupt("return",[]);case 10:return(y=function(e,t,r,o,n,s){var c,u,d=e.join("."),f=r.map(function(e,t){var r=e.validator,o=(0,l.default)((0,l.default)({},e),{},{ruleIndex:t});return r&&(o.validator=function(e,t,o){var n=!1,a=r(e,t,function(){for(var e=arguments.length,t=Array(e),r=0;r0&&void 0!==arguments[0]?arguments[0]:ev;if(n.validatePromise===d){n.validatePromise=null;var t,r=[],o=[];null==(t=e.forEach)||t.call(e,function(e){var t=e.rule.warningOnly,n=e.errors,a=void 0===n?ev:n;t?o.push.apply(o,(0,s.default)(a)):r.push.apply(r,(0,s.default)(a))}),n.errors=r,n.warnings=o,n.triggerMetaEvent(),n.reRender()}}),o.abrupt("return",y);case 13:case"end":return o.stop()}},o)})));return void 0!==u&&u||(n.validatePromise=d,n.dirty=!0,n.errors=ev,n.warnings=ev,n.triggerMetaEvent(),n.reRender()),d}),(0,h.default)((0,d.default)(n),"isFieldValidating",function(){return!!n.validatePromise}),(0,h.default)((0,d.default)(n),"isFieldTouched",function(){return n.touched}),(0,h.default)((0,d.default)(n),"isFieldDirty",function(){return!!n.dirty||void 0!==n.props.initialValue||void 0!==(0,n.props.fieldContext.getInternalHooks(y).getInitialValue)(n.getNamePath())}),(0,h.default)((0,d.default)(n),"getErrors",function(){return n.errors}),(0,h.default)((0,d.default)(n),"getWarnings",function(){return n.warnings}),(0,h.default)((0,d.default)(n),"isListField",function(){return n.props.isListField}),(0,h.default)((0,d.default)(n),"isList",function(){return n.props.isList}),(0,h.default)((0,d.default)(n),"isPreserve",function(){return n.props.preserve}),(0,h.default)((0,d.default)(n),"getMeta",function(){return n.prevValidating=n.isFieldValidating(),{touched:n.isFieldTouched(),validating:n.prevValidating,errors:n.errors,warnings:n.warnings,name:n.getNamePath(),validated:null===n.validatePromise}}),(0,h.default)((0,d.default)(n),"getOnlyChild",function(e){if("function"==typeof e){var t=n.getMeta();return(0,l.default)((0,l.default)({},n.getOnlyChild(e(n.getControlled(),t,n.props.fieldContext))),{},{isFunction:!0})}var o=(0,m.default)(e);return 1===o.length&&r.isValidElement(o[0])?{child:o[0],isFunction:!1}:{child:o,isFunction:!1}}),(0,h.default)((0,d.default)(n),"getValue",function(e){var t=n.props.fieldContext.getFieldsValue,r=n.getNamePath();return(0,em.default)(e||t(!0),r)}),(0,h.default)((0,d.default)(n),"getControlled",function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=n.props,r=t.name,o=t.trigger,a=t.validateTrigger,i=t.getValueFromEvent,s=t.normalize,c=t.valuePropName,u=t.getValueProps,d=t.fieldContext,f=void 0!==a?a:d.validateTrigger,p=n.getNamePath(),m=d.getInternalHooks,g=d.getFieldsValue,v=m(y).dispatch,b=n.getValue(),w=u||function(e){return(0,h.default)({},c,e)},$=e[o],x=void 0!==r?w(b):{},E=(0,l.default)((0,l.default)({},e),x);return E[o]=function(){n.touched=!0,n.dirty=!0,n.triggerMetaEvent();for(var e,t=arguments.length,r=Array(t),o=0;o=0&&t<=r.length?(f.keys=[].concat((0,s.default)(f.keys.slice(0,t)),[f.id],(0,s.default)(f.keys.slice(t))),o([].concat((0,s.default)(r.slice(0,t)),[e],(0,s.default)(r.slice(t))))):(f.keys=[].concat((0,s.default)(f.keys),[f.id]),o([].concat((0,s.default)(r),[e]))),f.id+=1},remove:function(e){var t=i(),r=new Set(Array.isArray(e)?e:[e]);r.size<=0||(f.keys=f.keys.filter(function(e,t){return!r.has(t)}),o(t.filter(function(e,t){return!r.has(t)})))},move:function(e,t){if(e!==t){var r=i();e<0||e>=r.length||t<0||t>=r.length||(f.keys=eh(f.keys,e,t),o(eh(r,e,t)))}}},t)})))};e.s(["default",0,e$],197091);var eC=e.i(392221),ex="__@field_split__";function eE(e){return e.map(function(e){return"".concat((0,x.default)(e),":").concat(e)}).join(ex)}var eS=function(){function e(){(0,c.default)(this,e),(0,h.default)(this,"kvs",new Map)}return(0,u.default)(e,[{key:"set",value:function(e,t){this.kvs.set(eE(e),t)}},{key:"get",value:function(e){return this.kvs.get(eE(e))}},{key:"update",value:function(e,t){var r=t(this.get(e));r?this.set(e,r):this.delete(e)}},{key:"delete",value:function(e){this.kvs.delete(eE(e))}},{key:"map",value:function(e){return(0,s.default)(this.kvs.entries()).map(function(t){var r=(0,eC.default)(t,2),o=r[0],n=r[1];return e({key:o.split(ex).map(function(e){var t=e.match(/^([^:]*):(.*)$/),r=(0,eC.default)(t,3),o=r[1],n=r[2];return"number"===o?Number(n):n}),value:n})})}},{key:"toJSON",value:function(){var e={};return this.map(function(t){var r=t.key,o=t.value;return e[r.join(".")]=o,null}),e}}]),e}(),em=es,ek=["name"],ej=(0,u.default)(function e(t){var r=this;(0,c.default)(this,e),(0,h.default)(this,"formHooked",!1),(0,h.default)(this,"forceRootUpdate",void 0),(0,h.default)(this,"subscribable",!0),(0,h.default)(this,"store",{}),(0,h.default)(this,"fieldEntities",[]),(0,h.default)(this,"initialValues",{}),(0,h.default)(this,"callbacks",{}),(0,h.default)(this,"validateMessages",null),(0,h.default)(this,"preserve",null),(0,h.default)(this,"lastValidatePromise",null),(0,h.default)(this,"getForm",function(){return{getFieldValue:r.getFieldValue,getFieldsValue:r.getFieldsValue,getFieldError:r.getFieldError,getFieldWarning:r.getFieldWarning,getFieldsError:r.getFieldsError,isFieldsTouched:r.isFieldsTouched,isFieldTouched:r.isFieldTouched,isFieldValidating:r.isFieldValidating,isFieldsValidating:r.isFieldsValidating,resetFields:r.resetFields,setFields:r.setFields,setFieldValue:r.setFieldValue,setFieldsValue:r.setFieldsValue,validateFields:r.validateFields,submit:r.submit,_init:!0,getInternalHooks:r.getInternalHooks}}),(0,h.default)(this,"getInternalHooks",function(e){return e===y?(r.formHooked=!0,{dispatch:r.dispatch,initEntityValue:r.initEntityValue,registerField:r.registerField,useSubscribe:r.useSubscribe,setInitialValues:r.setInitialValues,destroyForm:r.destroyForm,setCallbacks:r.setCallbacks,setValidateMessages:r.setValidateMessages,getFields:r.getFields,setPreserve:r.setPreserve,getInitialValue:r.getInitialValue,registerWatch:r.registerWatch}):((0,v.default)(!1,"`getInternalHooks` is internal usage. Should not call directly."),null)}),(0,h.default)(this,"useSubscribe",function(e){r.subscribable=e}),(0,h.default)(this,"prevWithoutPreserves",null),(0,h.default)(this,"setInitialValues",function(e,t){if(r.initialValues=e||{},t){var o,n=(0,er.merge)(e,r.store);null==(o=r.prevWithoutPreserves)||o.map(function(t){var r=t.key;n=(0,er.default)(n,r,(0,em.default)(e,r))}),r.prevWithoutPreserves=null,r.updateStore(n)}}),(0,h.default)(this,"destroyForm",function(e){if(e)r.updateStore({});else{var t=new eS;r.getFieldEntities(!0).forEach(function(e){r.isMergedPreserve(e.isPreserve())||t.set(e.getNamePath(),!0)}),r.prevWithoutPreserves=t}}),(0,h.default)(this,"getInitialValue",function(e){var t=(0,em.default)(r.initialValues,e);return e.length?(0,er.merge)(t):t}),(0,h.default)(this,"setCallbacks",function(e){r.callbacks=e}),(0,h.default)(this,"setValidateMessages",function(e){r.validateMessages=e}),(0,h.default)(this,"setPreserve",function(e){r.preserve=e}),(0,h.default)(this,"watchList",[]),(0,h.default)(this,"registerWatch",function(e){return r.watchList.push(e),function(){r.watchList=r.watchList.filter(function(t){return t!==e})}}),(0,h.default)(this,"notifyWatch",function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];if(r.watchList.length){var t=r.getFieldsValue(),o=r.getFieldsValue(!0);r.watchList.forEach(function(r){r(t,o,e)})}}),(0,h.default)(this,"timeoutId",null),(0,h.default)(this,"warningUnhooked",function(){}),(0,h.default)(this,"updateStore",function(e){r.store=e}),(0,h.default)(this,"getFieldEntities",function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return e?r.fieldEntities.filter(function(e){return e.getNamePath().length}):r.fieldEntities}),(0,h.default)(this,"getFieldsMap",function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=new eS;return r.getFieldEntities(e).forEach(function(e){var r=e.getNamePath();t.set(r,e)}),t}),(0,h.default)(this,"getFieldEntitiesForNamePathList",function(e){if(!e)return r.getFieldEntities(!0);var t=r.getFieldsMap(!0);return e.map(function(e){var r=ec(e);return t.get(r)||{INVALIDATE_NAME_PATH:ec(e)}})}),(0,h.default)(this,"getFieldsValue",function(e,t){if(r.warningUnhooked(),!0===e||Array.isArray(e)?(o=e,n=t):e&&"object"===(0,x.default)(e)&&(a=e.strict,n=e.filter),!0===o&&!n)return r.store;var o,n,a,i=r.getFieldEntitiesForNamePathList(Array.isArray(o)?o:null),l=[];return i.forEach(function(e){var t,r,i,s="INVALIDATE_NAME_PATH"in e?e.INVALIDATE_NAME_PATH:e.getNamePath();if(a){if(null!=(i=e.isList)&&i.call(e))return}else if(!o&&null!=(t=(r=e).isListField)&&t.call(r))return;if(n){var c="getMeta"in e?e.getMeta():null;n(c)&&l.push(s)}else l.push(s)}),eu(r.store,l.map(ec))}),(0,h.default)(this,"getFieldValue",function(e){r.warningUnhooked();var t=ec(e);return(0,em.default)(r.store,t)}),(0,h.default)(this,"getFieldsError",function(e){return r.warningUnhooked(),r.getFieldEntitiesForNamePathList(e).map(function(t,r){return!t||"INVALIDATE_NAME_PATH"in t?{name:ec(e[r]),errors:[],warnings:[]}:{name:t.getNamePath(),errors:t.getErrors(),warnings:t.getWarnings()}})}),(0,h.default)(this,"getFieldError",function(e){r.warningUnhooked();var t=ec(e);return r.getFieldsError([t])[0].errors}),(0,h.default)(this,"getFieldWarning",function(e){r.warningUnhooked();var t=ec(e);return r.getFieldsError([t])[0].warnings}),(0,h.default)(this,"isFieldsTouched",function(){r.warningUnhooked();for(var e,t=arguments.length,o=Array(t),n=0;n0&&void 0!==arguments[0]?arguments[0]:{},o=new eS,n=r.getFieldEntities(!0);n.forEach(function(e){var t=e.props.initialValue,r=e.getNamePath();if(void 0!==t){var n=o.get(r)||new Set;n.add({entity:e,value:t}),o.set(r,n)}}),t.entities?e=t.entities:t.namePathList?(e=[],t.namePathList.forEach(function(t){var r,n=o.get(t);n&&(r=e).push.apply(r,(0,s.default)((0,s.default)(n).map(function(e){return e.entity})))})):e=n,e.forEach(function(e){if(void 0!==e.props.initialValue){var n=e.getNamePath();if(void 0!==r.getInitialValue(n))(0,v.default)(!1,"Form already set 'initialValues' with path '".concat(n.join("."),"'. Field can not overwrite it."));else{var a=o.get(n);if(a&&a.size>1)(0,v.default)(!1,"Multiple Field with path '".concat(n.join("."),"' set 'initialValue'. Can not decide which one to pick."));else if(a){var i=r.getFieldValue(n);e.isListField()||t.skipExist&&void 0!==i||r.updateStore((0,er.default)(r.store,n,(0,s.default)(a)[0].value))}}}})}),(0,h.default)(this,"resetFields",function(e){r.warningUnhooked();var t=r.store;if(!e){r.updateStore((0,er.merge)(r.initialValues)),r.resetWithFieldInitialValue(),r.notifyObservers(t,null,{type:"reset"}),r.notifyWatch();return}var o=e.map(ec);o.forEach(function(e){var t=r.getInitialValue(e);r.updateStore((0,er.default)(r.store,e,t))}),r.resetWithFieldInitialValue({namePathList:o}),r.notifyObservers(t,o,{type:"reset"}),r.notifyWatch(o)}),(0,h.default)(this,"setFields",function(e){r.warningUnhooked();var t=r.store,o=[];e.forEach(function(e){var a=e.name,i=(0,n.default)(e,ek),l=ec(a);o.push(l),"value"in i&&r.updateStore((0,er.default)(r.store,l,i.value)),r.notifyObservers(t,[l],{type:"setField",data:e})}),r.notifyWatch(o)}),(0,h.default)(this,"getFields",function(){return r.getFieldEntities(!0).map(function(e){var t=e.getNamePath(),o=e.getMeta(),n=(0,l.default)((0,l.default)({},o),{},{name:t,value:r.getFieldValue(t)});return Object.defineProperty(n,"originRCField",{value:!0}),n})}),(0,h.default)(this,"initEntityValue",function(e){var t=e.props.initialValue;if(void 0!==t){var o=e.getNamePath();void 0===(0,em.default)(r.store,o)&&r.updateStore((0,er.default)(r.store,o,t))}}),(0,h.default)(this,"isMergedPreserve",function(e){var t=void 0!==e?e:r.preserve;return null==t||t}),(0,h.default)(this,"registerField",function(e){r.fieldEntities.push(e);var t=e.getNamePath();if(r.notifyWatch([t]),void 0!==e.props.initialValue){var o=r.store;r.resetWithFieldInitialValue({entities:[e],skipExist:!0}),r.notifyObservers(o,[e.getNamePath()],{type:"valueUpdate",source:"internal"})}return function(o,n){var a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];if(r.fieldEntities=r.fieldEntities.filter(function(t){return t!==e}),!r.isMergedPreserve(n)&&(!o||a.length>1)){var i=o?void 0:r.getInitialValue(t);if(t.length&&r.getFieldValue(t)!==i&&r.fieldEntities.every(function(e){return!ef(e.getNamePath(),t)})){var l=r.store;r.updateStore((0,er.default)(l,t,i,!0)),r.notifyObservers(l,[t],{type:"remove"}),r.triggerDependenciesUpdate(l,t)}}r.notifyWatch([t])}}),(0,h.default)(this,"dispatch",function(e){switch(e.type){case"updateValue":var t=e.namePath,o=e.value;r.updateValue(t,o);break;case"validateField":var n=e.namePath,a=e.triggerName;r.validateFields([n],{triggerName:a})}}),(0,h.default)(this,"notifyObservers",function(e,t,o){if(r.subscribable){var n=(0,l.default)((0,l.default)({},o),{},{store:r.getFieldsValue(!0)});r.getFieldEntities().forEach(function(r){(0,r.onStoreChange)(e,t,n)})}else r.forceRootUpdate()}),(0,h.default)(this,"triggerDependenciesUpdate",function(e,t){var o=r.getDependencyChildrenFields(t);return o.length&&r.validateFields(o),r.notifyObservers(e,o,{type:"dependenciesUpdate",relatedFields:[t].concat((0,s.default)(o))}),o}),(0,h.default)(this,"updateValue",function(e,t){var o=ec(e),n=r.store;r.updateStore((0,er.default)(r.store,o,t)),r.notifyObservers(n,[o],{type:"valueUpdate",source:"internal"}),r.notifyWatch([o]);var a=r.triggerDependenciesUpdate(n,o),i=r.callbacks.onValuesChange;i&&i(eu(r.store,[o]),r.getFieldsValue()),r.triggerOnFieldsChange([o].concat((0,s.default)(a)))}),(0,h.default)(this,"setFieldsValue",function(e){r.warningUnhooked();var t=r.store;if(e){var o=(0,er.merge)(r.store,e);r.updateStore(o)}r.notifyObservers(t,null,{type:"valueUpdate",source:"external"}),r.notifyWatch()}),(0,h.default)(this,"setFieldValue",function(e,t){r.setFields([{name:e,value:t,errors:[],warnings:[]}])}),(0,h.default)(this,"getDependencyChildrenFields",function(e){var t=new Set,o=[],n=new eS;return r.getFieldEntities().forEach(function(e){(e.props.dependencies||[]).forEach(function(t){var r=ec(t);n.update(r,function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:new Set;return t.add(e),t})})}),!function e(r){(n.get(r)||new Set).forEach(function(r){if(!t.has(r)){t.add(r);var n=r.getNamePath();r.isFieldDirty()&&n.length&&(o.push(n),e(n))}})}(e),o}),(0,h.default)(this,"triggerOnFieldsChange",function(e,t){var o=r.callbacks.onFieldsChange;if(o){var n=r.getFields();if(t){var a=new eS;t.forEach(function(e){var t=e.name,r=e.errors;a.set(t,r)}),n.forEach(function(e){e.errors=a.get(e.name)||e.errors})}var i=n.filter(function(t){return ed(e,t.name)});i.length&&o(i,n)}}),(0,h.default)(this,"validateFields",function(e,t){r.warningUnhooked(),Array.isArray(e)||"string"==typeof e||"string"==typeof t?(i=e,c=t):c=e;var o,n,a,i,c,u=!!i,d=u?i.map(ec):[],f=[],p=String(Date.now()),h=new Set,m=c||{},g=m.recursive,v=m.dirty;r.getFieldEntities(!0).forEach(function(e){if((u||d.push(e.getNamePath()),e.props.rules&&e.props.rules.length)&&(!v||e.isFieldDirty())){var t=e.getNamePath();if(h.add(t.join(p)),!u||ed(d,t,g)){var o=e.validateRules((0,l.default)({validateMessages:(0,l.default)((0,l.default)({},et),r.validateMessages)},c));f.push(o.then(function(){return{name:t,errors:[],warnings:[]}}).catch(function(e){var r,o=[],n=[];return(null==(r=e.forEach)||r.call(e,function(e){var t=e.rule.warningOnly,r=e.errors;t?n.push.apply(n,(0,s.default)(r)):o.push.apply(o,(0,s.default)(r))}),o.length)?Promise.reject({name:t,errors:o,warnings:n}):{name:t,errors:o,warnings:n}}))}}});var y=(o=!1,n=f.length,a=[],f.length?new Promise(function(e,t){f.forEach(function(r,i){r.catch(function(e){return o=!0,e}).then(function(r){n-=1,a[i]=r,n>0||(o&&t(a),e(a))})})}):Promise.resolve([]));r.lastValidatePromise=y,y.catch(function(e){return e}).then(function(e){var t=e.map(function(e){return e.name});r.notifyObservers(r.store,t,{type:"validateFinish"}),r.triggerOnFieldsChange(t,e)});var b=y.then(function(){return r.lastValidatePromise===y?Promise.resolve(r.getFieldsValue(d)):Promise.reject([])}).catch(function(e){var t=e.filter(function(e){return e&&e.errors.length});return Promise.reject({values:r.getFieldsValue(d),errorFields:t,outOfDate:r.lastValidatePromise!==y})});b.catch(function(e){return e});var w=d.filter(function(e){return h.has(e.join(p))});return r.triggerOnFieldsChange(w),b}),(0,h.default)(this,"submit",function(){r.warningUnhooked(),r.validateFields().then(function(e){var t=r.callbacks.onFinish;if(t)try{t(e)}catch(e){console.error(e)}}).catch(function(e){var t=r.callbacks.onFinishFailed;t&&t(e)})}),this.forceRootUpdate=t});let eO=function(e){var t=r.useRef(),o=r.useState({}),n=(0,eC.default)(o,2)[1];return t.current||(e?t.current=e:t.current=new ej(function(){n({})}).getForm()),[t.current]};e.s(["default",0,eO],787894);var eT=r.createContext({triggerFormChange:function(){},triggerFormFinish:function(){},registerForm:function(){},unregisterForm:function(){}}),eI=function(e){var t=e.validateMessages,o=e.onFormChange,n=e.onFormFinish,a=e.children,i=r.useContext(eT),s=r.useRef({});return r.createElement(eT.Provider,{value:(0,l.default)((0,l.default)({},i),{},{validateMessages:(0,l.default)((0,l.default)({},i.validateMessages),t),triggerFormChange:function(e,t){o&&o(e,{changedFields:t,forms:s.current}),i.triggerFormChange(e,t)},triggerFormFinish:function(e,t){n&&n(e,{values:t,forms:s.current}),i.triggerFormFinish(e,t)},registerForm:function(e,t){e&&(s.current=(0,l.default)((0,l.default)({},s.current),{},(0,h.default)({},e,t))),i.registerForm(e,t)},unregisterForm:function(e){var t=(0,l.default)({},s.current);delete t[e],s.current=t,i.unregisterForm(e)}})},a)};e.s(["FormProvider",()=>eI,"default",0,eT],696752);var e_=["name","initialValues","fields","form","preserve","children","component","validateMessages","validateTrigger","onValuesChange","onFieldsChange","onFinish","onFinishFailed","clearOnDestroy"],em=es;function eF(e){try{return JSON.stringify(e)}catch(e){return Math.random()}}var eP=function(){};let eR=function(){for(var e=arguments.length,t=Array(e),o=0;o1?t-1:0),o=1;o{"use strict";function t(e,t){var r=Object.assign({},e);return Array.isArray(t)&&t.forEach(function(e){delete r[e]}),r}e.s(["default",()=>t])},62139,e=>{"use strict";var t=e.i(271645);e.i(495347);var r=e.i(696752),o=e.i(529681);let n=t.createContext({labelAlign:"right",layout:"horizontal",itemRef:()=>{}}),a=t.createContext(null),i=t.createContext({prefixCls:""}),l=t.createContext({}),s=t.createContext(void 0);e.s(["FormContext",0,n,"FormItemInputContext",0,l,"FormItemPrefixContext",0,i,"FormProvider",0,e=>{let n=(0,o.default)(e,["prefixCls"]);return t.createElement(r.FormProvider,Object.assign({},n))},"NoFormStyle",0,({children:e,status:r,override:o})=>{let n=t.useContext(l),a=t.useMemo(()=>{let e=Object.assign({},n);return o&&delete e.isFormItemInput,r&&(delete e.status,delete e.hasFeedback,delete e.feedbackIcon),e},[r,o,n]);return t.createElement(l.Provider,{value:a},e)},"NoStyleItemContext",0,a,"VariantContext",0,s])},517455,e=>{"use strict";var t=e.i(271645),r=e.i(666365);e.s(["default",0,e=>{let o=t.default.useContext(r.default);return t.default.useMemo(()=>e?"string"==typeof e?null!=e?e:o:"function"==typeof e?e(o):o:o,[e,o])}])},249616,e=>{"use strict";var t=e.i(271645),r=e.i(343794),o=e.i(876556),n=e.i(242064),a=e.i(517455);let i=(0,e.i(246422).genStyleHooks)(["Space","Compact"],e=>[(e=>{let{componentCls:t}=e;return{[t]:{display:"inline-flex","&-block":{display:"flex",width:"100%"},"&-vertical":{flexDirection:"column"},"&-rtl":{direction:"rtl"}}}})(e)],()=>({}),{resetStyle:!1});var l=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let s=t.createContext(null),c=e=>{let{children:r}=e,o=l(e,["children"]);return t.createElement(s.Provider,{value:t.useMemo(()=>o,[o])},r)};e.s(["NoCompactStyle",0,e=>{let{children:r}=e;return t.createElement(s.Provider,{value:null},r)},"default",0,e=>{let{getPrefixCls:u,direction:d}=t.useContext(n.ConfigContext),{size:f,direction:p,block:h,prefixCls:m,className:g,rootClassName:v,children:y}=e,b=l(e,["size","direction","block","prefixCls","className","rootClassName","children"]),w=(0,a.default)(e=>null!=f?f:e),$=u("space-compact",m),[C,x]=i($),E=(0,r.default)($,x,{[`${$}-rtl`]:"rtl"===d,[`${$}-block`]:h,[`${$}-vertical`]:"vertical"===p},g,v),S=t.useContext(s),k=(0,o.default)(y),j=t.useMemo(()=>k.map((e,r)=>{let o=(null==e?void 0:e.key)||`${$}-item-${r}`;return t.createElement(c,{key:o,compactSize:w,compactDirection:p,isFirstItem:0===r&&(!S||(null==S?void 0:S.isFirstItem)),isLastItem:r===k.length-1&&(!S||(null==S?void 0:S.isLastItem))},e)}),[k,S,p,w,$]);return 0===k.length?null:C(t.createElement("div",Object.assign({className:E},b),j))},"useCompactItemContext",0,(e,o)=>{let n=t.useContext(s),a=t.useMemo(()=>{if(!n)return"";let{compactDirection:t,isFirstItem:a,isLastItem:i}=n,l="vertical"===t?"-vertical-":"-";return(0,r.default)(`${e}-compact${l}item`,{[`${e}-compact${l}first-item`]:a,[`${e}-compact${l}last-item`]:i,[`${e}-compact${l}item-rtl`]:"rtl"===o})},[e,o,n]);return{compactSize:null==n?void 0:n.compactSize,compactDirection:null==n?void 0:n.compactDirection,compactItemClassnames:a}}],249616)},617206,e=>{"use strict";var t=e.i(271645),r=e.i(62139),o=e.i(249616);e.s(["default",0,e=>{let{space:n,form:a,children:i}=e;if(null==i)return null;let l=i;return a&&(l=t.default.createElement(r.NoFormStyle,{override:!0,status:!0},l)),n&&(l=t.default.createElement(o.NoCompactStyle,null,l)),l}])},613541,e=>{"use strict";var t=e.i(242064);let r=()=>({height:0,opacity:0}),o=e=>{let{scrollHeight:t}=e;return{height:t,opacity:1}},n=e=>({height:e?e.offsetHeight:0}),a=(e,t)=>(null==t?void 0:t.deadline)===!0||"height"===t.propertyName,i=(e,t,r)=>void 0!==r?r:`${e}-${t}`;e.s(["default",0,(e=t.defaultPrefixCls)=>({motionName:`${e}-motion-collapse`,onAppearStart:r,onEnterStart:r,onAppearActive:o,onEnterActive:o,onLeaveStart:n,onLeaveActive:r,onAppearEnd:a,onEnterEnd:a,onLeaveEnd:a,motionDeadline:500}),"getTransitionName",()=>i])},805984,307358,320560,e=>{"use strict";e.i(296059);var t=e.i(915654);function r(e){let{sizePopupArrow:t,borderRadiusXS:r,borderRadiusOuter:o}=e,n=t/2,a=o/Math.sqrt(2),i=n-o*(1-1/Math.sqrt(2)),l=n-1/Math.sqrt(2)*r,s=o*(Math.sqrt(2)-1)+1/Math.sqrt(2)*r,c=n*Math.sqrt(2)+o*(Math.sqrt(2)-2),u=o*(Math.sqrt(2)-1),d=`polygon(${u}px 100%, 50% ${u}px, ${2*n-u}px 100%, ${u}px 100%)`;return{arrowShadowWidth:c,arrowPath:`path('M 0 ${n} A ${o} ${o} 0 0 0 ${a} ${i} L ${l} ${s} A ${r} ${r} 0 0 1 ${2*n-l} ${s} L ${2*n-a} ${i} A ${o} ${o} 0 0 0 ${2*n-0} ${n} Z')`,arrowPolygon:d}}let o=(e,r,o)=>{let{sizePopupArrow:n,arrowPolygon:a,arrowPath:i,arrowShadowWidth:l,borderRadiusXS:s,calc:c}=e;return{pointerEvents:"none",width:n,height:n,overflow:"hidden","&::before":{position:"absolute",bottom:0,insetInlineStart:0,width:n,height:c(n).div(2).equal(),background:r,clipPath:{_multi_value_:!0,value:[a,i]},content:'""'},"&::after":{content:'""',position:"absolute",width:l,height:l,bottom:0,insetInline:0,margin:"auto",borderRadius:{_skip_check_:!0,value:`0 0 ${(0,t.unit)(s)} 0`},transform:"translateY(50%) rotate(-135deg)",boxShadow:o,zIndex:0,background:"transparent"}}};function n(e){let{contentRadius:t,limitVerticalRadius:r}=e,o=t>12?t+2:12;return{arrowOffsetHorizontal:o,arrowOffsetVertical:r?8:o}}function a(e,r,n){var a,i,l,s,c,u,d,f;let{componentCls:p,boxShadowPopoverArrow:h,arrowOffsetVertical:m,arrowOffsetHorizontal:g}=e,{arrowDistance:v=0,arrowPlacement:y={left:!0,right:!0,top:!0,bottom:!0}}=n||{};return{[p]:Object.assign(Object.assign(Object.assign(Object.assign({[`${p}-arrow`]:[Object.assign(Object.assign({position:"absolute",zIndex:1,display:"block"},o(e,r,h)),{"&:before":{background:r}})]},(a=!!y.top,i={[`&-placement-top > ${p}-arrow,&-placement-topLeft > ${p}-arrow,&-placement-topRight > ${p}-arrow`]:{bottom:v,transform:"translateY(100%) rotate(180deg)"},[`&-placement-top > ${p}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(100%) rotate(180deg)"},"&-placement-topLeft":{"--arrow-offset-horizontal":g,[`> ${p}-arrow`]:{left:{_skip_check_:!0,value:g}}},"&-placement-topRight":{"--arrow-offset-horizontal":`calc(100% - ${(0,t.unit)(g)})`,[`> ${p}-arrow`]:{right:{_skip_check_:!0,value:g}}}},a?i:{})),(l=!!y.bottom,s={[`&-placement-bottom > ${p}-arrow,&-placement-bottomLeft > ${p}-arrow,&-placement-bottomRight > ${p}-arrow`]:{top:v,transform:"translateY(-100%)"},[`&-placement-bottom > ${p}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(-100%)"},"&-placement-bottomLeft":{"--arrow-offset-horizontal":g,[`> ${p}-arrow`]:{left:{_skip_check_:!0,value:g}}},"&-placement-bottomRight":{"--arrow-offset-horizontal":`calc(100% - ${(0,t.unit)(g)})`,[`> ${p}-arrow`]:{right:{_skip_check_:!0,value:g}}}},l?s:{})),(c=!!y.left,u={[`&-placement-left > ${p}-arrow,&-placement-leftTop > ${p}-arrow,&-placement-leftBottom > ${p}-arrow`]:{right:{_skip_check_:!0,value:v},transform:"translateX(100%) rotate(90deg)"},[`&-placement-left > ${p}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(100%) rotate(90deg)"},[`&-placement-leftTop > ${p}-arrow`]:{top:m},[`&-placement-leftBottom > ${p}-arrow`]:{bottom:m}},c?u:{})),(d=!!y.right,f={[`&-placement-right > ${p}-arrow,&-placement-rightTop > ${p}-arrow,&-placement-rightBottom > ${p}-arrow`]:{left:{_skip_check_:!0,value:v},transform:"translateX(-100%) rotate(-90deg)"},[`&-placement-right > ${p}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(-100%) rotate(-90deg)"},[`&-placement-rightTop > ${p}-arrow`]:{top:m},[`&-placement-rightBottom > ${p}-arrow`]:{bottom:m}},d?f:{}))}}e.s(["genRoundedArrow",0,o,"getArrowToken",()=>r],307358),e.s(["MAX_VERTICAL_CONTENT_RADIUS",0,8,"default",()=>a,"getArrowOffsetToken",()=>n],320560);let i={left:{points:["cr","cl"]},right:{points:["cl","cr"]},top:{points:["bc","tc"]},bottom:{points:["tc","bc"]},topLeft:{points:["bl","tl"]},leftTop:{points:["tr","tl"]},topRight:{points:["br","tr"]},rightTop:{points:["tl","tr"]},bottomRight:{points:["tr","br"]},rightBottom:{points:["bl","br"]},bottomLeft:{points:["tl","bl"]},leftBottom:{points:["br","bl"]}},l={topLeft:{points:["bl","tc"]},leftTop:{points:["tr","cl"]},topRight:{points:["br","tc"]},rightTop:{points:["tl","cr"]},bottomRight:{points:["tr","bc"]},rightBottom:{points:["bl","cr"]},bottomLeft:{points:["tl","bc"]},leftBottom:{points:["br","cl"]}},s=new Set(["topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"]);function c(e){let{arrowWidth:t,autoAdjustOverflow:r,arrowPointAtCenter:o,offset:a,borderRadius:c,visibleFirst:u}=e,d=t/2,f={},p=n({contentRadius:c,limitVerticalRadius:!0});return Object.keys(i).forEach(e=>{let n=Object.assign(Object.assign({},o&&l[e]||i[e]),{offset:[0,0],dynamicInset:!0});switch(f[e]=n,s.has(e)&&(n.autoArrow=!1),e){case"top":case"topLeft":case"topRight":n.offset[1]=-d-a;break;case"bottom":case"bottomLeft":case"bottomRight":n.offset[1]=d+a;break;case"left":case"leftTop":case"leftBottom":n.offset[0]=-d-a;break;case"right":case"rightTop":case"rightBottom":n.offset[0]=d+a}if(o)switch(e){case"topLeft":case"bottomLeft":n.offset[0]=-p.arrowOffsetHorizontal-d;break;case"topRight":case"bottomRight":n.offset[0]=p.arrowOffsetHorizontal+d;break;case"leftTop":case"rightTop":n.offset[1]=-(2*p.arrowOffsetHorizontal)+d;break;case"leftBottom":case"rightBottom":n.offset[1]=2*p.arrowOffsetHorizontal-d}n.overflow=function(e,t,r,o){if(!1===o)return{adjustX:!1,adjustY:!1};let n={};switch(e){case"top":case"bottom":n.shiftX=2*t.arrowOffsetHorizontal+r,n.shiftY=!0,n.adjustY=!0;break;case"left":case"right":n.shiftY=2*t.arrowOffsetVertical+r,n.shiftX=!0,n.adjustX=!0}let a=Object.assign(Object.assign({},n),o&&"object"==typeof o?o:{});return a.shiftX||(a.adjustX=!0),a.shiftY||(a.adjustY=!0),a}(e,p,t,r),u&&(n.htmlRegion="visibleFirst")}),f}e.s(["default",()=>c],805984)},763731,e=>{"use strict";var t=e.i(271645);function r(e){return e&&t.default.isValidElement(e)&&e.type===t.default.Fragment}let o=(e,r,o)=>t.default.isValidElement(e)?t.default.cloneElement(e,"function"==typeof o?o(e.props||{}):o):r;function n(e,t){return o(e,e,t)}e.s(["cloneElement",()=>n,"isFragment",()=>r,"replaceElement",0,o])},880476,e=>{"use strict";var t=e.i(552821);e.s(["Popup",()=>t.default])},402366,e=>{"use strict";e.s(["initMotion",0,(e,t,r,o,n=!1)=>{let a=n?"&":"";return{[` - ${a}${e}-enter, - ${a}${e}-appear - `]:Object.assign(Object.assign({},{animationDuration:o,animationFillMode:"both"}),{animationPlayState:"paused"}),[`${a}${e}-leave`]:Object.assign(Object.assign({},{animationDuration:o,animationFillMode:"both"}),{animationPlayState:"paused"}),[` - ${a}${e}-enter${e}-enter-active, - ${a}${e}-appear${e}-appear-active - `]:{animationName:t,animationPlayState:"running"},[`${a}${e}-leave${e}-leave-active`]:{animationName:r,animationPlayState:"running",pointerEvents:"none"}}}])},717356,e=>{"use strict";e.i(296059);var t=e.i(694758),r=e.i(402366);let o=new t.Keyframes("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),n=new t.Keyframes("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),a=new t.Keyframes("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),i=new t.Keyframes("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),l=new t.Keyframes("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),s=new t.Keyframes("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),c={zoom:{inKeyframes:o,outKeyframes:n},"zoom-big":{inKeyframes:a,outKeyframes:i},"zoom-big-fast":{inKeyframes:a,outKeyframes:i},"zoom-left":{inKeyframes:new t.Keyframes("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),outKeyframes:new t.Keyframes("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}})},"zoom-right":{inKeyframes:new t.Keyframes("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),outKeyframes:new t.Keyframes("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}})},"zoom-up":{inKeyframes:l,outKeyframes:s},"zoom-down":{inKeyframes:new t.Keyframes("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),outKeyframes:new t.Keyframes("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}})}};e.s(["initZoomMotion",0,(e,t)=>{let{antCls:o}=e,n=`${o}-${t}`,{inKeyframes:a,outKeyframes:i}=c[t];return[(0,r.initMotion)(n,a,i,"zoom-big-fast"===t?e.motionDurationFast:e.motionDurationMid),{[` - ${n}-enter, - ${n}-appear - `]:{transform:"scale(0)",opacity:0,animationTimingFunction:e.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${n}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]},"zoomIn",0,o])},617933,e=>{"use strict";e.s(["PresetColors",0,["blue","purple","cyan","green","magenta","pink","red","orange","yellow","volcano","geekblue","lime","gold"]])},403541,e=>{"use strict";var t=e.i(617933);function r(e,r){return t.PresetColors.reduce((t,o)=>{let n=e[`${o}1`],a=e[`${o}3`],i=e[`${o}6`],l=e[`${o}7`];return Object.assign(Object.assign({},t),r(o,{lightColor:n,lightBorderColor:a,darkColor:i,textColor:l}))},{})}e.s(["genPresetColor",()=>r],403541)},57667,e=>{"use strict";e.i(296059);var t=e.i(915654),r=e.i(183293),o=e.i(717356),n=e.i(320560),a=e.i(307358),i=e.i(403541),l=e.i(246422),s=e.i(838378);let c=e=>Object.assign(Object.assign({zIndexPopup:e.zIndexPopupBase+70},(0,n.getArrowOffsetToken)({contentRadius:e.borderRadius,limitVerticalRadius:!0})),(0,a.getArrowToken)((0,s.mergeToken)(e,{borderRadiusOuter:Math.min(e.borderRadiusOuter,4)})));e.s(["default",0,(e,a=!0)=>(0,l.genStyleHooks)("Tooltip",e=>{let{borderRadius:a,colorTextLightSolid:l,colorBgSpotlight:c}=e;return[(e=>{let{calc:o,componentCls:a,tooltipMaxWidth:l,tooltipColor:s,tooltipBg:c,tooltipBorderRadius:u,zIndexPopup:d,controlHeight:f,boxShadowSecondary:p,paddingSM:h,paddingXS:m,arrowOffsetHorizontal:g,sizePopupArrow:v}=e,y=o(u).add(v).add(g).equal(),b=o(u).mul(2).add(v).equal();return[{[a]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,r.resetComponent)(e)),{position:"absolute",zIndex:d,display:"block",width:"max-content",maxWidth:l,visibility:"visible","--valid-offset-x":"var(--arrow-offset-horizontal, var(--arrow-x))",transformOrigin:"var(--valid-offset-x, 50%) var(--arrow-y, 50%)","&-hidden":{display:"none"},"--antd-arrow-background-color":c,[`${a}-inner`]:{minWidth:b,minHeight:f,padding:`${(0,t.unit)(e.calc(h).div(2).equal())} ${(0,t.unit)(m)}`,color:`var(--ant-tooltip-color, ${s})`,textAlign:"start",textDecoration:"none",wordWrap:"break-word",backgroundColor:c,borderRadius:u,boxShadow:p,boxSizing:"border-box"},"&-placement-topLeft,&-placement-topRight,&-placement-bottomLeft,&-placement-bottomRight":{minWidth:y},"&-placement-left,&-placement-leftTop,&-placement-leftBottom,&-placement-right,&-placement-rightTop,&-placement-rightBottom":{[`${a}-inner`]:{borderRadius:e.min(u,n.MAX_VERTICAL_CONTENT_RADIUS)}},[`${a}-content`]:{position:"relative"}}),(0,i.genPresetColor)(e,(e,{darkColor:t})=>({[`&${a}-${e}`]:{[`${a}-inner`]:{backgroundColor:t},[`${a}-arrow`]:{"--antd-arrow-background-color":t}}}))),{"&-rtl":{direction:"rtl"}})},(0,n.default)(e,"var(--antd-arrow-background-color)"),{[`${a}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow}}]})((0,s.mergeToken)(e,{tooltipMaxWidth:250,tooltipColor:l,tooltipBorderRadius:a,tooltipBg:c})),(0,o.initZoomMotion)(e,"zoom-big-fast")]},c,{resetStyle:!1,injectStyle:a})(e)])},702779,e=>{"use strict";var t=e.i(8211),r=e.i(617933);let o=r.PresetColors.map(e=>`${e}-inverse`),n=["success","processing","error","default","warning"];function a(e,n=!0){return n?[].concat((0,t.default)(o),(0,t.default)(r.PresetColors)).includes(e):r.PresetColors.includes(e)}function i(e){return n.includes(e)}e.s(["isPresetColor",()=>a,"isPresetStatusColor",()=>i])},571070,814690,162464,509808,e=>{"use strict";var t=e.i(278409),r=e.i(233848);e.i(247167),e.i(931067);var o=e.i(211577),n=e.i(392221),a=e.i(271645),i=e.i(209428),l=e.i(868917),s=e.i(674813),c=e.i(703923),u=e.i(410160);e.i(262370);var d=e.i(135551),f=["b"],p=["v"],h=function(e){return Math.round(Number(e||0))},m=function(e){if(e instanceof d.FastColor)return e;if(e&&"object"===(0,u.default)(e)&&"h"in e&&"b"in e){var t=e.b,r=(0,c.default)(e,f);return(0,i.default)((0,i.default)({},r),{},{v:t})}return"string"==typeof e&&/hsb/.test(e)?e.replace(/hsb/,"hsv"):e},g=function(e){(0,l.default)(n,e);var o=(0,s.default)(n);function n(e){return(0,t.default)(this,n),o.call(this,m(e))}return(0,r.default)(n,[{key:"toHsbString",value:function(){var e=this.toHsb(),t=h(100*e.s),r=h(100*e.b),o=h(e.h),n=e.a,a="hsb(".concat(o,", ").concat(t,"%, ").concat(r,"%)"),i="hsba(".concat(o,", ").concat(t,"%, ").concat(r,"%, ").concat(n.toFixed(2*(0!==n)),")");return 1===n?a:i}},{key:"toHsb",value:function(){var e=this.toHsv(),t=e.v,r=(0,c.default)(e,p);return(0,i.default)((0,i.default)({},r),{},{b:t,a:this.a})}}]),n}(d.FastColor);e.s(["Color",()=>g],814690);var v=function(e){return e instanceof g?e:new g(e)};v("#1677ff");var y=e.i(343794);e.s(["default",0,function(e){var t=e.color,r=e.prefixCls,o=e.className,n=e.style,i=e.onClick,l="".concat(r,"-color-block");return a.default.createElement("div",{className:(0,y.default)(l,o),style:n,onClick:i},a.default.createElement("div",{className:"".concat(l,"-inner"),style:{background:t}}))}],162464);e.i(62664);e.i(697539);e.i(914949);e.s([],509808);let b=(0,r.default)(function e(r){var o;if((0,t.default)(this,e),this.cleared=!1,r instanceof e){this.metaColor=r.metaColor.clone(),this.colors=null==(o=r.colors)?void 0:o.map(t=>({color:new e(t.color),percent:t.percent})),this.cleared=r.cleared;return}let n=Array.isArray(r);n&&r.length?(this.colors=r.map(({color:t,percent:r})=>({color:new e(t),percent:r})),this.metaColor=new g(this.colors[0].color.metaColor)):this.metaColor=new g(n?"":r),r&&(!n||this.colors)||(this.metaColor=this.metaColor.setA(0),this.cleared=!0)},[{key:"toHsb",value:function(){return this.metaColor.toHsb()}},{key:"toHsbString",value:function(){return this.metaColor.toHsbString()}},{key:"toHex",value:function(){var e,t;return e=this.toHexString(),t=this.metaColor.a<1,e&&(null==e?void 0:e.replace(/[^\w/]/g,"").slice(0,t?8:6))||""}},{key:"toHexString",value:function(){return this.metaColor.toHexString()}},{key:"toRgb",value:function(){return this.metaColor.toRgb()}},{key:"toRgbString",value:function(){return this.metaColor.toRgbString()}},{key:"isGradient",value:function(){return!!this.colors&&!this.cleared}},{key:"getColors",value:function(){return this.colors||[{color:this,percent:0}]}},{key:"toCssString",value:function(){let{colors:e}=this;if(e){let t=e.map(e=>`${e.color.toRgbString()} ${e.percent}%`).join(", ");return`linear-gradient(90deg, ${t})`}return this.metaColor.toRgbString()}},{key:"equals",value:function(e){return!!e&&this.isGradient()===e.isGradient()&&(this.isGradient()?this.colors.length===e.colors.length&&this.colors.every((t,r)=>{let o=e.colors[r];return t.percent===o.percent&&t.color.equals(o.color)}):this.toHexString()===e.toHexString())}}]);e.s(["AggregationColor",()=>b],571070)},656449,e=>{"use strict";e.i(8211),e.i(509808),e.i(814690);var t=e.i(571070);e.s(["generateColor",0,e=>e instanceof t.AggregationColor?e:new t.AggregationColor(e)])},491816,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(793154),n=e.i(914949),a=e.i(617206),i=e.i(122767),l=e.i(613541),s=e.i(805984),c=e.i(763731),u=e.i(747656),d=e.i(340010),f=e.i(242064),p=e.i(104458),h=e.i(880476),m=e.i(57667),g=e.i(702779),v=e.i(656449);function y(e,t){let o=(0,g.isPresetColor)(t),n=(0,r.default)({[`${e}-${t}`]:t&&o}),a={},i={},l=(0,v.generateColor)(t).toRgb(),s=(.299*l.r+.587*l.g+.114*l.b)/255;return t&&!o&&(a.background=t,a["--ant-tooltip-color"]=s<.5?"#FFF":"#000",i["--antd-arrow-background-color"]=t),{className:n,overlayStyle:a,arrowStyle:i}}var b=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let w=t.forwardRef((e,h)=>{var g,v;let{prefixCls:w,openClassName:$,getTooltipContainer:C,color:x,overlayInnerStyle:E,children:S,afterOpenChange:k,afterVisibleChange:j,destroyTooltipOnHide:O,destroyOnHidden:T,arrow:I=!0,title:_,overlay:F,builtinPlacements:P,arrowPointAtCenter:R=!1,autoAdjustOverflow:N=!0,motion:M,getPopupContainer:B,placement:A="top",mouseEnterDelay:z=.1,mouseLeaveDelay:L=.1,overlayStyle:D,rootClassName:H,overlayClassName:V,styles:W,classNames:U}=e,G=b(e,["prefixCls","openClassName","getTooltipContainer","color","overlayInnerStyle","children","afterOpenChange","afterVisibleChange","destroyTooltipOnHide","destroyOnHidden","arrow","title","overlay","builtinPlacements","arrowPointAtCenter","autoAdjustOverflow","motion","getPopupContainer","placement","mouseEnterDelay","mouseLeaveDelay","overlayStyle","rootClassName","overlayClassName","styles","classNames"]),q=!!I,[,J]=(0,p.useToken)(),{getPopupContainer:K,getPrefixCls:X,direction:Y,className:Q,style:Z,classNames:ee,styles:et}=(0,f.useComponentConfig)("tooltip"),er=(0,u.devUseWarning)("Tooltip"),eo=t.useRef(null),en=()=>{var e;null==(e=eo.current)||e.forceAlign()};t.useImperativeHandle(h,()=>{var e,t;return{forceAlign:en,forcePopupAlign:()=>{er.deprecated(!1,"forcePopupAlign","forceAlign"),en()},nativeElement:null==(e=eo.current)?void 0:e.nativeElement,popupElement:null==(t=eo.current)?void 0:t.popupElement}});let[ea,ei]=(0,n.default)(!1,{value:null!=(g=e.open)?g:e.visible,defaultValue:null!=(v=e.defaultOpen)?v:e.defaultVisible}),el=!_&&!F&&0!==_,es=t.useMemo(()=>{var e,t;let r=R;return"object"==typeof I&&(r=null!=(t=null!=(e=I.pointAtCenter)?e:I.arrowPointAtCenter)?t:R),P||(0,s.default)({arrowPointAtCenter:r,autoAdjustOverflow:N,arrowWidth:q?J.sizePopupArrow:0,borderRadius:J.borderRadius,offset:J.marginXXS,visibleFirst:!0})},[R,I,P,J]),ec=t.useMemo(()=>0===_?_:F||_||"",[F,_]),eu=t.createElement(a.default,{space:!0},"function"==typeof ec?ec():ec),ed=X("tooltip",w),ef=X(),ep=e["data-popover-inject"],eh=ea;"open"in e||"visible"in e||!el||(eh=!1);let em=t.isValidElement(S)&&!(0,c.isFragment)(S)?S:t.createElement("span",null,S),eg=em.props,ev=eg.className&&"string"!=typeof eg.className?eg.className:(0,r.default)(eg.className,$||`${ed}-open`),[ey,eb,ew]=(0,m.default)(ed,!ep),e$=y(ed,x),eC=e$.arrowStyle,ex=(0,r.default)(V,{[`${ed}-rtl`]:"rtl"===Y},e$.className,H,eb,ew,Q,ee.root,null==U?void 0:U.root),eE=(0,r.default)(ee.body,null==U?void 0:U.body),[eS,ek]=(0,i.useZIndex)("Tooltip",G.zIndex),ej=t.createElement(o.default,Object.assign({},G,{zIndex:eS,showArrow:q,placement:A,mouseEnterDelay:z,mouseLeaveDelay:L,prefixCls:ed,classNames:{root:ex,body:eE},styles:{root:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},eC),et.root),Z),D),null==W?void 0:W.root),body:Object.assign(Object.assign(Object.assign(Object.assign({},et.body),E),null==W?void 0:W.body),e$.overlayStyle)},getTooltipContainer:B||C||K,ref:eo,builtinPlacements:es,overlay:eu,visible:eh,onVisibleChange:t=>{var r,o;ei(!el&&t),el||(null==(r=e.onOpenChange)||r.call(e,t),null==(o=e.onVisibleChange)||o.call(e,t))},afterVisibleChange:null!=k?k:j,arrowContent:t.createElement("span",{className:`${ed}-arrow-content`}),motion:{motionName:(0,l.getTransitionName)(ef,"zoom-big-fast",e.transitionName),motionDeadline:1e3},destroyTooltipOnHide:null!=T?T:!!O}),eh?(0,c.cloneElement)(em,{className:ev}):em);return ey(t.createElement(d.default.Provider,{value:ek},ej))});w._InternalPanelDoNotUseOrYouWillBeFired=e=>{let{prefixCls:o,className:n,placement:a="top",title:i,color:l,overlayInnerStyle:s}=e,{getPrefixCls:c}=t.useContext(f.ConfigContext),u=c("tooltip",o),[d,p,g]=(0,m.default)(u),v=y(u,l),b=v.arrowStyle,w=Object.assign(Object.assign({},s),v.overlayStyle),$=(0,r.default)(p,g,u,`${u}-pure`,`${u}-placement-${a}`,n,v.className);return d(t.createElement("div",{className:$,style:b},t.createElement("div",{className:`${u}-arrow`}),t.createElement(h.Popup,Object.assign({},e,{className:p,prefixCls:u,overlayInnerStyle:w}),i)))},e.s(["default",0,w],491816)},592968,e=>{"use strict";var t=e.i(491816);e.s(["Tooltip",()=>t.default])},408850,929447,e=>{"use strict";var t=e.i(271645),r=e.i(595575),o=e.i(87414);let n=(e,n)=>{let a=t.useContext(r.default);return[t.useMemo(()=>{var t;let r=n||o.default[e],i=null!=(t=null==a?void 0:a[e])?t:{};return Object.assign(Object.assign({},"function"==typeof r?r():r),i||{})},[e,n,a]),t.useMemo(()=>{let e=null==a?void 0:a.locale;return(null==a?void 0:a.exist)&&!e?o.default.locale:e},[a])]};e.s(["default",0,n],929447),e.s(["useLocale",0,n],408850)},121872,26905,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(606262),n=e.i(611935),a=e.i(242064),i=e.i(763731);let l=(0,e.i(246422).genComponentStyleHook)("Wave",e=>{let{componentCls:t,colorPrimary:r}=e;return{[t]:{position:"absolute",background:"transparent",pointerEvents:"none",boxSizing:"border-box",color:`var(--wave-color, ${r})`,boxShadow:"0 0 0 0 currentcolor",opacity:.2,"&.wave-motion-appear":{transition:`box-shadow 0.4s ${e.motionEaseOutCirc},opacity 2s ${e.motionEaseOutCirc}`,"&-active":{boxShadow:"0 0 0 6px currentcolor",opacity:0},"&.wave-quick":{transition:`box-shadow ${e.motionDurationSlow} ${e.motionEaseInOut},opacity ${e.motionDurationSlow} ${e.motionEaseInOut}`}}}}});var s=e.i(175066),c=e.i(963188),u=e.i(719581);let d=`${a.defaultPrefixCls}-wave-target`;e.s(["TARGET_CLS",0,d],26905);var f=e.i(361275),p=e.i(783164);function h(e){return e&&"#fff"!==e&&"#ffffff"!==e&&"rgb(255, 255, 255)"!==e&&"rgba(255, 255, 255, 1)"!==e&&!/rgba\((?:\d*, ){3}0\)/.test(e)&&"transparent"!==e&&"canvastext"!==e}function m(e){return Number.isNaN(e)?0:e}let g=e=>{let{className:o,target:a,component:i,registerUnmount:l}=e,s=t.useRef(null),u=t.useRef(null);t.useEffect(()=>{u.current=l()},[]);let[p,g]=t.useState(null),[v,y]=t.useState([]),[b,w]=t.useState(0),[$,C]=t.useState(0),[x,E]=t.useState(0),[S,k]=t.useState(0),[j,O]=t.useState(!1),T={left:b,top:$,width:x,height:S,borderRadius:v.map(e=>`${e}px`).join(" ")};function I(){let e=getComputedStyle(a);g(function(e){var t;let{borderTopColor:r,borderColor:o,backgroundColor:n}=getComputedStyle(e);return null!=(t=[r,o,n].find(h))?t:null}(a));let t="static"===e.position,{borderLeftWidth:r,borderTopWidth:o}=e;w(t?a.offsetLeft:m(-Number.parseFloat(r))),C(t?a.offsetTop:m(-Number.parseFloat(o))),E(a.offsetWidth),k(a.offsetHeight);let{borderTopLeftRadius:n,borderTopRightRadius:i,borderBottomLeftRadius:l,borderBottomRightRadius:s}=e;y([n,i,s,l].map(e=>m(Number.parseFloat(e))))}if(p&&(T["--wave-color"]=p),t.useEffect(()=>{if(a){let e,t=(0,c.default)(()=>{I(),O(!0)});return"u">typeof ResizeObserver&&(e=new ResizeObserver(I)).observe(a),()=>{c.default.cancel(t),null==e||e.disconnect()}}},[a]),!j)return null;let _=("Checkbox"===i||"Radio"===i)&&(null==a?void 0:a.classList.contains(d));return t.createElement(f.default,{visible:!0,motionAppear:!0,motionName:"wave-motion",motionDeadline:5e3,onAppearEnd:(e,t)=>{var r,o;if(t.deadline||"opacity"===t.propertyName){let e=null==(r=s.current)?void 0:r.parentElement;null==(o=u.current)||o.call(u).then(()=>{null==e||e.remove()})}return!1}},({className:e},a)=>t.createElement("div",{ref:(0,n.composeRef)(s,a),className:(0,r.default)(o,e,{"wave-quick":_}),style:T}))};e.s(["default",0,e=>{let{children:f,disabled:h,component:m}=e,{getPrefixCls:v}=(0,t.useContext)(a.ConfigContext),y=(0,t.useRef)(null),b=v("wave"),[,w]=l(b),$=((e,r,o)=>{let{wave:n}=t.useContext(a.ConfigContext),[,i,l]=(0,u.default)(),f=(0,s.default)(a=>{let s=e.current;if((null==n?void 0:n.disabled)||!s)return;let c=s.querySelector(`.${d}`)||s,{showEffect:u}=n||{};(u||((e,r)=>{var o;let{component:n}=r;if("Checkbox"===n&&!(null==(o=e.querySelector("input"))?void 0:o.checked))return;let a=document.createElement("div");a.style.position="absolute",a.style.left="0px",a.style.top="0px",null==e||e.insertBefore(a,null==e?void 0:e.firstChild);let i=(0,p.unstableSetRender)(),l=null;l=i(t.createElement(g,Object.assign({},r,{target:e,registerUnmount:function(){return l}})),a)}))(c,{className:r,token:i,component:o,event:a,hashId:l})}),h=t.useRef(null);return e=>{c.default.cancel(h.current),h.current=(0,c.default)(()=>{f(e)})}})(y,(0,r.default)(b,w),m);if(t.default.useEffect(()=>{let e=y.current;if(!e||e.nodeType!==window.Node.ELEMENT_NODE||h)return;let t=t=>{!(0,o.default)(t.target)||!e.getAttribute||e.getAttribute("disabled")||e.disabled||e.className.includes("disabled")&&!e.className.includes("disabled:")||"true"===e.getAttribute("aria-disabled")||e.className.includes("-leave")||$(t)};return e.addEventListener("click",t,!0),()=>{e.removeEventListener("click",t,!0)}},[h]),!t.default.isValidElement(f))return null!=f?f:null;let C=(0,n.supportRef)(f)?(0,n.composeRef)((0,n.getNodeRef)(f),y):y;return(0,i.cloneElement)(f,{ref:C})}],121872)},827252,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"}}]},name:"info-circle",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["InfoCircleOutlined",0,a],827252)},735996,e=>{"use strict";var t=e.i(271645),r=e.i(343794),o=e.i(242064),n=e.i(104458),a=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let i=t.createContext(void 0);e.s(["GroupSizeContext",0,i,"default",0,e=>{let{getPrefixCls:l,direction:s}=t.useContext(o.ConfigContext),{prefixCls:c,size:u,className:d}=e,f=a(e,["prefixCls","size","className"]),p=l("btn-group",c),[,,h]=(0,n.useToken)(),m=t.useMemo(()=>{switch(u){case"large":return"lg";case"small":return"sm";default:return""}},[u]),g=(0,r.default)(p,{[`${p}-${m}`]:m,[`${p}-rtl`]:"rtl"===s},d,h);return t.createElement(i.Provider,{value:u},t.createElement("div",Object.assign({},f,{className:g})))}])},62405,869693,868004,470977,e=>{"use strict";var t=e.i(8211),r=e.i(271645),o=e.i(763731),n=e.i(617933);let a=/^[\u4E00-\u9FA5]{2}$/,i=a.test.bind(a);function l(e){return"danger"===e?{danger:!0}:{type:e}}function s(e){return"string"==typeof e}function c(e){return"text"===e||"link"===e}function u(e,t){let n=!1,a=[];return r.default.Children.forEach(e,e=>{let t=typeof e,r="string"===t||"number"===t;if(n&&r){let t=a.length-1,r=a[t];a[t]=`${r}${e}`}else a.push(e);n=r}),r.default.Children.map(a,e=>(function(e,t){if(null==e)return;let n=t?" ":"";return"string"!=typeof e&&"number"!=typeof e&&s(e.type)&&i(e.props.children)?(0,o.cloneElement)(e,{children:e.props.children.split("").join(n)}):s(e)?i(e)?r.default.createElement("span",null,e.split("").join(n)):r.default.createElement("span",null,e):(0,o.isFragment)(e)?r.default.createElement("span",null,e):e})(e,t))}["default","primary","danger"].concat((0,t.default)(n.PresetColors)),e.s(["convertLegacyProps",()=>l,"isTwoCNChar",0,i,"isUnBorderedButtonVariant",()=>c,"spaceChildren",()=>u],62405);var d=e.i(739295),f=e.i(343794),p=e.i(361275);let h=(0,r.forwardRef)((e,t)=>{let{className:o,style:n,children:a,prefixCls:i}=e,l=(0,f.default)(`${i}-icon`,o);return r.default.createElement("span",{ref:t,className:l,style:n},a)});e.s(["default",0,h],869693);let m=(0,r.forwardRef)((e,t)=>{let{prefixCls:o,className:n,style:a,iconClassName:i}=e,l=(0,f.default)(`${o}-loading-icon`,n);return r.default.createElement(h,{prefixCls:o,className:l,style:a,ref:t},r.default.createElement(d.default,{className:i}))}),g=()=>({width:0,opacity:0,transform:"scale(0)"}),v=e=>({width:e.scrollWidth,opacity:1,transform:"scale(1)"});e.s(["default",0,e=>{let{prefixCls:t,loading:o,existIcon:n,className:a,style:i,mount:l}=e;return n?r.default.createElement(m,{prefixCls:t,className:a,style:i}):r.default.createElement(p.default,{visible:!!o,motionName:`${t}-loading-icon-motion`,motionAppear:!l,motionEnter:!l,motionLeave:!l,removeOnLeave:!0,onAppearStart:g,onAppearActive:v,onEnterStart:g,onEnterActive:v,onLeaveStart:v,onLeaveActive:g},({className:e,style:o},n)=>{let l=Object.assign(Object.assign({},i),o);return r.default.createElement(m,{prefixCls:t,className:(0,f.default)(a,e),style:l,ref:n})})}],868004);let y=(e,t)=>({[`> span, > ${e}`]:{"&:not(:last-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineEndColor:t}}},"&:not(:first-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineStartColor:t}}}}});e.s(["default",0,e=>{let{componentCls:t,fontSize:r,lineWidth:o,groupBorderColor:n,colorErrorHover:a}=e;return{[`${t}-group`]:[{position:"relative",display:"inline-flex",[`> span, > ${t}`]:{"&:not(:last-child)":{[`&, & > ${t}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},"&:not(:first-child)":{marginInlineStart:e.calc(o).mul(-1).equal(),[`&, & > ${t}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}},[t]:{position:"relative",zIndex:1,"&:hover, &:focus, &:active":{zIndex:2},"&[disabled]":{zIndex:0}},[`${t}-icon-only`]:{fontSize:r}},y(`${t}-primary`,n),y(`${t}-danger`,a)]}}],470977)},202599,e=>{"use strict";var t=e.i(162464);e.s(["ColorBlock",()=>t.default])},286612,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["default",0,a],286612)},301092,e=>{"use strict";var t=e.i(931067),r=e.i(8211),o=e.i(392221),n=e.i(410160),a=e.i(343794),i=e.i(914949),l=e.i(883110),s=e.i(271645),c=e.i(703923),u=e.i(876556),d=e.i(209428),f=e.i(211577),p=e.i(361275),h=e.i(404948),m=s.default.forwardRef(function(e,t){var r=e.prefixCls,n=e.forceRender,i=e.className,l=e.style,c=e.children,u=e.isActive,d=e.role,p=e.classNames,h=e.styles,m=s.default.useState(u||n),g=(0,o.default)(m,2),v=g[0],y=g[1];return(s.default.useEffect(function(){(n||u)&&y(!0)},[n,u]),v)?s.default.createElement("div",{ref:t,className:(0,a.default)("".concat(r,"-content"),(0,f.default)((0,f.default)({},"".concat(r,"-content-active"),u),"".concat(r,"-content-inactive"),!u),i),style:l,role:d},s.default.createElement("div",{className:(0,a.default)("".concat(r,"-content-box"),null==p?void 0:p.body),style:null==h?void 0:h.body},c)):null});m.displayName="PanelContent";var g=["showArrow","headerClass","isActive","onItemClick","forceRender","className","classNames","styles","prefixCls","collapsible","accordion","panelKey","extra","header","expandIcon","openMotion","destroyInactivePanel","children"],v=s.default.forwardRef(function(e,r){var o=e.showArrow,n=e.headerClass,i=e.isActive,l=e.onItemClick,u=e.forceRender,v=e.className,y=e.classNames,b=void 0===y?{}:y,w=e.styles,$=void 0===w?{}:w,C=e.prefixCls,x=e.collapsible,E=e.accordion,S=e.panelKey,k=e.extra,j=e.header,O=e.expandIcon,T=e.openMotion,I=e.destroyInactivePanel,_=e.children,F=(0,c.default)(e,g),P="disabled"===x,R=(0,f.default)((0,f.default)((0,f.default)({onClick:function(){null==l||l(S)},onKeyDown:function(e){("Enter"===e.key||e.keyCode===h.default.ENTER||e.which===h.default.ENTER)&&(null==l||l(S))},role:E?"tab":"button"},"aria-expanded",i),"aria-disabled",P),"tabIndex",P?-1:0),N="function"==typeof O?O(e):s.default.createElement("i",{className:"arrow"}),M=N&&s.default.createElement("div",(0,t.default)({className:"".concat(C,"-expand-icon")},["header","icon"].includes(x)?R:{}),N),B=(0,a.default)("".concat(C,"-item"),(0,f.default)((0,f.default)({},"".concat(C,"-item-active"),i),"".concat(C,"-item-disabled"),P),v),A=(0,a.default)(n,"".concat(C,"-header"),(0,f.default)({},"".concat(C,"-collapsible-").concat(x),!!x),b.header),z=(0,d.default)({className:A,style:$.header},["header","icon"].includes(x)?{}:R);return s.default.createElement("div",(0,t.default)({},F,{ref:r,className:B}),s.default.createElement("div",z,(void 0===o||o)&&M,s.default.createElement("span",(0,t.default)({className:"".concat(C,"-header-text")},"header"===x?R:{}),j),null!=k&&"boolean"!=typeof k&&s.default.createElement("div",{className:"".concat(C,"-extra")},k)),s.default.createElement(p.default,(0,t.default)({visible:i,leavedClassName:"".concat(C,"-content-hidden")},T,{forceRender:u,removeOnLeave:I}),function(e,t){var r=e.className,o=e.style;return s.default.createElement(m,{ref:t,prefixCls:C,className:r,classNames:b,style:o,styles:$,isActive:i,forceRender:u,role:E?"tabpanel":void 0},_)}))}),y=["children","label","key","collapsible","onItemClick","destroyInactivePanel"],b=function(e,r){var o=r.prefixCls,n=r.accordion,a=r.collapsible,i=r.destroyInactivePanel,l=r.onItemClick,u=r.activeKey,d=r.openMotion,f=r.expandIcon;return e.map(function(e,r){var p=e.children,h=e.label,m=e.key,g=e.collapsible,b=e.onItemClick,w=e.destroyInactivePanel,$=(0,c.default)(e,y),C=String(null!=m?m:r),x=null!=g?g:a,E=!1;return E=n?u[0]===C:u.indexOf(C)>-1,s.default.createElement(v,(0,t.default)({},$,{prefixCls:o,key:C,panelKey:C,isActive:E,accordion:n,openMotion:d,expandIcon:f,header:h,collapsible:x,onItemClick:function(e){"disabled"!==x&&(l(e),null==b||b(e))},destroyInactivePanel:null!=w?w:i}),p)})},w=function(e,t,r){if(!e)return null;var o=r.prefixCls,n=r.accordion,a=r.collapsible,i=r.destroyInactivePanel,l=r.onItemClick,c=r.activeKey,u=r.openMotion,d=r.expandIcon,f=e.key||String(t),p=e.props,h=p.header,m=p.headerClass,g=p.destroyInactivePanel,v=p.collapsible,y=p.onItemClick,b=!1;b=n?c[0]===f:c.indexOf(f)>-1;var w=null!=v?v:a,$={key:f,panelKey:f,header:h,headerClass:m,isActive:b,prefixCls:o,destroyInactivePanel:null!=g?g:i,openMotion:u,accordion:n,children:e.props.children,onItemClick:function(e){"disabled"!==w&&(l(e),null==y||y(e))},expandIcon:d,collapsible:w};return"string"==typeof e.type?e:(Object.keys($).forEach(function(e){void 0===$[e]&&delete $[e]}),s.default.cloneElement(e,$))},$=e.i(244009);function C(e){var t=e;if(!Array.isArray(t)){var r=(0,n.default)(t);t="number"===r||"string"===r?[t]:[]}return t.map(function(e){return String(e)})}let x=Object.assign(s.default.forwardRef(function(e,n){var c,d=e.prefixCls,f=void 0===d?"rc-collapse":d,p=e.destroyInactivePanel,h=e.style,m=e.accordion,g=e.className,v=e.children,y=e.collapsible,x=e.openMotion,E=e.expandIcon,S=e.activeKey,k=e.defaultActiveKey,j=e.onChange,O=e.items,T=(0,a.default)(f,g),I=(0,i.default)([],{value:S,onChange:function(e){return null==j?void 0:j(e)},defaultValue:k,postState:C}),_=(0,o.default)(I,2),F=_[0],P=_[1];(0,l.default)(!v,"[rc-collapse] `children` will be removed in next major version. Please use `items` instead.");var R=(c={prefixCls:f,accordion:m,openMotion:x,expandIcon:E,collapsible:y,destroyInactivePanel:void 0!==p&&p,onItemClick:function(e){return P(function(){return m?F[0]===e?[]:[e]:F.indexOf(e)>-1?F.filter(function(t){return t!==e}):[].concat((0,r.default)(F),[e])})},activeKey:F},Array.isArray(O)?b(O,c):(0,u.default)(v).map(function(e,t){return w(e,t,c)}));return s.default.createElement("div",(0,t.default)({ref:n,className:T,style:h,role:m?"tablist":void 0},(0,$.default)(e,{aria:!0,data:!0})),R)}),{Panel:v});x.Panel,e.s(["default",0,x],301092)},125234,e=>{"use strict";var t=e.i(271645),r=e.i(343794),o=e.i(301092),n=e.i(242064);let a=t.forwardRef((e,a)=>{let{getPrefixCls:i}=t.useContext(n.ConfigContext),{prefixCls:l,className:s,showArrow:c=!0}=e,u=i("collapse",l),d=(0,r.default)({[`${u}-no-arrow`]:!c},s);return t.createElement(o.default.Panel,Object.assign({ref:a},e,{prefixCls:u,className:d}))});e.s(["default",0,a])},447580,e=>{"use strict";e.s(["genCollapseMotion",0,e=>({[e.componentCls]:{[`${e.antCls}-motion-collapse-legacy`]:{overflow:"hidden","&-active":{transition:`height ${e.motionDurationMid} ${e.motionEaseInOut}, - opacity ${e.motionDurationMid} ${e.motionEaseInOut} !important`}},[`${e.antCls}-motion-collapse`]:{overflow:"hidden",transition:`height ${e.motionDurationMid} ${e.motionEaseInOut}, - opacity ${e.motionDurationMid} ${e.motionEaseInOut} !important`}}})],447580)},988122,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(286612),o=e.i(343794),n=e.i(301092),a=e.i(876556),i=e.i(529681),l=e.i(613541),s=e.i(763731),c=e.i(242064),u=e.i(517455),d=e.i(125234);e.i(296059);var f=e.i(915654),p=e.i(183293),h=e.i(447580),m=e.i(246422),g=e.i(838378);let v=(0,m.genStyleHooks)("Collapse",e=>{let t=(0,g.mergeToken)(e,{collapseHeaderPaddingSM:`${(0,f.unit)(e.paddingXS)} ${(0,f.unit)(e.paddingSM)}`,collapseHeaderPaddingLG:`${(0,f.unit)(e.padding)} ${(0,f.unit)(e.paddingLG)}`,collapsePanelBorderRadius:e.borderRadiusLG});return[(e=>{let{componentCls:t,contentBg:r,padding:o,headerBg:n,headerPadding:a,collapseHeaderPaddingSM:i,collapseHeaderPaddingLG:l,collapsePanelBorderRadius:s,lineWidth:c,lineType:u,colorBorder:d,colorText:h,colorTextHeading:m,colorTextDisabled:g,fontSizeLG:v,lineHeight:y,lineHeightLG:b,marginSM:w,paddingSM:$,paddingLG:C,paddingXS:x,motionDurationSlow:E,fontSizeIcon:S,contentPadding:k,fontHeight:j,fontHeightLG:O}=e,T=`${(0,f.unit)(c)} ${u} ${d}`;return{[t]:Object.assign(Object.assign({},(0,p.resetComponent)(e)),{backgroundColor:n,border:T,borderRadius:s,"&-rtl":{direction:"rtl"},[`& > ${t}-item`]:{borderBottom:T,"&:first-child":{[` - &, - & > ${t}-header`]:{borderRadius:`${(0,f.unit)(s)} ${(0,f.unit)(s)} 0 0`}},"&:last-child":{[` - &, - & > ${t}-header`]:{borderRadius:`0 0 ${(0,f.unit)(s)} ${(0,f.unit)(s)}`}},[`> ${t}-header`]:Object.assign(Object.assign({position:"relative",display:"flex",flexWrap:"nowrap",alignItems:"flex-start",padding:a,color:m,lineHeight:y,cursor:"pointer",transition:`all ${E}, visibility 0s`},(0,p.genFocusStyle)(e)),{[`> ${t}-header-text`]:{flex:"auto"},[`${t}-expand-icon`]:{height:j,display:"flex",alignItems:"center",paddingInlineEnd:w},[`${t}-arrow`]:Object.assign(Object.assign({},(0,p.resetIcon)()),{fontSize:S,transition:`transform ${E}`,svg:{transition:`transform ${E}`}}),[`${t}-header-text`]:{marginInlineEnd:"auto"}}),[`${t}-collapsible-header`]:{cursor:"default",[`${t}-header-text`]:{flex:"none",cursor:"pointer"},[`${t}-expand-icon`]:{cursor:"pointer"}},[`${t}-collapsible-icon`]:{cursor:"unset",[`${t}-expand-icon`]:{cursor:"pointer"}}},[`${t}-content`]:{color:h,backgroundColor:r,borderTop:T,[`& > ${t}-content-box`]:{padding:k},"&-hidden":{display:"none"}},"&-small":{[`> ${t}-item`]:{[`> ${t}-header`]:{padding:i,paddingInlineStart:x,[`> ${t}-expand-icon`]:{marginInlineStart:e.calc($).sub(x).equal()}},[`> ${t}-content > ${t}-content-box`]:{padding:$}}},"&-large":{[`> ${t}-item`]:{fontSize:v,lineHeight:b,[`> ${t}-header`]:{padding:l,paddingInlineStart:o,[`> ${t}-expand-icon`]:{height:O,marginInlineStart:e.calc(C).sub(o).equal()}},[`> ${t}-content > ${t}-content-box`]:{padding:C}}},[`${t}-item:last-child`]:{borderBottom:0,[`> ${t}-content`]:{borderRadius:`0 0 ${(0,f.unit)(s)} ${(0,f.unit)(s)}`}},[`& ${t}-item-disabled > ${t}-header`]:{[` - &, - & > .arrow - `]:{color:g,cursor:"not-allowed"}},[`&${t}-icon-position-end`]:{[`& > ${t}-item`]:{[`> ${t}-header`]:{[`${t}-expand-icon`]:{order:1,paddingInlineEnd:0,paddingInlineStart:w}}}}})}})(t),(e=>{let{componentCls:t,headerBg:r,borderlessContentPadding:o,borderlessContentBg:n,colorBorder:a}=e;return{[`${t}-borderless`]:{backgroundColor:r,border:0,[`> ${t}-item`]:{borderBottom:`1px solid ${a}`},[` - > ${t}-item:last-child, - > ${t}-item:last-child ${t}-header - `]:{borderRadius:0},[`> ${t}-item:last-child`]:{borderBottom:0},[`> ${t}-item > ${t}-content`]:{backgroundColor:n,borderTop:0},[`> ${t}-item > ${t}-content > ${t}-content-box`]:{padding:o}}}})(t),(e=>{let{componentCls:t,paddingSM:r}=e;return{[`${t}-ghost`]:{backgroundColor:"transparent",border:0,[`> ${t}-item`]:{borderBottom:0,[`> ${t}-content`]:{backgroundColor:"transparent",border:0,[`> ${t}-content-box`]:{paddingBlock:r}}}}}})(t),(e=>{let{componentCls:t}=e,r=`> ${t}-item > ${t}-header ${t}-arrow`;return{[`${t}-rtl`]:{[r]:{transform:"rotate(180deg)"}}}})(t),(0,h.genCollapseMotion)(t)]},e=>({headerPadding:`${e.paddingSM}px ${e.padding}px`,headerBg:e.colorFillAlter,contentPadding:`${e.padding}px 16px`,contentBg:e.colorBgContainer,borderlessContentPadding:`${e.paddingXXS}px 16px ${e.padding}px`,borderlessContentBg:"transparent"})),y=Object.assign(t.forwardRef((e,d)=>{let{getPrefixCls:f,direction:p,expandIcon:h,className:m,style:g}=(0,c.useComponentConfig)("collapse"),{prefixCls:y,className:b,rootClassName:w,style:$,bordered:C=!0,ghost:x,size:E,expandIconPosition:S="start",children:k,destroyInactivePanel:j,destroyOnHidden:O,expandIcon:T}=e,I=(0,u.default)(e=>{var t;return null!=(t=null!=E?E:e)?t:"middle"}),_=f("collapse",y),F=f(),[P,R,N]=v(_),M=t.useMemo(()=>"left"===S?"start":"right"===S?"end":S,[S]),B=null!=T?T:h,A=t.useCallback((e={})=>{let n="function"==typeof B?B(e):t.createElement(r.default,{rotate:e.isActive?"rtl"===p?-90:90:void 0,"aria-label":e.isActive?"expanded":"collapsed"});return(0,s.cloneElement)(n,()=>{var e;return{className:(0,o.default)(null==(e=n.props)?void 0:e.className,`${_}-arrow`)}})},[B,_,p]),z=(0,o.default)(`${_}-icon-position-${M}`,{[`${_}-borderless`]:!C,[`${_}-rtl`]:"rtl"===p,[`${_}-ghost`]:!!x,[`${_}-${I}`]:"middle"!==I},m,b,w,R,N),L=t.useMemo(()=>Object.assign(Object.assign({},(0,l.default)(F)),{motionAppear:!1,leavedClassName:`${_}-content-hidden`}),[F,_]),D=t.useMemo(()=>k?(0,a.default)(k).map((e,t)=>{var r,o;let n=e.props;if(null==n?void 0:n.disabled){let a=null!=(r=e.key)?r:String(t),l=Object.assign(Object.assign({},(0,i.default)(e.props,["disabled"])),{key:a,collapsible:null!=(o=n.collapsible)?o:"disabled"});return(0,s.cloneElement)(e,l)}return e}):null,[k]);return P(t.createElement(n.default,Object.assign({ref:d,openMotion:L},(0,i.default)(e,["rootClassName"]),{expandIcon:A,prefixCls:_,className:z,style:Object.assign(Object.assign({},g),$),destroyInactivePanel:null!=O?O:j}),D))}),{Panel:d.default});e.s(["default",0,y],988122)},432231,327174,e=>{"use strict";e.i(296059);var t=e.i(915654),r=e.i(183293),o=e.i(617933),n=e.i(246422),a=e.i(838378),i=e.i(470977),l=e.i(571070);e.i(271645),e.i(509808),e.i(202599);var s=e.i(814690);e.i(343794),e.i(914949),e.i(988122),e.i(408850),e.i(104458),e.i(656449);var c=e.i(988317),u=e.i(745978);let d=e=>{let{paddingInline:t,onlyIconSize:r}=e;return(0,a.mergeToken)(e,{buttonPaddingHorizontal:t,buttonPaddingVertical:0,buttonIconOnlyFontSize:r})},f=e=>{var r,n,a,i,d,f;let p=null!=(r=e.contentFontSize)?r:e.fontSize,h=null!=(n=e.contentFontSizeSM)?n:e.fontSize,m=null!=(a=e.contentFontSizeLG)?a:e.fontSizeLG,g=null!=(i=e.contentLineHeight)?i:(0,c.getLineHeight)(p),v=null!=(d=e.contentLineHeightSM)?d:(0,c.getLineHeight)(h),y=null!=(f=e.contentLineHeightLG)?f:(0,c.getLineHeight)(m),b=((e,t)=>{let{r,g:o,b:n,a}=e.toRgb(),i=new s.Color(e.toRgbString()).onBackground(t).toHsv();return a<=.5?i.v>.5:.299*r+.587*o+.114*n>192})(new l.AggregationColor(e.colorBgSolid),"#fff")?"#000":"#fff";return Object.assign(Object.assign({},o.PresetColors.reduce((r,o)=>Object.assign(Object.assign({},r),{[`${o}ShadowColor`]:`0 ${(0,t.unit)(e.controlOutlineWidth)} 0 ${(0,u.default)(e[`${o}1`],e.colorBgContainer)}`}),{})),{fontWeight:400,iconGap:e.marginXS,defaultShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlTmpOutline}`,primaryShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlOutline}`,dangerShadow:`0 ${e.controlOutlineWidth}px 0 ${e.colorErrorOutline}`,primaryColor:e.colorTextLightSolid,dangerColor:e.colorTextLightSolid,borderColorDisabled:e.colorBorder,defaultGhostColor:e.colorBgContainer,ghostBg:"transparent",defaultGhostBorderColor:e.colorBgContainer,paddingInline:e.paddingContentHorizontal-e.lineWidth,paddingInlineLG:e.paddingContentHorizontal-e.lineWidth,paddingInlineSM:8-e.lineWidth,onlyIconSize:"inherit",onlyIconSizeSM:"inherit",onlyIconSizeLG:"inherit",groupBorderColor:e.colorPrimaryHover,linkHoverBg:"transparent",textTextColor:e.colorText,textTextHoverColor:e.colorText,textTextActiveColor:e.colorText,textHoverBg:e.colorFillTertiary,defaultColor:e.colorText,defaultBg:e.colorBgContainer,defaultBorderColor:e.colorBorder,defaultBorderColorDisabled:e.colorBorder,defaultHoverBg:e.colorBgContainer,defaultHoverColor:e.colorPrimaryHover,defaultHoverBorderColor:e.colorPrimaryHover,defaultActiveBg:e.colorBgContainer,defaultActiveColor:e.colorPrimaryActive,defaultActiveBorderColor:e.colorPrimaryActive,solidTextColor:b,contentFontSize:p,contentFontSizeSM:h,contentFontSizeLG:m,contentLineHeight:g,contentLineHeightSM:v,contentLineHeightLG:y,paddingBlock:Math.max((e.controlHeight-p*g)/2-e.lineWidth,0),paddingBlockSM:Math.max((e.controlHeightSM-h*v)/2-e.lineWidth,0),paddingBlockLG:Math.max((e.controlHeightLG-m*y)/2-e.lineWidth,0)})};e.s(["prepareComponentToken",0,f,"prepareToken",0,d],327174);let p=(e,t,r)=>({[`&:not(:disabled):not(${e}-disabled)`]:{"&:hover":t,"&:active":r}}),h=(e,t,r,o,n,a,i,l)=>({[`&${e}-background-ghost`]:Object.assign(Object.assign({color:r||void 0,background:t,borderColor:o||void 0,boxShadow:"none"},p(e,Object.assign({background:t},i),Object.assign({background:t},l))),{"&:disabled":{cursor:"not-allowed",color:n||void 0,borderColor:a||void 0}})}),m=(e,t,r,o)=>Object.assign(Object.assign({},(o&&["link","text"].includes(o)?e=>({[`&:disabled, &${e.componentCls}-disabled`]:{cursor:"not-allowed",color:e.colorTextDisabled}}):e=>({[`&:disabled, &${e.componentCls}-disabled`]:Object.assign({},{cursor:"not-allowed",borderColor:e.borderColorDisabled,color:e.colorTextDisabled,background:e.colorBgContainerDisabled,boxShadow:"none"})}))(e)),p(e.componentCls,t,r)),g=(e,t,r,o,n)=>({[`&${e.componentCls}-variant-solid`]:Object.assign({color:t,background:r},m(e,o,n))}),v=(e,t,r,o,n)=>({[`&${e.componentCls}-variant-outlined, &${e.componentCls}-variant-dashed`]:Object.assign({borderColor:t,background:r},m(e,o,n))}),y=e=>({[`&${e.componentCls}-variant-dashed`]:{borderStyle:"dashed"}}),b=(e,t,r,o)=>({[`&${e.componentCls}-variant-filled`]:Object.assign({boxShadow:"none",background:t},m(e,r,o))}),w=(e,t,r,o,n)=>({[`&${e.componentCls}-variant-${r}`]:Object.assign({color:t,boxShadow:"none"},m(e,o,n,r))}),$=(e,r="")=>{let{componentCls:o,controlHeight:n,fontSize:a,borderRadius:i,buttonPaddingHorizontal:l,iconCls:s,buttonPaddingVertical:c,buttonIconOnlyFontSize:u}=e;return[{[r]:{fontSize:a,height:n,padding:`${(0,t.unit)(c)} ${(0,t.unit)(l)}`,borderRadius:i,[`&${o}-icon-only`]:{width:n,[s]:{fontSize:u}}}},{[`${o}${o}-circle${r}`]:{minWidth:e.controlHeight,paddingInline:0,borderRadius:"50%"}},{[`${o}${o}-round${r}`]:{borderRadius:e.controlHeight,[`&:not(${o}-icon-only)`]:{paddingInline:e.buttonPaddingHorizontal}}}]},C=(0,n.genStyleHooks)("Button",e=>{let n=d(e);return[(e=>{let{componentCls:o,iconCls:n,fontWeight:a,opacityLoading:i,motionDurationSlow:l,motionEaseInOut:s,iconGap:c,calc:u}=e;return{[o]:{outline:"none",position:"relative",display:"inline-flex",gap:c,alignItems:"center",justifyContent:"center",fontWeight:a,whiteSpace:"nowrap",textAlign:"center",backgroundImage:"none",background:"transparent",border:`${(0,t.unit)(e.lineWidth)} ${e.lineType} transparent`,cursor:"pointer",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,userSelect:"none",touchAction:"manipulation",color:e.colorText,"&:disabled > *":{pointerEvents:"none"},[`${o}-icon > svg`]:(0,r.resetIcon)(),"> a":{color:"currentColor"},"&:not(:disabled)":(0,r.genFocusStyle)(e),[`&${o}-two-chinese-chars::first-letter`]:{letterSpacing:"0.34em"},[`&${o}-two-chinese-chars > *:not(${n})`]:{marginInlineEnd:"-0.34em",letterSpacing:"0.34em"},[`&${o}-icon-only`]:{paddingInline:0,[`&${o}-compact-item`]:{flex:"none"}},[`&${o}-loading`]:{opacity:i,cursor:"default"},[`${o}-loading-icon`]:{transition:["width","opacity","margin"].map(e=>`${e} ${l} ${s}`).join(",")},[`&:not(${o}-icon-end)`]:{[`${o}-loading-icon-motion`]:{"&-appear-start, &-enter-start":{marginInlineEnd:u(c).mul(-1).equal()},"&-appear-active, &-enter-active":{marginInlineEnd:0},"&-leave-start":{marginInlineEnd:0},"&-leave-active":{marginInlineEnd:u(c).mul(-1).equal()}}},"&-icon-end":{flexDirection:"row-reverse",[`${o}-loading-icon-motion`]:{"&-appear-start, &-enter-start":{marginInlineStart:u(c).mul(-1).equal()},"&-appear-active, &-enter-active":{marginInlineStart:0},"&-leave-start":{marginInlineStart:0},"&-leave-active":{marginInlineStart:u(c).mul(-1).equal()}}}}}})(n),$((0,a.mergeToken)(n,{fontSize:n.contentFontSize}),n.componentCls),$((0,a.mergeToken)(n,{controlHeight:n.controlHeightSM,fontSize:n.contentFontSizeSM,padding:n.paddingXS,buttonPaddingHorizontal:n.paddingInlineSM,buttonPaddingVertical:0,borderRadius:n.borderRadiusSM,buttonIconOnlyFontSize:n.onlyIconSizeSM}),`${n.componentCls}-sm`),$((0,a.mergeToken)(n,{controlHeight:n.controlHeightLG,fontSize:n.contentFontSizeLG,buttonPaddingHorizontal:n.paddingInlineLG,buttonPaddingVertical:0,borderRadius:n.borderRadiusLG,buttonIconOnlyFontSize:n.onlyIconSizeLG}),`${n.componentCls}-lg`),(e=>{let{componentCls:t}=e;return{[t]:{[`&${t}-block`]:{width:"100%"}}}})(n),(e=>{let{componentCls:t}=e;return Object.assign({[`${t}-color-default`]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({color:e.defaultColor,boxShadow:e.defaultShadow},g(e,e.solidTextColor,e.colorBgSolid,{color:e.solidTextColor,background:e.colorBgSolidHover},{color:e.solidTextColor,background:e.colorBgSolidActive})),y(e)),b(e,e.colorFillTertiary,{color:e.defaultColor,background:e.colorFillSecondary},{color:e.defaultColor,background:e.colorFill})),h(e.componentCls,e.ghostBg,e.defaultGhostColor,e.defaultGhostBorderColor,e.colorTextDisabled,e.colorBorder)),w(e,e.textTextColor,"link",{color:e.colorLinkHover,background:e.linkHoverBg},{color:e.colorLinkActive})),[`${t}-color-primary`]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({color:e.colorPrimary,boxShadow:e.primaryShadow},v(e,e.colorPrimary,e.colorBgContainer,{color:e.colorPrimaryTextHover,borderColor:e.colorPrimaryHover,background:e.colorBgContainer},{color:e.colorPrimaryTextActive,borderColor:e.colorPrimaryActive,background:e.colorBgContainer})),y(e)),b(e,e.colorPrimaryBg,{color:e.colorPrimary,background:e.colorPrimaryBgHover},{color:e.colorPrimary,background:e.colorPrimaryBorder})),w(e,e.colorPrimaryText,"text",{color:e.colorPrimaryTextHover,background:e.colorPrimaryBg},{color:e.colorPrimaryTextActive,background:e.colorPrimaryBorder})),w(e,e.colorPrimaryText,"link",{color:e.colorPrimaryTextHover,background:e.linkHoverBg},{color:e.colorPrimaryTextActive})),h(e.componentCls,e.ghostBg,e.colorPrimary,e.colorPrimary,e.colorTextDisabled,e.colorBorder,{color:e.colorPrimaryHover,borderColor:e.colorPrimaryHover},{color:e.colorPrimaryActive,borderColor:e.colorPrimaryActive})),[`${t}-color-dangerous`]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({color:e.colorError,boxShadow:e.dangerShadow},g(e,e.dangerColor,e.colorError,{background:e.colorErrorHover},{background:e.colorErrorActive})),v(e,e.colorError,e.colorBgContainer,{color:e.colorErrorHover,borderColor:e.colorErrorBorderHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),y(e)),b(e,e.colorErrorBg,{color:e.colorError,background:e.colorErrorBgFilledHover},{color:e.colorError,background:e.colorErrorBgActive})),w(e,e.colorError,"text",{color:e.colorErrorHover,background:e.colorErrorBg},{color:e.colorErrorHover,background:e.colorErrorBgActive})),w(e,e.colorError,"link",{color:e.colorErrorHover},{color:e.colorErrorActive})),h(e.componentCls,e.ghostBg,e.colorError,e.colorError,e.colorTextDisabled,e.colorBorder,{color:e.colorErrorHover,borderColor:e.colorErrorHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),[`${t}-color-link`]:Object.assign(Object.assign({},w(e,e.colorLink,"link",{color:e.colorLinkHover},{color:e.colorLinkActive})),h(e.componentCls,e.ghostBg,e.colorInfo,e.colorInfo,e.colorTextDisabled,e.colorBorder,{color:e.colorInfoHover,borderColor:e.colorInfoHover},{color:e.colorInfoActive,borderColor:e.colorInfoActive}))},(e=>{let{componentCls:t}=e;return o.PresetColors.reduce((r,o)=>{let n=e[`${o}6`],a=e[`${o}1`],i=e[`${o}5`],l=e[`${o}2`],s=e[`${o}3`],c=e[`${o}7`];return Object.assign(Object.assign({},r),{[`&${t}-color-${o}`]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({color:n,boxShadow:e[`${o}ShadowColor`]},g(e,e.colorTextLightSolid,n,{background:i},{background:c})),v(e,n,e.colorBgContainer,{color:i,borderColor:i,background:e.colorBgContainer},{color:c,borderColor:c,background:e.colorBgContainer})),y(e)),b(e,a,{color:n,background:l},{color:n,background:s})),w(e,n,"link",{color:i},{color:c})),w(e,n,"text",{color:i,background:a},{color:c,background:s}))})},{})})(e))})(n),Object.assign(Object.assign(Object.assign(Object.assign({},v(n,n.defaultBorderColor,n.defaultBg,{color:n.defaultHoverColor,borderColor:n.defaultHoverBorderColor,background:n.defaultHoverBg},{color:n.defaultActiveColor,borderColor:n.defaultActiveBorderColor,background:n.defaultActiveBg})),w(n,n.textTextColor,"text",{color:n.textTextHoverColor,background:n.textHoverBg},{color:n.textTextActiveColor,background:n.colorBgTextActive})),g(n,n.primaryColor,n.colorPrimary,{background:n.colorPrimaryHover,color:n.primaryColor},{background:n.colorPrimaryActive,color:n.primaryColor})),w(n,n.colorLink,"link",{color:n.colorLinkHover,background:n.linkHoverBg},{color:n.colorLinkActive})),(0,i.default)(n)]},f,{unitless:{fontWeight:!0,contentLineHeight:!0,contentLineHeightSM:!0,contentLineHeightLG:!0}});e.s(["default",0,C],432231)},372409,e=>{"use strict";function t(e,r={focus:!0}){let{componentCls:o}=e,{componentCls:n}=r,a=n||o,i=`${a}-compact`;return{[i]:Object.assign(Object.assign({},function(e,t,r,o){let{focusElCls:n,focus:a,borderElCls:i}=r,l=i?"> *":"",s=["hover",a?"focus":null,"active"].filter(Boolean).map(e=>`&:${e} ${l}`).join(",");return{[`&-item:not(${t}-last-item)`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal()},[`&-item:not(${o}-status-success)`]:{zIndex:2},"&-item":Object.assign(Object.assign({[s]:{zIndex:3}},n?{[`&${n}`]:{zIndex:3}}:{}),{[`&[disabled] ${l}`]:{zIndex:0}})}}(e,i,r,a)),function(e,t,r){let{borderElCls:o}=r,n=o?`> ${o}`:"";return{[`&-item:not(${t}-first-item):not(${t}-last-item) ${n}`]:{borderRadius:0},[`&-item:not(${t}-last-item)${t}-first-item`]:{[`& ${n}, &${e}-sm ${n}, &${e}-lg ${n}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&-item:not(${t}-first-item)${t}-last-item`]:{[`& ${n}, &${e}-sm ${n}, &${e}-lg ${n}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}}}(a,i,r))}}e.s(["genCompactItemStyle",()=>t])},920228,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(174428),n=e.i(529681),a=e.i(611935),i=e.i(121872),l=e.i(242064),s=e.i(937328),c=e.i(517455),u=e.i(249616),d=e.i(735996),f=e.i(62405),p=e.i(868004),h=e.i(869693),m=e.i(432231),g=e.i(372409),v=e.i(246422),y=e.i(327174);let b=(0,v.genSubStyleComponent)(["Button","compact"],e=>{var t,r;let o,n=(0,y.prepareToken)(e);return[(0,g.genCompactItemStyle)(n),{[o=`${n.componentCls}-compact-vertical`]:Object.assign(Object.assign({},(t=n.componentCls,{[`&-item:not(${o}-last-item)`]:{marginBottom:n.calc(n.lineWidth).mul(-1).equal()},[`&-item:not(${t}-status-success)`]:{zIndex:2},"&-item":{"&:hover,&:focus,&:active":{zIndex:3},"&[disabled]":{zIndex:0}}})),(r=n.componentCls,{[`&-item:not(${o}-first-item):not(${o}-last-item)`]:{borderRadius:0},[`&-item${o}-first-item:not(${o}-last-item)`]:{[`&, &${r}-sm, &${r}-lg`]:{borderEndEndRadius:0,borderEndStartRadius:0}},[`&-item${o}-last-item:not(${o}-first-item)`]:{[`&, &${r}-sm, &${r}-lg`]:{borderStartStartRadius:0,borderStartEndRadius:0}}}))},(e=>{let{componentCls:t,colorPrimaryHover:r,lineWidth:o,calc:n}=e,a=n(o).mul(-1).equal(),i=e=>{let n=`${t}-compact${e?"-vertical":""}-item${t}-primary:not([disabled])`;return{[`${n} + ${n}::before`]:{position:"absolute",top:e?a:0,insetInlineStart:e?0:a,backgroundColor:r,content:'""',width:e?"100%":o,height:e?o:"100%"}}};return Object.assign(Object.assign({},i()),i(!0))})(n)]},y.prepareComponentToken);var w=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let $={default:["default","outlined"],primary:["primary","solid"],dashed:["default","dashed"],link:["link","link"],text:["default","text"]},C=t.default.forwardRef((e,g)=>{var v,y;let C,{loading:x=!1,prefixCls:E,color:S,variant:k,type:j,danger:O=!1,shape:T,size:I,styles:_,disabled:F,className:P,rootClassName:R,children:N,icon:M,iconPosition:B="start",ghost:A=!1,block:z=!1,htmlType:L="button",classNames:D,style:H={},autoInsertSpace:V,autoFocus:W}=e,U=w(e,["loading","prefixCls","color","variant","type","danger","shape","size","styles","disabled","className","rootClassName","children","icon","iconPosition","ghost","block","htmlType","classNames","style","autoInsertSpace","autoFocus"]),G=j||"default",{button:q}=t.default.useContext(l.ConfigContext),J=T||(null==q?void 0:q.shape)||"default",[K,X]=(0,t.useMemo)(()=>{if(S&&k)return[S,k];if(j||O){let e=$[G]||[];return O?["danger",e[1]]:e}return(null==q?void 0:q.color)&&(null==q?void 0:q.variant)?[q.color,q.variant]:["default","outlined"]},[S,k,j,O,null==q?void 0:q.color,null==q?void 0:q.variant,G]),Y="danger"===K?"dangerous":K,{getPrefixCls:Q,direction:Z,autoInsertSpace:ee,className:et,style:er,classNames:eo,styles:en}=(0,l.useComponentConfig)("button"),ea=null==(v=null!=V?V:ee)||v,ei=Q("btn",E),[el,es,ec]=(0,m.default)(ei),eu=(0,t.useContext)(s.default),ed=null!=F?F:eu,ef=(0,t.useContext)(d.GroupSizeContext),ep=(0,t.useMemo)(()=>(function(e){if("object"==typeof e&&e){let t=null==e?void 0:e.delay;return{loading:(t=Number.isNaN(t)||"number"!=typeof t?0:t)<=0,delay:t}}return{loading:!!e,delay:0}})(x),[x]),[eh,em]=(0,t.useState)(ep.loading),[eg,ev]=(0,t.useState)(!1),ey=(0,t.useRef)(null),eb=(0,a.useComposeRef)(g,ey),ew=1===t.Children.count(N)&&!M&&!(0,f.isUnBorderedButtonVariant)(X),e$=(0,t.useRef)(!0);t.default.useEffect(()=>(e$.current=!1,()=>{e$.current=!0}),[]),(0,o.default)(()=>{let e=null;return ep.delay>0?e=setTimeout(()=>{e=null,em(!0)},ep.delay):em(ep.loading),function(){e&&(clearTimeout(e),e=null)}},[ep.delay,ep.loading]),(0,t.useEffect)(()=>{if(!ey.current||!ea)return;let e=ey.current.textContent||"";ew&&(0,f.isTwoCNChar)(e)?eg||ev(!0):eg&&ev(!1)}),(0,t.useEffect)(()=>{W&&ey.current&&ey.current.focus()},[]);let eC=t.default.useCallback(t=>{var r;eh||ed?t.preventDefault():null==(r=e.onClick)||r.call(e,("href"in e,t))},[e.onClick,eh,ed]),{compactSize:ex,compactItemClassnames:eE}=(0,u.useCompactItemContext)(ei,Z),eS=(0,c.default)(e=>{var t,r;return null!=(r=null!=(t=null!=I?I:ex)?t:ef)?r:e}),ek=eS&&null!=(y=({large:"lg",small:"sm",middle:void 0})[eS])?y:"",ej=eh?"loading":M,eO=(0,n.default)(U,["navigate"]),eT=(0,r.default)(ei,es,ec,{[`${ei}-${J}`]:"default"!==J&&J,[`${ei}-${G}`]:G,[`${ei}-dangerous`]:O,[`${ei}-color-${Y}`]:Y,[`${ei}-variant-${X}`]:X,[`${ei}-${ek}`]:ek,[`${ei}-icon-only`]:!N&&0!==N&&!!ej,[`${ei}-background-ghost`]:A&&!(0,f.isUnBorderedButtonVariant)(X),[`${ei}-loading`]:eh,[`${ei}-two-chinese-chars`]:eg&&ea&&!eh,[`${ei}-block`]:z,[`${ei}-rtl`]:"rtl"===Z,[`${ei}-icon-end`]:"end"===B},eE,P,R,et),eI=Object.assign(Object.assign({},er),H),e_=(0,r.default)(null==D?void 0:D.icon,eo.icon),eF=Object.assign(Object.assign({},(null==_?void 0:_.icon)||{}),en.icon||{}),eP=e=>t.default.createElement(h.default,{prefixCls:ei,className:e_,style:eF},e);C=M&&!eh?eP(M):x&&"object"==typeof x&&x.icon?eP(x.icon):t.default.createElement(p.default,{existIcon:!!M,prefixCls:ei,loading:eh,mount:e$.current});let eR=N||0===N?(0,f.spaceChildren)(N,ew&&ea):null;if(void 0!==eO.href)return el(t.default.createElement("a",Object.assign({},eO,{className:(0,r.default)(eT,{[`${ei}-disabled`]:ed}),href:ed?void 0:eO.href,style:eI,onClick:eC,ref:eb,tabIndex:ed?-1:0,"aria-disabled":ed}),C,eR));let eN=t.default.createElement("button",Object.assign({},U,{type:L,className:eT,style:eI,onClick:eC,disabled:ed,ref:eb}),C,eR,eE&&t.default.createElement(b,{prefixCls:ei}));return(0,f.isUnBorderedButtonVariant)(X)||(eN=t.default.createElement(i.default,{component:"Button",disabled:eh},eN)),el(eN)});C.Group=d.default,C.__ANT_BUTTON=!0,e.s(["default",0,C],920228)},756570,e=>{"use strict";e.i(296059);var t=e.i(915654),r=e.i(246422),o=e.i(838378);let n=(e,t)=>((e,t)=>{let{prefixCls:r,componentCls:o,gridColumns:n}=e,a={};for(let e=n;e>=0;e--)0===e?(a[`${o}${t}-${e}`]={display:"none"},a[`${o}-push-${e}`]={insetInlineStart:"auto"},a[`${o}-pull-${e}`]={insetInlineEnd:"auto"},a[`${o}${t}-push-${e}`]={insetInlineStart:"auto"},a[`${o}${t}-pull-${e}`]={insetInlineEnd:"auto"},a[`${o}${t}-offset-${e}`]={marginInlineStart:0},a[`${o}${t}-order-${e}`]={order:0}):(a[`${o}${t}-${e}`]=[{"--ant-display":"block",display:"block"},{display:"var(--ant-display)",flex:`0 0 ${e/n*100}%`,maxWidth:`${e/n*100}%`}],a[`${o}${t}-push-${e}`]={insetInlineStart:`${e/n*100}%`},a[`${o}${t}-pull-${e}`]={insetInlineEnd:`${e/n*100}%`},a[`${o}${t}-offset-${e}`]={marginInlineStart:`${e/n*100}%`},a[`${o}${t}-order-${e}`]={order:e});return a[`${o}${t}-flex`]={flex:`var(--${r}${t}-flex)`},a})(e,t),a=(0,r.genStyleHooks)("Grid",e=>{let{componentCls:t}=e;return{[t]:{display:"flex",flexFlow:"row wrap",minWidth:0,"&::before, &::after":{display:"flex"},"&-no-wrap":{flexWrap:"nowrap"},"&-start":{justifyContent:"flex-start"},"&-center":{justifyContent:"center"},"&-end":{justifyContent:"flex-end"},"&-space-between":{justifyContent:"space-between"},"&-space-around":{justifyContent:"space-around"},"&-space-evenly":{justifyContent:"space-evenly"},"&-top":{alignItems:"flex-start"},"&-middle":{alignItems:"center"},"&-bottom":{alignItems:"flex-end"}}}},()=>({})),i=e=>({xs:e.screenXSMin,sm:e.screenSMMin,md:e.screenMDMin,lg:e.screenLGMin,xl:e.screenXLMin,xxl:e.screenXXLMin}),l=(0,r.genStyleHooks)("Grid",e=>{let r=(0,o.mergeToken)(e,{gridColumns:24}),a=i(r);return delete a.xs,[(e=>{let{componentCls:t}=e;return{[t]:{position:"relative",maxWidth:"100%",minHeight:1}}})(r),n(r,""),n(r,"-xs"),Object.keys(a).map(e=>{let o,i;return o=a[e],i=`-${e}`,{[`@media (min-width: ${(0,t.unit)(o)})`]:Object.assign({},n(r,i))}}).reduce((e,t)=>Object.assign(Object.assign({},e),t),{})]},()=>({}));e.s(["getMediaSize",0,i,"useColStyle",0,l,"useRowStyle",0,a])},805484,e=>{"use strict";var t=e.i(271645),r=e.i(914949),o=e.i(609587),n=e.i(242064);function a(e){return r=>t.createElement(o.default,{theme:{token:{motion:!1,zIndexPopupBase:0}}},t.createElement(e,Object.assign({},r)))}e.s(["default",0,(e,o,i,l,s)=>a(a=>{let{prefixCls:c,style:u}=a,d=t.useRef(null),[f,p]=t.useState(0),[h,m]=t.useState(0),[g,v]=(0,r.default)(!1,{value:a.open}),{getPrefixCls:y}=t.useContext(n.ConfigContext),b=y(l||"select",c);t.useEffect(()=>{if(v(!0),"u">typeof ResizeObserver){let e=new ResizeObserver(e=>{let t=e[0].target;p(t.offsetHeight+8),m(t.offsetWidth)}),t=setInterval(()=>{var r;let o=s?`.${s(b)}`:`.${b}-dropdown`,n=null==(r=d.current)?void 0:r.querySelector(o);n&&(clearInterval(t),e.observe(n))},10);return()=>{clearInterval(t),e.disconnect()}}},[b]);let w=Object.assign(Object.assign({},a),{style:Object.assign(Object.assign({},u),{margin:0}),open:g,visible:g,getPopupContainer:()=>d.current});return i&&(w=i(w)),o&&Object.assign(w,{[o]:{overflow:{adjustX:!1,adjustY:!1}}}),t.createElement("div",{ref:d,style:{paddingBottom:f,position:"relative",minWidth:h}},t.createElement(e,Object.assign({},w)))}),"withPureRenderTheme",()=>a])},830919,e=>{"use strict";var t=e.i(271645);function r(e){let[r,o]=t.useState(e);return t.useEffect(()=>{let t=setTimeout(()=>{o(e)},10*!e.length);return()=>{clearTimeout(t)}},[e]),r}e.s(["default",()=>r])},782074,908709,53058,923624,e=>{"use strict";var t=e.i(8211),r=e.i(271645),o=e.i(343794),n=e.i(361275),a=e.i(629587),i=e.i(613541),l=e.i(321883),s=e.i(62139),c=e.i(830919);e.i(296059);var u=e.i(915654),d=e.i(183293),f=e.i(447580),p=e.i(717356),h=e.i(246422),m=e.i(838378);let g=(e,t)=>{let{formItemCls:r}=e;return{[r]:{[`${r}-label > label`]:{height:t},[`${r}-control-input`]:{minHeight:t}}}},v=e=>({padding:e.verticalLabelPadding,margin:e.verticalLabelMargin,whiteSpace:"initial",textAlign:"start","> label":{margin:0,"&::after":{visibility:"hidden"}}}),y=(e,t)=>(0,m.mergeToken)(e,{formItemCls:`${e.componentCls}-item`,rootPrefixCls:t}),b=(0,h.genStyleHooks)("Form",(e,{rootPrefixCls:t})=>{let r=y(e,t);return[(e=>{let{componentCls:t}=e;return{[e.componentCls]:Object.assign(Object.assign(Object.assign({},(0,d.resetComponent)(e)),{legend:{display:"block",width:"100%",marginBottom:e.marginLG,padding:0,color:e.colorTextDescription,fontSize:e.fontSizeLG,lineHeight:"inherit",border:0,borderBottom:`${(0,u.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},'input[type="search"]':{boxSizing:"border-box"},'input[type="radio"], input[type="checkbox"]':{lineHeight:"normal"},'input[type="file"]':{display:"block"},'input[type="range"]':{display:"block",width:"100%"},"select[multiple], select[size]":{height:"auto"},[`input[type='file']:focus, - input[type='radio']:focus, - input[type='checkbox']:focus`]:{outline:0,boxShadow:`0 0 0 ${(0,u.unit)(e.controlOutlineWidth)} ${e.controlOutline}`},output:{display:"block",paddingTop:15,color:e.colorText,fontSize:e.fontSize,lineHeight:e.lineHeight}}),{[`${t}-text`]:{display:"inline-block",paddingInlineEnd:e.paddingSM},"&-small":Object.assign({},g(e,e.controlHeightSM)),"&-large":Object.assign({},g(e,e.controlHeightLG))})}})(r),(e=>{let{formItemCls:t,iconCls:r,rootPrefixCls:o,antCls:n,labelRequiredMarkColor:a,labelColor:i,labelFontSize:l,labelHeight:s,labelColonMarginInlineStart:c,labelColonMarginInlineEnd:u,itemMarginBottom:f}=e;return{[t]:Object.assign(Object.assign({},(0,d.resetComponent)(e)),{marginBottom:f,verticalAlign:"top","&-with-help":{transition:"none"},[`&-hidden, - &-hidden${n}-row`]:{display:"none"},"&-has-warning":{[`${t}-split`]:{color:e.colorError}},"&-has-error":{[`${t}-split`]:{color:e.colorWarning}},[`${t}-label`]:{flexGrow:0,overflow:"hidden",whiteSpace:"nowrap",textAlign:"end",verticalAlign:"middle","&-left":{textAlign:"start"},"&-wrap":{overflow:"unset",lineHeight:e.lineHeight,whiteSpace:"unset","> label":{verticalAlign:"middle",textWrap:"balance"}},"> label":{position:"relative",display:"inline-flex",alignItems:"center",maxWidth:"100%",height:s,color:i,fontSize:l,[`> ${r}`]:{fontSize:e.fontSize,verticalAlign:"top"},[`&${t}-required`]:{"&::before":{display:"inline-block",marginInlineEnd:e.marginXXS,color:a,fontSize:e.fontSize,fontFamily:"SimSun, sans-serif",lineHeight:1,content:'"*"'},[`&${t}-required-mark-hidden, &${t}-required-mark-optional`]:{"&::before":{display:"none"}}},[`${t}-optional`]:{display:"inline-block",marginInlineStart:e.marginXXS,color:e.colorTextDescription,[`&${t}-required-mark-hidden`]:{display:"none"}},[`${t}-tooltip`]:{color:e.colorTextDescription,cursor:"help",writingMode:"horizontal-tb",marginInlineStart:e.marginXXS},"&::after":{content:'":"',position:"relative",marginBlock:0,marginInlineStart:c,marginInlineEnd:u},[`&${t}-no-colon::after`]:{content:'"\\a0"'}}},[`${t}-control`]:{"--ant-display":"flex",flexDirection:"column",flexGrow:1,[`&:first-child:not([class^="'${o}-col-'"]):not([class*="' ${o}-col-'"])`]:{width:"100%"},"&-input":{position:"relative",display:"flex",alignItems:"center",minHeight:e.controlHeight,"&-content":{flex:"auto",maxWidth:"100%",[`&:has(> ${n}-switch:only-child, > ${n}-rate:only-child)`]:{display:"flex",alignItems:"center"}}}},[t]:{"&-additional":{display:"flex",flexDirection:"column"},"&-explain, &-extra":{clear:"both",color:e.colorTextDescription,fontSize:e.fontSize,lineHeight:e.lineHeight},"&-explain-connected":{width:"100%"},"&-extra":{minHeight:e.controlHeightSM,transition:`color ${e.motionDurationMid} ${e.motionEaseOut}`},"&-explain":{"&-error":{color:e.colorError},"&-warning":{color:e.colorWarning}}},[`&-with-help ${t}-explain`]:{height:"auto",opacity:1},[`${t}-feedback-icon`]:{fontSize:e.fontSize,textAlign:"center",visibility:"visible",animationName:p.zoomIn,animationDuration:e.motionDurationMid,animationTimingFunction:e.motionEaseOutBack,pointerEvents:"none","&-success":{color:e.colorSuccess},"&-error":{color:e.colorError},"&-warning":{color:e.colorWarning},"&-validating":{color:e.colorPrimary}}})}})(r),(e=>{let{componentCls:t}=e,r=`${t}-show-help`,o=`${t}-show-help-item`;return{[r]:{transition:`opacity ${e.motionDurationFast} ${e.motionEaseInOut}`,"&-appear, &-enter":{opacity:0,"&-active":{opacity:1}},"&-leave":{opacity:1,"&-active":{opacity:0}},[o]:{overflow:"hidden",transition:`height ${e.motionDurationFast} ${e.motionEaseInOut}, - opacity ${e.motionDurationFast} ${e.motionEaseInOut}, - transform ${e.motionDurationFast} ${e.motionEaseInOut} !important`,[`&${o}-appear, &${o}-enter`]:{transform:"translateY(-5px)",opacity:0,"&-active":{transform:"translateY(0)",opacity:1}},[`&${o}-leave-active`]:{transform:"translateY(-5px)"}}}}})(r),(e=>{let{antCls:t,formItemCls:r}=e;return{[`${r}-horizontal`]:{[`${r}-label`]:{flexGrow:0},[`${r}-control`]:{flex:"1 1 0",minWidth:0},[`${r}-label[class$='-24'], ${r}-label[class*='-24 ']`]:{[`& + ${r}-control`]:{minWidth:"unset"}},[`${t}-col-24${r}-label, - ${t}-col-xl-24${r}-label`]:v(e)}}})(r),(e=>{let{componentCls:t,formItemCls:r,inlineItemMarginBottom:o}=e;return{[`${t}-inline`]:{display:"flex",flexWrap:"wrap",[`${r}-inline`]:{flex:"none",marginInlineEnd:e.margin,marginBottom:o,"&-row":{flexWrap:"nowrap"},[`> ${r}-label, - > ${r}-control`]:{display:"inline-block",verticalAlign:"top"},[`> ${r}-label`]:{flex:"none"},[`${t}-text`]:{display:"inline-block"},[`${r}-has-feedback`]:{display:"inline-block"}}}}})(r),(e=>{let{componentCls:t,formItemCls:r,antCls:o}=e;return{[`${r}-vertical`]:{[`${r}-row`]:{flexDirection:"column"},[`${r}-label > label`]:{height:"auto"},[`${r}-control`]:{width:"100%"},[`${r}-label, - ${o}-col-24${r}-label, - ${o}-col-xl-24${r}-label`]:v(e)},[`@media (max-width: ${(0,u.unit)(e.screenXSMax)})`]:[(e=>{let{componentCls:t,formItemCls:r,rootPrefixCls:o}=e;return{[`${r} ${r}-label`]:v(e),[`${t}:not(${t}-inline)`]:{[r]:{flexWrap:"wrap",[`${r}-label, ${r}-control`]:{[`&:not([class*=" ${o}-col-xs"])`]:{flex:"0 0 100%",maxWidth:"100%"}}}}}})(e),{[t]:{[`${r}:not(${r}-horizontal)`]:{[`${o}-col-xs-24${r}-label`]:v(e)}}}],[`@media (max-width: ${(0,u.unit)(e.screenSMMax)})`]:{[t]:{[`${r}:not(${r}-horizontal)`]:{[`${o}-col-sm-24${r}-label`]:v(e)}}},[`@media (max-width: ${(0,u.unit)(e.screenMDMax)})`]:{[t]:{[`${r}:not(${r}-horizontal)`]:{[`${o}-col-md-24${r}-label`]:v(e)}}},[`@media (max-width: ${(0,u.unit)(e.screenLGMax)})`]:{[t]:{[`${r}:not(${r}-horizontal)`]:{[`${o}-col-lg-24${r}-label`]:v(e)}}}}})(r),(0,f.genCollapseMotion)(r),p.zoomIn]},e=>({labelRequiredMarkColor:e.colorError,labelColor:e.colorTextHeading,labelFontSize:e.fontSize,labelHeight:e.controlHeight,labelColonMarginInlineStart:e.marginXXS/2,labelColonMarginInlineEnd:e.marginXS,itemMarginBottom:e.marginLG,verticalLabelPadding:`0 0 ${e.paddingXS}px`,verticalLabelMargin:0,inlineItemMarginBottom:0}),{order:-1e3});e.s(["default",0,b,"prepareToken",0,y],908709);let w=[];function $(e,t,r,o=0){return{key:"string"==typeof e?e:`${t}-${o}`,error:e,errorStatus:r}}e.s(["default",0,({help:e,helpStatus:u,errors:d=w,warnings:f=w,className:p,fieldId:h,onVisibleChanged:m})=>{let{prefixCls:g}=r.useContext(s.FormItemPrefixContext),v=`${g}-item-explain`,y=(0,l.default)(g),[C,x,E]=b(g,y),S=r.useMemo(()=>(0,i.default)(g),[g]),k=(0,c.default)(d),j=(0,c.default)(f),O=r.useMemo(()=>null!=e?[$(e,"help",u)]:[].concat((0,t.default)(k.map((e,t)=>$(e,"error","error",t))),(0,t.default)(j.map((e,t)=>$(e,"warning","warning",t)))),[e,u,k,j]),T=r.useMemo(()=>{let e={};return O.forEach(({key:t})=>{e[t]=(e[t]||0)+1}),O.map((t,r)=>Object.assign(Object.assign({},t),{key:e[t.key]>1?`${t.key}-fallback-${r}`:t.key}))},[O]),I={};return h&&(I.id=`${h}_help`),C(r.createElement(n.default,{motionDeadline:S.motionDeadline,motionName:`${g}-show-help`,visible:!!T.length,onVisibleChanged:m},e=>{let{className:t,style:n}=e;return r.createElement("div",Object.assign({},I,{className:(0,o.default)(v,t,E,y,p,x),style:n}),r.createElement(a.CSSMotionList,Object.assign({keys:T},(0,i.default)(g),{motionName:`${g}-show-help-item`,component:!1}),e=>{let{key:t,error:n,errorStatus:a,className:i,style:l}=e;return r.createElement("div",{key:t,className:(0,o.default)(i,{[`${v}-${a}`]:a}),style:l},n)}))}))}],782074);var C=e.i(197091);e.s(["List",()=>C.default],53058);var x=e.i(621796);e.s(["useWatch",()=>x.default],923624)},286039,531880,e=>{"use strict";var t=e.i(271645);e.i(495347);var r=e.i(787894),r=r,o=e.i(279697);let n=e=>"object"==typeof e&&null!=e&&1===e.nodeType,a=(e,t)=>(!t||"hidden"!==e)&&"visible"!==e&&"clip"!==e,i=(e,t)=>{if(e.clientHeight{if(!e.ownerDocument||!e.ownerDocument.defaultView)return null;try{return e.ownerDocument.defaultView.frameElement}catch(e){return null}})(e))&&(r.clientHeightat||a>e&&i=t&&l>=r?a-e-o:i>t&&lr?i-t+n:0,s=e=>{let t=e.parentElement;return null==t?e.getRootNode().host||null:t},c=(e,t)=>{var r,o,a,c;let u;if("u"e!==h;if(!n(e))throw TypeError("Invalid target");let v=document.scrollingElement||document.documentElement,y=[],b=e;for(;n(b)&&g(b);){if((b=s(b))===v){y.push(b);break}null!=b&&b===document.body&&i(b)&&!i(document.documentElement)||null!=b&&i(b,m)&&y.push(b)}let w=null!=(o=null==(r=window.visualViewport)?void 0:r.width)?o:innerWidth,$=null!=(c=null==(a=window.visualViewport)?void 0:a.height)?c:innerHeight,{scrollX:C,scrollY:x}=window,{height:E,width:S,top:k,right:j,bottom:O,left:T}=e.getBoundingClientRect(),{top:I,right:_,bottom:F,left:P}={top:parseFloat((u=window.getComputedStyle(e)).scrollMarginTop)||0,right:parseFloat(u.scrollMarginRight)||0,bottom:parseFloat(u.scrollMarginBottom)||0,left:parseFloat(u.scrollMarginLeft)||0},R="start"===f||"nearest"===f?k-I:"end"===f?O+F:k+E/2-I+F,N="center"===p?T+S/2-P+_:"end"===p?j+_:T-P,M=[];for(let e=0;e=0&&T>=0&&O<=$&&j<=w&&(t===v&&!i(t)||k>=n&&O<=s&&T>=c&&j<=a))break;let u=getComputedStyle(t),h=parseInt(u.borderLeftWidth,10),m=parseInt(u.borderTopWidth,10),g=parseInt(u.borderRightWidth,10),b=parseInt(u.borderBottomWidth,10),I=0,_=0,F="offsetWidth"in t?t.offsetWidth-t.clientWidth-h-g:0,P="offsetHeight"in t?t.offsetHeight-t.clientHeight-m-b:0,B="offsetWidth"in t?0===t.offsetWidth?0:o/t.offsetWidth:0,A="offsetHeight"in t?0===t.offsetHeight?0:r/t.offsetHeight:0;if(v===t)I="start"===f?R:"end"===f?R-$:"nearest"===f?l(x,x+$,$,m,b,x+R,x+R+E,E):R-$/2,_="start"===p?N:"center"===p?N-w/2:"end"===p?N-w:l(C,C+w,w,h,g,C+N,C+N+S,S),I=Math.max(0,I+x),_=Math.max(0,_+C);else{I="start"===f?R-n-m:"end"===f?R-s+b+P:"nearest"===f?l(n,s,r,m,b+P,R,R+E,E):R-(n+r/2)+P/2,_="start"===p?N-c-h:"center"===p?N-(c+o/2)+F/2:"end"===p?N-a+g+F:l(c,a,o,h,g+F,N,N+S,S);let{scrollLeft:e,scrollTop:i}=t;I=0===A?0:Math.max(0,Math.min(i+I/A,t.scrollHeight-r/A+P)),_=0===B?0:Math.max(0,Math.min(e+_/B,t.scrollWidth-o/B+F)),R+=i-I,N+=e-_}M.push({el:t,top:I,left:_})}return M},u=["parentNode"];function d(e){return void 0===e||!1===e?[]:Array.isArray(e)?e:[e]}function f(e,t){if(!e.length)return;let r=e.join("_");return t?`${t}_${r}`:u.includes(r)?`form_item_${r}`:r}function p(e,t,r,o,n,a){let i=o;return void 0!==a?i=a:r.validating?i="validating":e.length?i="error":t.length?i="warning":(r.touched||n&&r.validated)&&(i="success"),i}e.s(["getFieldId",()=>f,"getStatus",()=>p,"toArray",()=>d],531880);var h=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};function m(e){return d(e).join("_")}function g(e,t){let r=t.getFieldInstance(e),n=(0,o.getDOM)(r);if(n)return n;let a=f(d(e),t.__INTERNAL__.name);if(a)return document.getElementById(a)}function v(e){let[o]=(0,r.default)(),n=t.useRef({}),a=t.useMemo(()=>null!=e?e:Object.assign(Object.assign({},o),{__INTERNAL__:{itemRef:e=>t=>{let r=m(e);t?n.current[r]=t:delete n.current[r]}},scrollToField:(e,t={})=>{let{focus:r}=t,o=h(t,["focus"]),n=g(e,a);n&&(!function(e,t){let r;if(!e.isConnected||!(e=>{let t=e;for(;t&&t.parentNode;){if(t.parentNode===document)return!0;t=t.parentNode instanceof ShadowRoot?t.parentNode.host:t.parentNode}return!1})(e))return;let o={top:parseFloat((r=window.getComputedStyle(e)).scrollMarginTop)||0,right:parseFloat(r.scrollMarginRight)||0,bottom:parseFloat(r.scrollMarginBottom)||0,left:parseFloat(r.scrollMarginLeft)||0};if("object"==typeof t&&"function"==typeof t.behavior)return t.behavior(c(e,t));let n="boolean"==typeof t||null==t?void 0:t.behavior;for(let{el:r,top:a,left:i}of c(e,!1===t?{block:"end",inline:"nearest"}:t===Object(t)&&0!==Object.keys(t).length?t:{block:"start",inline:"nearest"})){let e=a-o.top+o.bottom,t=i-o.left+o.right;r.scroll({top:e,left:t,behavior:n})}}(n,Object.assign({scrollMode:"if-needed",block:"nearest"},o)),r&&a.focusField(e))},focusField:e=>{var t,r;let o=a.getFieldInstance(e);"function"==typeof(null==o?void 0:o.focus)?o.focus():null==(r=null==(t=g(e,a))?void 0:t.focus)||r.call(t)},getFieldInstance:e=>{let t=m(e);return n.current[t]}}),[e,o]);return[a]}e.s(["default",()=>v,"toNamePathStr",()=>m],286039)},56117,411412,420422,355268,220489,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(495347);e.i(53058),e.i(923624);var n=e.i(242064),a=e.i(937328),i=e.i(321883),l=e.i(517455),s=e.i(666365),c=e.i(62139),u=e.i(286039),d=e.i(908709),f=e.i(819828),p=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let h=t.forwardRef((e,h)=>{let m=t.useContext(a.default),{getPrefixCls:g,direction:v,requiredMark:y,colon:b,scrollToFirstError:w,className:$,style:C}=(0,n.useComponentConfig)("form"),{prefixCls:x,className:E,rootClassName:S,size:k,disabled:j=m,form:O,colon:T,labelAlign:I,labelWrap:_,labelCol:F,wrapperCol:P,hideRequiredMark:R,layout:N="horizontal",scrollToFirstError:M,requiredMark:B,onFinishFailed:A,name:z,style:L,feedbackIcons:D,variant:H}=e,V=p(e,["prefixCls","className","rootClassName","size","disabled","form","colon","labelAlign","labelWrap","labelCol","wrapperCol","hideRequiredMark","layout","scrollToFirstError","requiredMark","onFinishFailed","name","style","feedbackIcons","variant"]),W=(0,l.default)(k),U=t.useContext(f.default),G=t.useMemo(()=>void 0!==B?B:!R&&(void 0===y||y),[R,B,y]),q=null!=T?T:b,J=g("form",x),K=(0,i.default)(J),[X,Y,Q]=(0,d.default)(J,K),Z=(0,r.default)(J,`${J}-${N}`,{[`${J}-hide-required-mark`]:!1===G,[`${J}-rtl`]:"rtl"===v,[`${J}-${W}`]:W},Q,K,Y,$,E,S),[ee]=(0,u.default)(O),{__INTERNAL__:et}=ee;et.name=z;let er=t.useMemo(()=>({name:z,labelAlign:I,labelCol:F,labelWrap:_,wrapperCol:P,layout:N,colon:q,requiredMark:G,itemRef:et.itemRef,form:ee,feedbackIcons:D}),[z,I,F,P,N,q,G,ee,D]),eo=t.useRef(null);t.useImperativeHandle(h,()=>{var e;return Object.assign(Object.assign({},ee),{nativeElement:null==(e=eo.current)?void 0:e.nativeElement})});let en=(e,t)=>{if(e){let r={block:"nearest"};"object"==typeof e&&(r=Object.assign(Object.assign({},r),e)),ee.scrollToField(t,r)}};return X(t.createElement(c.VariantContext.Provider,{value:H},t.createElement(a.DisabledContextProvider,{disabled:j},t.createElement(s.default.Provider,{value:W},t.createElement(c.FormProvider,{validateMessages:U},t.createElement(c.FormContext.Provider,{value:er},t.createElement(c.NoFormStyle,{status:!0},t.createElement(o.default,Object.assign({id:z},V,{name:z,onFinishFailed:e=>{if(null==A||A(e),e.errorFields.length){let t=e.errorFields[0].name;if(void 0!==M)return void en(M,t);void 0!==w&&en(w,t)}},form:ee,ref:eo,style:Object.assign(Object.assign({},C),L),className:Z})))))))))});e.s(["default",0,h],56117),e.s(["useForm",()=>u.default],411412);var m=e.i(162129);e.s(["Field",()=>m.default],420422);var g=e.i(177886);e.s(["FieldContext",()=>g.default],355268);var v=e.i(786944);e.s(["ListContext",()=>v.default],220489)},522228,893872,857034,606836,e=>{"use strict";var t=e.i(876556);function r(e){if("function"==typeof e)return e;let r=(0,t.default)(e);return r.length<=1?r[0]:r}e.s(["default",()=>r],522228),e.i(247167);var o=e.i(271645),n=e.i(62139);let a=()=>{let{status:e,errors:t=[],warnings:r=[]}=o.useContext(n.FormItemInputContext);return{status:e,errors:t,warnings:r}};a.Context=n.FormItemInputContext,e.s(["default",0,a],893872);var i=e.i(963188);function l(e){let[t,r]=o.useState(e),n=o.useRef(null),a=o.useRef([]),l=o.useRef(!1);return o.useEffect(()=>(l.current=!1,()=>{l.current=!0,i.default.cancel(n.current),n.current=null}),[]),[t,function(e){l.current||(null===n.current&&(a.current=[],n.current=(0,i.default)(()=>{n.current=null,r(e=>{let t=e;return a.current.forEach(e=>{t=e(t)}),t})})),a.current.push(e))}]}e.s(["default",()=>l],857034);var s=e.i(611935);function c(){let{itemRef:e}=o.useContext(n.FormContext),t=o.useRef({});return function(r,o){let n=o&&"object"==typeof o&&(0,s.getNodeRef)(o),a=r.join("_");return(t.current.name!==a||t.current.originRef!==n)&&(t.current.name=a,t.current.originRef=n,t.current.ref=(0,s.composeRef)(e(r),n)),t.current.ref}}e.s(["default",()=>c],606836)},958503,e=>{"use strict";e.s(["addMediaQueryListener",0,(e,t)=>{void 0!==(null==e?void 0:e.addEventListener)?e.addEventListener("change",t):void 0!==(null==e?void 0:e.addListener)&&e.addListener(t)},"removeMediaQueryListener",0,(e,t)=>{void 0!==(null==e?void 0:e.removeEventListener)?e.removeEventListener("change",t):void 0!==(null==e?void 0:e.removeListener)&&e.removeListener(t)}])},908206,e=>{"use strict";var t=e.i(271645),r=e.i(104458),o=e.i(958503);let n=["xxl","xl","lg","md","sm","xs"];e.s(["default",0,()=>{let e,[,a]=(0,r.useToken)(),i=((e=[].concat(n).reverse()).forEach((t,r)=>{let o=t.toUpperCase(),n=`screen${o}Min`,i=`screen${o}`;if(!(a[n]<=a[i]))throw Error(`${n}<=${i} fails : !(${a[n]}<=${a[i]})`);if(r{let e=new Map,t=-1,r={};return{responsiveMap:i,matchHandlers:{},dispatch:t=>(r=t,e.forEach(e=>e(r)),e.size>=1),subscribe(o){return e.size||this.register(),t+=1,e.set(t,o),o(r),t},unsubscribe(t){e.delete(t),e.size||this.unregister()},register(){Object.entries(i).forEach(([e,t])=>{let n=({matches:t})=>{this.dispatch(Object.assign(Object.assign({},r),{[e]:t}))},a=window.matchMedia(t);(0,o.addMediaQueryListener)(a,n),this.matchHandlers[t]={mql:a,listener:n},n(a)})},unregister(){Object.values(i).forEach(e=>{let t=this.matchHandlers[e];(0,o.removeMediaQueryListener)(null==t?void 0:t.mql,null==t?void 0:t.listener)}),e.clear()}}},[i])},"matchScreen",0,(e,t)=>{if(t){for(let r of n)if(e[r]&&(null==t?void 0:t[r])!==void 0)return t[r]}},"responsiveArray",0,n])},149809,e=>{"use strict";var t=e.i(271645);e.s(["useForceUpdate",0,()=>t.default.useReducer(e=>e+1,0)])},150073,e=>{"use strict";var t=e.i(271645),r=e.i(174428),o=e.i(149809),n=e.i(908206);e.s(["default",0,function(e=!0,a={}){let i=(0,t.useRef)(a),[,l]=(0,o.useForceUpdate)(),s=(0,n.default)();return(0,r.default)(()=>{let t=s.subscribe(t=>{i.current=t,e&&l()});return()=>s.unsubscribe(t)},[]),i.current}])},39874,559442,e=>{"use strict";var t=e.i(908206);function r(e,r){let o=[void 0,void 0],n=Array.isArray(e)?e:[e,void 0],a=r||{xs:!0,sm:!0,md:!0,lg:!0,xl:!0,xxl:!0};return n.forEach((e,r)=>{if("object"==typeof e&&null!==e)for(let n=0;nr],39874);let o=(0,e.i(271645).createContext)({});e.s(["default",0,o],559442)},264042,131757,292169,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(908206),n=e.i(242064),a=e.i(150073),i=e.i(39874),l=e.i(559442),s=e.i(756570),c=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};function u(e,r){let[n,a]=t.useState("string"==typeof e?e:"");return t.useEffect(()=>{(()=>{if("string"==typeof e&&a(e),"object"==typeof e)for(let t=0;t{let{prefixCls:d,justify:f,align:p,className:h,style:m,children:g,gutter:v=0,wrap:y}=e,b=c(e,["prefixCls","justify","align","className","style","children","gutter","wrap"]),{getPrefixCls:w,direction:$}=t.useContext(n.ConfigContext),C=(0,a.default)(!0,null),x=u(p,C),E=u(f,C),S=w("row",d),[k,j,O]=(0,s.useRowStyle)(S),T=(0,i.default)(v,C),I=(0,r.default)(S,{[`${S}-no-wrap`]:!1===y,[`${S}-${E}`]:E,[`${S}-${x}`]:x,[`${S}-rtl`]:"rtl"===$},h,j,O),_={};if(null==T?void 0:T[0]){let e="number"==typeof T[0]?`${-(T[0]/2)}px`:`calc(${T[0]} / -2)`;_.marginLeft=e,_.marginRight=e}let[F,P]=T;_.rowGap=P;let R=t.useMemo(()=>({gutter:[F,P],wrap:y}),[F,P,y]);return k(t.createElement(l.default.Provider,{value:R},t.createElement("div",Object.assign({},b,{className:I,style:Object.assign(Object.assign({},_),m),ref:o}),g)))});e.s(["Row",0,d],264042),e.i(62664);var f=e.i(657791),f=f,p=e.i(349057),p=p,h=e.i(174428),m=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};function g(e){return"auto"===e?"1 1 auto":"number"==typeof e?`${e} ${e} auto`:/^\d+(\.\d+)?(px|em|rem|%)$/.test(e)?`0 0 ${e}`:e}let v=["xs","sm","md","lg","xl","xxl"],y=t.forwardRef((e,o)=>{let{getPrefixCls:a,direction:i}=t.useContext(n.ConfigContext),{gutter:c,wrap:u}=t.useContext(l.default),{prefixCls:d,span:f,order:p,offset:h,push:y,pull:b,className:w,children:$,flex:C,style:x}=e,E=m(e,["prefixCls","span","order","offset","push","pull","className","children","flex","style"]),S=a("col",d),[k,j,O]=(0,s.useColStyle)(S),T={},I={};v.forEach(t=>{let r={},o=e[t];"number"==typeof o?r.span=o:"object"==typeof o&&(r=o||{}),delete E[t],I=Object.assign(Object.assign({},I),{[`${S}-${t}-${r.span}`]:void 0!==r.span,[`${S}-${t}-order-${r.order}`]:r.order||0===r.order,[`${S}-${t}-offset-${r.offset}`]:r.offset||0===r.offset,[`${S}-${t}-push-${r.push}`]:r.push||0===r.push,[`${S}-${t}-pull-${r.pull}`]:r.pull||0===r.pull,[`${S}-rtl`]:"rtl"===i}),r.flex&&(I[`${S}-${t}-flex`]=!0,T[`--${S}-${t}-flex`]=g(r.flex))});let _=(0,r.default)(S,{[`${S}-${f}`]:void 0!==f,[`${S}-order-${p}`]:p,[`${S}-offset-${h}`]:h,[`${S}-push-${y}`]:y,[`${S}-pull-${b}`]:b},w,I,j,O),F={};if(null==c?void 0:c[0]){let e="number"==typeof c[0]?`${c[0]/2}px`:`calc(${c[0]} / 2)`;F.paddingLeft=e,F.paddingRight=e}return C&&(F.flex=g(C),!1!==u||F.minWidth||(F.minWidth=0)),k(t.createElement("div",Object.assign({},E,{style:Object.assign(Object.assign(Object.assign({},F),x),T),className:_,ref:o}),$))});e.s(["default",0,y],131757);var b=e.i(62139),w=e.i(782074),$=e.i(908709);let C=(0,e.i(246422).genSubStyleComponent)(["Form","item-item"],(e,{rootPrefixCls:t})=>(e=>{let{formItemCls:t}=e;return{"@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none)":{[`${t}-control`]:{display:"flex"}}}})((0,$.prepareToken)(e,t)));var x=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};e.s(["default",0,e=>{let{prefixCls:o,status:n,labelCol:a,wrapperCol:i,children:l,errors:s,warnings:c,_internalItemRender:u,extra:d,help:m,fieldId:g,marginBottom:v,onErrorVisibleChanged:$,label:E}=e,S=`${o}-item`,k=t.useContext(b.FormContext),j=t.useMemo(()=>{let e=Object.assign({},i||k.wrapperCol||{});return null!==E||a||i||!k.labelCol||[void 0,"xs","sm","md","lg","xl","xxl"].forEach(t=>{let r=t?[t]:[],o=(0,f.default)(k.labelCol,r),n="object"==typeof o?o:{},a=(0,f.default)(e,r);"span"in n&&!("offset"in("object"==typeof a?a:{}))&&n.span<24&&(e=(0,p.default)(e,[].concat(r,["offset"]),n.span))}),e},[i,k.wrapperCol,k.labelCol,E,a]),O=(0,r.default)(`${S}-control`,j.className),T=t.useMemo(()=>{let{labelCol:e,wrapperCol:t}=k;return x(k,["labelCol","wrapperCol"])},[k]),I=t.useRef(null),[_,F]=t.useState(0);(0,h.default)(()=>{d&&I.current?F(I.current.clientHeight):F(0)},[d]);let P=t.createElement("div",{className:`${S}-control-input`},t.createElement("div",{className:`${S}-control-input-content`},l)),R=t.useMemo(()=>({prefixCls:o,status:n}),[o,n]),N=null!==v||s.length||c.length?t.createElement(b.FormItemPrefixContext.Provider,{value:R},t.createElement(w.default,{fieldId:g,errors:s,warnings:c,help:m,helpStatus:n,className:`${S}-explain-connected`,onVisibleChanged:$})):null,M={};g&&(M.id=`${g}_extra`);let B=d?t.createElement("div",Object.assign({},M,{className:`${S}-extra`,ref:I}),d):null,A=N||B?t.createElement("div",{className:`${S}-additional`,style:v?{minHeight:v+_}:{}},N,B):null,z=u&&"pro_table_render"===u.mark&&u.render?u.render(e,{input:P,errorList:N,extra:B}):t.createElement(t.Fragment,null,P,A);return t.createElement(b.FormContext.Provider,{value:T},t.createElement(y,Object.assign({},j,{className:O}),z),t.createElement(C,{prefixCls:o}))}],292169)},684024,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"}}]},name:"question-circle",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["default",0,a],684024)},995144,e=>{"use strict";var t=e.i(271645);e.s(["default",0,function(e){return null==e?null:"object"!=typeof e||(0,t.isValidElement)(e)?{title:e}:e}])},808613,905536,e=>{"use strict";e.i(247167);var t=e.i(62139),r=e.i(782074),o=e.i(56117),n=e.i(411412),a=e.i(923624),i=e.i(8211),l=e.i(271645),s=e.i(343794);e.i(495347);var c=e.i(420422),u=e.i(355268),d=e.i(220489),f=e.i(290967),p=e.i(611935),h=e.i(763731),m=e.i(747656),g=e.i(242064),v=e.i(321883),y=e.i(522228),b=e.i(893872),w=e.i(857034),$=e.i(606836),C=e.i(908709),x=e.i(531880),E=e.i(606262),S=e.i(174428),k=e.i(529681),j=e.i(264042),O=e.i(292169),T=e.i(684024),I=e.i(995144),_=e.i(131757),F=e.i(408850),P=e.i(87414),R=e.i(491816),N=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let M=({prefixCls:e,label:r,htmlFor:o,labelCol:n,labelAlign:a,colon:i,required:c,requiredMark:u,tooltip:d,vertical:f})=>{var p;let h,[m]=(0,F.useLocale)("Form"),{labelAlign:g,labelCol:v,labelWrap:y,colon:b}=l.useContext(t.FormContext);if(!r)return null;let w=n||v||{},$=`${e}-item-label`,C=(0,s.default)($,"left"===(a||g)&&`${$}-left`,w.className,{[`${$}-wrap`]:!!y}),x=r,E=!0===i||!1!==b&&!1!==i;E&&!f&&"string"==typeof r&&r.trim()&&(x=r.replace(/[:|:]\s*$/,""));let S=(0,I.default)(d);if(S){let{icon:t=l.createElement(T.default,null)}=S,r=N(S,["icon"]),o=l.createElement(R.default,Object.assign({},r),l.cloneElement(t,{className:`${e}-item-tooltip`,title:"",onClick:e=>{e.preventDefault()},tabIndex:null}));x=l.createElement(l.Fragment,null,x,o)}let k="optional"===u,j="function"==typeof u;j?x=u(x,{required:!!c}):k&&!c&&(x=l.createElement(l.Fragment,null,x,l.createElement("span",{className:`${e}-item-optional`,title:""},(null==m?void 0:m.optional)||(null==(p=P.default.Form)?void 0:p.optional)))),!1===u?h="hidden":(k||j)&&(h="optional");let O=(0,s.default)({[`${e}-item-required`]:c,[`${e}-item-required-mark-${h}`]:h,[`${e}-item-no-colon`]:!E});return l.createElement(_.default,Object.assign({},w,{className:C}),l.createElement("label",{htmlFor:o,className:O,title:"string"==typeof r?r:""},x))};var B=e.i(830919),A=e.i(201072),z=e.i(726289),L=e.i(562901),D=e.i(739295);let H={success:A.default,warning:L.default,error:z.default,validating:D.default};function V({children:e,errors:r,warnings:o,hasFeedback:n,validateStatus:a,prefixCls:i,meta:c,noStyle:u,name:d}){let f=`${i}-item`,{feedbackIcons:p}=l.useContext(t.FormContext),h=(0,x.getStatus)(r,o,c,null,!!n,a),{isFormItemInput:m,status:g,hasFeedback:v,feedbackIcon:y,name:b}=l.useContext(t.FormItemInputContext),w=l.useMemo(()=>{var e;let t;if(n){let a=!0!==n&&n.icons||p,i=h&&(null==(e=null==a?void 0:a({status:h,errors:r,warnings:o}))?void 0:e[h]),c=h?H[h]:null;t=!1!==i&&c?l.createElement("span",{className:(0,s.default)(`${f}-feedback-icon`,`${f}-feedback-icon-${h}`)},i||l.createElement(c,null)):null}let a={status:h||"",errors:r,warnings:o,hasFeedback:!!n,feedbackIcon:t,isFormItemInput:!0,name:d};return u&&(a.status=(null!=h?h:g)||"",a.isFormItemInput=m,a.hasFeedback=!!(null!=n?n:v),a.feedbackIcon=void 0!==n?a.feedbackIcon:y,a.name=null!=d?d:b),a},[h,n,u,m,g]);return l.createElement(t.FormItemInputContext.Provider,{value:w},e)}var W=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};function U(e){let{prefixCls:r,className:o,rootClassName:n,style:a,help:i,errors:c,warnings:u,validateStatus:d,meta:f,hasFeedback:p,hidden:h,children:m,fieldId:g,required:v,isRequired:y,onSubItemMetaChange:b,layout:w,name:$}=e,C=W(e,["prefixCls","className","rootClassName","style","help","errors","warnings","validateStatus","meta","hasFeedback","hidden","children","fieldId","required","isRequired","onSubItemMetaChange","layout","name"]),T=`${r}-item`,{requiredMark:I,layout:_}=l.useContext(t.FormContext),F=w||_,P="vertical"===F,R=l.useRef(null),N=(0,B.default)(c),A=(0,B.default)(u),z=null!=i,L=!!(z||c.length||u.length),D=!!R.current&&(0,E.default)(R.current),[H,U]=l.useState(null);(0,S.default)(()=>{L&&R.current&&U(Number.parseInt(getComputedStyle(R.current).marginBottom,10))},[L,D]);let G=((e=!1)=>{let t=e?N:f.errors,r=e?A:f.warnings;return(0,x.getStatus)(t,r,f,"",!!p,d)})(),q=(0,s.default)(T,o,n,{[`${T}-with-help`]:z||N.length||A.length,[`${T}-has-feedback`]:G&&p,[`${T}-has-success`]:"success"===G,[`${T}-has-warning`]:"warning"===G,[`${T}-has-error`]:"error"===G,[`${T}-is-validating`]:"validating"===G,[`${T}-hidden`]:h,[`${T}-${F}`]:F});return l.createElement("div",{className:q,style:a,ref:R},l.createElement(j.Row,Object.assign({className:`${T}-row`},(0,k.default)(C,["_internalItemRender","colon","dependencies","extra","fieldKey","getValueFromEvent","getValueProps","htmlFor","id","initialValue","isListField","label","labelAlign","labelCol","labelWrap","messageVariables","name","normalize","noStyle","preserve","requiredMark","rules","shouldUpdate","trigger","tooltip","validateFirst","validateTrigger","valuePropName","wrapperCol","validateDebounce"])),l.createElement(M,Object.assign({htmlFor:g},e,{requiredMark:I,required:null!=v?v:y,prefixCls:r,vertical:P})),l.createElement(O.default,Object.assign({},e,f,{errors:N,warnings:A,prefixCls:r,status:G,help:i,marginBottom:H,onErrorVisibleChanged:e=>{e||U(null)}}),l.createElement(t.NoStyleItemContext.Provider,{value:b},l.createElement(V,{prefixCls:r,meta:f,errors:f.errors,warnings:f.warnings,hasFeedback:p,validateStatus:G,name:$},m)))),!!H&&l.createElement("div",{className:`${T}-margin-offset`,style:{marginBottom:-H}}))}let G=l.memo(({children:e})=>e,(e,t)=>{var r,o;let n,a;return r=e.control,o=t.control,n=Object.keys(r),a=Object.keys(o),n.length===a.length&&n.every(e=>{let t=r[e],n=o[e];return t===n||"function"==typeof t||"function"==typeof n})&&e.update===t.update&&e.childProps.length===t.childProps.length&&e.childProps.every((e,r)=>e===t.childProps[r])});function q(){return{errors:[],warnings:[],touched:!1,validating:!1,name:[],validated:!1}}let J=function(e){let{name:r,noStyle:o,className:n,dependencies:a,prefixCls:b,shouldUpdate:E,rules:S,children:k,required:j,label:O,messageVariables:T,trigger:I="onChange",validateTrigger:_,hidden:F,help:P,layout:R}=e,{getPrefixCls:N}=l.useContext(g.ConfigContext),{name:M}=l.useContext(t.FormContext),B=(0,y.default)(k),A="function"==typeof B,z=l.useContext(t.NoStyleItemContext),{validateTrigger:L}=l.useContext(u.FieldContext),D=void 0!==_?_:L,H=null!=r,W=N("form",b),J=(0,v.default)(W),[K,X,Y]=(0,C.default)(W,J);(0,m.devUseWarning)("Form.Item");let Q=l.useContext(d.ListContext),Z=l.useRef(null),[ee,et]=(0,w.default)({}),[er,eo]=(0,f.default)(()=>q()),en=(e,t)=>{et(r=>{let o=Object.assign({},r),n=[].concat((0,i.default)(e.name.slice(0,-1)),(0,i.default)(t)).join("__SPLIT__");return e.destroy?delete o[n]:o[n]=e,o})},[ea,ei]=l.useMemo(()=>{let e=(0,i.default)(er.errors),t=(0,i.default)(er.warnings);return Object.values(ee).forEach(r=>{e.push.apply(e,(0,i.default)(r.errors||[])),t.push.apply(t,(0,i.default)(r.warnings||[]))}),[e,t]},[ee,er.errors,er.warnings]),el=(0,$.default)();function es(t,a,i){return o&&!F?l.createElement(V,{prefixCls:W,hasFeedback:e.hasFeedback,validateStatus:e.validateStatus,meta:er,errors:ea,warnings:ei,noStyle:!0,name:r},t):l.createElement(U,Object.assign({key:"row"},e,{className:(0,s.default)(n,Y,J,X),prefixCls:W,fieldId:a,isRequired:i,errors:ea,warnings:ei,meta:er,onSubItemMetaChange:en,layout:R,name:r}),t)}if(!H&&!A&&!a)return K(es(B));let ec={};return"string"==typeof O?ec.label=O:r&&(ec.label=String(r)),T&&(ec=Object.assign(Object.assign({},ec),T)),K(l.createElement(c.Field,Object.assign({},e,{messageVariables:ec,trigger:I,validateTrigger:D,onMetaChange:e=>{let t=null==Q?void 0:Q.getKey(e.name);if(eo(e.destroy?q():e,!0),o&&!1!==P&&z){let r=e.name;if(e.destroy)r=Z.current||r;else if(void 0!==t){let[e,o]=t;Z.current=r=[e].concat((0,i.default)(o))}z(e,r)}}}),(t,o,n)=>{let s=(0,x.toArray)(r).length&&o?o.name:[],c=(0,x.getFieldId)(s,M),u=void 0!==j?j:!!(null==S?void 0:S.some(e=>{if(e&&"object"==typeof e&&e.required&&!e.warningOnly)return!0;if("function"==typeof e){let t=e(n);return(null==t?void 0:t.required)&&!(null==t?void 0:t.warningOnly)}return!1})),d=Object.assign({},t),f=null;if(Array.isArray(B)&&H)f=B;else if(A&&(!(E||a)||H));else if(!a||A||H)if(l.isValidElement(B)){let t=Object.assign(Object.assign({},B.props),d);if(t.id||(t.id=c),P||ea.length>0||ei.length>0||e.extra){let r=[];(P||ea.length>0)&&r.push(`${c}_help`),e.extra&&r.push(`${c}_extra`),t["aria-describedby"]=r.join(" ")}ea.length>0&&(t["aria-invalid"]="true"),u&&(t["aria-required"]="true"),(0,p.supportRef)(B)&&(t.ref=el(s,B)),new Set([].concat((0,i.default)((0,x.toArray)(I)),(0,i.default)((0,x.toArray)(D)))).forEach(e=>{t[e]=(...t)=>{var r,o,n;null==(r=d[e])||r.call.apply(r,[d].concat(t)),null==(n=(o=B.props)[e])||n.call.apply(n,[o].concat(t))}});let r=[t["aria-required"],t["aria-invalid"],t["aria-describedby"]];f=l.createElement(G,{control:d,update:B,childProps:r},(0,h.cloneElement)(B,t))}else f=A&&(E||a)&&!H?B(n):B;return es(f,c,u)}))};J.useStatus=b.default,e.s(["default",0,J],905536);var K=e.i(53058),X=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let Y=o.default;Y.Item=J,Y.List=e=>{var{prefixCls:r,children:o}=e,n=X(e,["prefixCls","children"]);let{getPrefixCls:a}=l.useContext(g.ConfigContext),i=a("form",r),s=l.useMemo(()=>({prefixCls:i,status:"error"}),[i]);return l.createElement(K.List,Object.assign({},n),(e,r,n)=>l.createElement(t.FormItemPrefixContext.Provider,{value:s},o(e.map(e=>Object.assign(Object.assign({},e),{fieldKey:e.key})),r,{errors:n.errors,warnings:n.warnings})))},Y.ErrorList=r.default,Y.useForm=n.useForm,Y.useFormInstance=function(){let{form:e}=l.useContext(t.FormContext);return e},Y.useWatch=a.useWatch,Y.Provider=t.FormProvider,Y.create=()=>{},e.s(["Form",0,Y],808613)},121229,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"}}]},name:"check",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["default",0,a],121229)},268004,e=>{"use strict";function t(){let e=window.location.pathname.match(/\/ui(?=\/|$)/);return e&&void 0!==e.index?window.location.pathname.substring(0,e.index+3):"/ui"}function r(){if("u"{document.cookie=`token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${t};`,document.cookie=`token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${t}; domain=${e};`,n.forEach(r=>{let o="None"===r?" Secure;":"";document.cookie=`token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${t}; SameSite=${r};${o}`,document.cookie=`token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${t}; domain=${e}; SameSite=${r};${o}`})});try{sessionStorage.removeItem("token")}catch{}}function o(e){if(e&&e.trim()){try{let r="https:"===window.location.protocol?"; Secure":"",o=t();document.cookie=`token=${encodeURIComponent(e)}; path=${o}; SameSite=Lax${r}`}catch{}try{sessionStorage.setItem("token",e)}catch{}}}function n(e){if("u"t.startsWith(e+"="));if(t){let e=t.split("=").slice(1).join("=");try{return decodeURIComponent(e)}catch{return e}}if("token"===e)try{return sessionStorage.getItem(e)}catch{}return null}e.s(["clearTokenCookies",()=>r,"getCookie",()=>n,"storeLoginToken",()=>o])},349942,517458,889943,e=>{"use strict";e.i(296059);var t=e.i(915654),r=e.i(183293),o=e.i(372409),n=e.i(246422),a=e.i(838378);function i(e){return(0,a.mergeToken)(e,{inputAffixPadding:e.paddingXXS})}let l=e=>{let{controlHeight:t,fontSize:r,lineHeight:o,lineWidth:n,controlHeightSM:a,controlHeightLG:i,fontSizeLG:l,lineHeightLG:s,paddingSM:c,controlPaddingHorizontalSM:u,controlPaddingHorizontal:d,colorFillAlter:f,colorPrimaryHover:p,colorPrimary:h,controlOutlineWidth:m,controlOutline:g,colorErrorOutline:v,colorWarningOutline:y,colorBgContainer:b,inputFontSize:w,inputFontSizeLG:$,inputFontSizeSM:C}=e,x=w||r,E=C||x,S=$||l;return{paddingBlock:Math.max(Math.round((t-x*o)/2*10)/10-n,0),paddingBlockSM:Math.max(Math.round((a-E*o)/2*10)/10-n,0),paddingBlockLG:Math.max(Math.ceil((i-S*s)/2*10)/10-n,0),paddingInline:c-n,paddingInlineSM:u-n,paddingInlineLG:d-n,addonBg:f,activeBorderColor:h,hoverBorderColor:p,activeShadow:`0 0 0 ${m}px ${g}`,errorActiveShadow:`0 0 0 ${m}px ${v}`,warningActiveShadow:`0 0 0 ${m}px ${y}`,hoverBg:b,activeBg:b,inputFontSize:x,inputFontSizeLG:S,inputFontSizeSM:E}};e.s(["initComponentToken",0,l,"initInputToken",()=>i],517458);let s=e=>{let t;return{color:e.colorTextDisabled,backgroundColor:e.colorBgContainerDisabled,borderColor:e.colorBorder,boxShadow:"none",cursor:"not-allowed",opacity:1,"input[disabled], textarea[disabled]":{cursor:"not-allowed"},"&:hover:not([disabled])":Object.assign({},{borderColor:(t=(0,a.mergeToken)(e,{hoverBorderColor:e.colorBorder,hoverBg:e.colorBgContainerDisabled})).hoverBorderColor,backgroundColor:t.hoverBg})}},c=(e,t)=>({background:e.colorBgContainer,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:t.borderColor,"&:hover":{borderColor:t.hoverBorderColor,backgroundColor:e.hoverBg},"&:focus, &:focus-within":{borderColor:t.activeBorderColor,boxShadow:t.activeShadow,outline:0,backgroundColor:e.activeBg}}),u=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},c(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}}),[`&${e.componentCls}-status-${t.status}${e.componentCls}-disabled`]:{borderColor:t.borderColor}}),d=(e,t)=>({"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},c(e,{borderColor:e.colorBorder,hoverBorderColor:e.hoverBorderColor,activeBorderColor:e.activeBorderColor,activeShadow:e.activeShadow})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},s(e))}),u(e,{status:"error",borderColor:e.colorError,hoverBorderColor:e.colorErrorBorderHover,activeBorderColor:e.colorError,activeShadow:e.errorActiveShadow,affixColor:e.colorError})),u(e,{status:"warning",borderColor:e.colorWarning,hoverBorderColor:e.colorWarningBorderHover,activeBorderColor:e.colorWarning,activeShadow:e.warningActiveShadow,affixColor:e.colorWarning})),t)}),f=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{borderColor:t.addonBorderColor,color:t.addonColor}}}),p=e=>({"&-outlined":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group`]:{"&-addon":{background:e.addonBg,border:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:first-child":{borderInlineEnd:0},"&-addon:last-child":{borderInlineStart:0}}},f(e,{status:"error",addonBorderColor:e.colorError,addonColor:e.colorErrorText})),f(e,{status:"warning",addonBorderColor:e.colorWarning,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group-addon`]:Object.assign({},s(e))}})}),h=(e,t)=>{let{componentCls:r}=e;return{"&-borderless":Object.assign({background:"transparent",border:"none","&:focus, &:focus-within":{outline:"none"},[`&${r}-disabled, &[disabled]`]:{color:e.colorTextDisabled,cursor:"not-allowed"},[`&${r}-status-error`]:{"&, & input, & textarea":{color:e.colorError}},[`&${r}-status-warning`]:{"&, & input, & textarea":{color:e.colorWarning}}},t)}},m=(e,t)=>{var r;return{background:t.bg,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:"transparent","input&, & input, textarea&, & textarea":{color:null!=(r=null==t?void 0:t.inputColor)?r:"unset"},"&:hover":{background:t.hoverBg},"&:focus, &:focus-within":{outline:0,borderColor:t.activeBorderColor,backgroundColor:e.activeBg}}},g=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},m(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}})}),v=(e,t)=>({"&-filled":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},m(e,{bg:e.colorFillTertiary,hoverBg:e.colorFillSecondary,activeBorderColor:e.activeBorderColor})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},s(e))}),g(e,{status:"error",bg:e.colorErrorBg,hoverBg:e.colorErrorBgHover,activeBorderColor:e.colorError,inputColor:e.colorErrorText,affixColor:e.colorError})),g(e,{status:"warning",bg:e.colorWarningBg,hoverBg:e.colorWarningBgHover,activeBorderColor:e.colorWarning,inputColor:e.colorWarningText,affixColor:e.colorWarning})),t)}),y=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{background:t.addonBg,color:t.addonColor}}}),b=e=>({"&-filled":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group-addon`]:{background:e.colorFillTertiary,"&:last-child":{position:"static"}}},y(e,{status:"error",addonBg:e.colorErrorBg,addonColor:e.colorErrorText})),y(e,{status:"warning",addonBg:e.colorWarningBg,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group`]:{"&-addon":{background:e.colorFillTertiary,color:e.colorTextDisabled},"&-addon:first-child":{borderInlineStart:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:last-child":{borderInlineEnd:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${(0,t.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`}}}})}),w=(e,r)=>({background:e.colorBgContainer,borderWidth:`${(0,t.unit)(e.lineWidth)} 0`,borderStyle:`${e.lineType} none`,borderColor:`transparent transparent ${r.borderColor} transparent`,borderRadius:0,"&:hover":{borderColor:`transparent transparent ${r.hoverBorderColor} transparent`,backgroundColor:e.hoverBg},"&:focus, &:focus-within":{borderColor:`transparent transparent ${r.activeBorderColor} transparent`,outline:0,backgroundColor:e.activeBg}}),$=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},w(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}}),[`&${e.componentCls}-status-${t.status}${e.componentCls}-disabled`]:{borderColor:`transparent transparent ${t.borderColor} transparent`}}),C=(e,t)=>({"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},w(e,{borderColor:e.colorBorder,hoverBorderColor:e.hoverBorderColor,activeBorderColor:e.activeBorderColor,activeShadow:e.activeShadow})),{[`&${e.componentCls}-disabled, &[disabled]`]:{color:e.colorTextDisabled,boxShadow:"none",cursor:"not-allowed","&:hover":{borderColor:`transparent transparent ${e.colorBorder} transparent`}},"input[disabled], textarea[disabled]":{cursor:"not-allowed"}}),$(e,{status:"error",borderColor:e.colorError,hoverBorderColor:e.colorErrorBorderHover,activeBorderColor:e.colorError,activeShadow:e.errorActiveShadow,affixColor:e.colorError})),$(e,{status:"warning",borderColor:e.colorWarning,hoverBorderColor:e.colorWarningBorderHover,activeBorderColor:e.colorWarning,activeShadow:e.warningActiveShadow,affixColor:e.colorWarning})),t)});e.s(["genBaseOutlinedStyle",0,c,"genBorderlessStyle",0,h,"genDisabledStyle",0,s,"genFilledGroupStyle",0,b,"genFilledStyle",0,v,"genOutlinedGroupStyle",0,p,"genOutlinedStyle",0,d,"genUnderlinedStyle",0,C],889943);let x=e=>({"&::-moz-placeholder":{opacity:1},"&::placeholder":{color:e,userSelect:"none"},"&:placeholder-shown":{textOverflow:"ellipsis"}}),E=e=>{let{paddingBlockLG:r,lineHeightLG:o,borderRadiusLG:n,paddingInlineLG:a}=e;return{padding:`${(0,t.unit)(r)} ${(0,t.unit)(a)}`,fontSize:e.inputFontSizeLG,lineHeight:o,borderRadius:n}},S=e=>({padding:`${(0,t.unit)(e.paddingBlockSM)} ${(0,t.unit)(e.paddingInlineSM)}`,fontSize:e.inputFontSizeSM,borderRadius:e.borderRadiusSM}),k=e=>Object.assign(Object.assign({position:"relative",display:"inline-block",width:"100%",minWidth:0,padding:`${(0,t.unit)(e.paddingBlock)} ${(0,t.unit)(e.paddingInline)}`,color:e.colorText,fontSize:e.inputFontSize,lineHeight:e.lineHeight,borderRadius:e.borderRadius,transition:`all ${e.motionDurationMid}`},x(e.colorTextPlaceholder)),{"&-lg":Object.assign({},E(e)),"&-sm":Object.assign({},S(e)),"&-rtl, &-textarea-rtl":{direction:"rtl"}}),j=e=>{let{componentCls:o,antCls:n}=e;return{position:"relative",display:"table",width:"100%",borderCollapse:"separate",borderSpacing:0,"&[class*='col-']":{paddingInlineEnd:e.paddingXS,"&:last-child":{paddingInlineEnd:0}},[`&-lg ${o}, &-lg > ${o}-group-addon`]:Object.assign({},E(e)),[`&-sm ${o}, &-sm > ${o}-group-addon`]:Object.assign({},S(e)),[`&-lg ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightLG},[`&-sm ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightSM},[`> ${o}`]:{display:"table-cell","&:not(:first-child):not(:last-child)":{borderRadius:0}},[`${o}-group`]:{"&-addon, &-wrap":{display:"table-cell",width:1,whiteSpace:"nowrap",verticalAlign:"middle","&:not(:first-child):not(:last-child)":{borderRadius:0}},"&-wrap > *":{display:"block !important"},"&-addon":{position:"relative",padding:`0 ${(0,t.unit)(e.paddingInline)}`,color:e.colorText,fontWeight:"normal",fontSize:e.inputFontSize,textAlign:"center",borderRadius:e.borderRadius,transition:`all ${e.motionDurationSlow}`,lineHeight:1,[`${n}-select`]:{margin:`${(0,t.unit)(e.calc(e.paddingBlock).add(1).mul(-1).equal())} ${(0,t.unit)(e.calc(e.paddingInline).mul(-1).equal())}`,[`&${n}-select-single:not(${n}-select-customize-input):not(${n}-pagination-size-changer)`]:{[`${n}-select-selector`]:{backgroundColor:"inherit",border:`${(0,t.unit)(e.lineWidth)} ${e.lineType} transparent`,boxShadow:"none"}}},[`${n}-cascader-picker`]:{margin:`-9px ${(0,t.unit)(e.calc(e.paddingInline).mul(-1).equal())}`,backgroundColor:"transparent",[`${n}-cascader-input`]:{textAlign:"start",border:0,boxShadow:"none"}}}},[o]:{width:"100%",marginBottom:0,textAlign:"inherit","&:focus":{zIndex:1,borderInlineEndWidth:1},"&:hover":{zIndex:1,borderInlineEndWidth:1,[`${o}-search-with-button &`]:{zIndex:0}}},[`> ${o}:first-child, ${o}-group-addon:first-child`]:{borderStartEndRadius:0,borderEndEndRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${o}-affix-wrapper`]:{[`&:not(:first-child) ${o}`]:{borderStartStartRadius:0,borderEndStartRadius:0},[`&:not(:last-child) ${o}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${o}:last-child, ${o}-group-addon:last-child`]:{borderStartStartRadius:0,borderEndStartRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`${o}-affix-wrapper`]:{"&:not(:last-child)":{borderStartEndRadius:0,borderEndEndRadius:0,[`${o}-search &`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius}},[`&:not(:first-child), ${o}-search &:not(:first-child)`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&${o}-group-compact`]:Object.assign(Object.assign({display:"block"},(0,r.clearFix)()),{[`${o}-group-addon, ${o}-group-wrap, > ${o}`]:{"&:not(:first-child):not(:last-child)":{borderInlineEndWidth:e.lineWidth,"&:hover, &:focus":{zIndex:1}}},"& > *":{display:"inline-flex",float:"none",verticalAlign:"top",borderRadius:0},[` - & > ${o}-affix-wrapper, - & > ${o}-number-affix-wrapper, - & > ${n}-picker-range - `]:{display:"inline-flex"},"& > *:not(:last-child)":{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderInlineEndWidth:e.lineWidth},[o]:{float:"none"},[`& > ${n}-select > ${n}-select-selector, - & > ${n}-select-auto-complete ${o}, - & > ${n}-cascader-picker ${o}, - & > ${o}-group-wrapper ${o}`]:{borderInlineEndWidth:e.lineWidth,borderRadius:0,"&:hover, &:focus":{zIndex:1}},[`& > ${n}-select-focused`]:{zIndex:1},[`& > ${n}-select > ${n}-select-arrow`]:{zIndex:1},[`& > *:first-child, - & > ${n}-select:first-child > ${n}-select-selector, - & > ${n}-select-auto-complete:first-child ${o}, - & > ${n}-cascader-picker:first-child ${o}`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius},[`& > *:last-child, - & > ${n}-select:last-child > ${n}-select-selector, - & > ${n}-cascader-picker:last-child ${o}, - & > ${n}-cascader-picker-focused:last-child ${o}`]:{borderInlineEndWidth:e.lineWidth,borderStartEndRadius:e.borderRadius,borderEndEndRadius:e.borderRadius},[`& > ${n}-select-auto-complete ${o}`]:{verticalAlign:"top"},[`${o}-group-wrapper + ${o}-group-wrapper`]:{marginInlineStart:e.calc(e.lineWidth).mul(-1).equal(),[`${o}-affix-wrapper`]:{borderRadius:0}},[`${o}-group-wrapper:not(:last-child)`]:{[`&${o}-search > ${o}-group`]:{[`& > ${o}-group-addon > ${o}-search-button`]:{borderRadius:0},[`& > ${o}`]:{borderStartStartRadius:e.borderRadius,borderStartEndRadius:0,borderEndEndRadius:0,borderEndStartRadius:e.borderRadius}}}})}},O=(0,n.genStyleHooks)(["Input","Shared"],e=>{let o=(0,a.mergeToken)(e,i(e));return[(e=>{let{componentCls:t,controlHeightSM:o,lineWidth:n,calc:a}=e,i=a(o).sub(a(n).mul(2)).sub(16).div(2).equal();return{[t]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},(0,r.resetComponent)(e)),k(e)),d(e)),v(e)),h(e)),C(e)),{'&[type="color"]':{height:e.controlHeight,[`&${t}-lg`]:{height:e.controlHeightLG},[`&${t}-sm`]:{height:o,paddingTop:i,paddingBottom:i}},'&[type="search"]::-webkit-search-cancel-button, &[type="search"]::-webkit-search-decoration':{appearance:"none"}})}})(o),(e=>{let{componentCls:r,inputAffixPadding:o,colorTextDescription:n,motionDurationSlow:a,colorIcon:i,colorIconHover:l,iconCls:s}=e,c=`${r}-affix-wrapper`,u=`${r}-affix-wrapper-disabled`;return{[c]:Object.assign(Object.assign(Object.assign(Object.assign({},k(e)),{display:"inline-flex",[`&:not(${r}-disabled):hover`]:{zIndex:1,[`${r}-search-with-button &`]:{zIndex:0}},"&-focused, &:focus":{zIndex:1},[`> input${r}`]:{padding:0},[`> input${r}, > textarea${r}`]:{fontSize:"inherit",border:"none",borderRadius:0,outline:"none",background:"transparent",color:"inherit","&::-ms-reveal":{display:"none"},"&:focus":{boxShadow:"none !important"}},"&::before":{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'},[r]:{"&-prefix, &-suffix":{display:"flex",flex:"none",alignItems:"center","> *:not(:last-child)":{marginInlineEnd:e.paddingXS}},"&-show-count-suffix":{color:n,direction:"ltr"},"&-show-count-has-suffix":{marginInlineEnd:e.paddingXXS},"&-prefix":{marginInlineEnd:o},"&-suffix":{marginInlineStart:o}}}),(e=>{let{componentCls:r}=e;return{[`${r}-clear-icon`]:{margin:0,padding:0,lineHeight:0,color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,verticalAlign:-1,cursor:"pointer",transition:`color ${e.motionDurationSlow}`,border:"none",outline:"none",backgroundColor:"transparent","&:hover":{color:e.colorIcon},"&:active":{color:e.colorText},"&-hidden":{visibility:"hidden"},"&-has-suffix":{margin:`0 ${(0,t.unit)(e.inputAffixPadding)}`}}}})(e)),{[`${s}${r}-password-icon`]:{color:i,cursor:"pointer",transition:`all ${a}`,"&:hover":{color:l}}}),[`${r}-underlined`]:{borderRadius:0},[u]:{[`${s}${r}-password-icon`]:{color:i,cursor:"not-allowed","&:hover":{color:i}}}}})(o)]},l,{resetFont:!1}),T=(0,n.genStyleHooks)(["Input","Component"],e=>{let t=(0,a.mergeToken)(e,i(e));return[(e=>{let{componentCls:t,borderRadiusLG:o,borderRadiusSM:n}=e;return{[`${t}-group`]:Object.assign(Object.assign(Object.assign({},(0,r.resetComponent)(e)),j(e)),{"&-rtl":{direction:"rtl"},"&-wrapper":Object.assign(Object.assign(Object.assign({display:"inline-block",width:"100%",textAlign:"start",verticalAlign:"top","&-rtl":{direction:"rtl"},"&-lg":{[`${t}-group-addon`]:{borderRadius:o,fontSize:e.inputFontSizeLG}},"&-sm":{[`${t}-group-addon`]:{borderRadius:n}}},p(e)),b(e)),{[`&:not(${t}-compact-first-item):not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}, ${t}-group-addon`]:{borderRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-first-item`]:{[`${t}, ${t}-group-addon`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&:not(${t}-compact-first-item)${t}-compact-last-item`]:{[`${t}, ${t}-group-addon`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}-affix-wrapper`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&:not(${t}-compact-first-item)${t}-compact-item`]:{[`${t}-affix-wrapper`]:{borderStartStartRadius:0,borderEndStartRadius:0}}})})}})(t),(e=>{let{componentCls:t,antCls:r}=e,o=`${t}-search`;return{[o]:{[t]:{"&:not([disabled]):hover, &:not([disabled]):focus":{[`+ ${t}-group-addon ${o}-button:not(${r}-btn-color-primary):not(${r}-btn-variant-text)`]:{borderInlineStartColor:e.colorPrimaryHover}}},[`${t}-affix-wrapper`]:{height:e.controlHeight,borderRadius:0},[`${t}-lg`]:{lineHeight:e.calc(e.lineHeightLG).sub(2e-4).equal()},[`> ${t}-group`]:{[`> ${t}-group-addon:last-child`]:{insetInlineStart:-1,padding:0,border:0,[`${o}-button`]:{marginInlineEnd:-1,borderStartStartRadius:0,borderEndStartRadius:0,boxShadow:"none"},[`${o}-button:not(${r}-btn-color-primary)`]:{color:e.colorTextDescription,"&:not([disabled]):hover":{color:e.colorPrimaryHover},"&:active":{color:e.colorPrimaryActive},[`&${r}-btn-loading::before`]:{inset:0}}}},[`${o}-button`]:{height:e.controlHeight,"&:hover, &:focus":{zIndex:1}},"&-large":{[`${t}-affix-wrapper, ${o}-button`]:{height:e.controlHeightLG}},"&-small":{[`${t}-affix-wrapper, ${o}-button`]:{height:e.controlHeightSM}},"&-rtl":{direction:"rtl"},[`&${t}-compact-item`]:{[`&:not(${t}-compact-last-item)`]:{[`${t}-group-addon`]:{[`${t}-search-button`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderRadius:0}}},[`&:not(${t}-compact-first-item)`]:{[`${t},${t}-affix-wrapper`]:{borderRadius:0}},[`> ${t}-group-addon ${t}-search-button, - > ${t}, - ${t}-affix-wrapper`]:{"&:hover, &:focus, &:active":{zIndex:2}},[`> ${t}-affix-wrapper-focused`]:{zIndex:2}}}}})(t),(e=>{let{componentCls:t}=e;return{[`${t}-out-of-range`]:{[`&, & input, & textarea, ${t}-show-count-suffix, ${t}-data-count`]:{color:e.colorError}}}})(t),(0,o.genCompactItemStyle)(t)]},l,{resetFont:!1});e.s(["default",0,T,"genBasicInputStyle",0,k,"genInputGroupStyle",0,j,"genInputSmallStyle",0,S,"genPlaceholderStyle",0,x,"useSharedStyle",0,O],349942)},831357,e=>{"use strict";var t=e.i(271645),r=e.i(343794),o=e.i(242064),n=e.i(62139),a=e.i(349942);e.s(["default",0,e=>{let{getPrefixCls:i,direction:l}=(0,t.useContext)(o.ConfigContext),{prefixCls:s,className:c}=e,u=i("input-group",s),d=i("input"),[f,p,h]=(0,a.default)(d),m=(0,r.default)(u,h,{[`${u}-lg`]:"large"===e.size,[`${u}-sm`]:"small"===e.size,[`${u}-compact`]:e.compact,[`${u}-rtl`]:"rtl"===l},p,c),g=(0,t.useContext)(n.FormItemInputContext),v=(0,t.useMemo)(()=>Object.assign(Object.assign({},g),{isFormItemInput:!1}),[g]);return f(t.createElement("span",{className:m,style:e.style,onMouseEnter:e.onMouseEnter,onMouseLeave:e.onMouseLeave,onFocus:e.onFocus,onBlur:e.onBlur},t.createElement(n.FormItemInputContext.Provider,{value:v},e.children)))}])},175636,131299,367397,874460,e=>{"use strict";var t=e.i(209428),r=e.i(931067),o=e.i(211577),n=e.i(410160),a=e.i(343794),i=e.i(271645);function l(e){return!!(e.addonBefore||e.addonAfter)}function s(e){return!!(e.prefix||e.suffix||e.allowClear)}function c(e,t,r){var o=t.cloneNode(!0),n=Object.create(e,{target:{value:o},currentTarget:{value:o}});return o.value=r,"number"==typeof t.selectionStart&&"number"==typeof t.selectionEnd&&(o.selectionStart=t.selectionStart,o.selectionEnd=t.selectionEnd),o.setSelectionRange=function(){t.setSelectionRange.apply(t,arguments)},n}function u(e,t,r,o){if(r){var n=t;if("click"===t.type)return void r(n=c(t,e,""));if("file"!==e.type&&void 0!==o)return void r(n=c(t,e,o));r(n)}}function d(e,t){if(e){e.focus(t);var r=(t||{}).cursor;if(r){var o=e.value.length;switch(r){case"start":e.setSelectionRange(0,0);break;case"end":e.setSelectionRange(o,o);break;default:e.setSelectionRange(0,o)}}}}e.s(["hasAddon",()=>l,"hasPrefixSuffix",()=>s,"resolveOnChange",()=>u,"triggerFocus",()=>d],131299);var f=i.default.forwardRef(function(e,c){var u,d,f,p=e.inputElement,h=e.children,m=e.prefixCls,g=e.prefix,v=e.suffix,y=e.addonBefore,b=e.addonAfter,w=e.className,$=e.style,C=e.disabled,x=e.readOnly,E=e.focused,S=e.triggerFocus,k=e.allowClear,j=e.value,O=e.handleReset,T=e.hidden,I=e.classes,_=e.classNames,F=e.dataAttrs,P=e.styles,R=e.components,N=e.onClear,M=null!=h?h:p,B=(null==R?void 0:R.affixWrapper)||"span",A=(null==R?void 0:R.groupWrapper)||"span",z=(null==R?void 0:R.wrapper)||"span",L=(null==R?void 0:R.groupAddon)||"span",D=(0,i.useRef)(null),H=s(e),V=(0,i.cloneElement)(M,{value:j,className:(0,a.default)(null==(u=M.props)?void 0:u.className,!H&&(null==_?void 0:_.variant))||null}),W=(0,i.useRef)(null);if(i.default.useImperativeHandle(c,function(){return{nativeElement:W.current||D.current}}),H){var U=null;if(k){var G=!C&&!x&&j,q="".concat(m,"-clear-icon"),J="object"===(0,n.default)(k)&&null!=k&&k.clearIcon?k.clearIcon:"✖";U=i.default.createElement("button",{type:"button",tabIndex:-1,onClick:function(e){null==O||O(e),null==N||N()},onMouseDown:function(e){return e.preventDefault()},className:(0,a.default)(q,(0,o.default)((0,o.default)({},"".concat(q,"-hidden"),!G),"".concat(q,"-has-suffix"),!!v))},J)}var K="".concat(m,"-affix-wrapper"),X=(0,a.default)(K,(0,o.default)((0,o.default)((0,o.default)((0,o.default)((0,o.default)({},"".concat(m,"-disabled"),C),"".concat(K,"-disabled"),C),"".concat(K,"-focused"),E),"".concat(K,"-readonly"),x),"".concat(K,"-input-with-clear-btn"),v&&k&&j),null==I?void 0:I.affixWrapper,null==_?void 0:_.affixWrapper,null==_?void 0:_.variant),Y=(v||k)&&i.default.createElement("span",{className:(0,a.default)("".concat(m,"-suffix"),null==_?void 0:_.suffix),style:null==P?void 0:P.suffix},U,v);V=i.default.createElement(B,(0,r.default)({className:X,style:null==P?void 0:P.affixWrapper,onClick:function(e){var t;null!=(t=D.current)&&t.contains(e.target)&&(null==S||S())}},null==F?void 0:F.affixWrapper,{ref:D}),g&&i.default.createElement("span",{className:(0,a.default)("".concat(m,"-prefix"),null==_?void 0:_.prefix),style:null==P?void 0:P.prefix},g),V,Y)}if(l(e)){var Q="".concat(m,"-group"),Z="".concat(Q,"-addon"),ee="".concat(Q,"-wrapper"),et=(0,a.default)("".concat(m,"-wrapper"),Q,null==I?void 0:I.wrapper,null==_?void 0:_.wrapper),er=(0,a.default)(ee,(0,o.default)({},"".concat(ee,"-disabled"),C),null==I?void 0:I.group,null==_?void 0:_.groupWrapper);V=i.default.createElement(A,{className:er,ref:W},i.default.createElement(z,{className:et},y&&i.default.createElement(L,{className:Z},y),V,b&&i.default.createElement(L,{className:Z},b)))}return i.default.cloneElement(V,{className:(0,a.default)(null==(d=V.props)?void 0:d.className,w)||null,style:(0,t.default)((0,t.default)({},null==(f=V.props)?void 0:f.style),$),hidden:T})});e.s(["default",0,f],367397);var p=e.i(8211),h=e.i(392221),m=e.i(703923),g=e.i(914949),v=e.i(529681),y=["show"];function b(e,r){return i.useMemo(function(){var o={};r&&(o.show="object"===(0,n.default)(r)&&r.formatter?r.formatter:!!r);var a=o=(0,t.default)((0,t.default)({},o),e),i=a.show,l=(0,m.default)(a,y);return(0,t.default)((0,t.default)({},l),{},{show:!!i,showFormatter:"function"==typeof i?i:void 0,strategy:l.strategy||function(e){return e.length}})},[e,r])}e.s(["default",()=>b],874460);var w=["autoComplete","onChange","onFocus","onBlur","onPressEnter","onKeyDown","onKeyUp","prefixCls","disabled","htmlSize","className","maxLength","suffix","showCount","count","type","classes","classNames","styles","onCompositionStart","onCompositionEnd"],$=(0,i.forwardRef)(function(e,n){var l,s=e.autoComplete,c=e.onChange,y=e.onFocus,$=e.onBlur,C=e.onPressEnter,x=e.onKeyDown,E=e.onKeyUp,S=e.prefixCls,k=void 0===S?"rc-input":S,j=e.disabled,O=e.htmlSize,T=e.className,I=e.maxLength,_=e.suffix,F=e.showCount,P=e.count,R=e.type,N=e.classes,M=e.classNames,B=e.styles,A=e.onCompositionStart,z=e.onCompositionEnd,L=(0,m.default)(e,w),D=(0,i.useState)(!1),H=(0,h.default)(D,2),V=H[0],W=H[1],U=(0,i.useRef)(!1),G=(0,i.useRef)(!1),q=(0,i.useRef)(null),J=(0,i.useRef)(null),K=function(e){q.current&&d(q.current,e)},X=(0,g.default)(e.defaultValue,{value:e.value}),Y=(0,h.default)(X,2),Q=Y[0],Z=Y[1],ee=null==Q?"":String(Q),et=(0,i.useState)(null),er=(0,h.default)(et,2),eo=er[0],en=er[1],ea=b(P,F),ei=ea.max||I,el=ea.strategy(ee),es=!!ei&&el>ei;(0,i.useImperativeHandle)(n,function(){var e;return{focus:K,blur:function(){var e;null==(e=q.current)||e.blur()},setSelectionRange:function(e,t,r){var o;null==(o=q.current)||o.setSelectionRange(e,t,r)},select:function(){var e;null==(e=q.current)||e.select()},input:q.current,nativeElement:(null==(e=J.current)?void 0:e.nativeElement)||q.current}}),(0,i.useEffect)(function(){G.current&&(G.current=!1),W(function(e){return(!e||!j)&&e})},[j]);var ec=function(e,t,r){var o,n,a=t;if(!U.current&&ea.exceedFormatter&&ea.max&&ea.strategy(t)>ea.max)a=ea.exceedFormatter(t,{max:ea.max}),t!==a&&en([(null==(o=q.current)?void 0:o.selectionStart)||0,(null==(n=q.current)?void 0:n.selectionEnd)||0]);else if("compositionEnd"===r.source)return;Z(a),q.current&&u(q.current,e,c,a)};(0,i.useEffect)(function(){if(eo){var e;null==(e=q.current)||e.setSelectionRange.apply(e,(0,p.default)(eo))}},[eo]);var eu=es&&"".concat(k,"-out-of-range");return i.default.createElement(f,(0,r.default)({},L,{prefixCls:k,className:(0,a.default)(T,eu),handleReset:function(e){Z(""),K(),q.current&&u(q.current,e,c)},value:ee,focused:V,triggerFocus:K,suffix:function(){var e=Number(ei)>0;if(_||ea.show){var r=ea.showFormatter?ea.showFormatter({value:ee,count:el,maxLength:ei}):"".concat(el).concat(e?" / ".concat(ei):"");return i.default.createElement(i.default.Fragment,null,ea.show&&i.default.createElement("span",{className:(0,a.default)("".concat(k,"-show-count-suffix"),(0,o.default)({},"".concat(k,"-show-count-has-suffix"),!!_),null==M?void 0:M.count),style:(0,t.default)({},null==B?void 0:B.count)},r),_)}return null}(),disabled:j,classes:N,classNames:M,styles:B,ref:J}),(l=(0,v.default)(e,["prefixCls","onPressEnter","addonBefore","addonAfter","prefix","suffix","allowClear","defaultValue","showCount","count","classes","htmlSize","styles","classNames","onClear"]),i.default.createElement("input",(0,r.default)({autoComplete:s},l,{onChange:function(e){ec(e,e.target.value,{source:"change"})},onFocus:function(e){W(!0),null==y||y(e)},onBlur:function(e){G.current&&(G.current=!1),W(!1),null==$||$(e)},onKeyDown:function(e){C&&"Enter"===e.key&&!G.current&&(G.current=!0,C(e)),null==x||x(e)},onKeyUp:function(e){"Enter"===e.key&&(G.current=!1),null==E||E(e)},className:(0,a.default)(k,(0,o.default)({},"".concat(k,"-disabled"),j),null==M?void 0:M.input),style:null==B?void 0:B.input,ref:q,size:O,type:void 0===R?"text":R,onCompositionStart:function(e){U.current=!0,null==A||A(e)},onCompositionEnd:function(e){U.current=!1,ec(e,e.currentTarget.value,{source:"compositionEnd"}),null==z||z(e)}}))))});e.s(["default",0,$],175636)},330683,e=>{"use strict";var t=e.i(271645),r=e.i(726289);e.s(["default",0,e=>{let o;return"object"==typeof e&&(null==e?void 0:e.clearIcon)?o=e:e&&(o={clearIcon:t.default.createElement(r.default,null)}),o}])},52956,e=>{"use strict";var t=e.i(343794);function r(e,r,o){return(0,t.default)({[`${e}-status-success`]:"success"===r,[`${e}-status-warning`]:"warning"===r,[`${e}-status-error`]:"error"===r,[`${e}-status-validating`]:"validating"===r,[`${e}-has-feedback`]:o})}e.s(["getMergedStatus",0,(e,t)=>t||e,"getStatusClassNames",()=>r])},792812,e=>{"use strict";var t=e.i(271645),r=e.i(242064),o=e.i(62139);e.s(["default",0,(e,n,a)=>{var i,l;let s,{variant:c,[e]:u}=t.useContext(r.ConfigContext),d=t.useContext(o.VariantContext),f=null==u?void 0:u.variant;s=void 0!==n?n:!1===a?"borderless":null!=(l=null!=(i=null!=d?d:f)?i:c)?l:"outlined";let p=r.Variants.includes(s);return[s,p]}])},90635,545719,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(175636);e.i(131299);var n=e.i(611935),a=e.i(617206),i=e.i(330683),l=e.i(52956),s=e.i(242064),c=e.i(937328),u=e.i(321883),d=e.i(517455),f=e.i(62139),p=e.i(792812),h=e.i(249616);function m(e,r){let o=(0,t.useRef)([]),n=()=>{o.current.push(setTimeout(()=>{var t,r,o,n;(null==(t=e.current)?void 0:t.input)&&(null==(r=e.current)?void 0:r.input.getAttribute("type"))==="password"&&(null==(o=e.current)?void 0:o.input.hasAttribute("value"))&&(null==(n=e.current)||n.input.removeAttribute("value"))}))};return(0,t.useEffect)(()=>(r&&n(),()=>o.current.forEach(e=>{e&&clearTimeout(e)})),[]),n}e.s(["default",()=>m],545719);var g=e.i(349942),v=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let y=(0,t.forwardRef)((e,y)=>{let{prefixCls:b,bordered:w=!0,status:$,size:C,disabled:x,onBlur:E,onFocus:S,suffix:k,allowClear:j,addonAfter:O,addonBefore:T,className:I,style:_,styles:F,rootClassName:P,onChange:R,classNames:N,variant:M,_skipAddonWarning:B}=e,A=v(e,["prefixCls","bordered","status","size","disabled","onBlur","onFocus","suffix","allowClear","addonAfter","addonBefore","className","style","styles","rootClassName","onChange","classNames","variant","_skipAddonWarning"]),{getPrefixCls:z,direction:L,allowClear:D,autoComplete:H,className:V,style:W,classNames:U,styles:G}=(0,s.useComponentConfig)("input"),q=z("input",b),J=(0,t.useRef)(null),K=(0,u.default)(q),[X,Y,Q]=(0,g.useSharedStyle)(q,P),[Z]=(0,g.default)(q,K),{compactSize:ee,compactItemClassnames:et}=(0,h.useCompactItemContext)(q,L),er=(0,d.default)(e=>{var t;return null!=(t=null!=C?C:ee)?t:e}),eo=t.default.useContext(c.default),{status:en,hasFeedback:ea,feedbackIcon:ei}=(0,t.useContext)(f.FormItemInputContext),el=(0,l.getMergedStatus)(en,$),es=!!(e.prefix||e.suffix||e.allowClear||e.showCount)||!!ea;(0,t.useRef)(es);let ec=m(J,!0),eu=(ea||k)&&t.default.createElement(t.default.Fragment,null,k,ea&&ei),ed=(0,i.default)(null!=j?j:D),[ef,ep]=(0,p.default)("input",M,w);return X(Z(t.default.createElement(o.default,Object.assign({ref:(0,n.composeRef)(y,J),prefixCls:q,autoComplete:H},A,{disabled:null!=x?x:eo,onBlur:e=>{ec(),null==E||E(e)},onFocus:e=>{ec(),null==S||S(e)},style:Object.assign(Object.assign({},W),_),styles:Object.assign(Object.assign({},G),F),suffix:eu,allowClear:ed,className:(0,r.default)(I,P,Q,K,et,V),onChange:e=>{ec(),null==R||R(e)},addonBefore:T&&t.default.createElement(a.default,{form:!0,space:!0},T),addonAfter:O&&t.default.createElement(a.default,{form:!0,space:!0},O),classNames:Object.assign(Object.assign(Object.assign({},N),U),{input:(0,r.default)({[`${q}-sm`]:"small"===er,[`${q}-lg`]:"large"===er,[`${q}-rtl`]:"rtl"===L},null==N?void 0:N.input,U.input,Y),variant:(0,r.default)({[`${q}-${ef}`]:ep},(0,l.getStatusClassNames)(q,el)),affixWrapper:(0,r.default)({[`${q}-affix-wrapper-sm`]:"small"===er,[`${q}-affix-wrapper-lg`]:"large"===er,[`${q}-affix-wrapper-rtl`]:"rtl"===L},Y),wrapper:(0,r.default)({[`${q}-group-rtl`]:"rtl"===L},Y),groupWrapper:(0,r.default)({[`${q}-group-wrapper-sm`]:"small"===er,[`${q}-group-wrapper-lg`]:"large"===er,[`${q}-group-wrapper-rtl`]:"rtl"===L,[`${q}-group-wrapper-${ef}`]:ep},(0,l.getStatusClassNames)(`${q}-group-wrapper`,el,ea),Y)})}))))});e.s(["default",0,y],90635)},932399,741585,984125,236798,e=>{"use strict";e.i(247167);var t=e.i(8211),r=e.i(271645),o=e.i(343794),n=e.i(175066),a=e.i(244009),i=e.i(52956),l=e.i(242064),s=e.i(517455),c=e.i(62139),u=e.i(246422),d=e.i(838378),f=e.i(517458);let p=(0,u.genStyleHooks)(["Input","OTP"],e=>(e=>{let{componentCls:t,paddingXS:r}=e;return{[t]:{display:"inline-flex",alignItems:"center",flexWrap:"nowrap",columnGap:r,[`${t}-input-wrapper`]:{position:"relative",[`${t}-mask-icon`]:{position:"absolute",zIndex:"1",top:"50%",right:"50%",transform:"translate(50%, -50%)",pointerEvents:"none"},[`${t}-mask-input`]:{color:"transparent",caretColor:e.colorText},[`${t}-mask-input[type=number]::-webkit-inner-spin-button`]:{"-webkit-appearance":"none",margin:0},[`${t}-mask-input[type=number]`]:{"-moz-appearance":"textfield"}},"&-rtl":{direction:"rtl"},[`${t}-input`]:{textAlign:"center",paddingInline:e.paddingXXS},[`&${t}-sm ${t}-input`]:{paddingInline:e.calc(e.paddingXXS).div(2).equal()},[`&${t}-lg ${t}-input`]:{paddingInline:e.paddingXS}}}})((0,d.mergeToken)(e,(0,f.initInputToken)(e))),f.initComponentToken);var h=e.i(963188),m=e.i(90635),g=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let v=r.forwardRef((e,t)=>{let{className:n,value:a,onChange:i,onActiveChange:s,index:c,mask:u}=e,d=g(e,["className","value","onChange","onActiveChange","index","mask"]),{getPrefixCls:f}=r.useContext(l.ConfigContext),p=f("otp"),v="string"==typeof u?u:a,y=r.useRef(null);r.useImperativeHandle(t,()=>y.current);let b=()=>{(0,h.default)(()=>{var e;let t=null==(e=y.current)?void 0:e.input;document.activeElement===t&&t&&t.select()})};return r.createElement("span",{className:`${p}-input-wrapper`,role:"presentation"},u&&""!==a&&void 0!==a&&r.createElement("span",{className:`${p}-mask-icon`,"aria-hidden":"true"},v),r.createElement(m.default,Object.assign({"aria-label":`OTP Input ${c+1}`,type:!0===u?"password":"text"},d,{ref:y,value:a,onInput:e=>{i(c,e.target.value)},onFocus:b,onKeyDown:e=>{let{key:t,ctrlKey:r,metaKey:o}=e;"ArrowLeft"===t?s(c-1):"ArrowRight"===t?s(c+1):"z"===t&&(r||o)?e.preventDefault():"Backspace"!==t||a||s(c-1),b()},onMouseDown:b,onMouseUp:b,className:(0,o.default)(n,{[`${p}-mask-input`]:u})})))});var y=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};function b(e){return(e||"").split("")}let w=e=>{let{index:t,prefixCls:o,separator:n}=e,a="function"==typeof n?n(t):n;return a?r.createElement("span",{className:`${o}-separator`},a):null},$=r.forwardRef((e,u)=>{let{prefixCls:d,length:f=6,size:h,defaultValue:m,value:g,onChange:$,formatter:C,separator:x,variant:E,disabled:S,status:k,autoFocus:j,mask:O,type:T,onInput:I,inputMode:_}=e,F=y(e,["prefixCls","length","size","defaultValue","value","onChange","formatter","separator","variant","disabled","status","autoFocus","mask","type","onInput","inputMode"]),{getPrefixCls:P,direction:R}=r.useContext(l.ConfigContext),N=P("otp",d),M=(0,a.default)(F,{aria:!0,data:!0,attr:!0}),[B,A,z]=p(N),L=(0,s.default)(e=>null!=h?h:e),D=r.useContext(c.FormItemInputContext),H=(0,i.getMergedStatus)(D.status,k),V=r.useMemo(()=>Object.assign(Object.assign({},D),{status:H,hasFeedback:!1,feedbackIcon:null}),[D,H]),W=r.useRef(null),U=r.useRef({});r.useImperativeHandle(u,()=>({focus:()=>{var e;null==(e=U.current[0])||e.focus()},blur:()=>{var e;for(let t=0;tC?C(e):e,[q,J]=r.useState(()=>b(G(m||"")));r.useEffect(()=>{void 0!==g&&J(b(g))},[g]);let K=(0,n.default)(e=>{J(e),I&&I(e),$&&e.length===f&&e.every(e=>e)&&e.some((e,t)=>q[t]!==e)&&$(e.join(""))}),X=(0,n.default)((e,r)=>{let o=(0,t.default)(q);for(let t=0;t=0&&!o[e];e-=1)o.pop();return o=b(G(o.map(e=>e||" ").join(""))).map((e,t)=>" "!==e||o[t]?e:o[t])}),Y=(e,t)=>{var r;let o=X(e,t),n=Math.min(e+t.length,f-1);n!==e&&void 0!==o[e]&&(null==(r=U.current[n])||r.focus()),K(o)},Q=e=>{var t;null==(t=U.current[e])||t.focus()},Z={variant:E,disabled:S,status:H,mask:O,type:T,inputMode:_};return B(r.createElement("div",Object.assign({},M,{ref:W,className:(0,o.default)(N,{[`${N}-sm`]:"small"===L,[`${N}-lg`]:"large"===L,[`${N}-rtl`]:"rtl"===R},z,A),role:"group"}),r.createElement(c.FormItemInputContext.Provider,{value:V},Array.from({length:f}).map((e,t)=>{let o=`otp-${t}`,n=q[t]||"";return r.createElement(r.Fragment,{key:o},r.createElement(v,Object.assign({ref:e=>{U.current[t]=e},index:t,size:L,htmlSize:1,className:`${N}-input`,onChange:Y,value:n,onActiveChange:Q,autoFocus:0===t&&j},Z)),tt.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let P=e=>e?r.createElement(j,null):r.createElement(S,null),R={click:"onClick",hover:"onMouseOver"},N=r.forwardRef((e,t)=>{let n,a,i,{disabled:s,action:c="click",visibilityToggle:u=!0,iconRender:d=P,suffix:f}=e,p=r.useContext(I.default),h=null!=s?s:p,g="object"==typeof u&&void 0!==u.visible,[v,y]=(0,r.useState)(()=>!!g&&u.visible),b=(0,r.useRef)(null);r.useEffect(()=>{g&&y(u.visible)},[g,u]);let w=(0,_.default)(b),{className:$,prefixCls:C,inputPrefixCls:x,size:E}=e,S=F(e,["className","prefixCls","inputPrefixCls","size"]),{getPrefixCls:k}=r.useContext(l.ConfigContext),j=k("input",x),N=k("input-password",C),M=u&&(n=R[c]||"",a=d(v),i={[n]:()=>{var e;if(h)return;v&&w();let t=!v;y(t),"object"==typeof u&&(null==(e=u.onVisibleChange)||e.call(u,t))},className:`${N}-icon`,key:"passwordIcon",onMouseDown:e=>{e.preventDefault()},onMouseUp:e=>{e.preventDefault()}},r.cloneElement(r.isValidElement(a)?a:r.createElement("span",null,a),i)),B=(0,o.default)(N,$,{[`${N}-${E}`]:!!E}),A=Object.assign(Object.assign({},(0,O.default)(S,["suffix","iconRender","visibilityToggle"])),{type:v?"text":"password",className:B,prefixCls:j,suffix:r.createElement(r.Fragment,null,M,f)});return E&&(A.size=E),r.createElement(m.default,Object.assign({ref:(0,T.composeRef)(t,b)},A))});e.s(["default",0,N],236798)},38953,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"}}]},name:"search",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["default",0,a],38953)},995387,e=>{"use strict";var t=e.i(271645),r=e.i(38953),o=e.i(343794),n=e.i(611935),a=e.i(763731),i=e.i(920228),l=e.i(242064),s=e.i(517455),c=e.i(249616),u=e.i(90635),d=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let f=t.forwardRef((e,f)=>{let p,{prefixCls:h,inputPrefixCls:m,className:g,size:v,suffix:y,enterButton:b=!1,addonAfter:w,loading:$,disabled:C,onSearch:x,onChange:E,onCompositionStart:S,onCompositionEnd:k,variant:j,onPressEnter:O}=e,T=d(e,["prefixCls","inputPrefixCls","className","size","suffix","enterButton","addonAfter","loading","disabled","onSearch","onChange","onCompositionStart","onCompositionEnd","variant","onPressEnter"]),{getPrefixCls:I,direction:_}=t.useContext(l.ConfigContext),F=t.useRef(!1),P=I("input-search",h),R=I("input",m),{compactSize:N}=(0,c.useCompactItemContext)(P,_),M=(0,s.default)(e=>{var t;return null!=(t=null!=v?v:N)?t:e}),B=t.useRef(null),A=e=>{var t;document.activeElement===(null==(t=B.current)?void 0:t.input)&&e.preventDefault()},z=e=>{var t,r;x&&x(null==(r=null==(t=B.current)?void 0:t.input)?void 0:r.value,e,{source:"input"})},L="boolean"==typeof b?t.createElement(r.default,null):null,D=`${P}-button`,H=b||{},V=H.type&&!0===H.type.__ANT_BUTTON;p=V||"button"===H.type?(0,a.cloneElement)(H,Object.assign({onMouseDown:A,onClick:e=>{var t,r;null==(r=null==(t=null==H?void 0:H.props)?void 0:t.onClick)||r.call(t,e),z(e)},key:"enterButton"},V?{className:D,size:M}:{})):t.createElement(i.default,{className:D,color:b?"primary":"default",size:M,disabled:C,key:"enterButton",onMouseDown:A,onClick:z,loading:$,icon:L,variant:"borderless"===j||"filled"===j||"underlined"===j?"text":b?"solid":void 0},b),w&&(p=[p,(0,a.cloneElement)(w,{key:"addonAfter"})]);let W=(0,o.default)(P,{[`${P}-rtl`]:"rtl"===_,[`${P}-${M}`]:!!M,[`${P}-with-button`]:!!b},g),U=Object.assign(Object.assign({},T),{className:W,prefixCls:R,type:"search",size:M,variant:j,onPressEnter:e=>{F.current||$||(null==O||O(e),z(e))},onCompositionStart:e=>{F.current=!0,null==S||S(e)},onCompositionEnd:e=>{F.current=!1,null==k||k(e)},addonAfter:p,suffix:y,onChange:e=>{(null==e?void 0:e.target)&&"click"===e.type&&x&&x(e.target.value,e,{source:"clear"}),null==E||E(e)},disabled:C,_skipAddonWarning:!0});return t.createElement(u.default,Object.assign({ref:(0,n.composeRef)(B,f)},U))});e.s(["default",0,f])},302384,e=>{"use strict";var t=e.i(367397);e.s(["BaseInput",()=>t.default])},598030,e=>{"use strict";var t,r=e.i(931067),o=e.i(211577),n=e.i(209428),a=e.i(8211),i=e.i(392221),l=e.i(703923),s=e.i(343794);e.i(175636);var c=e.i(302384),u=e.i(874460),d=e.i(131299),f=e.i(914949),p=e.i(271645);e.i(247167);var h=e.i(410160),m=e.i(430073),g=e.i(174428),v=e.i(963188),y=["letter-spacing","line-height","padding-top","padding-bottom","font-family","font-weight","font-size","font-variant","text-rendering","text-transform","width","text-indent","padding-left","padding-right","border-width","box-sizing","word-break","white-space"],b={},w=["prefixCls","defaultValue","value","autoSize","onResize","className","style","disabled","onChange","onInternalAutoSize"],$=p.forwardRef(function(e,a){var c=e.prefixCls,u=e.defaultValue,d=e.value,$=e.autoSize,C=e.onResize,x=e.className,E=e.style,S=e.disabled,k=e.onChange,j=(e.onInternalAutoSize,(0,l.default)(e,w)),O=(0,f.default)(u,{value:d,postState:function(e){return null!=e?e:""}}),T=(0,i.default)(O,2),I=T[0],_=T[1],F=p.useRef();p.useImperativeHandle(a,function(){return{textArea:F.current}});var P=p.useMemo(function(){return $&&"object"===(0,h.default)($)?[$.minRows,$.maxRows]:[]},[$]),R=(0,i.default)(P,2),N=R[0],M=R[1],B=!!$,A=p.useState(2),z=(0,i.default)(A,2),L=z[0],D=z[1],H=p.useState(),V=(0,i.default)(H,2),W=V[0],U=V[1],G=function(){D(0)};(0,g.default)(function(){B&&G()},[d,N,M,B]),(0,g.default)(function(){if(0===L)D(1);else if(1===L){var e=function(e){var r,o=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;t||((t=document.createElement("textarea")).setAttribute("tab-index","-1"),t.setAttribute("aria-hidden","true"),t.setAttribute("name","hiddenTextarea"),document.body.appendChild(t)),e.getAttribute("wrap")?t.setAttribute("wrap",e.getAttribute("wrap")):t.removeAttribute("wrap");var i=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=e.getAttribute("id")||e.getAttribute("data-reactid")||e.getAttribute("name");if(t&&b[r])return b[r];var o=window.getComputedStyle(e),n=o.getPropertyValue("box-sizing")||o.getPropertyValue("-moz-box-sizing")||o.getPropertyValue("-webkit-box-sizing"),a=parseFloat(o.getPropertyValue("padding-bottom"))+parseFloat(o.getPropertyValue("padding-top")),i=parseFloat(o.getPropertyValue("border-bottom-width"))+parseFloat(o.getPropertyValue("border-top-width")),l={sizingStyle:y.map(function(e){return"".concat(e,":").concat(o.getPropertyValue(e))}).join(";"),paddingSize:a,borderSize:i,boxSizing:n};return t&&r&&(b[r]=l),l}(e,o),l=i.paddingSize,s=i.borderSize,c=i.boxSizing,u=i.sizingStyle;t.setAttribute("style","".concat(u,";").concat("\n min-height:0 !important;\n max-height:none !important;\n height:0 !important;\n visibility:hidden !important;\n overflow:hidden !important;\n position:absolute !important;\n z-index:-1000 !important;\n top:0 !important;\n right:0 !important;\n pointer-events: none !important;\n")),t.value=e.value||e.placeholder||"";var d=void 0,f=void 0,p=t.scrollHeight;if("border-box"===c?p+=s:"content-box"===c&&(p-=l),null!==n||null!==a){t.value=" ";var h=t.scrollHeight-l;null!==n&&(d=h*n,"border-box"===c&&(d=d+l+s),p=Math.max(d,p)),null!==a&&(f=h*a,"border-box"===c&&(f=f+l+s),r=p>f?"":"hidden",p=Math.min(f,p))}var m={height:p,overflowY:r,resize:"none"};return d&&(m.minHeight=d),f&&(m.maxHeight=f),m}(F.current,!1,N,M);D(2),U(e)}},[L]);var q=p.useRef(),J=function(){v.default.cancel(q.current)};p.useEffect(function(){return J},[]);var K=(0,n.default)((0,n.default)({},E),B?W:null);return(0===L||1===L)&&(K.overflowY="hidden",K.overflowX="hidden"),p.createElement(m.default,{onResize:function(e){2===L&&(null==C||C(e),$&&(J(),q.current=(0,v.default)(function(){G()})))},disabled:!($||C)},p.createElement("textarea",(0,r.default)({},j,{ref:F,style:K,className:(0,s.default)(c,x,(0,o.default)({},"".concat(c,"-disabled"),S)),disabled:S,value:I,onChange:function(e){_(e.target.value),null==k||k(e)}})))}),C=["defaultValue","value","onFocus","onBlur","onChange","allowClear","maxLength","onCompositionStart","onCompositionEnd","suffix","prefixCls","showCount","count","className","style","disabled","hidden","classNames","styles","onResize","onClear","onPressEnter","readOnly","autoSize","onKeyDown"],x=p.default.forwardRef(function(e,t){var h,m,g=e.defaultValue,v=e.value,y=e.onFocus,b=e.onBlur,w=e.onChange,x=e.allowClear,E=e.maxLength,S=e.onCompositionStart,k=e.onCompositionEnd,j=e.suffix,O=e.prefixCls,T=void 0===O?"rc-textarea":O,I=e.showCount,_=e.count,F=e.className,P=e.style,R=e.disabled,N=e.hidden,M=e.classNames,B=e.styles,A=e.onResize,z=e.onClear,L=e.onPressEnter,D=e.readOnly,H=e.autoSize,V=e.onKeyDown,W=(0,l.default)(e,C),U=(0,f.default)(g,{value:v,defaultValue:g}),G=(0,i.default)(U,2),q=G[0],J=G[1],K=null==q?"":String(q),X=p.default.useState(!1),Y=(0,i.default)(X,2),Q=Y[0],Z=Y[1],ee=p.default.useRef(!1),et=p.default.useState(null),er=(0,i.default)(et,2),eo=er[0],en=er[1],ea=(0,p.useRef)(null),ei=(0,p.useRef)(null),el=function(){var e;return null==(e=ei.current)?void 0:e.textArea},es=function(){el().focus()};(0,p.useImperativeHandle)(t,function(){var e;return{resizableTextArea:ei.current,focus:es,blur:function(){el().blur()},nativeElement:(null==(e=ea.current)?void 0:e.nativeElement)||el()}}),(0,p.useEffect)(function(){Z(function(e){return!R&&e})},[R]);var ec=p.default.useState(null),eu=(0,i.default)(ec,2),ed=eu[0],ef=eu[1];p.default.useEffect(function(){if(ed){var e;(e=el()).setSelectionRange.apply(e,(0,a.default)(ed))}},[ed]);var ep=(0,u.default)(_,I),eh=null!=(h=ep.max)?h:E,em=Number(eh)>0,eg=ep.strategy(K),ev=!!eh&&eg>eh,ey=function(e,t){var r=t;!ee.current&&ep.exceedFormatter&&ep.max&&ep.strategy(t)>ep.max&&(r=ep.exceedFormatter(t,{max:ep.max}),t!==r&&ef([el().selectionStart||0,el().selectionEnd||0])),J(r),(0,d.resolveOnChange)(e.currentTarget,e,w,r)},eb=j;ep.show&&(m=ep.showFormatter?ep.showFormatter({value:K,count:eg,maxLength:eh}):"".concat(eg).concat(em?" / ".concat(eh):""),eb=p.default.createElement(p.default.Fragment,null,eb,p.default.createElement("span",{className:(0,s.default)("".concat(T,"-data-count"),null==M?void 0:M.count),style:null==B?void 0:B.count},m)));var ew=!H&&!I&&!x;return p.default.createElement(c.BaseInput,{ref:ea,value:K,allowClear:x,handleReset:function(e){J(""),es(),(0,d.resolveOnChange)(el(),e,w)},suffix:eb,prefixCls:T,classNames:(0,n.default)((0,n.default)({},M),{},{affixWrapper:(0,s.default)(null==M?void 0:M.affixWrapper,(0,o.default)((0,o.default)({},"".concat(T,"-show-count"),I),"".concat(T,"-textarea-allow-clear"),x))}),disabled:R,focused:Q,className:(0,s.default)(F,ev&&"".concat(T,"-out-of-range")),style:(0,n.default)((0,n.default)({},P),eo&&!ew?{height:"auto"}:{}),dataAttrs:{affixWrapper:{"data-count":"string"==typeof m?m:void 0}},hidden:N,readOnly:D,onClear:z},p.default.createElement($,(0,r.default)({},W,{autoSize:H,maxLength:E,onKeyDown:function(e){"Enter"===e.key&&L&&L(e),null==V||V(e)},onChange:function(e){ey(e,e.target.value)},onFocus:function(e){Z(!0),null==y||y(e)},onBlur:function(e){Z(!1),null==b||b(e)},onCompositionStart:function(e){ee.current=!0,null==S||S(e)},onCompositionEnd:function(e){ee.current=!1,ey(e,e.currentTarget.value),null==k||k(e)},className:(0,s.default)(null==M?void 0:M.textarea),style:(0,n.default)((0,n.default)({},null==B?void 0:B.textarea),{},{resize:null==P?void 0:P.resize}),disabled:R,prefixCls:T,onResize:function(e){var t;null==A||A(e),null!=(t=el())&&t.style.height&&en(!0)},ref:ei,readOnly:D})))});e.s(["default",0,x],598030)},635432,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(598030),n=e.i(330683),a=e.i(52956),i=e.i(242064),l=e.i(937328),s=e.i(321883),c=e.i(517455),u=e.i(62139),d=e.i(792812),f=e.i(249616),p=e.i(131299),h=e.i(349942),m=e.i(246422),g=e.i(838378),v=e.i(517458);let y=(0,m.genStyleHooks)(["Input","TextArea"],e=>(e=>{let{componentCls:t,paddingLG:r}=e,o=`${t}-textarea`;return{[`textarea${t}`]:{maxWidth:"100%",height:"auto",minHeight:e.controlHeight,lineHeight:e.lineHeight,verticalAlign:"bottom",transition:`all ${e.motionDurationSlow}`,resize:"vertical",[`&${t}-mouse-active`]:{transition:`all ${e.motionDurationSlow}, height 0s, width 0s`}},[`${t}-textarea-affix-wrapper-resize-dirty`]:{width:"auto"},[o]:{position:"relative","&-show-count":{[`${t}-data-count`]:{position:"absolute",bottom:e.calc(e.fontSize).mul(e.lineHeight).mul(-1).equal(),insetInlineEnd:0,color:e.colorTextDescription,whiteSpace:"nowrap",pointerEvents:"none"}},[` - &-allow-clear > ${t}, - &-affix-wrapper${o}-has-feedback ${t} - `]:{paddingInlineEnd:r},[`&-affix-wrapper${t}-affix-wrapper`]:{padding:0,[`> textarea${t}`]:{fontSize:"inherit",border:"none",outline:"none",background:"transparent",minHeight:e.calc(e.controlHeight).sub(e.calc(e.lineWidth).mul(2)).equal(),"&:focus":{boxShadow:"none !important"}},[`${t}-suffix`]:{margin:0,"> *:not(:last-child)":{marginInline:0},[`${t}-clear-icon`]:{position:"absolute",insetInlineEnd:e.paddingInline,insetBlockStart:e.paddingXS},[`${o}-suffix`]:{position:"absolute",top:0,insetInlineEnd:e.paddingInline,bottom:0,zIndex:1,display:"inline-flex",alignItems:"center",margin:"auto",pointerEvents:"none"}}},[`&-affix-wrapper${t}-affix-wrapper-rtl`]:{[`${t}-suffix`]:{[`${t}-data-count`]:{direction:"ltr",insetInlineStart:0}}},[`&-affix-wrapper${t}-affix-wrapper-sm`]:{[`${t}-suffix`]:{[`${t}-clear-icon`]:{insetInlineEnd:e.paddingInlineSM}}}}}})((0,g.mergeToken)(e,(0,v.initInputToken)(e))),v.initComponentToken,{resetFont:!1});var b=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let w=(0,t.forwardRef)((e,m)=>{var g;let{prefixCls:v,bordered:w=!0,size:$,disabled:C,status:x,allowClear:E,classNames:S,rootClassName:k,className:j,style:O,styles:T,variant:I,showCount:_,onMouseDown:F,onResize:P}=e,R=b(e,["prefixCls","bordered","size","disabled","status","allowClear","classNames","rootClassName","className","style","styles","variant","showCount","onMouseDown","onResize"]),{getPrefixCls:N,direction:M,allowClear:B,autoComplete:A,className:z,style:L,classNames:D,styles:H}=(0,i.useComponentConfig)("textArea"),V=t.useContext(l.default),{status:W,hasFeedback:U,feedbackIcon:G}=t.useContext(u.FormItemInputContext),q=(0,a.getMergedStatus)(W,x),J=t.useRef(null);t.useImperativeHandle(m,()=>{var e;return{resizableTextArea:null==(e=J.current)?void 0:e.resizableTextArea,focus:e=>{var t,r;(0,p.triggerFocus)(null==(r=null==(t=J.current)?void 0:t.resizableTextArea)?void 0:r.textArea,e)},blur:()=>{var e;return null==(e=J.current)?void 0:e.blur()}}});let K=N("input",v),X=(0,s.default)(K),[Y,Q,Z]=(0,h.useSharedStyle)(K,k),[ee]=y(K,X),{compactSize:et,compactItemClassnames:er}=(0,f.useCompactItemContext)(K,M),eo=(0,c.default)(e=>{var t;return null!=(t=null!=$?$:et)?t:e}),[en,ea]=(0,d.default)("textArea",I,w),ei=(0,n.default)(null!=E?E:B),[el,es]=t.useState(!1),[ec,eu]=t.useState(!1);return Y(ee(t.createElement(o.default,Object.assign({autoComplete:A},R,{style:Object.assign(Object.assign({},L),O),styles:Object.assign(Object.assign({},H),T),disabled:null!=C?C:V,allowClear:ei,className:(0,r.default)(Z,X,j,k,er,z,ec&&`${K}-textarea-affix-wrapper-resize-dirty`),classNames:Object.assign(Object.assign(Object.assign({},S),D),{textarea:(0,r.default)({[`${K}-sm`]:"small"===eo,[`${K}-lg`]:"large"===eo},Q,null==S?void 0:S.textarea,D.textarea,el&&`${K}-mouse-active`),variant:(0,r.default)({[`${K}-${en}`]:ea},(0,a.getStatusClassNames)(K,q)),affixWrapper:(0,r.default)(`${K}-textarea-affix-wrapper`,{[`${K}-affix-wrapper-rtl`]:"rtl"===M,[`${K}-affix-wrapper-sm`]:"small"===eo,[`${K}-affix-wrapper-lg`]:"large"===eo,[`${K}-textarea-show-count`]:_||(null==(g=e.count)?void 0:g.show)},Q)}),prefixCls:K,suffix:U&&t.createElement("span",{className:`${K}-textarea-suffix`},G),showCount:_,ref:J,onResize:e=>{var t,r;if(null==P||P(e),el&&"function"==typeof getComputedStyle){let e=null==(r=null==(t=J.current)?void 0:t.nativeElement)?void 0:r.querySelector("textarea");e&&"both"===getComputedStyle(e).resize&&eu(!0)}},onMouseDown:e=>{es(!0),null==F||F(e);let t=()=>{es(!1),document.removeEventListener("mouseup",t)};document.addEventListener("mouseup",t)}}))))});e.s(["default",0,w],635432)},311451,e=>{"use strict";var t=e.i(831357),r=e.i(90635),o=e.i(932399),n=e.i(236798),a=e.i(995387),i=e.i(635432);let l=r.default;l.Group=t.default,l.Search=a.default,l.TextArea=i.default,l.Password=n.default,l.OTP=o.default,e.s(["Input",0,l],311451)},247153,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"}}]},name:"down",theme:"outlined"};var n=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(n.default,(0,t.default)({},e,{ref:a,icon:o}))});e.s(["default",0,a],247153)},28651,536591,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(247153),o=e.i(931067);let n={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"}}]},name:"up",theme:"outlined"};var a=e.i(9583),i=t.forwardRef(function(e,r){return t.createElement(a.default,(0,o.default)({},e,{ref:r,icon:n}))});e.s(["default",0,i],536591);var l=e.i(343794),s=e.i(211577),c=e.i(410160),u=e.i(392221),d=e.i(703923),f=e.i(278409),p=e.i(233848);function h(){return"function"==typeof BigInt}function m(e){return!e&&0!==e&&!Number.isNaN(e)||!String(e).trim()}function g(e){var t=e.trim(),r=t.startsWith("-");r&&(t=t.slice(1)),(t=t.replace(/(\.\d*[^0])0*$/,"$1").replace(/\.0*$/,"").replace(/^0+/,"")).startsWith(".")&&(t="0".concat(t));var o=t||"0",n=o.split("."),a=n[0]||"0",i=n[1]||"0";"0"===a&&"0"===i&&(r=!1);var l=r?"-":"";return{negative:r,negativeStr:l,trimStr:o,integerStr:a,decimalStr:i,fullStr:"".concat(l).concat(o)}}function v(e){var t=String(e);return!Number.isNaN(Number(t))&&t.includes("e")}function y(e){var t=String(e);if(v(e)){var r=Number(t.slice(t.indexOf("e-")+2)),o=t.match(/\.(\d+)/);return null!=o&&o[1]&&(r+=o[1].length),r}return t.includes(".")&&w(t)?t.length-t.indexOf(".")-1:0}function b(e){var t=String(e);if(v(e)){if(e>Number.MAX_SAFE_INTEGER)return String(h()?BigInt(e).toString():Number.MAX_SAFE_INTEGER);if(e=this.add(e.negate().toString()).toNumber()}},{key:"toNumber",value:function(){return this.isNaN()?NaN:Number(this.toString())}},{key:"toString",value:function(){var e=!(arguments.length>0)||void 0===arguments[0]||arguments[0];return e?this.isInvalidate()?"":g("".concat(this.getMark()).concat(this.getIntegerStr(),".").concat(this.getDecimalStr())).fullStr:this.origin}}]),e}(),C=function(){function e(t){if((0,f.default)(this,e),(0,s.default)(this,"origin",""),(0,s.default)(this,"number",void 0),(0,s.default)(this,"empty",void 0),m(t)){this.empty=!0;return}this.origin=String(t),this.number=Number(t)}return(0,p.default)(e,[{key:"negate",value:function(){return new e(-this.toNumber())}},{key:"add",value:function(t){if(this.isInvalidate())return new e(t);var r=Number(t);if(Number.isNaN(r))return this;var o=this.number+r;if(o>Number.MAX_SAFE_INTEGER)return new e(Number.MAX_SAFE_INTEGER);if(oNumber.MAX_SAFE_INTEGER)return new e(Number.MAX_SAFE_INTEGER);if(o=this.add(e.negate().toString()).toNumber()}},{key:"toNumber",value:function(){return this.number}},{key:"toString",value:function(){var e=!(arguments.length>0)||void 0===arguments[0]||arguments[0];return e?this.isInvalidate()?"":b(this.number):this.origin}}]),e}();function x(e){return h()?new $(e):new C(e)}function E(e,t,r){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(""===e)return"";var n=g(e),a=n.negativeStr,i=n.integerStr,l=n.decimalStr,s="".concat(t).concat(l),c="".concat(a).concat(i);if(r>=0){var u=Number(l[r]);return u>=5&&!o?E(x(e).add("".concat(a,"0.").concat("0".repeat(r)).concat(10-u)).toString(),t,r,o):0===r?c:"".concat(c).concat(t).concat(l.padEnd(r,"0").slice(0,r))}return".0"===s?c:"".concat(c).concat(s)}e.s(["default",()=>x,"toFixed",()=>E],522181),e.i(522181),e.i(175636);var S=e.i(302384),k=e.i(174428),j=e.i(611935),O=e.i(883110),T=e.i(614761);let I=function(){var e=(0,t.useState)(!1),r=(0,u.default)(e,2),o=r[0],n=r[1];return(0,k.default)(function(){n((0,T.default)())},[]),o};var _=e.i(963188);function F(e){var r=e.prefixCls,n=e.upNode,a=e.downNode,i=e.upDisabled,c=e.downDisabled,u=e.onStep,d=t.useRef(),f=t.useRef([]),p=t.useRef();p.current=u;var h=function(){clearTimeout(d.current)},m=function(e,t){e.preventDefault(),h(),p.current(t),d.current=setTimeout(function e(){p.current(t),d.current=setTimeout(e,200)},600)};if(t.useEffect(function(){return function(){h(),f.current.forEach(function(e){return _.default.cancel(e)})}},[]),I())return null;var g="".concat(r,"-handler"),v=(0,l.default)(g,"".concat(g,"-up"),(0,s.default)({},"".concat(g,"-up-disabled"),i)),y=(0,l.default)(g,"".concat(g,"-down"),(0,s.default)({},"".concat(g,"-down-disabled"),c)),b=function(){return f.current.push((0,_.default)(h))},w={unselectable:"on",role:"button",onMouseUp:b,onMouseLeave:b};return t.createElement("div",{className:"".concat(g,"-wrap")},t.createElement("span",(0,o.default)({},w,{onMouseDown:function(e){m(e,!0)},"aria-label":"Increase Value","aria-disabled":i,className:v}),n||t.createElement("span",{unselectable:"on",className:"".concat(r,"-handler-up-inner")})),t.createElement("span",(0,o.default)({},w,{onMouseDown:function(e){m(e,!1)},"aria-label":"Decrease Value","aria-disabled":c,className:y}),a||t.createElement("span",{unselectable:"on",className:"".concat(r,"-handler-down-inner")})))}function P(e){var t="number"==typeof e?b(e):g(e).fullStr;return t.includes(".")?g(t.replace(/(\d)\.(\d)/g,"$1$2.")).fullStr:e+"0"}var R=e.i(131299);let N=function(){var e=(0,t.useRef)(0),r=function(){_.default.cancel(e.current)};return(0,t.useEffect)(function(){return r},[]),function(t){r(),e.current=(0,_.default)(function(){t()})}};var M=["prefixCls","className","style","min","max","step","defaultValue","value","disabled","readOnly","upHandler","downHandler","keyboard","changeOnWheel","controls","classNames","stringMode","parser","formatter","precision","decimalSeparator","onChange","onInput","onPressEnter","onStep","changeOnBlur","domRef"],B=["disabled","style","prefixCls","value","prefix","suffix","addonBefore","addonAfter","className","classNames"],A=function(e,t){return e||t.isEmpty()?t.toString():t.toNumber()},z=function(e){var t=x(e);return t.isInvalidate()?null:t},L=t.forwardRef(function(e,r){var n,a,i=e.prefixCls,f=e.className,p=e.style,h=e.min,m=e.max,g=e.step,v=void 0===g?1:g,$=e.defaultValue,C=e.value,S=e.disabled,T=e.readOnly,I=e.upHandler,_=e.downHandler,R=e.keyboard,B=e.changeOnWheel,L=void 0!==B&&B,D=e.controls,H=(e.classNames,e.stringMode),V=e.parser,W=e.formatter,U=e.precision,G=e.decimalSeparator,q=e.onChange,J=e.onInput,K=e.onPressEnter,X=e.onStep,Y=e.changeOnBlur,Q=void 0===Y||Y,Z=e.domRef,ee=(0,d.default)(e,M),et="".concat(i,"-input"),er=t.useRef(null),eo=t.useState(!1),en=(0,u.default)(eo,2),ea=en[0],ei=en[1],el=t.useRef(!1),es=t.useRef(!1),ec=t.useRef(!1),eu=t.useState(function(){return x(null!=C?C:$)}),ed=(0,u.default)(eu,2),ef=ed[0],ep=ed[1],eh=t.useCallback(function(e,t){if(!t)return U>=0?U:Math.max(y(e),y(v))},[U,v]),em=t.useCallback(function(e){var t=String(e);if(V)return V(t);var r=t;return G&&(r=r.replace(G,".")),r.replace(/[^\w.-]+/g,"")},[V,G]),eg=t.useRef(""),ev=t.useCallback(function(e,t){if(W)return W(e,{userTyping:t,input:String(eg.current)});var r="number"==typeof e?b(e):e;if(!t){var o=eh(r,t);w(r)&&(G||o>=0)&&(r=E(r,G||".",o))}return r},[W,eh,G]),ey=t.useState(function(){var e=null!=$?$:C;return ef.isInvalidate()&&["string","number"].includes((0,c.default)(e))?Number.isNaN(e)?"":e:ev(ef.toString(),!1)}),eb=(0,u.default)(ey,2),ew=eb[0],e$=eb[1];function eC(e,t){e$(ev(e.isInvalidate()?e.toString(!1):e.toString(!t),t))}eg.current=ew;var ex=t.useMemo(function(){return z(m)},[m,U]),eE=t.useMemo(function(){return z(h)},[h,U]),eS=t.useMemo(function(){return!(!ex||!ef||ef.isInvalidate())&&ex.lessEquals(ef)},[ex,ef]),ek=t.useMemo(function(){return!(!eE||!ef||ef.isInvalidate())&&ef.lessEquals(eE)},[eE,ef]),ej=(n=er.current,a=(0,t.useRef)(null),[function(){try{var e=n.selectionStart,t=n.selectionEnd,r=n.value,o=r.substring(0,e),i=r.substring(t);a.current={start:e,end:t,value:r,beforeTxt:o,afterTxt:i}}catch(e){}},function(){if(n&&a.current&&ea)try{var e=n.value,t=a.current,r=t.beforeTxt,o=t.afterTxt,i=t.start,l=e.length;if(e.startsWith(r))l=r.length;else if(e.endsWith(o))l=e.length-a.current.afterTxt.length;else{var s=r[i-1],c=e.indexOf(s,i-1);-1!==c&&(l=c+1)}n.setSelectionRange(l,l)}catch(e){(0,O.default)(!1,"Something warning of cursor restore. Please fire issue about this: ".concat(e.message))}}]),eO=(0,u.default)(ej,2),eT=eO[0],eI=eO[1],e_=function(e){return ex&&!e.lessEquals(ex)?ex:eE&&!eE.lessEquals(e)?eE:null},eF=function(e){return!e_(e)},eP=function(e,t){var r=e,o=eF(r)||r.isEmpty();if(r.isEmpty()||t||(r=e_(r)||r,o=!0),!T&&!S&&o){var n,a=r.toString(),i=eh(a,t);return i>=0&&(eF(r=x(E(a,".",i)))||(r=x(E(a,".",i,!0)))),r.equals(ef)||(n=r,void 0===C&&ep(n),null==q||q(r.isEmpty()?null:A(H,r)),void 0===C&&eC(r,t)),r}return ef},eR=N(),eN=function e(t){if(eT(),eg.current=t,e$(t),!es.current){var r=x(em(t));r.isNaN()||eP(r,!0)}null==J||J(t),eR(function(){var r=t;V||(r=t.replace(/。/g,".")),r!==t&&e(r)})},eM=function(e){if((!e||!eS)&&(e||!ek)){el.current=!1;var t,r=x(ec.current?P(v):v);e||(r=r.negate());var o=eP((ef||x(0)).add(r.toString()),!1);null==X||X(A(H,o),{offset:ec.current?P(v):v,type:e?"up":"down"}),null==(t=er.current)||t.focus()}},eB=function(e){var t,r=x(em(ew));t=r.isNaN()?eP(ef,e):eP(r,e),void 0!==C?eC(ef,!1):t.isNaN()||eC(t,!1)};return t.useEffect(function(){if(L&&ea){var e=function(e){eM(e.deltaY<0),e.preventDefault()},t=er.current;if(t)return t.addEventListener("wheel",e,{passive:!1}),function(){return t.removeEventListener("wheel",e)}}}),(0,k.useLayoutUpdateEffect)(function(){ef.isInvalidate()||eC(ef,!1)},[U,W]),(0,k.useLayoutUpdateEffect)(function(){var e=x(C);ep(e);var t=x(em(ew));e.equals(t)&&el.current&&!W||eC(e,el.current)},[C]),(0,k.useLayoutUpdateEffect)(function(){W&&eI()},[ew]),t.createElement("div",{ref:Z,className:(0,l.default)(i,f,(0,s.default)((0,s.default)((0,s.default)((0,s.default)((0,s.default)({},"".concat(i,"-focused"),ea),"".concat(i,"-disabled"),S),"".concat(i,"-readonly"),T),"".concat(i,"-not-a-number"),ef.isNaN()),"".concat(i,"-out-of-range"),!ef.isInvalidate()&&!eF(ef))),style:p,onFocus:function(){ei(!0)},onBlur:function(){Q&&eB(!1),ei(!1),el.current=!1},onKeyDown:function(e){var t=e.key,r=e.shiftKey;el.current=!0,ec.current=r,"Enter"===t&&(es.current||(el.current=!1),eB(!1),null==K||K(e)),!1!==R&&!es.current&&["Up","ArrowUp","Down","ArrowDown"].includes(t)&&(eM("Up"===t||"ArrowUp"===t),e.preventDefault())},onKeyUp:function(){el.current=!1,ec.current=!1},onCompositionStart:function(){es.current=!0},onCompositionEnd:function(){es.current=!1,eN(er.current.value)},onBeforeInput:function(){el.current=!0}},(void 0===D||D)&&t.createElement(F,{prefixCls:i,upNode:I,downNode:_,upDisabled:eS,downDisabled:ek,onStep:eM}),t.createElement("div",{className:"".concat(et,"-wrap")},t.createElement("input",(0,o.default)({autoComplete:"off",role:"spinbutton","aria-valuemin":h,"aria-valuemax":m,"aria-valuenow":ef.isInvalidate()?null:ef.toString(),step:v},ee,{ref:(0,j.composeRef)(er,r),className:et,value:ew,onChange:function(e){eN(e.target.value)},disabled:S,readOnly:T}))))}),D=t.forwardRef(function(e,r){var n=e.disabled,a=e.style,i=e.prefixCls,l=void 0===i?"rc-input-number":i,s=e.value,c=e.prefix,u=e.suffix,f=e.addonBefore,p=e.addonAfter,h=e.className,m=e.classNames,g=(0,d.default)(e,B),v=t.useRef(null),y=t.useRef(null),b=t.useRef(null),w=function(e){b.current&&(0,R.triggerFocus)(b.current,e)};return t.useImperativeHandle(r,function(){var e,t;return e=b.current,t={focus:w,nativeElement:v.current.nativeElement||y.current},"u">typeof Proxy&&e?new Proxy(e,{get:function(e,r){if(t[r])return t[r];var o=e[r];return"function"==typeof o?o.bind(e):o}}):e}),t.createElement(S.BaseInput,{className:h,triggerFocus:w,prefixCls:l,value:s,disabled:n,style:a,prefix:c,suffix:u,addonAfter:p,addonBefore:f,classNames:m,components:{affixWrapper:"div",groupWrapper:"div",wrapper:"div",groupAddon:"div"},ref:v},t.createElement(L,(0,o.default)({prefixCls:l,disabled:n,ref:b,domRef:y,className:null==m?void 0:m.input},g)))}),H=e.i(617206),V=e.i(52956),W=e.i(609587),U=e.i(242064),G=e.i(937328),q=e.i(321883),J=e.i(517455),K=e.i(62139),X=e.i(792812),Y=e.i(249616);e.i(296059);var Q=e.i(915654),Z=e.i(349942),ee=e.i(517458),et=e.i(889943),er=e.i(183293),eo=e.i(372409),en=e.i(246422),ea=e.i(838378);e.i(262370);var ei=e.i(135551);let el=({componentCls:e,borderRadiusSM:t,borderRadiusLG:r},o)=>{let n="lg"===o?r:t;return{[`&-${o}`]:{[`${e}-handler-wrap`]:{borderStartEndRadius:n,borderEndEndRadius:n},[`${e}-handler-up`]:{borderStartEndRadius:n},[`${e}-handler-down`]:{borderEndEndRadius:n}}}},es=(0,en.genStyleHooks)("InputNumber",e=>{let t=(0,ea.mergeToken)(e,(0,ee.initInputToken)(e));return[(e=>{let{componentCls:t,lineWidth:r,lineType:o,borderRadius:n,inputFontSizeSM:a,inputFontSizeLG:i,controlHeightLG:l,controlHeightSM:s,colorError:c,paddingInlineSM:u,paddingBlockSM:d,paddingBlockLG:f,paddingInlineLG:p,colorIcon:h,motionDurationMid:m,handleHoverColor:g,handleOpacity:v,paddingInline:y,paddingBlock:b,handleBg:w,handleActiveBg:$,colorTextDisabled:C,borderRadiusSM:x,borderRadiusLG:E,controlWidth:S,handleBorderColor:k,filledHandleBg:j,lineHeightLG:O,calc:T}=e;return[{[t]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},(0,er.resetComponent)(e)),(0,Z.genBasicInputStyle)(e)),{display:"inline-block",width:S,margin:0,padding:0,borderRadius:n}),(0,et.genOutlinedStyle)(e,{[`${t}-handler-wrap`]:{background:w,[`${t}-handler-down`]:{borderBlockStart:`${(0,Q.unit)(r)} ${o} ${k}`}}})),(0,et.genFilledStyle)(e,{[`${t}-handler-wrap`]:{background:j,[`${t}-handler-down`]:{borderBlockStart:`${(0,Q.unit)(r)} ${o} ${k}`}},"&:focus-within":{[`${t}-handler-wrap`]:{background:w}}})),(0,et.genUnderlinedStyle)(e,{[`${t}-handler-wrap`]:{background:w,[`${t}-handler-down`]:{borderBlockStart:`${(0,Q.unit)(r)} ${o} ${k}`}}})),(0,et.genBorderlessStyle)(e)),{"&-rtl":{direction:"rtl",[`${t}-input`]:{direction:"rtl"}},"&-lg":{padding:0,fontSize:i,lineHeight:O,borderRadius:E,[`input${t}-input`]:{height:T(l).sub(T(r).mul(2)).equal(),padding:`${(0,Q.unit)(f)} ${(0,Q.unit)(p)}`}},"&-sm":{padding:0,fontSize:a,borderRadius:x,[`input${t}-input`]:{height:T(s).sub(T(r).mul(2)).equal(),padding:`${(0,Q.unit)(d)} ${(0,Q.unit)(u)}`}},"&-out-of-range":{[`${t}-input-wrap`]:{input:{color:c}}},"&-group":Object.assign(Object.assign(Object.assign({},(0,er.resetComponent)(e)),(0,Z.genInputGroupStyle)(e)),{"&-wrapper":Object.assign(Object.assign(Object.assign({display:"inline-block",textAlign:"start",verticalAlign:"top",[`${t}-affix-wrapper`]:{width:"100%"},"&-lg":{[`${t}-group-addon`]:{borderRadius:E,fontSize:e.fontSizeLG}},"&-sm":{[`${t}-group-addon`]:{borderRadius:x}}},(0,et.genOutlinedGroupStyle)(e)),(0,et.genFilledGroupStyle)(e)),{[`&:not(${t}-compact-first-item):not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}, ${t}-group-addon`]:{borderRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-first-item`]:{[`${t}, ${t}-group-addon`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&:not(${t}-compact-first-item)${t}-compact-last-item`]:{[`${t}, ${t}-group-addon`]:{borderStartStartRadius:0,borderEndStartRadius:0}}})}),[`&-disabled ${t}-input`]:{cursor:"not-allowed"},[t]:{"&-input":Object.assign(Object.assign(Object.assign(Object.assign({},(0,er.resetComponent)(e)),{width:"100%",padding:`${(0,Q.unit)(b)} ${(0,Q.unit)(y)}`,textAlign:"start",backgroundColor:"transparent",border:0,borderRadius:n,outline:0,transition:`all ${m} linear`,appearance:"textfield",fontSize:"inherit"}),(0,Z.genPlaceholderStyle)(e.colorTextPlaceholder)),{'&[type="number"]::-webkit-inner-spin-button, &[type="number"]::-webkit-outer-spin-button':{margin:0,appearance:"none"}})},[`&:hover ${t}-handler-wrap, &-focused ${t}-handler-wrap`]:{width:e.handleWidth,opacity:1}})},{[t]:Object.assign(Object.assign(Object.assign({[`${t}-handler-wrap`]:{position:"absolute",insetBlockStart:0,insetInlineEnd:0,width:e.handleVisibleWidth,opacity:v,height:"100%",borderStartStartRadius:0,borderStartEndRadius:n,borderEndEndRadius:n,borderEndStartRadius:0,display:"flex",flexDirection:"column",alignItems:"stretch",transition:`all ${m}`,overflow:"hidden",[`${t}-handler`]:{display:"flex",alignItems:"center",justifyContent:"center",flex:"auto",height:"40%",[` - ${t}-handler-up-inner, - ${t}-handler-down-inner - `]:{marginInlineEnd:0,fontSize:e.handleFontSize}}},[`${t}-handler`]:{height:"50%",overflow:"hidden",color:h,fontWeight:"bold",lineHeight:0,textAlign:"center",cursor:"pointer",borderInlineStart:`${(0,Q.unit)(r)} ${o} ${k}`,transition:`all ${m} linear`,"&:active":{background:$},"&:hover":{height:"60%",[` - ${t}-handler-up-inner, - ${t}-handler-down-inner - `]:{color:g}},"&-up-inner, &-down-inner":Object.assign(Object.assign({},(0,er.resetIcon)()),{color:h,transition:`all ${m} linear`,userSelect:"none"})},[`${t}-handler-up`]:{borderStartEndRadius:n},[`${t}-handler-down`]:{borderEndEndRadius:n}},el(e,"lg")),el(e,"sm")),{"&-disabled, &-readonly":{[`${t}-handler-wrap`]:{display:"none"},[`${t}-input`]:{color:"inherit"}},[` - ${t}-handler-up-disabled, - ${t}-handler-down-disabled - `]:{cursor:"not-allowed"},[` - ${t}-handler-up-disabled:hover &-handler-up-inner, - ${t}-handler-down-disabled:hover &-handler-down-inner - `]:{color:C}})}]})(t),(e=>{let{componentCls:t,paddingBlock:r,paddingInline:o,inputAffixPadding:n,controlWidth:a,borderRadiusLG:i,borderRadiusSM:l,paddingInlineLG:s,paddingInlineSM:c,paddingBlockLG:u,paddingBlockSM:d,motionDurationMid:f}=e;return{[`${t}-affix-wrapper`]:Object.assign(Object.assign({[`input${t}-input`]:{padding:`${(0,Q.unit)(r)} 0`}},(0,Z.genBasicInputStyle)(e)),{position:"relative",display:"inline-flex",alignItems:"center",width:a,padding:0,paddingInlineStart:o,"&-lg":{borderRadius:i,paddingInlineStart:s,[`input${t}-input`]:{padding:`${(0,Q.unit)(u)} 0`}},"&-sm":{borderRadius:l,paddingInlineStart:c,[`input${t}-input`]:{padding:`${(0,Q.unit)(d)} 0`}},[`&:not(${t}-disabled):hover`]:{zIndex:1},"&-focused, &:focus":{zIndex:1},[`&-disabled > ${t}-disabled`]:{background:"transparent"},[`> div${t}`]:{width:"100%",border:"none",outline:"none",[`&${t}-focused`]:{boxShadow:"none !important"}},"&::before":{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'},[`${t}-handler-wrap`]:{zIndex:2},[t]:{position:"static",color:"inherit","&-prefix, &-suffix":{display:"flex",flex:"none",alignItems:"center",pointerEvents:"none"},"&-prefix":{marginInlineEnd:n},"&-suffix":{insetBlockStart:0,insetInlineEnd:0,height:"100%",marginInlineEnd:o,marginInlineStart:n,transition:`margin ${f}`}},[`&:hover ${t}-handler-wrap, &-focused ${t}-handler-wrap`]:{width:e.handleWidth,opacity:1},[`&:not(${t}-affix-wrapper-without-controls):hover ${t}-suffix`]:{marginInlineEnd:e.calc(e.handleWidth).add(o).equal()}}),[`${t}-underlined`]:{borderRadius:0}}})(t),(0,eo.genCompactItemStyle)(t)]},e=>{var t;let r=null!=(t=e.handleVisible)?t:"auto",o=e.controlHeightSM-2*e.lineWidth;return Object.assign(Object.assign({},(0,ee.initComponentToken)(e)),{controlWidth:90,handleWidth:o,handleFontSize:e.fontSize/2,handleVisible:r,handleActiveBg:e.colorFillAlter,handleBg:e.colorBgContainer,filledHandleBg:new ei.FastColor(e.colorFillSecondary).onBackground(e.colorBgContainer).toHexString(),handleHoverColor:e.colorPrimary,handleBorderColor:e.colorBorder,handleOpacity:+(!0===r),handleVisibleWidth:!0===r?o:0})},{unitless:{handleOpacity:!0},resetFont:!1});var ec=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let eu=t.forwardRef((e,o)=>{let{getPrefixCls:n,direction:a}=t.useContext(U.ConfigContext),s=t.useRef(null);t.useImperativeHandle(o,()=>s.current);let{className:c,rootClassName:u,size:d,disabled:f,prefixCls:p,addonBefore:h,addonAfter:m,prefix:g,suffix:v,bordered:y,readOnly:b,status:w,controls:$,variant:C}=e,x=ec(e,["className","rootClassName","size","disabled","prefixCls","addonBefore","addonAfter","prefix","suffix","bordered","readOnly","status","controls","variant"]),E=n("input-number",p),S=(0,q.default)(E),[k,j,O]=es(E,S),{compactSize:T,compactItemClassnames:I}=(0,Y.useCompactItemContext)(E,a),_=t.createElement(i,{className:`${E}-handler-up-inner`}),F=t.createElement(r.default,{className:`${E}-handler-down-inner`}),P="boolean"==typeof $?$:void 0;"object"==typeof $&&(_=void 0===$.upIcon?_:t.createElement("span",{className:`${E}-handler-up-inner`},$.upIcon),F=void 0===$.downIcon?F:t.createElement("span",{className:`${E}-handler-down-inner`},$.downIcon));let{hasFeedback:R,status:N,isFormItemInput:M,feedbackIcon:B}=t.useContext(K.FormItemInputContext),A=(0,V.getMergedStatus)(N,w),z=(0,J.default)(e=>{var t;return null!=(t=null!=d?d:T)?t:e}),L=t.useContext(G.default),W=null!=f?f:L,[Q,Z]=(0,X.default)("inputNumber",C,y),ee=R&&t.createElement(t.Fragment,null,B),et=(0,l.default)({[`${E}-lg`]:"large"===z,[`${E}-sm`]:"small"===z,[`${E}-rtl`]:"rtl"===a,[`${E}-in-form-item`]:M},j),er=`${E}-group`;return k(t.createElement(D,Object.assign({ref:s,disabled:W,className:(0,l.default)(O,S,c,u,I),upHandler:_,downHandler:F,prefixCls:E,readOnly:b,controls:P,prefix:g,suffix:ee||v,addonBefore:h&&t.createElement(H.default,{form:!0,space:!0},h),addonAfter:m&&t.createElement(H.default,{form:!0,space:!0},m),classNames:{input:et,variant:(0,l.default)({[`${E}-${Q}`]:Z},(0,V.getStatusClassNames)(E,A,R)),affixWrapper:(0,l.default)({[`${E}-affix-wrapper-sm`]:"small"===z,[`${E}-affix-wrapper-lg`]:"large"===z,[`${E}-affix-wrapper-rtl`]:"rtl"===a,[`${E}-affix-wrapper-without-controls`]:!1===$||W||b},j),wrapper:(0,l.default)({[`${er}-rtl`]:"rtl"===a},j),groupWrapper:(0,l.default)({[`${E}-group-wrapper-sm`]:"small"===z,[`${E}-group-wrapper-lg`]:"large"===z,[`${E}-group-wrapper-rtl`]:"rtl"===a,[`${E}-group-wrapper-${Q}`]:Z},(0,V.getStatusClassNames)(`${E}-group-wrapper`,A,R),j)}},x)))});eu._InternalPanelDoNotUseOrYouWillBeFired=e=>t.createElement(W.default,{theme:{components:{InputNumber:{handleVisible:!0}}}},t.createElement(eu,Object.assign({},e))),e.s(["InputNumber",0,eu],28651)},147138,210803,266623,794721,232176,843375,229548,e=>{"use strict";var t=e.i(410160),r=e.i(271645),o=e.i(343794);let n=function(e){var t=e.className,n=e.customizeIcon,a=e.customizeIconProps,i=e.children,l=e.onMouseDown,s=e.onClick,c="function"==typeof n?n(a):n;return r.createElement("span",{className:t,onMouseDown:function(e){e.preventDefault(),null==l||l(e)},style:{userSelect:"none",WebkitUserSelect:"none"},unselectable:"on",onClick:s,"aria-hidden":!0},void 0!==c?c:r.createElement("span",{className:(0,o.default)(t.split(/\s+/).map(function(e){return"".concat(e,"-icon")}))},i))};e.s(["default",0,n],210803);var a=function(e,o,a,i,l){var s=arguments.length>5&&void 0!==arguments[5]&&arguments[5],c=arguments.length>6?arguments[6]:void 0,u=arguments.length>7?arguments[7]:void 0,d=r.default.useMemo(function(){return"object"===(0,t.default)(i)?i.clearIcon:l||void 0},[i,l]);return{allowClear:r.default.useMemo(function(){return!s&&!!i&&(!!a.length||!!c)&&("combobox"!==u||""!==c)},[i,s,a.length,c,u]),clearIcon:r.default.createElement(n,{className:"".concat(e,"-clear"),onMouseDown:o,customizeIcon:d},"×")}};e.s(["useAllowClear",()=>a],147138);var i=r.createContext(null);function l(){return r.useContext(i)}e.s(["BaseSelectContext",()=>i,"default",()=>l],266623);var s=e.i(392221);function c(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:10,t=r.useState(!1),o=(0,s.default)(t,2),n=o[0],a=o[1],i=r.useRef(null),l=function(){window.clearTimeout(i.current)};return r.useEffect(function(){return l},[]),[n,function(t,r){l(),i.current=window.setTimeout(function(){a(t),r&&r()},e)},l]}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:250,t=r.useRef(null),o=r.useRef(null);return r.useEffect(function(){return function(){window.clearTimeout(o.current)}},[]),[function(){return t.current},function(r){(r||null===t.current)&&(t.current=r),window.clearTimeout(o.current),o.current=window.setTimeout(function(){t.current=null},e)}]}function d(e,t,o,n){var a=r.useRef(null);a.current={open:t,triggerOpen:o,customizedTrigger:n},r.useEffect(function(){function t(t){if(null==(r=a.current)||!r.customizedTrigger){var r,o=t.target;o.shadowRoot&&t.composed&&(o=t.composedPath()[0]||o),a.current.open&&e().filter(function(e){return e}).every(function(e){return!e.contains(o)&&e!==o})&&a.current.triggerOpen(!1)}}return window.addEventListener("mousedown",t),function(){return window.removeEventListener("mousedown",t)}},[])}e.s(["default",()=>c],794721),e.s(["default",()=>u],232176),e.s(["default",()=>d],843375);var f=e.i(404948);function p(e){return e&&![f.default.ESC,f.default.SHIFT,f.default.BACKSPACE,f.default.TAB,f.default.WIN_KEY,f.default.ALT,f.default.META,f.default.WIN_KEY_RIGHT,f.default.CTRL,f.default.SEMICOLON,f.default.EQUALS,f.default.CAPS_LOCK,f.default.CONTEXT_MENU,f.default.F1,f.default.F2,f.default.F3,f.default.F4,f.default.F5,f.default.F6,f.default.F7,f.default.F8,f.default.F9,f.default.F10,f.default.F11,f.default.F12].includes(e)}e.s(["isValidateOpenKey",()=>p],229548)},658315,e=>{"use strict";var t=e.i(931067),r=e.i(209428),o=e.i(392221),n=e.i(703923),a=e.i(271645),i=e.i(343794),l=e.i(430073),s=e.i(174428),c=["prefixCls","invalidate","item","renderItem","responsive","responsiveDisabled","registerSize","itemKey","className","style","children","display","order","component"],u=void 0,d=a.forwardRef(function(e,o){var s,d=e.prefixCls,f=e.invalidate,p=e.item,h=e.renderItem,m=e.responsive,g=e.responsiveDisabled,v=e.registerSize,y=e.itemKey,b=e.className,w=e.style,$=e.children,C=e.display,x=e.order,E=e.component,S=(0,n.default)(e,c),k=m&&!C;a.useEffect(function(){return function(){v(y,null)}},[]);var j=h&&p!==u?h(p,{index:x}):$;f||(s={opacity:+!k,height:k?0:u,overflowY:k?"hidden":u,order:m?x:u,pointerEvents:k?"none":u,position:k?"absolute":u});var O={};k&&(O["aria-hidden"]=!0);var T=a.createElement(void 0===E?"div":E,(0,t.default)({className:(0,i.default)(!f&&d,b),style:(0,r.default)((0,r.default)({},s),w)},O,S,{ref:o}),j);return m&&(T=a.createElement(l.default,{onResize:function(e){v(y,e.offsetWidth)},disabled:g},T)),T});d.displayName="Item";var f=e.i(175066),p=e.i(174080),h=e.i(963188);function m(e,t){var r=a.useState(t),n=(0,o.default)(r,2),i=n[0],l=n[1];return[i,(0,f.default)(function(t){e(function(){l(t)})})]}var g=a.default.createContext(null),v=["component"],y=["className"],b=["className"],w=a.forwardRef(function(e,r){var o=a.useContext(g);if(!o){var l=e.component,s=(0,n.default)(e,v);return a.createElement(void 0===l?"div":l,(0,t.default)({},s,{ref:r}))}var c=o.className,u=(0,n.default)(o,y),f=e.className,p=(0,n.default)(e,b);return a.createElement(g.Provider,{value:null},a.createElement(d,(0,t.default)({ref:r,className:(0,i.default)(c,f)},u,p)))});w.displayName="RawItem";var $=["prefixCls","data","renderItem","renderRawItem","itemKey","itemWidth","ssr","style","className","maxCount","renderRest","renderRawRest","prefix","suffix","component","itemComponent","onVisibleChange"],C="responsive",x="invalidate";function E(e){return"+ ".concat(e.length," ...")}var S=a.forwardRef(function(e,c){var u,f=e.prefixCls,v=void 0===f?"rc-overflow":f,y=e.data,b=void 0===y?[]:y,w=e.renderItem,S=e.renderRawItem,k=e.itemKey,j=e.itemWidth,O=void 0===j?10:j,T=e.ssr,I=e.style,_=e.className,F=e.maxCount,P=e.renderRest,R=e.renderRawRest,N=e.prefix,M=e.suffix,B=e.component,A=e.itemComponent,z=e.onVisibleChange,L=(0,n.default)(e,$),D="full"===T,H=(u=a.useRef(null),function(e){if(!u.current){u.current=[];var t=function(){(0,p.unstable_batchedUpdates)(function(){u.current.forEach(function(e){e()}),u.current=null})};if("u"F,eP=(0,a.useMemo)(function(){var e=b;return eI?e=null===U&&D?b:b.slice(0,Math.min(b.length,q/O)):"number"==typeof F&&(e=b.slice(0,F)),e},[b,O,U,F,eI]),eR=(0,a.useMemo)(function(){return eI?b.slice(eC+1):b.slice(eP.length)},[b,eP,eI,eC]),eN=(0,a.useCallback)(function(e,t){var r;return"function"==typeof k?k(e):null!=(r=k&&(null==e?void 0:e[k]))?r:t},[k]),eM=(0,a.useCallback)(w||function(e){return e},[w]);function eB(e,t,r){(ew!==e||void 0!==t&&t!==eg)&&(e$(e),r||(ek(eq){eB(o-1,e-n-ef+en);break}}M&&ez(0)+ef>q&&ev(null)}},[q,X,en,es,ef,eN,eP]);var eL=eS&&!!eR.length,eD={};null!==eg&&eI&&(eD={position:"absolute",left:eg,top:0});var eH={prefixCls:ej,responsive:eI,component:A,invalidate:e_},eV=S?function(e,t){var o=eN(e,t);return a.createElement(g.Provider,{key:o,value:(0,r.default)((0,r.default)({},eH),{},{order:t,item:e,itemKey:o,registerSize:eA,display:t<=eC})},S(e,t))}:function(e,r){var o=eN(e,r);return a.createElement(d,(0,t.default)({},eH,{order:r,key:o,item:e,renderItem:eM,itemKey:o,registerSize:eA,display:r<=eC}))},eW={order:eL?eC:Number.MAX_SAFE_INTEGER,className:"".concat(ej,"-rest"),registerSize:function(e,t){ea(t),et(en)},display:eL},eU=P||E,eG=R?a.createElement(g.Provider,{value:(0,r.default)((0,r.default)({},eH),eW)},R(eR)):a.createElement(d,(0,t.default)({},eH,eW),"function"==typeof eU?eU(eR):eU),eq=a.createElement(void 0===B?"div":B,(0,t.default)({className:(0,i.default)(!e_&&v,_),style:I,ref:c},L),N&&a.createElement(d,(0,t.default)({},eH,{responsive:eT,responsiveDisabled:!eI,order:-1,className:"".concat(ej,"-prefix"),registerSize:function(e,t){ec(t)},display:!0}),N),eP.map(eV),eF?eG:null,M&&a.createElement(d,(0,t.default)({},eH,{responsive:eT,responsiveDisabled:!eI,order:eC,className:"".concat(ej,"-suffix"),registerSize:function(e,t){ep(t)},display:!0,style:eD}),M));return eT?a.createElement(l.default,{onResize:function(e,t){G(t.clientWidth)},disabled:!eI},eq):eq});S.displayName="Overflow",S.Item=w,S.RESPONSIVE=C,S.INVALIDATE=x,e.s(["default",0,S],658315)},823744,207427,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(392221),o=e.i(404948),n=e.i(271645),a=e.i(232176),i=e.i(229548),l=e.i(211577),s=e.i(343794),c=e.i(244009),u=e.i(658315),d=e.i(210803),f=e.i(209428),p=e.i(703923),h=e.i(611935),m=e.i(883110);let g=function(e,t,r){var o=(0,f.default)((0,f.default)({},e),r?t:{});return Object.keys(t).forEach(function(r){var n=t[r];"function"==typeof n&&(o[r]=function(){for(var t,o=arguments.length,a=Array(o),i=0;itypeof window&&window.document&&window.document.documentElement;function C(e){return null!=e}function x(e){return!e&&0!==e}function E(e){return["string","number"].includes((0,b.default)(e))}function S(e){var t=void 0;return e&&(E(e.title)?t=e.title.toString():E(e.label)&&(t=e.label.toString())),t}function k(e){var t;return null!=(t=e.key)?t:e.value}e.s(["getTitle",()=>S,"hasValue",()=>C,"isBrowserClient",()=>$,"isComboNoValue",()=>x,"toArray",()=>w],207427);var j=function(e){e.preventDefault(),e.stopPropagation()};let O=function(e){var t,o,a=e.id,i=e.prefixCls,f=e.values,p=e.open,h=e.searchValue,m=e.autoClearSearchValue,g=e.inputRef,v=e.placeholder,b=e.disabled,w=e.mode,C=e.showSearch,x=e.autoFocus,E=e.autoComplete,O=e.activeDescendantId,T=e.tabIndex,I=e.removeIcon,_=e.maxTagCount,F=e.maxTagTextLength,P=e.maxTagPlaceholder,R=void 0===P?function(e){return"+ ".concat(e.length," ...")}:P,N=e.tagRender,M=e.onToggleOpen,B=e.onRemove,A=e.onInputChange,z=e.onInputPaste,L=e.onInputKeyDown,D=e.onInputMouseDown,H=e.onInputCompositionStart,V=e.onInputCompositionEnd,W=e.onInputBlur,U=n.useRef(null),G=(0,n.useState)(0),q=(0,r.default)(G,2),J=q[0],K=q[1],X=(0,n.useState)(!1),Y=(0,r.default)(X,2),Q=Y[0],Z=Y[1],ee="".concat(i,"-selection"),et=p||"multiple"===w&&!1===m||"tags"===w?h:"",er="tags"===w||"multiple"===w&&!1===m||C&&(p||Q);t=function(){K(U.current.scrollWidth)},o=[et],$?n.useLayoutEffect(t,o):n.useEffect(t,o);var eo=function(e,t,r,o,a){return n.createElement("span",{title:S(e),className:(0,s.default)("".concat(ee,"-item"),(0,l.default)({},"".concat(ee,"-item-disabled"),r))},n.createElement("span",{className:"".concat(ee,"-item-content")},t),o&&n.createElement(d.default,{className:"".concat(ee,"-item-remove"),onMouseDown:j,onClick:a,customizeIcon:I},"×"))},en=function(e,t,r,o,a,i){return n.createElement("span",{onMouseDown:function(e){j(e),M(!p)}},N({label:t,value:e,disabled:r,closable:o,onClose:a,isMaxTag:!!i}))},ea=n.createElement("div",{className:"".concat(ee,"-search"),style:{width:J},onFocus:function(){Z(!0)},onBlur:function(){Z(!1)}},n.createElement(y,{ref:g,open:p,prefixCls:i,id:a,inputElement:null,disabled:b,autoFocus:x,autoComplete:E,editable:er,activeDescendantId:O,value:et,onKeyDown:L,onMouseDown:D,onChange:A,onPaste:z,onCompositionStart:H,onCompositionEnd:V,onBlur:W,tabIndex:T,attrs:(0,c.default)(e,!0)}),n.createElement("span",{ref:U,className:"".concat(ee,"-search-mirror"),"aria-hidden":!0},et," ")),ei=n.createElement(u.default,{prefixCls:"".concat(ee,"-overflow"),data:f,renderItem:function(e){var t=e.disabled,r=e.label,o=e.value,n=!b&&!t,a=r;if("number"==typeof F&&("string"==typeof r||"number"==typeof r)){var i=String(a);i.length>F&&(a="".concat(i.slice(0,F),"..."))}var l=function(t){t&&t.stopPropagation(),B(e)};return"function"==typeof N?en(o,a,t,n,l):eo(e,a,t,n,l)},renderRest:function(e){if(!f.length)return null;var t="function"==typeof R?R(e):R;return"function"==typeof N?en(void 0,t,!1,!1,void 0,!0):eo({title:t},t,!1)},suffix:ea,itemKey:k,maxCount:_});return n.createElement("span",{className:"".concat(ee,"-wrap")},ei,!f.length&&!et&&n.createElement("span",{className:"".concat(ee,"-placeholder")},v))},T=function(e){var t=e.inputElement,o=e.prefixCls,a=e.id,i=e.inputRef,l=e.disabled,s=e.autoFocus,u=e.autoComplete,d=e.activeDescendantId,f=e.mode,p=e.open,h=e.values,m=e.placeholder,g=e.tabIndex,v=e.showSearch,b=e.searchValue,w=e.activeValue,$=e.maxLength,C=e.onInputKeyDown,x=e.onInputMouseDown,E=e.onInputChange,k=e.onInputPaste,j=e.onInputCompositionStart,O=e.onInputCompositionEnd,T=e.onInputBlur,I=e.title,_=n.useState(!1),F=(0,r.default)(_,2),P=F[0],R=F[1],N="combobox"===f,M=N||v,B=h[0],A=b||"";N&&w&&!P&&(A=w),n.useEffect(function(){N&&R(!1)},[N,w]);var z=("combobox"===f||!!p||!!v)&&!!A,L=void 0===I?S(B):I,D=n.useMemo(function(){return B?null:n.createElement("span",{className:"".concat(o,"-selection-placeholder"),style:z?{visibility:"hidden"}:void 0},m)},[B,z,m,o]);return n.createElement("span",{className:"".concat(o,"-selection-wrap")},n.createElement("span",{className:"".concat(o,"-selection-search")},n.createElement(y,{ref:i,prefixCls:o,id:a,open:p,inputElement:t,disabled:l,autoFocus:s,autoComplete:u,editable:M,activeDescendantId:d,value:A,onKeyDown:C,onMouseDown:x,onChange:function(e){R(!0),E(e)},onPaste:k,onCompositionStart:j,onCompositionEnd:O,onBlur:T,tabIndex:g,attrs:(0,c.default)(e,!0),maxLength:N?$:void 0})),!N&&B?n.createElement("span",{className:"".concat(o,"-selection-item"),title:L,style:z?{visibility:"hidden"}:void 0},B.label):null,D)};var I=n.forwardRef(function(e,l){var s=(0,n.useRef)(null),c=(0,n.useRef)(!1),u=e.prefixCls,d=e.open,f=e.mode,p=e.showSearch,h=e.tokenWithEnter,m=e.disabled,g=e.prefix,v=e.autoClearSearchValue,y=e.onSearch,b=e.onSearchSubmit,w=e.onToggleOpen,$=e.onInputKeyDown,C=e.onInputBlur,x=e.domRef;n.useImperativeHandle(l,function(){return{focus:function(e){s.current.focus(e)},blur:function(){s.current.blur()}}});var E=(0,a.default)(0),S=(0,r.default)(E,2),k=S[0],j=S[1],I=(0,n.useRef)(null),_=function(e){!1!==y(e,!0,c.current)&&w(!0)},F={inputRef:s,onInputKeyDown:function(e){var t=e.which,r=s.current instanceof HTMLTextAreaElement;!r&&d&&(t===o.default.UP||t===o.default.DOWN)&&e.preventDefault(),$&&$(e),t!==o.default.ENTER||"tags"!==f||c.current||d||null==b||b(e.target.value),!(r&&!d&&~[o.default.UP,o.default.DOWN,o.default.LEFT,o.default.RIGHT].indexOf(t))&&(0,i.isValidateOpenKey)(t)&&w(!0)},onInputMouseDown:function(){j(!0)},onInputChange:function(e){var t=e.target.value;if(h&&I.current&&/[\r\n]/.test(I.current)){var r=I.current.replace(/[\r\n]+$/,"").replace(/\r\n/g," ").replace(/[\r\n]/g," ");t=t.replace(r,I.current)}I.current=null,_(t)},onInputPaste:function(e){var t=e.clipboardData;I.current=(null==t?void 0:t.getData("text"))||""},onInputCompositionStart:function(){c.current=!0},onInputCompositionEnd:function(e){c.current=!1,"combobox"!==f&&_(e.target.value)},onInputBlur:C},P="multiple"===f||"tags"===f?n.createElement(O,(0,t.default)({},e,F)):n.createElement(T,(0,t.default)({},e,F));return n.createElement("div",{ref:x,className:"".concat(u,"-selector"),onClick:function(e){e.target!==s.current&&(void 0!==document.body.style.msTouchAction?setTimeout(function(){s.current.focus()}):s.current.focus())},onMouseDown:function(e){var t=k();e.target===s.current||t||"combobox"===f&&m||e.preventDefault(),("combobox"===f||p&&t)&&d||(d&&!1!==v&&y("",!0,!1),w())}},g&&n.createElement("div",{className:"".concat(u,"-prefix")},g),P)});e.s(["default",0,I],823744)},331290,670532,300877,567770,750756,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(211577),o=e.i(8211),n=e.i(392221),a=e.i(209428),i=e.i(703923),l=e.i(343794),s=e.i(174428),c=e.i(914949),u=e.i(614761),d=e.i(611935),f=e.i(271645),p=e.i(147138),h=e.i(266623),m=e.i(794721),g=e.i(232176),v=e.i(843375),y=e.i(823744),b=e.i(707067),w=["prefixCls","disabled","visible","children","popupElement","animation","transitionName","dropdownStyle","dropdownClassName","direction","placement","builtinPlacements","dropdownMatchSelectWidth","dropdownRender","dropdownAlign","getPopupContainer","empty","getTriggerDOMNode","onPopupVisibleChange","onPopupMouseEnter"],$=function(e){var t=+(!0!==e);return{bottomLeft:{points:["tl","bl"],offset:[0,4],overflow:{adjustX:t,adjustY:1},htmlRegion:"scroll"},bottomRight:{points:["tr","br"],offset:[0,4],overflow:{adjustX:t,adjustY:1},htmlRegion:"scroll"},topLeft:{points:["bl","tl"],offset:[0,-4],overflow:{adjustX:t,adjustY:1},htmlRegion:"scroll"},topRight:{points:["br","tr"],offset:[0,-4],overflow:{adjustX:t,adjustY:1},htmlRegion:"scroll"}}},C=f.forwardRef(function(e,o){var n=e.prefixCls,s=(e.disabled,e.visible),c=e.children,u=e.popupElement,d=e.animation,p=e.transitionName,h=e.dropdownStyle,m=e.dropdownClassName,g=e.direction,v=e.placement,y=e.builtinPlacements,C=e.dropdownMatchSelectWidth,x=e.dropdownRender,E=e.dropdownAlign,S=e.getPopupContainer,k=e.empty,j=e.getTriggerDOMNode,O=e.onPopupVisibleChange,T=e.onPopupMouseEnter,I=(0,i.default)(e,w),_="".concat(n,"-dropdown"),F=u;x&&(F=x(u));var P=f.useMemo(function(){return y||$(C)},[y,C]),R=d?"".concat(_,"-").concat(d):p,N="number"==typeof C,M=f.useMemo(function(){return N?null:!1===C?"minWidth":"width"},[C,N]),B=h;N&&(B=(0,a.default)((0,a.default)({},B),{},{width:C}));var A=f.useRef(null);return f.useImperativeHandle(o,function(){return{getPopupElement:function(){var e;return null==(e=A.current)?void 0:e.popupElement}}}),f.createElement(b.default,(0,t.default)({},I,{showAction:O?["click"]:[],hideAction:O?["click"]:[],popupPlacement:v||("rtl"===(void 0===g?"ltr":g)?"bottomRight":"bottomLeft"),builtinPlacements:P,prefixCls:_,popupTransitionName:R,popup:f.createElement("div",{onMouseEnter:T},F),ref:A,stretch:M,popupAlign:E,popupVisible:s,getPopupContainer:S,popupClassName:(0,l.default)(m,(0,r.default)({},"".concat(_,"-empty"),k)),popupStyle:B,getTriggerDOMNode:j,onPopupVisibleChange:O}),c)}),x=e.i(210803),E=e.i(865610),S=e.i(883110);function k(e,t){var r,o=e.key;return("value"in e&&(r=e.value),null!=o)?o:void 0!==r?r:"rc-index-key-".concat(t)}function j(e){return void 0!==e&&!Number.isNaN(e)}function O(e,t){var r=e||{},o=r.label,n=r.value,a=r.options,i=r.groupLabel,l=o||(t?"children":"label");return{label:l,value:n||"value",options:a||"options",groupLabel:i||l}}function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=t.fieldNames,o=t.childrenAsData,n=[],a=O(r,!1),i=a.label,l=a.value,s=a.options,c=a.groupLabel;return!function e(t,r){Array.isArray(t)&&t.forEach(function(t){if(!r&&s in t){var a=t[c];void 0===a&&o&&(a=t.label),n.push({key:k(t,n.length),group:!0,data:t,label:a}),e(t[s],!0)}else{var u=t[l];n.push({key:k(t,n.length),groupOption:r,data:t,label:t[i],value:u})}})}(e,!1),n}function I(e){var t=(0,a.default)({},e);return"props"in t||Object.defineProperty(t,"props",{get:function(){return(0,S.default)(!1,"Return type is option instead of Option instance. Please read value directly instead of reading from `props`."),t}}),t}var _=function(e,t,r){if(!t||!t.length)return null;var n=!1,a=function e(t,r){var a=(0,E.default)(r),i=a[0],l=a.slice(1);if(!i)return[t];var s=t.split(i);return n=n||s.length>1,s.reduce(function(t,r){return[].concat((0,o.default)(t),(0,o.default)(e(r,l)))},[]).filter(Boolean)}(e,t);return n?void 0!==r?a.slice(0,r):a:null};e.s(["fillFieldNames",()=>O,"flattenOptions",()=>T,"getSeparatedContent",()=>_,"injectPropsWithOption",()=>I,"isValidCount",()=>j],670532);var F=f.createContext(null);e.s(["default",0,F],300877);var P=e.i(410160);function R(e){var t=e.visible,r=e.values;return t?f.createElement("span",{"aria-live":"polite",style:{width:0,height:0,position:"absolute",overflow:"hidden",opacity:0}},"".concat(r.slice(0,50).map(function(e){var t=e.label,r=e.value;return["number","string"].includes((0,P.default)(t))?t:r}).join(", ")),r.length>50?", ...":null):null}var N=["id","prefixCls","className","showSearch","tagRender","direction","omitDomProps","displayValues","onDisplayValuesChange","emptyOptions","notFoundContent","onClear","mode","disabled","loading","getInputElement","getRawInputElement","open","defaultOpen","onDropdownVisibleChange","activeValue","onActiveValueChange","activeDescendantId","searchValue","autoClearSearchValue","onSearch","onSearchSplit","tokenSeparators","allowClear","prefix","suffixIcon","clearIcon","OptionList","animation","transitionName","dropdownStyle","dropdownClassName","dropdownMatchSelectWidth","dropdownRender","dropdownAlign","placement","builtinPlacements","getPopupContainer","showAction","onFocus","onBlur","onKeyUp","onKeyDown","onMouseDown"],M=["value","onChange","removeIcon","placeholder","autoFocus","maxTagCount","maxTagTextLength","maxTagPlaceholder","choiceTransitionName","onInputKeyDown","onPopupScroll","tabIndex"],B=function(e){return"tags"===e||"multiple"===e},A=f.forwardRef(function(e,b){var w,$,E,S,k=e.id,O=e.prefixCls,T=e.className,I=e.showSearch,P=e.tagRender,A=e.direction,z=e.omitDomProps,L=e.displayValues,D=e.onDisplayValuesChange,H=e.emptyOptions,V=e.notFoundContent,W=void 0===V?"Not Found":V,U=e.onClear,G=e.mode,q=e.disabled,J=e.loading,K=e.getInputElement,X=e.getRawInputElement,Y=e.open,Q=e.defaultOpen,Z=e.onDropdownVisibleChange,ee=e.activeValue,et=e.onActiveValueChange,er=e.activeDescendantId,eo=e.searchValue,en=e.autoClearSearchValue,ea=e.onSearch,ei=e.onSearchSplit,el=e.tokenSeparators,es=e.allowClear,ec=e.prefix,eu=e.suffixIcon,ed=e.clearIcon,ef=e.OptionList,ep=e.animation,eh=e.transitionName,em=e.dropdownStyle,eg=e.dropdownClassName,ev=e.dropdownMatchSelectWidth,ey=e.dropdownRender,eb=e.dropdownAlign,ew=e.placement,e$=e.builtinPlacements,eC=e.getPopupContainer,ex=e.showAction,eE=void 0===ex?[]:ex,eS=e.onFocus,ek=e.onBlur,ej=e.onKeyUp,eO=e.onKeyDown,eT=e.onMouseDown,eI=(0,i.default)(e,N),e_=B(G),eF=(void 0!==I?I:e_)||"combobox"===G,eP=(0,a.default)({},eI);M.forEach(function(e){delete eP[e]}),null==z||z.forEach(function(e){delete eP[e]});var eR=f.useState(!1),eN=(0,n.default)(eR,2),eM=eN[0],eB=eN[1];f.useEffect(function(){eB((0,u.default)())},[]);var eA=f.useRef(null),ez=f.useRef(null),eL=f.useRef(null),eD=f.useRef(null),eH=f.useRef(null),eV=f.useRef(!1),eW=(0,m.default)(),eU=(0,n.default)(eW,3),eG=eU[0],eq=eU[1],eJ=eU[2];f.useImperativeHandle(b,function(){var e,t;return{focus:null==(e=eD.current)?void 0:e.focus,blur:null==(t=eD.current)?void 0:t.blur,scrollTo:function(e){var t;return null==(t=eH.current)?void 0:t.scrollTo(e)},nativeElement:eA.current||ez.current}});var eK=f.useMemo(function(){if("combobox"!==G)return eo;var e,t=null==(e=L[0])?void 0:e.value;return"string"==typeof t||"number"==typeof t?String(t):""},[eo,G,L]),eX="combobox"===G&&"function"==typeof K&&K()||null,eY="function"==typeof X&&X(),eQ=(0,d.useComposeRef)(ez,null==eY||null==(w=eY.props)?void 0:w.ref),eZ=f.useState(!1),e0=(0,n.default)(eZ,2),e1=e0[0],e2=e0[1];(0,s.default)(function(){e2(!0)},[]);var e4=(0,c.default)(!1,{defaultValue:Q,value:Y}),e6=(0,n.default)(e4,2),e3=e6[0],e7=e6[1],e5=!!e1&&e3,e9=!W&&H;(q||e9&&e5&&"combobox"===G)&&(e5=!1);var e8=!e9&&e5,te=f.useCallback(function(e){var t=void 0!==e?e:!e5;q||(e7(t),e5!==t&&(null==Z||Z(t)))},[q,e5,e7,Z]),tt=f.useMemo(function(){return(el||[]).some(function(e){return["\n","\r\n"].includes(e)})},[el]),tr=f.useContext(F)||{},to=tr.maxCount,tn=tr.rawValues,ta=function(e,t,r){if(!(e_&&j(to))||!((null==tn?void 0:tn.size)>=to)){var o=!0,n=e;null==et||et(null);var a=_(e,el,j(to)?to-tn.size:void 0),i=r?null:a;return"combobox"!==G&&i&&(n="",null==ei||ei(i),te(!1),o=!1),ea&&eK!==n&&ea(n,{source:t?"typing":"effect"}),o}};f.useEffect(function(){e5||e_||"combobox"===G||ta("",!1,!1)},[e5]),f.useEffect(function(){e3&&q&&e7(!1),q&&!eV.current&&eq(!1)},[q]);var ti=(0,g.default)(),tl=(0,n.default)(ti,2),ts=tl[0],tc=tl[1],tu=f.useRef(!1),td=f.useRef(!1),tf=[];f.useEffect(function(){return function(){tf.forEach(function(e){return clearTimeout(e)}),tf.splice(0,tf.length)}},[]);var tp=f.useState({}),th=(0,n.default)(tp,2)[1];eY&&($=function(e){te(e)}),(0,v.default)(function(){var e;return[eA.current,null==(e=eL.current)?void 0:e.getPopupElement()]},e8,te,!!eY);var tm=f.useMemo(function(){return(0,a.default)((0,a.default)({},e),{},{notFoundContent:W,open:e5,triggerOpen:e8,id:k,showSearch:eF,multiple:e_,toggleOpen:te})},[e,W,e8,e5,k,eF,e_,te]),tg=!!eu||J;tg&&(E=f.createElement(x.default,{className:(0,l.default)("".concat(O,"-arrow"),(0,r.default)({},"".concat(O,"-arrow-loading"),J)),customizeIcon:eu,customizeIconProps:{loading:J,searchValue:eK,open:e5,focused:eG,showSearch:eF}}));var tv=(0,p.useAllowClear)(O,function(){var e;null==U||U(),null==(e=eD.current)||e.focus(),D([],{type:"clear",values:L}),ta("",!1,!1)},L,es,ed,q,eK,G),ty=tv.allowClear,tb=tv.clearIcon,tw=f.createElement(ef,{ref:eH}),t$=(0,l.default)(O,T,(0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)((0,r.default)({},"".concat(O,"-focused"),eG),"".concat(O,"-multiple"),e_),"".concat(O,"-single"),!e_),"".concat(O,"-allow-clear"),es),"".concat(O,"-show-arrow"),tg),"".concat(O,"-disabled"),q),"".concat(O,"-loading"),J),"".concat(O,"-open"),e5),"".concat(O,"-customize-input"),eX),"".concat(O,"-show-search"),eF)),tC=f.createElement(C,{ref:eL,disabled:q,prefixCls:O,visible:e8,popupElement:tw,animation:ep,transitionName:eh,dropdownStyle:em,dropdownClassName:eg,direction:A,dropdownMatchSelectWidth:ev,dropdownRender:ey,dropdownAlign:eb,placement:ew,builtinPlacements:e$,getPopupContainer:eC,empty:H,getTriggerDOMNode:function(e){return ez.current||e},onPopupVisibleChange:$,onPopupMouseEnter:function(){th({})}},eY?f.cloneElement(eY,{ref:eQ}):f.createElement(y.default,(0,t.default)({},e,{domRef:ez,prefixCls:O,inputElement:eX,ref:eD,id:k,prefix:ec,showSearch:eF,autoClearSearchValue:en,mode:G,activeDescendantId:er,tagRender:P,values:L,open:e5,onToggleOpen:te,activeValue:ee,searchValue:eK,onSearch:ta,onSearchSubmit:function(e){e&&e.trim()&&ea(e,{source:"submit"})},onRemove:function(e){D(L.filter(function(t){return t!==e}),{type:"remove",values:[e]})},tokenWithEnter:tt,onInputBlur:function(){tu.current=!1}})));return S=eY?tC:f.createElement("div",(0,t.default)({className:t$},eP,{ref:eA,onMouseDown:function(e){var t,r=e.target,o=null==(t=eL.current)?void 0:t.getPopupElement();if(o&&o.contains(r)){var n=setTimeout(function(){var e,t=tf.indexOf(n);-1!==t&&tf.splice(t,1),eJ(),eM||o.contains(document.activeElement)||null==(e=eD.current)||e.focus()});tf.push(n)}for(var a=arguments.length,i=Array(a>1?a-1:0),l=1;l=0;s-=1){var c=i[s];if(!c.disabled){i.splice(s,1),l=c;break}}l&&D(i,{type:"remove",values:[l]})}for(var u=arguments.length,d=Array(u>1?u-1:0),f=1;f1?r-1:0),n=1;nB],331290);var z=function(){return null};z.isSelectOptGroup=!0,e.s(["default",0,z],567770);var L=function(){return null};L.isSelectOption=!0,e.s(["default",0,L],750756)},323002,e=>{"use strict";var t=e.i(931067),r=e.i(410160),o=e.i(209428),n=e.i(211577),a=e.i(392221),i=e.i(703923),l=e.i(343794),s=e.i(430073);e.i(62664);var c=e.i(697539),u=e.i(174428),d=e.i(271645),f=e.i(174080),p=d.forwardRef(function(e,r){var a=e.height,i=e.offsetY,c=e.offsetX,u=e.children,f=e.prefixCls,p=e.onInnerResize,h=e.innerProps,m=e.rtl,g=e.extra,v={},y={display:"flex",flexDirection:"column"};return void 0!==i&&(v={height:a,position:"relative",overflow:"hidden"},y=(0,o.default)((0,o.default)({},y),{},(0,n.default)((0,n.default)((0,n.default)((0,n.default)((0,n.default)({transform:"translateY(".concat(i,"px)")},m?"marginRight":"marginLeft",-c),"position","absolute"),"left",0),"right",0),"top",0))),d.createElement("div",{style:v},d.createElement(s.default,{onResize:function(e){e.offsetHeight&&p&&p()}},d.createElement("div",(0,t.default)({style:y,className:(0,l.default)((0,n.default)({},"".concat(f,"-holder-inner"),f)),ref:r},h),u,g)))});function h(e){var t=e.children,r=e.setRef,o=d.useCallback(function(e){r(e)},[]);return d.cloneElement(t,{ref:o})}p.displayName="Filler";var m=e.i(963188),g=("u"2&&void 0!==arguments[2]&&arguments[2],o=e?t<0&&i.current.left||t>0&&i.current.right:t<0&&i.current.top||t>0&&i.current.bottom;return r&&o?(clearTimeout(a.current),n.current=!1):(!o||n.current)&&(clearTimeout(a.current),n.current=!0,a.current=setTimeout(function(){n.current=!1},50)),!n.current&&o}};var y=e.i(278409),b=e.i(233848),w=function(){function e(){(0,y.default)(this,e),(0,n.default)(this,"maps",void 0),(0,n.default)(this,"id",0),(0,n.default)(this,"diffRecords",new Map),this.maps=Object.create(null)}return(0,b.default)(e,[{key:"set",value:function(e,t){this.diffRecords.set(e,this.maps[e]),this.maps[e]=t,this.id+=1}},{key:"get",value:function(e){return this.maps[e]}},{key:"resetRecord",value:function(){this.diffRecords.clear()}},{key:"getRecord",value:function(){return this.diffRecords}}]),e}();function $(e){var t=parseFloat(e);return isNaN(t)?0:t}var C=14/15;function x(e){return Math.floor(Math.pow(e,.5))}function E(e,t){return("touches"in e?e.touches[0]:e)[t?"pageX":"pageY"]-window[t?"scrollX":"scrollY"]}e.i(247167);var S=d.forwardRef(function(e,t){var r=e.prefixCls,i=e.rtl,s=e.scrollOffset,c=e.scrollRange,u=e.onStartMove,f=e.onStopMove,p=e.onScroll,h=e.horizontal,g=e.spinSize,v=e.containerSize,y=e.style,b=e.thumbStyle,w=e.showScrollBar,$=d.useState(!1),C=(0,a.default)($,2),x=C[0],S=C[1],k=d.useState(null),j=(0,a.default)(k,2),O=j[0],T=j[1],I=d.useState(null),_=(0,a.default)(I,2),F=_[0],P=_[1],R=!i,N=d.useRef(),M=d.useRef(),B=d.useState(w),A=(0,a.default)(B,2),z=A[0],L=A[1],D=d.useRef(),H=function(){!0!==w&&!1!==w&&(clearTimeout(D.current),L(!0),D.current=setTimeout(function(){L(!1)},3e3))},V=c-v||0,W=v-g||0,U=d.useMemo(function(){return 0===s||0===V?0:s/V*W},[s,V,W]),G=d.useRef({top:U,dragging:x,pageY:O,startTop:F});G.current={top:U,dragging:x,pageY:O,startTop:F};var q=function(e){S(!0),T(E(e,h)),P(G.current.top),u(),e.stopPropagation(),e.preventDefault()};d.useEffect(function(){var e=function(e){e.preventDefault()},t=N.current,r=M.current;return t.addEventListener("touchstart",e,{passive:!1}),r.addEventListener("touchstart",q,{passive:!1}),function(){t.removeEventListener("touchstart",e),r.removeEventListener("touchstart",q)}},[]);var J=d.useRef();J.current=V;var K=d.useRef();K.current=W,d.useEffect(function(){if(x){var e,t=function(t){var r=G.current,o=r.dragging,n=r.pageY,a=r.startTop;m.default.cancel(e);var i=N.current.getBoundingClientRect(),l=v/(h?i.width:i.height);if(o){var s=(E(t,h)-n)*l,c=a;!R&&h?c-=s:c+=s;var u=J.current,d=K.current,f=Math.ceil((d?c/d:0)*u);f=Math.min(f=Math.max(f,0),u),e=(0,m.default)(function(){p(f,h)})}},r=function(){S(!1),f()};return window.addEventListener("mousemove",t,{passive:!0}),window.addEventListener("touchmove",t,{passive:!0}),window.addEventListener("mouseup",r,{passive:!0}),window.addEventListener("touchend",r,{passive:!0}),function(){window.removeEventListener("mousemove",t),window.removeEventListener("touchmove",t),window.removeEventListener("mouseup",r),window.removeEventListener("touchend",r),m.default.cancel(e)}}},[x]),d.useEffect(function(){return H(),function(){clearTimeout(D.current)}},[s]),d.useImperativeHandle(t,function(){return{delayHidden:H}});var X="".concat(r,"-scrollbar"),Y={position:"absolute",visibility:z?null:"hidden"},Q={position:"absolute",borderRadius:99,background:"var(--rc-virtual-list-scrollbar-bg, rgba(0, 0, 0, 0.5))",cursor:"pointer",userSelect:"none"};return h?(Object.assign(Y,{height:8,left:0,right:0,bottom:0}),Object.assign(Q,(0,n.default)({height:"100%",width:g},R?"left":"right",U))):(Object.assign(Y,(0,n.default)({width:8,top:0,bottom:0},R?"right":"left",0)),Object.assign(Q,{width:"100%",height:g,top:U})),d.createElement("div",{ref:N,className:(0,l.default)(X,(0,n.default)((0,n.default)((0,n.default)({},"".concat(X,"-horizontal"),h),"".concat(X,"-vertical"),!h),"".concat(X,"-visible"),z)),style:(0,o.default)((0,o.default)({},Y),y),onMouseDown:function(e){e.stopPropagation(),e.preventDefault()},onMouseMove:H},d.createElement("div",{ref:M,className:(0,l.default)("".concat(X,"-thumb"),(0,n.default)({},"".concat(X,"-thumb-moving"),x)),style:(0,o.default)((0,o.default)({},Q),b),onMouseDown:q}))});function k(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,r=e/t*e;return isNaN(r)&&(r=0),Math.floor(r=Math.max(r,20))}var j=["prefixCls","className","height","itemHeight","fullHeight","style","data","children","itemKey","virtual","direction","scrollWidth","component","onScroll","onVirtualScroll","onVisibleChange","innerProps","extraRender","styles","showScrollBar"],O=[],T={overflowY:"auto",overflowAnchor:"none"},I=d.forwardRef(function(e,y){var b,I,_,F,P,R,N,M,B,A,z,L,D,H,V,W,U,G,q,J,K,X,Y,Q,Z,ee,et,er,eo,en,ea,ei,el,es,ec,eu,ed,ef=e.prefixCls,ep=void 0===ef?"rc-virtual-list":ef,eh=e.className,em=e.height,eg=e.itemHeight,ev=e.fullHeight,ey=e.style,eb=e.data,ew=e.children,e$=e.itemKey,eC=e.virtual,ex=e.direction,eE=e.scrollWidth,eS=e.component,ek=e.onScroll,ej=e.onVirtualScroll,eO=e.onVisibleChange,eT=e.innerProps,eI=e.extraRender,e_=e.styles,eF=e.showScrollBar,eP=void 0===eF?"optional":eF,eR=(0,i.default)(e,j),eN=d.useCallback(function(e){return"function"==typeof e$?e$(e):null==e?void 0:e[e$]},[e$]),eM=function(e,t,r){var o=d.useState(0),n=(0,a.default)(o,2),i=n[0],l=n[1],s=(0,d.useRef)(new Map),c=(0,d.useRef)(new w),u=(0,d.useRef)(0);function f(){u.current+=1}function p(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];f();var t=function(){var e=!1;s.current.forEach(function(t,r){if(t&&t.offsetParent){var o=t.offsetHeight,n=getComputedStyle(t),a=n.marginTop,i=n.marginBottom,l=o+$(a)+$(i);c.current.get(r)!==l&&(c.current.set(r,l),e=!0)}}),e&&l(function(e){return e+1})};if(e)t();else{u.current+=1;var r=u.current;Promise.resolve().then(function(){r===u.current&&t()})}}return(0,d.useEffect)(function(){return f},[]),[function(o,n){var a=e(o),i=s.current.get(a);n?(s.current.set(a,n),p()):s.current.delete(a),!i!=!n&&(n?null==t||t(o):null==r||r(o))},p,c.current,i]}(eN,null,null),eB=(0,a.default)(eM,4),eA=eB[0],ez=eB[1],eL=eB[2],eD=eB[3],eH=!!(!1!==eC&&em&&eg),eV=d.useMemo(function(){return Object.values(eL.maps).reduce(function(e,t){return e+t},0)},[eL.id,eL.maps]),eW=eH&&eb&&(Math.max(eg*eb.length,eV)>em||!!eE),eU="rtl"===ex,eG=(0,l.default)(ep,(0,n.default)({},"".concat(ep,"-rtl"),eU),eh),eq=eb||O,eJ=(0,d.useRef)(),eK=(0,d.useRef)(),eX=(0,d.useRef)(),eY=(0,d.useState)(0),eQ=(0,a.default)(eY,2),eZ=eQ[0],e0=eQ[1],e1=(0,d.useState)(0),e2=(0,a.default)(e1,2),e4=e2[0],e6=e2[1],e3=(0,d.useState)(!1),e7=(0,a.default)(e3,2),e5=e7[0],e9=e7[1],e8=function(){e9(!0)},te=function(){e9(!1)};function tt(e){e0(function(t){var r,o=(r="function"==typeof e?e(t):e,Number.isNaN(tb.current)||(r=Math.min(r,tb.current)),r=Math.max(r,0));return eJ.current.scrollTop=o,o})}var tr=(0,d.useRef)({start:0,end:eq.length}),to=(0,d.useRef)(),tn=(b=d.useState(eq),_=(I=(0,a.default)(b,2))[0],F=I[1],P=d.useState(null),N=(R=(0,a.default)(P,2))[0],M=R[1],d.useEffect(function(){var e=function(e,t,r){var o,n,a=e.length,i=t.length;if(0===a&&0===i)return null;a=eZ&&void 0===t&&(t=i,r=n),c>eZ+em&&void 0===o&&(o=i),n=c}return void 0===t&&(t=0,r=0,o=Math.ceil(em/eg)),void 0===o&&(o=eq.length-1),{scrollHeight:n,start:t,end:o=Math.min(o+1,eq.length-1),offset:r}},[eW,eH,eZ,eq,eD,em]),ti=ta.scrollHeight,tl=ta.start,ts=ta.end,tc=ta.offset;tr.current.start=tl,tr.current.end=ts,d.useLayoutEffect(function(){var e=eL.getRecord();if(1===e.size){var t=Array.from(e.keys())[0],r=e.get(t),o=eq[tl];if(o&&void 0===r&&eN(o)===t){var n=eL.get(t)-eg;tt(function(e){return e+n})}}eL.resetRecord()},[ti]);var tu=d.useState({width:0,height:em}),td=(0,a.default)(tu,2),tf=td[0],tp=td[1],th=(0,d.useRef)(),tm=(0,d.useRef)(),tg=d.useMemo(function(){return k(tf.width,eE)},[tf.width,eE]),tv=d.useMemo(function(){return k(tf.height,ti)},[tf.height,ti]),ty=ti-em,tb=(0,d.useRef)(ty);tb.current=ty;var tw=eZ<=0,t$=eZ>=ty,tC=e4<=0,tx=e4>=eE,tE=v(tw,t$,tC,tx),tS=function(){return{x:eU?-e4:e4,y:eZ}},tk=(0,d.useRef)(tS()),tj=(0,c.useEvent)(function(e){if(ej){var t=(0,o.default)((0,o.default)({},tS()),e);(tk.current.x!==t.x||tk.current.y!==t.y)&&(ej(t),tk.current=t)}});function tO(e,t){t?((0,f.flushSync)(function(){e6(e)}),tj()):tt(e)}var tT=function(e){var t=e,r=eE?eE-tf.width:0;return Math.min(t=Math.max(t,0),r)},tI=(0,c.useEvent)(function(e,t){t?((0,f.flushSync)(function(){e6(function(t){return tT(t+(eU?-e:e))})}),tj()):tt(function(t){return t+e})}),t_=(B=!!eE,A=(0,d.useRef)(0),z=(0,d.useRef)(null),L=(0,d.useRef)(null),D=(0,d.useRef)(!1),H=v(tw,t$,tC,tx),V=(0,d.useRef)(null),W=(0,d.useRef)(null),[function(e){if(eH){m.default.cancel(W.current),W.current=(0,m.default)(function(){V.current=null},2);var t,r,o=e.deltaX,n=e.deltaY,a=e.shiftKey,i=o,l=n;("sx"===V.current||!V.current&&a&&n&&!o)&&(i=n,l=0,V.current="sx");var s=Math.abs(i),c=Math.abs(l);if(null===V.current&&(V.current=B&&s>c?"x":"y"),"y"===V.current){t=e,r=l,m.default.cancel(z.current),!H(!1,r)&&(t._virtualHandled||(t._virtualHandled=!0,A.current+=r,L.current=r,g||t.preventDefault(),z.current=(0,m.default)(function(){var e=D.current?10:1;tI(A.current*e,!1),A.current=0})))}else tI(i,!0),g||e.preventDefault()}},function(e){eH&&(D.current=e.detail===L.current)}]),tF=(0,a.default)(t_,2),tP=tF[0],tR=tF[1];U=function(e,t,r,o){return!tE(e,t,r)&&(!o||!o._virtualHandled)&&(o&&(o._virtualHandled=!0),tP({preventDefault:function(){},deltaX:e?t:0,deltaY:e?0:t}),!0)},q=(0,d.useRef)(!1),J=(0,d.useRef)(0),K=(0,d.useRef)(0),X=(0,d.useRef)(null),Y=(0,d.useRef)(null),Q=function(e){if(q.current){var t=Math.ceil(e.touches[0].pageX),r=Math.ceil(e.touches[0].pageY),o=J.current-t,n=K.current-r,a=Math.abs(o)>Math.abs(n);a?J.current=t:K.current=r;var i=U(a,a?o:n,!1,e);i&&e.preventDefault(),clearInterval(Y.current),i&&(Y.current=setInterval(function(){a?o*=C:n*=C;var e=Math.floor(a?o:n);(!U(a,e,!0)||.1>=Math.abs(e))&&clearInterval(Y.current)},16))}},Z=function(){q.current=!1,G()},ee=function(e){G(),1!==e.touches.length||q.current||(q.current=!0,J.current=Math.ceil(e.touches[0].pageX),K.current=Math.ceil(e.touches[0].pageY),X.current=e.target,X.current.addEventListener("touchmove",Q,{passive:!1}),X.current.addEventListener("touchend",Z,{passive:!0}))},G=function(){X.current&&(X.current.removeEventListener("touchmove",Q),X.current.removeEventListener("touchend",Z))},(0,u.default)(function(){return eH&&eJ.current.addEventListener("touchstart",ee,{passive:!0}),function(){var e;null==(e=eJ.current)||e.removeEventListener("touchstart",ee),G(),clearInterval(Y.current)}},[eH]),et=function(e){tt(function(t){return t+e})},d.useEffect(function(){var e=eJ.current;if(eW&&e){var t,r,o=!1,n=function(){m.default.cancel(t)},a=function e(){n(),t=(0,m.default)(function(){et(r),e()})},i=function(){o=!1,n()},l=function(e){!e.target.draggable&&0===e.button&&(e._virtualHandled||(e._virtualHandled=!0,o=!0))},s=function(t){if(o){var i=E(t,!1),l=e.getBoundingClientRect(),s=l.top,c=l.bottom;i<=s?(r=-x(s-i),a()):i>=c?(r=x(i-c),a()):n()}};return e.addEventListener("mousedown",l),e.ownerDocument.addEventListener("mouseup",i),e.ownerDocument.addEventListener("mousemove",s),e.ownerDocument.addEventListener("dragend",i),function(){e.removeEventListener("mousedown",l),e.ownerDocument.removeEventListener("mouseup",i),e.ownerDocument.removeEventListener("mousemove",s),e.ownerDocument.removeEventListener("dragend",i),n()}}},[eW]),(0,u.default)(function(){function e(e){var t=tw&&e.detail<0,r=t$&&e.detail>0;!eH||t||r||e.preventDefault()}var t=eJ.current;return t.addEventListener("wheel",tP,{passive:!1}),t.addEventListener("DOMMouseScroll",tR,{passive:!0}),t.addEventListener("MozMousePixelScroll",e,{passive:!1}),function(){t.removeEventListener("wheel",tP),t.removeEventListener("DOMMouseScroll",tR),t.removeEventListener("MozMousePixelScroll",e)}},[eH,tw,t$]),(0,u.default)(function(){if(eE){var e=tT(e4);e6(e),tj({x:e})}},[tf.width,eE]);var tN=function(){var e,t;null==(e=th.current)||e.delayHidden(),null==(t=tm.current)||t.delayHidden()},tM=(er=function(){return ez(!0)},eo=d.useRef(),en=d.useState(null),ei=(ea=(0,a.default)(en,2))[0],el=ea[1],(0,u.default)(function(){if(ei&&ei.times<10){if(!eJ.current)return void el(function(e){return(0,o.default)({},e)});er();var e=ei.targetAlign,t=ei.originAlign,r=ei.index,n=ei.offset,a=eJ.current.clientHeight,i=!1,l=e,s=null;if(a){for(var c=e||t,u=0,d=0,f=0,p=Math.min(eq.length-1,r),h=0;h<=p;h+=1){var m=eN(eq[h]);d=u;var g=eL.get(m);u=f=d+(void 0===g?eg:g)}for(var v="top"===c?n:a-n,y=p;y>=0;y-=1){var b=eN(eq[y]),w=eL.get(b);if(void 0===w){i=!0;break}if((v-=w)<=0)break}switch(c){case"top":s=d-n;break;case"bottom":s=f-a+n;break;default:var $=eJ.current.scrollTop;d<$?l="top":f>$+a&&(l="bottom")}null!==s&&tt(s),s!==ei.lastTop&&(i=!0)}i&&el((0,o.default)((0,o.default)({},ei),{},{times:ei.times+1,targetAlign:l,lastTop:s}))}},[ei,eJ.current]),function(e){if(null==e)return void tN();if(m.default.cancel(eo.current),"number"==typeof e)tt(e);else if(e&&"object"===(0,r.default)(e)){var t,o=e.align;t="index"in e?e.index:eq.findIndex(function(t){return eN(t)===e.key});var n=e.offset;el({times:0,index:t,offset:void 0===n?0:n,originAlign:o})}});d.useImperativeHandle(y,function(){return{nativeElement:eX.current,getScrollInfo:tS,scrollTo:function(e){e&&"object"===(0,r.default)(e)&&("left"in e||"top"in e)?(void 0!==e.left&&e6(tT(e.left)),tM(e.top)):tM(e)}}}),(0,u.default)(function(){eO&&eO(eq.slice(tl,ts+1),eq)},[tl,ts,eq]);var tB=(es=d.useMemo(function(){return[new Map,[]]},[eq,eL.id,eg]),eu=(ec=(0,a.default)(es,2))[0],ed=ec[1],function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:e,r=eu.get(e),o=eu.get(t);if(void 0===r||void 0===o)for(var n=eq.length,a=ed.length;aem&&d.createElement(S,{ref:th,prefixCls:ep,scrollOffset:eZ,scrollRange:ti,rtl:eU,onScroll:tO,onStartMove:e8,onStopMove:te,spinSize:tv,containerSize:tf.height,style:null==e_?void 0:e_.verticalScrollBar,thumbStyle:null==e_?void 0:e_.verticalScrollBarThumb,showScrollBar:eP}),eW&&eE>tf.width&&d.createElement(S,{ref:tm,prefixCls:ep,scrollOffset:e4,scrollRange:eE,rtl:eU,onScroll:tO,onStartMove:e8,onStopMove:te,spinSize:tg,containerSize:tf.width,horizontal:!0,style:null==e_?void 0:e_.horizontalScrollBar,thumbStyle:null==e_?void 0:e_.horizontalScrollBarThumb,showScrollBar:eP}))});I.displayName="List",e.s(["default",0,I],323002)},123829,955492,869301,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(8211),o=e.i(211577),n=e.i(209428),a=e.i(392221),i=e.i(703923),l=e.i(410160),s=e.i(914949);e.i(883110);var c=e.i(271645),u=e.i(331290),d=e.i(567770),f=e.i(750756),p=e.i(343794),h=e.i(404948),m=e.i(182585),g=e.i(529681),v=e.i(244009),y=e.i(323002),b=e.i(300877),w=e.i(210803),$=e.i(266623),C=e.i(670532),x=["disabled","title","children","style","className"];function E(e){return"string"==typeof e||"number"==typeof e}var S=c.forwardRef(function(e,n){var l=(0,$.default)(),s=l.prefixCls,u=l.id,d=l.open,f=l.multiple,S=l.mode,k=l.searchValue,j=l.toggleOpen,O=l.notFoundContent,T=l.onPopupScroll,I=c.useContext(b.default),_=I.maxCount,F=I.flattenOptions,P=I.onActiveValue,R=I.defaultActiveFirstOption,N=I.onSelect,M=I.menuItemSelectedIcon,B=I.rawValues,A=I.fieldNames,z=I.virtual,L=I.direction,D=I.listHeight,H=I.listItemHeight,V=I.optionRender,W="".concat(s,"-item"),U=(0,m.default)(function(){return F},[d,F],function(e,t){return t[0]&&e[1]!==t[1]}),G=c.useRef(null),q=c.useMemo(function(){return f&&(0,C.isValidCount)(_)&&(null==B?void 0:B.size)>=_},[f,_,null==B?void 0:B.size]),J=function(e){e.preventDefault()},K=function(e){var t;null==(t=G.current)||t.scrollTo("number"==typeof e?{index:e}:e)},X=c.useCallback(function(e){return"combobox"!==S&&B.has(e)},[S,(0,r.default)(B).toString(),B.size]),Y=function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,r=U.length,o=0;o1&&void 0!==arguments[1]&&arguments[1];et(e);var r={source:t?"keyboard":"mouse"},o=U[e];o?P(o.value,e,r):P(null,-1,r)};(0,c.useEffect)(function(){er(!1!==R?Y(0):-1)},[U.length,k]);var eo=c.useCallback(function(e){return"combobox"===S?String(e).toLowerCase()===k.toLowerCase():B.has(e)},[S,k,(0,r.default)(B).toString(),B.size]);(0,c.useEffect)(function(){var e,t=setTimeout(function(){if(!f&&d&&1===B.size){var e=Array.from(B)[0],t=U.findIndex(function(t){var r=t.data;return k?String(r.value).startsWith(k):r.value===e});-1!==t&&(er(t),K(t))}});return d&&(null==(e=G.current)||e.scrollTo(void 0)),function(){return clearTimeout(t)}},[d,k]);var en=function(e){void 0!==e&&N(e,{selected:!B.has(e)}),f||j(!1)};if(c.useImperativeHandle(n,function(){return{onKeyDown:function(e){var t=e.which,r=e.ctrlKey;switch(t){case h.default.N:case h.default.P:case h.default.UP:case h.default.DOWN:var o=0;if(t===h.default.UP?o=-1:t===h.default.DOWN?o=1:/(mac\sos|macintosh)/i.test(navigator.appVersion)&&r&&(t===h.default.N?o=1:t===h.default.P&&(o=-1)),0!==o){var n=Y(ee+o,o);K(n),er(n,!0)}break;case h.default.TAB:case h.default.ENTER:var a,i=U[ee];!i||null!=i&&null!=(a=i.data)&&a.disabled||q?en(void 0):en(i.value),d&&e.preventDefault();break;case h.default.ESC:j(!1),d&&e.stopPropagation()}},onKeyUp:function(){},scrollTo:function(e){K(e)}}}),0===U.length)return c.createElement("div",{role:"listbox",id:"".concat(u,"_list"),className:"".concat(W,"-empty"),onMouseDown:J},O);var ea=Object.keys(A).map(function(e){return A[e]}),ei=function(e){return e.label};function el(e,t){return{role:e.group?"presentation":"option",id:"".concat(u,"_list_").concat(t)}}var es=function(e){var r=U[e];if(!r)return null;var o=r.data||{},n=o.value,a=r.group,i=(0,v.default)(o,!0),l=ei(r);return r?c.createElement("div",(0,t.default)({"aria-label":"string"!=typeof l||a?null:l},i,{key:e},el(r,e),{"aria-selected":eo(n)}),n):null},ec={role:"listbox",id:"".concat(u,"_list")};return c.createElement(c.Fragment,null,z&&c.createElement("div",(0,t.default)({},ec,{style:{height:0,width:0,overflow:"hidden"}}),es(ee-1),es(ee),es(ee+1)),c.createElement(y.default,{itemKey:"key",ref:G,data:U,height:D,itemHeight:H,fullHeight:!1,onMouseDown:J,onScroll:T,virtual:z,direction:L,innerProps:z?null:ec},function(e,r){var n=e.group,a=e.groupOption,l=e.data,s=e.label,u=e.value,d=l.key;if(n){var f,h=null!=(f=l.title)?f:E(s)?s.toString():void 0;return c.createElement("div",{className:(0,p.default)(W,"".concat(W,"-group"),l.className),title:h},void 0!==s?s:d)}var m=l.disabled,y=l.title,b=(l.children,l.style),$=l.className,C=(0,i.default)(l,x),S=(0,g.default)(C,ea),k=X(u),j=m||!k&&q,O="".concat(W,"-option"),T=(0,p.default)(W,O,$,(0,o.default)((0,o.default)((0,o.default)((0,o.default)({},"".concat(O,"-grouped"),a),"".concat(O,"-active"),ee===r&&!j),"".concat(O,"-disabled"),j),"".concat(O,"-selected"),k)),I=ei(e),_=!M||"function"==typeof M||k,F="number"==typeof I?I:I||u,P=E(F)?F.toString():void 0;return void 0!==y&&(P=y),c.createElement("div",(0,t.default)({},(0,v.default)(S),z?{}:el(e,r),{"aria-selected":eo(u),className:T,title:P,onMouseMove:function(){ee===r||j||er(r)},onClick:function(){j||en(u)},style:b}),c.createElement("div",{className:"".concat(O,"-content")},"function"==typeof V?V(e,{index:r}):F),c.isValidElement(M)||k,_&&c.createElement(w.default,{className:"".concat(W,"-option-state"),customizeIcon:M,customizeIconProps:{value:u,disabled:j,isSelected:k}},k?"✓":null))}))});let k=function(e,t){var r=c.useRef({values:new Map,options:new Map});return[c.useMemo(function(){var o=r.current,a=o.values,i=o.options,l=e.map(function(e){if(void 0===e.label){var t;return(0,n.default)((0,n.default)({},e),{},{label:null==(t=a.get(e.value))?void 0:t.label})}return e}),s=new Map,c=new Map;return l.forEach(function(e){s.set(e.value,e),c.set(e.value,t.get(e.value)||i.get(e.value))}),r.current.values=s,r.current.options=c,l},[e,t]),c.useCallback(function(e){return t.get(e)||r.current.options.get(e)},[t])]};var j=e.i(207427);function O(e,t){return(0,j.toArray)(e).join("").toUpperCase().includes(t)}var T=e.i(654310),I=0,_=(0,T.default)(),F=e.i(876556),P=["children","value"],R=["children"];function N(e){var t=c.useRef();return t.current=e,c.useCallback(function(){return t.current.apply(t,arguments)},[])}var M=["id","mode","prefixCls","backfill","fieldNames","inputValue","searchValue","onSearch","autoClearSearchValue","onSelect","onDeselect","dropdownMatchSelectWidth","filterOption","filterSort","optionFilterProp","optionLabelProp","options","optionRender","children","defaultActiveFirstOption","menuItemSelectedIcon","virtual","direction","listHeight","listItemHeight","labelRender","value","defaultValue","labelInValue","onChange","maxCount"],B=["inputValue"],A=c.forwardRef(function(e,d){var f,p,h,m,g,v=e.id,y=e.mode,w=e.prefixCls,$=e.backfill,x=e.fieldNames,E=e.inputValue,T=e.searchValue,A=e.onSearch,z=e.autoClearSearchValue,L=void 0===z||z,D=e.onSelect,H=e.onDeselect,V=e.dropdownMatchSelectWidth,W=void 0===V||V,U=e.filterOption,G=e.filterSort,q=e.optionFilterProp,J=e.optionLabelProp,K=e.options,X=e.optionRender,Y=e.children,Q=e.defaultActiveFirstOption,Z=e.menuItemSelectedIcon,ee=e.virtual,et=e.direction,er=e.listHeight,eo=void 0===er?200:er,en=e.listItemHeight,ea=void 0===en?20:en,ei=e.labelRender,el=e.value,es=e.defaultValue,ec=e.labelInValue,eu=e.onChange,ed=e.maxCount,ef=(0,i.default)(e,M),ep=(f=c.useState(),h=(p=(0,a.default)(f,2))[0],m=p[1],c.useEffect(function(){var e;m("rc_select_".concat((_?(e=I,I+=1):e="TEST_OR_SSR",e)))},[]),v||h),eh=(0,u.isMultiple)(y),em=!!(!K&&Y),eg=c.useMemo(function(){return(void 0!==U||"combobox"!==y)&&U},[U,y]),ev=c.useMemo(function(){return(0,C.fillFieldNames)(x,em)},[JSON.stringify(x),em]),ey=(0,s.default)("",{value:void 0!==T?T:E,postState:function(e){return e||""}}),eb=(0,a.default)(ey,2),ew=eb[0],e$=eb[1],eC=c.useMemo(function(){var e=K;K||(e=function e(t){var r=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,F.default)(t).map(function(t,o){if(!c.isValidElement(t)||!t.type)return null;var a,l,s,u,d,f=t.type.isSelectOptGroup,p=t.key,h=t.props,m=h.children,g=(0,i.default)(h,R);return r||!f?(a=t.key,s=(l=t.props).children,u=l.value,d=(0,i.default)(l,P),(0,n.default)({key:a,value:void 0!==u?u:a,children:s},d)):(0,n.default)((0,n.default)({key:"__RC_SELECT_GRP__".concat(null===p?o:p,"__"),label:p},g),{},{options:e(m)})}).filter(function(e){return e})}(Y));var t=new Map,r=new Map,o=function(e,t,r){r&&"string"==typeof r&&e.set(t[r],t)};return!function e(n){for(var a=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=0;i0?e(t.options):t.options}):t})}(ez):ez},[ez,G,ew]),eD=c.useMemo(function(){return(0,C.flattenOptions)(eL,{fieldNames:ev,childrenAsData:em})},[eL,ev,em]),eH=function(e){var t=ek(e);if(eI(t),eu&&(t.length!==eP.length||t.some(function(e,t){var r;return(null==(r=eP[t])?void 0:r.value)!==(null==e?void 0:e.value)}))){var r=ec?t:t.map(function(e){return e.value}),o=t.map(function(e){return(0,C.injectPropsWithOption)(eR(e.value))});eu(eh?r:r[0],eh?o:o[0])}},eV=c.useState(null),eW=(0,a.default)(eV,2),eU=eW[0],eG=eW[1],eq=c.useState(0),eJ=(0,a.default)(eq,2),eK=eJ[0],eX=eJ[1],eY=void 0!==Q?Q:"combobox"!==y,eQ=c.useCallback(function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=r.source;eX(t),$&&"combobox"===y&&null!==e&&"keyboard"===(void 0===o?"keyboard":o)&&eG(String(e))},[$,y]),eZ=function(e,t,r){var o=function(){var t,r=eR(e);return[ec?{label:null==r?void 0:r[ev.label],value:e,key:null!=(t=null==r?void 0:r.key)?t:e}:e,(0,C.injectPropsWithOption)(r)]};if(t&&D){var n=o(),i=(0,a.default)(n,2);D(i[0],i[1])}else if(!t&&H&&"clear"!==r){var l=o(),s=(0,a.default)(l,2);H(s[0],s[1])}},e0=N(function(e,t){var o=!eh||t.selected;eH(o?eh?[].concat((0,r.default)(eP),[e]):[e]:eP.filter(function(t){return t.value!==e})),eZ(e,o),"combobox"===y?eG(""):(!u.isMultiple||L)&&(e$(""),eG(""))}),e1=c.useMemo(function(){var e=!1!==ee&&!1!==W;return(0,n.default)((0,n.default)({},eC),{},{flattenOptions:eD,onActiveValue:eQ,defaultActiveFirstOption:eY,onSelect:e0,menuItemSelectedIcon:Z,rawValues:eM,fieldNames:ev,virtual:e,direction:et,listHeight:eo,listItemHeight:ea,childrenAsData:em,maxCount:ed,optionRender:X})},[ed,eC,eD,eQ,eY,e0,Z,eM,ev,ee,W,et,eo,ea,em,X]);return c.createElement(b.default.Provider,{value:e1},c.createElement(u.default,(0,t.default)({},ef,{id:ep,prefixCls:void 0===w?"rc-select":w,ref:d,omitDomProps:B,mode:y,displayValues:eN,onDisplayValuesChange:function(e,t){eH(e);var r=t.type,o=t.values;("remove"===r||"clear"===r)&&o.forEach(function(e){eZ(e.value,!1,r)})},direction:et,searchValue:ew,onSearch:function(e,t){if(e$(e),eG(null),"submit"===t.source){var o=(e||"").trim();o&&(eH(Array.from(new Set([].concat((0,r.default)(eM),[o])))),eZ(o,!0),e$(""));return}"blur"!==t.source&&("combobox"===y&&eH(e),null==A||A(e))},autoClearSearchValue:L,onSearchSplit:function(e){var t=e;"tags"!==y&&(t=e.map(function(e){var t=eE.get(e);return null==t?void 0:t.value}).filter(function(e){return void 0!==e}));var o=Array.from(new Set([].concat((0,r.default)(eM),(0,r.default)(t))));eH(o),o.forEach(function(e){eZ(e,!0)})},dropdownMatchSelectWidth:W,OptionList:S,emptyOptions:!eD.length,activeValue:eU,activeDescendantId:"".concat(ep,"_list_").concat(eK)})))});A.Option=f.default,A.OptGroup=d.default,e.s(["default",0,A],123829),e.s(["OptGroup",()=>d.default],955492),e.s(["Option",()=>f.default],869301)},721132,616303,e=>{"use strict";var t=e.i(271645),r=e.i(242064);e.i(247167);var o=e.i(343794),n=e.i(408850);e.i(262370);var a=e.i(135551),i=e.i(104458),l=e.i(246422),s=e.i(838378);let c=(0,l.genStyleHooks)("Empty",e=>{let{componentCls:t,controlHeightLG:r,calc:o}=e;return(e=>{let{componentCls:t,margin:r,marginXS:o,marginXL:n,fontSize:a,lineHeight:i}=e;return{[t]:{marginInline:o,fontSize:a,lineHeight:i,textAlign:"center",[`${t}-image`]:{height:e.emptyImgHeight,marginBottom:o,opacity:e.opacityImage,img:{height:"100%"},svg:{maxWidth:"100%",height:"100%",margin:"auto"}},[`${t}-description`]:{color:e.colorTextDescription},[`${t}-footer`]:{marginTop:r},"&-normal":{marginBlock:n,color:e.colorTextDescription,[`${t}-description`]:{color:e.colorTextDescription},[`${t}-image`]:{height:e.emptyImgHeightMD}},"&-small":{marginBlock:o,color:e.colorTextDescription,[`${t}-image`]:{height:e.emptyImgHeightSM}}}}})((0,s.mergeToken)(e,{emptyImgCls:`${t}-img`,emptyImgHeight:o(r).mul(2.5).equal(),emptyImgHeightMD:r,emptyImgHeightSM:o(r).mul(.875).equal()}))});var u=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let d=t.createElement(()=>{let[,e]=(0,i.useToken)(),[r]=(0,n.useLocale)("Empty"),o=new a.FastColor(e.colorBgBase).toHsl().l<.5?{opacity:.65}:{};return t.createElement("svg",{style:o,width:"184",height:"152",viewBox:"0 0 184 152",xmlns:"http://www.w3.org/2000/svg"},t.createElement("title",null,(null==r?void 0:r.description)||"Empty"),t.createElement("g",{fill:"none",fillRule:"evenodd"},t.createElement("g",{transform:"translate(24 31.67)"},t.createElement("ellipse",{fillOpacity:".8",fill:"#F5F5F7",cx:"67.797",cy:"106.89",rx:"67.797",ry:"12.668"}),t.createElement("path",{d:"M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z",fill:"#AEB8C2"}),t.createElement("path",{d:"M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z",fill:"url(#linearGradient-1)",transform:"translate(13.56)"}),t.createElement("path",{d:"M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z",fill:"#F5F5F7"}),t.createElement("path",{d:"M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z",fill:"#DCE0E6"})),t.createElement("path",{d:"M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z",fill:"#DCE0E6"}),t.createElement("g",{transform:"translate(149.65 15.383)",fill:"#FFF"},t.createElement("ellipse",{cx:"20.654",cy:"3.167",rx:"2.849",ry:"2.815"}),t.createElement("path",{d:"M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"}))))},null),f=t.createElement(()=>{let[,e]=(0,i.useToken)(),[r]=(0,n.useLocale)("Empty"),{colorFill:o,colorFillTertiary:l,colorFillQuaternary:s,colorBgContainer:c}=e,{borderColor:u,shadowColor:d,contentColor:f}=(0,t.useMemo)(()=>({borderColor:new a.FastColor(o).onBackground(c).toHexString(),shadowColor:new a.FastColor(l).onBackground(c).toHexString(),contentColor:new a.FastColor(s).onBackground(c).toHexString()}),[o,l,s,c]);return t.createElement("svg",{width:"64",height:"41",viewBox:"0 0 64 41",xmlns:"http://www.w3.org/2000/svg"},t.createElement("title",null,(null==r?void 0:r.description)||"Empty"),t.createElement("g",{transform:"translate(0 1)",fill:"none",fillRule:"evenodd"},t.createElement("ellipse",{fill:d,cx:"32",cy:"33",rx:"32",ry:"7"}),t.createElement("g",{fillRule:"nonzero",stroke:u},t.createElement("path",{d:"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"}),t.createElement("path",{d:"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z",fill:f}))))},null),p=e=>{var a;let{className:i,rootClassName:l,prefixCls:s,image:p,description:h,children:m,imageStyle:g,style:v,classNames:y,styles:b}=e,w=u(e,["className","rootClassName","prefixCls","image","description","children","imageStyle","style","classNames","styles"]),{getPrefixCls:$,direction:C,className:x,style:E,classNames:S,styles:k,image:j}=(0,r.useComponentConfig)("empty"),O=$("empty",s),[T,I,_]=c(O),[F]=(0,n.useLocale)("Empty"),P=void 0!==h?h:null==F?void 0:F.description,R="string"==typeof P?P:"empty",N=null!=(a=null!=p?p:j)?a:d,M=null;return M="string"==typeof N?t.createElement("img",{draggable:!1,alt:R,src:N}):N,T(t.createElement("div",Object.assign({className:(0,o.default)(I,_,O,x,{[`${O}-normal`]:N===f,[`${O}-rtl`]:"rtl"===C},i,l,S.root,null==y?void 0:y.root),style:Object.assign(Object.assign(Object.assign(Object.assign({},k.root),E),null==b?void 0:b.root),v)},w),t.createElement("div",{className:(0,o.default)(`${O}-image`,S.image,null==y?void 0:y.image),style:Object.assign(Object.assign(Object.assign({},g),k.image),null==b?void 0:b.image)},M),P&&t.createElement("div",{className:(0,o.default)(`${O}-description`,S.description,null==y?void 0:y.description),style:Object.assign(Object.assign({},k.description),null==b?void 0:b.description)},P),m&&t.createElement("div",{className:(0,o.default)(`${O}-footer`,S.footer,null==y?void 0:y.footer),style:Object.assign(Object.assign({},k.footer),null==b?void 0:b.footer)},m)))};p.PRESENTED_IMAGE_DEFAULT=d,p.PRESENTED_IMAGE_SIMPLE=f,e.s(["default",0,p],616303),e.s(["default",0,e=>{let{componentName:o}=e,{getPrefixCls:n}=(0,t.useContext)(r.ConfigContext),a=n("empty");switch(o){case"Table":case"List":return t.default.createElement(p,{image:p.PRESENTED_IMAGE_SIMPLE});case"Select":case"TreeSelect":case"Cascader":case"Transfer":case"Mentions":return t.default.createElement(p,{image:p.PRESENTED_IMAGE_SIMPLE,className:`${a}-small`});case"Table.filter":return null;default:return t.default.createElement(p,null)}}],721132)},85566,e=>{"use strict";e.s(["default",0,function(e,t){let r;return e||{bottomLeft:Object.assign(Object.assign({},r={overflow:{adjustX:!0,adjustY:!0,shiftY:!0},htmlRegion:"scroll"===t?"scroll":"visible",dynamicInset:!0}),{points:["tl","bl"],offset:[0,4]}),bottomRight:Object.assign(Object.assign({},r),{points:["tr","br"],offset:[0,4]}),topLeft:Object.assign(Object.assign({},r),{points:["bl","tl"],offset:[0,-4]}),topRight:Object.assign(Object.assign({},r),{points:["br","tr"],offset:[0,-4]})}}])},777489,e=>{"use strict";e.i(296059);var t=e.i(694758),r=e.i(402366);let o=new t.Keyframes("antMoveDownIn",{"0%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),n=new t.Keyframes("antMoveDownOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0}}),a=new t.Keyframes("antMoveLeftIn",{"0%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),i=new t.Keyframes("antMoveLeftOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),l=new t.Keyframes("antMoveRightIn",{"0%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),s=new t.Keyframes("antMoveRightOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),c={"move-up":{inKeyframes:new t.Keyframes("antMoveUpIn",{"0%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),outKeyframes:new t.Keyframes("antMoveUpOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0}})},"move-down":{inKeyframes:o,outKeyframes:n},"move-left":{inKeyframes:a,outKeyframes:i},"move-right":{inKeyframes:l,outKeyframes:s}};e.s(["initMoveMotion",0,(e,t)=>{let{antCls:o}=e,n=`${o}-${t}`,{inKeyframes:a,outKeyframes:i}=c[t];return[(0,r.initMotion)(n,a,i,e.motionDurationMid),{[` - ${n}-enter, - ${n}-appear - `]:{opacity:0,animationTimingFunction:e.motionEaseOutCirc},[`${n}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]}])},664142,e=>{"use strict";e.i(296059);var t=e.i(694758),r=e.i(402366);let o=new t.Keyframes("antSlideUpIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1}}),n=new t.Keyframes("antSlideUpOut",{"0%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0}}),a=new t.Keyframes("antSlideDownIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1}}),i=new t.Keyframes("antSlideDownOut",{"0%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0}}),l={"slide-up":{inKeyframes:o,outKeyframes:n},"slide-down":{inKeyframes:a,outKeyframes:i},"slide-left":{inKeyframes:new t.Keyframes("antSlideLeftIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1}}),outKeyframes:new t.Keyframes("antSlideLeftOut",{"0%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0}})},"slide-right":{inKeyframes:new t.Keyframes("antSlideRightIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1}}),outKeyframes:new t.Keyframes("antSlideRightOut",{"0%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0}})}};e.s(["initSlideMotion",0,(e,t)=>{let{antCls:o}=e,n=`${o}-${t}`,{inKeyframes:a,outKeyframes:i}=l[t];return[(0,r.initMotion)(n,a,i,e.motionDurationMid),{[` - ${n}-enter, - ${n}-appear - `]:{transform:"scale(0)",transformOrigin:"0% 0%",opacity:0,animationTimingFunction:e.motionEaseOutQuint,"&-prepare":{transform:"scale(1)"}},[`${n}-leave`]:{animationTimingFunction:e.motionEaseInQuint}}]},"slideDownIn",0,a,"slideDownOut",0,i,"slideUpIn",0,o,"slideUpOut",0,n])},950302,e=>{"use strict";var t=e.i(183293),r=e.i(372409),o=e.i(246422),n=e.i(838378),a=e.i(777489),i=e.i(664142);let l=e=>{let{optionHeight:t,optionFontSize:r,optionLineHeight:o,optionPadding:n}=e;return{position:"relative",display:"block",minHeight:t,padding:n,color:e.colorText,fontWeight:"normal",fontSize:r,lineHeight:o,boxSizing:"border-box"}};e.i(296059);var s=e.i(915654);function c(e,r){let{componentCls:o}=e,n=r?`${o}-${r}`:"",a={[`${o}-multiple${n}`]:{fontSize:e.fontSize,[`${o}-selector`]:{[`${o}-show-search&`]:{cursor:"text"}},[` - &${o}-show-arrow ${o}-selector, - &${o}-allow-clear ${o}-selector - `]:{paddingInlineEnd:e.calc(e.fontSizeIcon).add(e.controlPaddingHorizontal).equal()}}};return[((e,r)=>{let{componentCls:o,INTERNAL_FIXED_ITEM_MARGIN:n}=e,a=`${o}-selection-overflow`,i=e.multipleSelectItemHeight,l=(e=>{let{multipleSelectItemHeight:t,selectHeight:r,lineWidth:o}=e;return e.calc(r).sub(t).div(2).sub(o).equal()})(e),c=r?`${o}-${r}`:"",u=(e=>{let{multipleSelectItemHeight:t,paddingXXS:r,lineWidth:o,INTERNAL_FIXED_ITEM_MARGIN:n}=e,a=e.max(e.calc(r).sub(o).equal(),0),i=e.max(e.calc(a).sub(n).equal(),0);return{basePadding:a,containerPadding:i,itemHeight:(0,s.unit)(t),itemLineHeight:(0,s.unit)(e.calc(t).sub(e.calc(e.lineWidth).mul(2)).equal())}})(e);return{[`${o}-multiple${c}`]:Object.assign(Object.assign({},(e=>{let{componentCls:r,iconCls:o,borderRadiusSM:n,motionDurationSlow:a,paddingXS:i,multipleItemColorDisabled:l,multipleItemBorderColorDisabled:s,colorIcon:c,colorIconHover:u,INTERNAL_FIXED_ITEM_MARGIN:d}=e;return{[`${r}-selection-overflow`]:{position:"relative",display:"flex",flex:"auto",flexWrap:"wrap",maxWidth:"100%","&-item":{flex:"none",alignSelf:"center",maxWidth:"calc(100% - 4px)",display:"inline-flex"},[`${r}-selection-item`]:{display:"flex",alignSelf:"center",flex:"none",boxSizing:"border-box",maxWidth:"100%",marginBlock:d,borderRadius:n,cursor:"default",transition:`font-size ${a}, line-height ${a}, height ${a}`,marginInlineEnd:e.calc(d).mul(2).equal(),paddingInlineStart:i,paddingInlineEnd:e.calc(i).div(2).equal(),[`${r}-disabled&`]:{color:l,borderColor:s,cursor:"not-allowed"},"&-content":{display:"inline-block",marginInlineEnd:e.calc(i).div(2).equal(),overflow:"hidden",whiteSpace:"pre",textOverflow:"ellipsis"},"&-remove":Object.assign(Object.assign({},(0,t.resetIcon)()),{display:"inline-flex",alignItems:"center",color:c,fontWeight:"bold",fontSize:10,lineHeight:"inherit",cursor:"pointer",[`> ${o}`]:{verticalAlign:"-0.2em"},"&:hover":{color:u}})}}}})(e)),{[`${o}-selector`]:{display:"flex",alignItems:"center",width:"100%",height:"100%",paddingInline:u.basePadding,paddingBlock:u.containerPadding,borderRadius:e.borderRadius,[`${o}-disabled&`]:{background:e.multipleSelectorBgDisabled,cursor:"not-allowed"},"&:after":{display:"inline-block",width:0,margin:`${(0,s.unit)(n)} 0`,lineHeight:(0,s.unit)(i),visibility:"hidden",content:'"\\a0"'}},[`${o}-selection-item`]:{height:u.itemHeight,lineHeight:(0,s.unit)(u.itemLineHeight)},[`${o}-selection-wrap`]:{alignSelf:"flex-start","&:after":{lineHeight:(0,s.unit)(i),marginBlock:n}},[`${o}-prefix`]:{marginInlineStart:e.calc(e.inputPaddingHorizontalBase).sub(u.basePadding).equal()},[`${a}-item + ${a}-item, - ${o}-prefix + ${o}-selection-wrap - `]:{[`${o}-selection-search`]:{marginInlineStart:0},[`${o}-selection-placeholder`]:{insetInlineStart:0}},[`${a}-item-suffix`]:{minHeight:u.itemHeight,marginBlock:n},[`${o}-selection-search`]:{display:"inline-flex",position:"relative",maxWidth:"100%",marginInlineStart:e.calc(e.inputPaddingHorizontalBase).sub(l).equal(),[` - &-input, - &-mirror - `]:{height:i,fontFamily:e.fontFamily,lineHeight:(0,s.unit)(i),transition:`all ${e.motionDurationSlow}`},"&-input":{width:"100%",minWidth:4.1},"&-mirror":{position:"absolute",top:0,insetInlineStart:0,insetInlineEnd:"auto",zIndex:999,whiteSpace:"pre",visibility:"hidden"}},[`${o}-selection-placeholder`]:{position:"absolute",top:"50%",insetInlineStart:e.calc(e.inputPaddingHorizontalBase).sub(u.basePadding).equal(),insetInlineEnd:e.inputPaddingHorizontalBase,transform:"translateY(-50%)",transition:`all ${e.motionDurationSlow}`}})}})(e,r),a]}function u(e,r){let{componentCls:o,inputPaddingHorizontalBase:n,borderRadius:a}=e,i=e.calc(e.controlHeight).sub(e.calc(e.lineWidth).mul(2)).equal(),l=r?`${o}-${r}`:"";return{[`${o}-single${l}`]:{fontSize:e.fontSize,height:e.controlHeight,[`${o}-selector`]:Object.assign(Object.assign({},(0,t.resetComponent)(e,!0)),{display:"flex",borderRadius:a,flex:"1 1 auto",[`${o}-selection-wrap:after`]:{lineHeight:(0,s.unit)(i)},[`${o}-selection-search`]:{position:"absolute",inset:0,width:"100%","&-input":{width:"100%",WebkitAppearance:"textfield"}},[` - ${o}-selection-item, - ${o}-selection-placeholder - `]:{display:"block",padding:0,lineHeight:(0,s.unit)(i),transition:`all ${e.motionDurationSlow}, visibility 0s`,alignSelf:"center"},[`${o}-selection-placeholder`]:{transition:"none",pointerEvents:"none"},[`&:after,${o}-selection-item:empty:after,${o}-selection-placeholder:empty:after`]:{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'}}),[` - &${o}-show-arrow ${o}-selection-item, - &${o}-show-arrow ${o}-selection-search, - &${o}-show-arrow ${o}-selection-placeholder - `]:{paddingInlineEnd:e.showArrowPaddingInlineEnd},[`&${o}-open ${o}-selection-item`]:{color:e.colorTextPlaceholder},[`&:not(${o}-customize-input)`]:{[`${o}-selector`]:{width:"100%",height:"100%",alignItems:"center",padding:`0 ${(0,s.unit)(n)}`,[`${o}-selection-search-input`]:{height:i,fontSize:e.fontSize},"&:after":{lineHeight:(0,s.unit)(i)}}},[`&${o}-customize-input`]:{[`${o}-selector`]:{"&:after":{display:"none"},[`${o}-selection-search`]:{position:"static",width:"100%"},[`${o}-selection-placeholder`]:{position:"absolute",insetInlineStart:0,insetInlineEnd:0,padding:`0 ${(0,s.unit)(n)}`,"&:after":{display:"none"}}}}}}}let d=(e,t)=>{let{componentCls:r,antCls:o,controlOutlineWidth:n}=e;return{[`&:not(${r}-customize-input) ${r}-selector`]:{border:`${(0,s.unit)(e.lineWidth)} ${e.lineType} ${t.borderColor}`,background:e.selectorBg},[`&:not(${r}-disabled):not(${r}-customize-input):not(${o}-pagination-size-changer)`]:{[`&:hover ${r}-selector`]:{borderColor:t.hoverBorderHover},[`${r}-focused& ${r}-selector`]:{borderColor:t.activeBorderColor,boxShadow:`0 0 0 ${(0,s.unit)(n)} ${t.activeOutlineColor}`,outline:0},[`${r}-prefix`]:{color:t.color}}}},f=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},d(e,t))}),p=(e,t)=>{let{componentCls:r,antCls:o}=e;return{[`&:not(${r}-customize-input) ${r}-selector`]:{background:t.bg,border:`${(0,s.unit)(e.lineWidth)} ${e.lineType} transparent`,color:t.color},[`&:not(${r}-disabled):not(${r}-customize-input):not(${o}-pagination-size-changer)`]:{[`&:hover ${r}-selector`]:{background:t.hoverBg},[`${r}-focused& ${r}-selector`]:{background:e.selectorBg,borderColor:t.activeBorderColor,outline:0}}}},h=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},p(e,t))}),m=(e,t)=>{let{componentCls:r,antCls:o}=e;return{[`&:not(${r}-customize-input) ${r}-selector`]:{borderWidth:`${(0,s.unit)(e.lineWidth)} 0`,borderStyle:`${e.lineType} none`,borderColor:`transparent transparent ${t.borderColor} transparent`,background:e.selectorBg,borderRadius:0},[`&:not(${r}-disabled):not(${r}-customize-input):not(${o}-pagination-size-changer)`]:{[`&:hover ${r}-selector`]:{borderColor:`transparent transparent ${t.hoverBorderHover} transparent`},[`${r}-focused& ${r}-selector`]:{borderColor:`transparent transparent ${t.activeBorderColor} transparent`,outline:0},[`${r}-prefix`]:{color:t.color}}}},g=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},m(e,t))}),v=(0,o.genStyleHooks)("Select",(e,{rootPrefixCls:o})=>{let v=(0,n.mergeToken)(e,{rootPrefixCls:o,inputPaddingHorizontalBase:e.calc(e.paddingSM).sub(1).equal(),multipleSelectItemHeight:e.multipleItemHeight,selectHeight:e.controlHeight});return[(e=>{let{componentCls:o}=e;return[{[o]:{[`&${o}-in-form-item`]:{width:"100%"}}},(e=>{let{antCls:r,componentCls:o,inputPaddingHorizontalBase:n,iconCls:a}=e,i={[`${o}-clear`]:{opacity:1,background:e.colorBgBase,borderRadius:"50%"}};return{[o]:Object.assign(Object.assign({},(0,t.resetComponent)(e)),{position:"relative",display:"inline-flex",cursor:"pointer",[`&:not(${o}-customize-input) ${o}-selector`]:Object.assign(Object.assign({},(e=>{let{componentCls:t}=e;return{position:"relative",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,input:{cursor:"pointer"},[`${t}-show-search&`]:{cursor:"text",input:{cursor:"auto",color:"inherit",height:"100%"}},[`${t}-disabled&`]:{cursor:"not-allowed",input:{cursor:"not-allowed"}}}})(e)),(e=>{let{componentCls:t}=e;return{[`${t}-selection-search-input`]:{margin:0,padding:0,background:"transparent",border:"none",outline:"none",appearance:"none",fontFamily:"inherit","&::-webkit-search-cancel-button":{display:"none",appearance:"none"}}}})(e)),[`${o}-selection-item`]:Object.assign(Object.assign({flex:1,fontWeight:"normal",position:"relative",userSelect:"none"},t.textEllipsis),{[`> ${r}-typography`]:{display:"inline"}}),[`${o}-selection-placeholder`]:Object.assign(Object.assign({},t.textEllipsis),{flex:1,color:e.colorTextPlaceholder,pointerEvents:"none"}),[`${o}-arrow`]:Object.assign(Object.assign({},(0,t.resetIcon)()),{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:n,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,lineHeight:1,textAlign:"center",pointerEvents:"none",display:"flex",alignItems:"center",transition:`opacity ${e.motionDurationSlow} ease`,[a]:{verticalAlign:"top",transition:`transform ${e.motionDurationSlow}`,"> svg":{verticalAlign:"top"},[`&:not(${o}-suffix)`]:{pointerEvents:"auto"}},[`${o}-disabled &`]:{cursor:"not-allowed"},"> *:not(:last-child)":{marginInlineEnd:8}}),[`${o}-selection-wrap`]:{display:"flex",width:"100%",position:"relative",minWidth:0,"&:after":{content:'"\\a0"',width:0,overflow:"hidden"}},[`${o}-prefix`]:{flex:"none",marginInlineEnd:e.selectAffixPadding},[`${o}-clear`]:{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:n,zIndex:1,display:"inline-block",width:e.fontSizeIcon,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,fontStyle:"normal",lineHeight:1,textAlign:"center",textTransform:"none",cursor:"pointer",opacity:0,transition:`color ${e.motionDurationMid} ease, opacity ${e.motionDurationSlow} ease`,textRendering:"auto",transform:"translateZ(0)","&:before":{display:"block"},"&:hover":{color:e.colorIcon}},"@media(hover:none)":i,"&:hover":i}),[`${o}-status`]:{"&-error, &-warning, &-success, &-validating":{[`&${o}-has-feedback`]:{[`${o}-clear`]:{insetInlineEnd:e.calc(n).add(e.fontSize).add(e.paddingXS).equal()}}}}}})(e),function(e){let{componentCls:t}=e,r=e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal();return[u(e),u((0,n.mergeToken)(e,{controlHeight:e.controlHeightSM,borderRadius:e.borderRadiusSM}),"sm"),{[`${t}-single${t}-sm`]:{[`&:not(${t}-customize-input)`]:{[`${t}-selector`]:{padding:`0 ${(0,s.unit)(r)}`},[`&${t}-show-arrow ${t}-selection-search`]:{insetInlineEnd:e.calc(r).add(e.calc(e.fontSize).mul(1.5)).equal()},[` - &${t}-show-arrow ${t}-selection-item, - &${t}-show-arrow ${t}-selection-placeholder - `]:{paddingInlineEnd:e.calc(e.fontSize).mul(1.5).equal()}}}},u((0,n.mergeToken)(e,{controlHeight:e.singleItemHeightLG,fontSize:e.fontSizeLG,borderRadius:e.borderRadiusLG}),"lg")]}(e),(e=>{let{componentCls:t}=e,r=(0,n.mergeToken)(e,{selectHeight:e.controlHeightSM,multipleSelectItemHeight:e.multipleItemHeightSM,borderRadius:e.borderRadiusSM,borderRadiusSM:e.borderRadiusXS}),o=(0,n.mergeToken)(e,{fontSize:e.fontSizeLG,selectHeight:e.controlHeightLG,multipleSelectItemHeight:e.multipleItemHeightLG,borderRadius:e.borderRadiusLG,borderRadiusSM:e.borderRadius});return[c(e),c(r,"sm"),{[`${t}-multiple${t}-sm`]:{[`${t}-selection-placeholder`]:{insetInline:e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal()},[`${t}-selection-search`]:{marginInlineStart:2}}},c(o,"lg")]})(e),(e=>{let{antCls:r,componentCls:o}=e,n=`${o}-item`,s=`&${r}-slide-up-enter${r}-slide-up-enter-active`,c=`&${r}-slide-up-appear${r}-slide-up-appear-active`,u=`&${r}-slide-up-leave${r}-slide-up-leave-active`,d=`${o}-dropdown-placement-`,f=`${n}-option-selected`;return[{[`${o}-dropdown`]:Object.assign(Object.assign({},(0,t.resetComponent)(e)),{position:"absolute",top:-9999,zIndex:e.zIndexPopup,boxSizing:"border-box",padding:e.paddingXXS,overflow:"hidden",fontSize:e.fontSize,fontVariant:"initial",backgroundColor:e.colorBgElevated,borderRadius:e.borderRadiusLG,outline:"none",boxShadow:e.boxShadowSecondary,[` - ${s}${d}bottomLeft, - ${c}${d}bottomLeft - `]:{animationName:i.slideUpIn},[` - ${s}${d}topLeft, - ${c}${d}topLeft, - ${s}${d}topRight, - ${c}${d}topRight - `]:{animationName:i.slideDownIn},[`${u}${d}bottomLeft`]:{animationName:i.slideUpOut},[` - ${u}${d}topLeft, - ${u}${d}topRight - `]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[n]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},t.textEllipsis),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${n}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${n}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${n}-option-state`]:{color:e.colorPrimary}},"&-disabled":{[`&${n}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},l(e)),{color:e.colorTextDisabled})}),[`${f}:has(+ ${f})`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${f}`]:{borderStartStartRadius:0,borderStartEndRadius:0}},"&-rtl":{direction:"rtl"}})},(0,i.initSlideMotion)(e,"slide-up"),(0,i.initSlideMotion)(e,"slide-down"),(0,a.initMoveMotion)(e,"move-up"),(0,a.initMoveMotion)(e,"move-down")]})(e),{[`${o}-rtl`]:{direction:"rtl"}},(0,r.genCompactItemStyle)(e,{borderElCls:`${o}-selector`,focusElCls:`${o}-focused`})]})(v),{[v.componentCls]:Object.assign(Object.assign(Object.assign(Object.assign({},{"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},d(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),f(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),f(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})}),{"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},p(v,{bg:v.colorFillTertiary,hoverBg:v.colorFillSecondary,activeBorderColor:v.activeBorderColor,color:v.colorText})),h(v,{status:"error",bg:v.colorErrorBg,hoverBg:v.colorErrorBgHover,activeBorderColor:v.colorError,color:v.colorError})),h(v,{status:"warning",bg:v.colorWarningBg,hoverBg:v.colorWarningBgHover,activeBorderColor:v.colorWarning,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{borderColor:v.colorBorder,background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.colorBgContainer,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.colorSplit}`}})}),{"&-borderless":{[`${v.componentCls}-selector`]:{background:"transparent",border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} transparent`},[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`},[`&${v.componentCls}-status-error`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorError}},[`&${v.componentCls}-status-warning`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorWarning}}}}),{"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign({},m(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),g(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),g(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})})}]},e=>{let{fontSize:t,lineHeight:r,lineWidth:o,controlHeight:n,controlHeightSM:a,controlHeightLG:i,paddingXXS:l,controlPaddingHorizontal:s,zIndexPopupBase:c,colorText:u,fontWeightStrong:d,controlItemBgActive:f,controlItemBgHover:p,colorBgContainer:h,colorFillSecondary:m,colorBgContainerDisabled:g,colorTextDisabled:v,colorPrimaryHover:y,colorPrimary:b,controlOutline:w}=e,$=2*l,C=2*o,x=Math.min(n-$,n-C),E=Math.min(a-$,a-C),S=Math.min(i-$,i-C);return{INTERNAL_FIXED_ITEM_MARGIN:Math.floor(l/2),zIndexPopup:c+50,optionSelectedColor:u,optionSelectedFontWeight:d,optionSelectedBg:f,optionActiveBg:p,optionPadding:`${(n-t*r)/2}px ${s}px`,optionFontSize:t,optionLineHeight:r,optionHeight:n,selectorBg:h,clearBg:h,singleItemHeightLG:i,multipleItemBg:m,multipleItemBorderColor:"transparent",multipleItemHeight:x,multipleItemHeightSM:E,multipleItemHeightLG:S,multipleSelectorBgDisabled:g,multipleItemColorDisabled:v,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(1.25*e.fontSize),hoverBorderColor:y,activeBorderColor:b,activeOutlineColor:w,selectAffixPadding:l}},{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});e.s(["default",0,v],950302)},729151,e=>{"use strict";var t=e.i(271645),r=e.i(121229),o=e.i(726289),n=e.i(864517),a=e.i(247153),i=e.i(739295),l=e.i(38953);function s({suffixIcon:e,clearIcon:s,menuItemSelectedIcon:c,removeIcon:u,loading:d,multiple:f,hasFeedback:p,prefixCls:h,showSuffixIcon:m,feedbackIcon:g,showArrow:v,componentName:y}){let b=null!=s?s:t.createElement(o.default,null),w=r=>null!==e||p||v?t.createElement(t.Fragment,null,!1!==m&&r,p&&g):null,$=null;if(void 0!==e)$=w(e);else if(d)$=w(t.createElement(i.default,{spin:!0}));else{let e=`${h}-suffix`;$=({open:r,showSearch:o})=>r&&o?w(t.createElement(l.default,{className:e})):w(t.createElement(a.default,{className:e}))}let C=null;C=void 0!==c?c:f?t.createElement(r.default,null):null;return{clearIcon:b,suffixIcon:$,itemIcon:C,removeIcon:void 0!==u?u:t.createElement(n.default,null)}}e.s(["default",()=>s])},327494,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),o=e.i(123829),n=e.i(955492),a=e.i(869301),i=e.i(529681),l=e.i(122767),s=e.i(613541),c=e.i(805484),u=e.i(52956),d=e.i(242064),f=e.i(721132),p=e.i(937328),h=e.i(321883),m=e.i(517455),g=e.i(62139),v=e.i(792812),y=e.i(249616),b=e.i(104458),w=e.i(85566),$=e.i(950302),C=e.i(729151),x=e.i(617206),E=function(e,t){var r={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>t.indexOf(o)&&(r[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var n=0,o=Object.getOwnPropertySymbols(e);nt.indexOf(o[n])&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(r[o[n]]=e[o[n]]);return r};let S="SECRET_COMBOBOX_MODE_DO_NOT_USE",k=t.forwardRef((e,n)=>{var a,c,k,j,O,T,I,_;let F,{prefixCls:P,bordered:R,className:N,rootClassName:M,getPopupContainer:B,popupClassName:A,dropdownClassName:z,listHeight:L=256,placement:D,listItemHeight:H,size:V,disabled:W,notFoundContent:U,status:G,builtinPlacements:q,dropdownMatchSelectWidth:J,popupMatchSelectWidth:K,direction:X,style:Y,allowClear:Q,variant:Z,dropdownStyle:ee,transitionName:et,tagRender:er,maxCount:eo,prefix:en,dropdownRender:ea,popupRender:ei,onDropdownVisibleChange:el,onOpenChange:es,styles:ec,classNames:eu}=e,ed=E(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount","prefix","dropdownRender","popupRender","onDropdownVisibleChange","onOpenChange","styles","classNames"]),{getPopupContainer:ef,getPrefixCls:ep,renderEmpty:eh,direction:em,virtual:eg,popupMatchSelectWidth:ev,popupOverflow:ey}=t.useContext(d.ConfigContext),{showSearch:eb,style:ew,styles:e$,className:eC,classNames:ex}=(0,d.useComponentConfig)("select"),[,eE]=(0,b.useToken)(),eS=null!=H?H:null==eE?void 0:eE.controlHeight,ek=ep("select",P),ej=ep(),eO=null!=X?X:em,{compactSize:eT,compactItemClassnames:eI}=(0,y.useCompactItemContext)(ek,eO),[e_,eF]=(0,v.default)("select",Z,R),eP=(0,h.default)(ek),[eR,eN,eM]=(0,$.default)(ek,eP),eB=t.useMemo(()=>{let{mode:t}=e;if("combobox"!==t)return t===S?"combobox":t},[e.mode]),eA="multiple"===eB||"tags"===eB,ez=(T=e.suffixIcon,void 0!==(I=e.showArrow)?I:null!==T),eL=null!=(a=null!=K?K:J)?a:ev,eD=(null==(c=null==ec?void 0:ec.popup)?void 0:c.root)||(null==(k=e$.popup)?void 0:k.root)||ee,eH=(_=ei||ea,t.default.useMemo(()=>{if(_)return(...e)=>t.default.createElement(x.default,{space:!0},_.apply(void 0,e))},[_])),{status:eV,hasFeedback:eW,isFormItemInput:eU,feedbackIcon:eG}=t.useContext(g.FormItemInputContext),eq=(0,u.getMergedStatus)(eV,G);F=void 0!==U?U:"combobox"===eB?null:(null==eh?void 0:eh("Select"))||t.createElement(f.default,{componentName:"Select"});let{suffixIcon:eJ,itemIcon:eK,removeIcon:eX,clearIcon:eY}=(0,C.default)(Object.assign(Object.assign({},ed),{multiple:eA,hasFeedback:eW,feedbackIcon:eG,showSuffixIcon:ez,prefixCls:ek,componentName:"Select"})),eQ=(0,i.default)(ed,["suffixIcon","itemIcon"]),eZ=(0,r.default)((null==(j=null==eu?void 0:eu.popup)?void 0:j.root)||(null==(O=null==ex?void 0:ex.popup)?void 0:O.root)||A||z,{[`${ek}-dropdown-${eO}`]:"rtl"===eO},M,ex.root,null==eu?void 0:eu.root,eM,eP,eN),e0=(0,m.default)(e=>{var t;return null!=(t=null!=V?V:eT)?t:e}),e1=t.useContext(p.default),e2=(0,r.default)({[`${ek}-lg`]:"large"===e0,[`${ek}-sm`]:"small"===e0,[`${ek}-rtl`]:"rtl"===eO,[`${ek}-${e_}`]:eF,[`${ek}-in-form-item`]:eU},(0,u.getStatusClassNames)(ek,eq,eW),eI,eC,N,ex.root,null==eu?void 0:eu.root,M,eM,eP,eN),e4=t.useMemo(()=>void 0!==D?D:"rtl"===eO?"bottomRight":"bottomLeft",[D,eO]),[e6]=(0,l.useZIndex)("SelectLike",null==eD?void 0:eD.zIndex);return eR(t.createElement(o.default,Object.assign({ref:n,virtual:eg,showSearch:eb},eQ,{style:Object.assign(Object.assign(Object.assign(Object.assign({},e$.root),null==ec?void 0:ec.root),ew),Y),dropdownMatchSelectWidth:eL,transitionName:(0,s.getTransitionName)(ej,"slide-up",et),builtinPlacements:(0,w.default)(q,ey),listHeight:L,listItemHeight:eS,mode:eB,prefixCls:ek,placement:e4,direction:eO,prefix:en,suffixIcon:eJ,menuItemSelectedIcon:eK,removeIcon:eX,allowClear:!0===Q?{clearIcon:eY}:Q,notFoundContent:F,className:e2,getPopupContainer:B||ef,dropdownClassName:eZ,disabled:null!=W?W:e1,dropdownStyle:Object.assign(Object.assign({},eD),{zIndex:e6}),maxCount:eA?eo:void 0,tagRender:eA?er:void 0,dropdownRender:eH,onDropdownVisibleChange:es||el})))}),j=(0,c.default)(k,"dropdownAlign");k.SECRET_COMBOBOX_MODE_DO_NOT_USE=S,k.Option=a.Option,k.OptGroup=n.OptGroup,k._InternalPanelDoNotUseOrYouWillBeFired=j,e.s(["default",0,k],327494)},199133,e=>{"use strict";var t=e.i(327494);e.s(["Select",()=>t.default])},689074,21243,98801,e=>{"use strict";var t=e.i(290571),r=e.i(271645);let o=e=>{var o=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},o),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM11 15V17H13V15H11ZM11 7V13H13V7H11Z"}))};e.s(["default",()=>o],689074);let n=e=>{var o=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},o),r.default.createElement("path",{d:"M1.18164 12C2.12215 6.87976 6.60812 3 12.0003 3C17.3924 3 21.8784 6.87976 22.8189 12C21.8784 17.1202 17.3924 21 12.0003 21C6.60812 21 2.12215 17.1202 1.18164 12ZM12.0003 17C14.7617 17 17.0003 14.7614 17.0003 12C17.0003 9.23858 14.7617 7 12.0003 7C9.23884 7 7.00026 9.23858 7.00026 12C7.00026 14.7614 9.23884 17 12.0003 17ZM12.0003 15C10.3434 15 9.00026 13.6569 9.00026 12C9.00026 10.3431 10.3434 9 12.0003 9C13.6571 9 15.0003 10.3431 15.0003 12C15.0003 13.6569 13.6571 15 12.0003 15Z"}))};e.s(["default",()=>n],21243);let a=e=>{var o=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},o),r.default.createElement("path",{d:"M4.52047 5.93457L1.39366 2.80777L2.80788 1.39355L22.6069 21.1925L21.1927 22.6068L17.8827 19.2968C16.1814 20.3755 14.1638 21.0002 12.0003 21.0002C6.60812 21.0002 2.12215 17.1204 1.18164 12.0002C1.61832 9.62282 2.81932 7.5129 4.52047 5.93457ZM14.7577 16.1718L13.2937 14.7078C12.902 14.8952 12.4634 15.0002 12.0003 15.0002C10.3434 15.0002 9.00026 13.657 9.00026 12.0002C9.00026 11.537 9.10522 11.0984 9.29263 10.7067L7.82866 9.24277C7.30514 10.0332 7.00026 10.9811 7.00026 12.0002C7.00026 14.7616 9.23884 17.0002 12.0003 17.0002C13.0193 17.0002 13.9672 16.6953 14.7577 16.1718ZM7.97446 3.76015C9.22127 3.26959 10.5793 3.00016 12.0003 3.00016C17.3924 3.00016 21.8784 6.87992 22.8189 12.0002C22.5067 13.6998 21.8038 15.2628 20.8068 16.5925L16.947 12.7327C16.9821 12.4936 17.0003 12.249 17.0003 12.0002C17.0003 9.23873 14.7617 7.00016 12.0003 7.00016C11.7514 7.00016 11.5068 7.01833 11.2677 7.05343L7.97446 3.76015Z"}))};e.s(["default",()=>a],98801)},103471,e=>{"use strict";var t=e.i(444755),r=e.i(271645);let o=e=>["string","number"].includes(typeof e)?e:e instanceof Array?e.map(o).join(""):"object"==typeof e&&e?o(e.props.children):void 0;function n(e){let t=new Map;return r.default.Children.map(e,e=>{var r;t.set(e.props.value,null!=(r=o(e))?r:e.props.value)}),t}function a(e,t){return r.default.Children.map(t,t=>{var r;if((null!=(r=o(t))?r:t.props.value).toLowerCase().includes(e.toLowerCase()))return t})}let i=(e,r,o=!1)=>(0,t.tremorTwMerge)(r?"bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle":"bg-tremor-background dark:bg-dark-tremor-background",!r&&"hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted",e?"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis":"text-tremor-content dark:text-dark-tremor-content",r&&"text-tremor-content-subtle dark:text-dark-tremor-content-subtle",o&&"text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500",o?"border-red-500 dark:border-red-500":"border-tremor-border dark:border-dark-tremor-border");function l(e){return null!=e&&""!==e}e.s(["constructValueToNameMapping",()=>n,"getFilteredOptions",()=>a,"getNodeText",()=>o,"getSelectButtonColors",()=>i,"hasValue",()=>l])},779241,677955,e=>{"use strict";var t=e.i(290571),r=e.i(271645),o=e.i(673706),n=e.i(689074),a=e.i(21243),i=e.i(98801),l=e.i(103471),s=e.i(444755);let c=r.default.forwardRef((e,c)=>{let{value:u,defaultValue:d,type:f,placeholder:p="Type...",icon:h,error:m=!1,errorMessage:g,disabled:v=!1,stepper:y,makeInputClassName:b,className:w,onChange:$,onValueChange:C,autoFocus:x,pattern:E}=e,S=(0,t.__rest)(e,["value","defaultValue","type","placeholder","icon","error","errorMessage","disabled","stepper","makeInputClassName","className","onChange","onValueChange","autoFocus","pattern"]),[k,j]=(0,r.useState)(x||!1),[O,T]=(0,r.useState)(!1),I=(0,r.useCallback)(()=>T(!O),[O,T]),_=(0,r.useRef)(null),F=(0,l.hasValue)(u||d);return r.default.useEffect(()=>{let e=()=>j(!0),t=()=>j(!1),r=_.current;return r&&(r.addEventListener("focus",e),r.addEventListener("blur",t),x&&r.focus()),()=>{r&&(r.removeEventListener("focus",e),r.removeEventListener("blur",t))}},[x]),r.default.createElement(r.default.Fragment,null,r.default.createElement("div",{className:(0,s.tremorTwMerge)(b("root"),"relative w-full flex items-center min-w-[10rem] outline-none rounded-tremor-default transition duration-100 border","shadow-tremor-input","dark:shadow-dark-tremor-input",(0,l.getSelectButtonColors)(F,v,m),k&&(0,s.tremorTwMerge)("ring-2","border-tremor-brand-subtle ring-tremor-brand-muted","dark:border-dark-tremor-brand-subtle dark:ring-dark-tremor-brand-muted"),w)},h?r.default.createElement(h,{className:(0,s.tremorTwMerge)(b("icon"),"shrink-0 h-5 w-5 mx-2.5 absolute left-0 flex items-center","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}):null,r.default.createElement("input",Object.assign({ref:(0,o.mergeRefs)([_,c]),defaultValue:d,value:u,type:O?"text":f,className:(0,s.tremorTwMerge)(b("input"),"w-full bg-transparent focus:outline-none focus:ring-0 border-none text-tremor-default rounded-tremor-default transition duration-100 py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis","[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none","password"===f?m?"pr-16":"pr-12":m?"pr-8":"pr-3",h?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content"),placeholder:p,disabled:v,"data-testid":"base-input",onChange:e=>{null==$||$(e),null==C||C(e.target.value)},pattern:E},S)),"password"!==f||v?null:r.default.createElement("button",{className:(0,s.tremorTwMerge)(b("toggleButton"),"absolute inset-y-0 right-0 flex items-center px-2.5 rounded-lg"),type:"button",onClick:()=>I(),"aria-label":O?"Hide password":"Show Password"},O?r.default.createElement(i.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0}):r.default.createElement(a.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0})),m?r.default.createElement(n.default,{className:(0,s.tremorTwMerge)(b("errorIcon"),"text-red-500 shrink-0 h-5 w-5 absolute right-0 flex items-center","password"===f?"mr-10":"number"===f?y?"mr-20":"mr-3":"mx-2.5")}):null,null!=y?y:null),m&&g?r.default.createElement("p",{className:(0,s.tremorTwMerge)(b("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});c.displayName="BaseInput",e.s(["default",()=>c],677955);let u=(0,o.makeClassName)("TextInput"),d=r.default.forwardRef((e,o)=>{let{type:n="text"}=e,a=(0,t.__rest)(e,["type"]);return r.default.createElement(c,Object.assign({ref:o,type:n,makeInputClassName:u},a))});d.displayName="TextInput",e.s(["TextInput",()=>d],779241)},764205,122550,82946,e=>{"use strict";e.s(["addAllowedIP",()=>eL,"adminGlobalActivity",()=>e0,"adminGlobalActivityPerModel",()=>e2,"adminGlobalCacheActivity",()=>e1,"adminSpendLogsCall",()=>eX,"adminTopEndUsersCall",()=>eQ,"adminTopKeysCall",()=>eY,"adminTopModelsCall",()=>e4,"adminspendByProvider",()=>eZ,"agentDailyActivityCall",()=>ek,"agentHubPublicModelsCall",()=>eN,"alertingSettingsCall",()=>ee,"allEndUsersCall",()=>eq,"allTagNamesCall",()=>eG,"applyGuardrail",()=>oh,"approveGuardrailSubmission",()=>tW,"approveMCPServer",()=>rN,"availableTeamListCall",()=>ep,"budgetCreateCall",()=>Y,"budgetDeleteCall",()=>X,"budgetUpdateCall",()=>Q,"buildMcpOAuthAuthorizeUrl",()=>oj,"cacheTemporaryMcpServer",()=>oS,"cachingHealthCheckCall",()=>tN,"callMCPTool",()=>rW,"cancelModelCostMapReload",()=>U,"checkEuAiActCompliance",()=>oq,"checkGdprCompliance",()=>oJ,"claimOnboardingToken",()=>eO,"convertPromptFileToJson",()=>rh,"createAgentCall",()=>rm,"createGuardrailCall",()=>rg,"createMCPServer",()=>rk,"createMCPToolset",()=>rI,"createMemory",()=>o5,"createPassThroughEndpoint",()=>tT,"createPolicyAttachmentCall",()=>rr,"createPolicyCall",()=>t6,"createPolicyVersion",()=>t5,"createPromptCall",()=>rd,"createSearchTool",()=>rA,"credentialCreateCall",()=>tr,"credentialDeleteCall",()=>ta,"credentialGetCall",()=>tn,"credentialListCall",()=>to,"credentialUpdateCall",()=>ti,"customerDailyActivityCall",()=>eS,"deleteAgentCall",()=>ot,"deleteAllowedIP",()=>eD,"deleteCallback",()=>ox,"deleteClaudeCodePlugin",()=>oG,"deleteConfigFieldSetting",()=>t_,"deleteGuardrailCall",()=>on,"deleteMCPOAuthUserCredential",()=>o2,"deleteMCPServer",()=>rO,"deleteMCPToolset",()=>rF,"deleteMemory",()=>o8,"deletePassThroughEndpointsCall",()=>tF,"deletePolicyAttachmentCall",()=>ro,"deletePolicyCall",()=>t8,"deletePromptCall",()=>rp,"deleteSearchTool",()=>rL,"deleteToolPolicyOverride",()=>o0,"deriveErrorMessage",()=>oB,"disableClaudeCodePlugin",()=>oU,"enableClaudeCodePlugin",()=>oW,"enrichPolicyTemplate",()=>tZ,"enrichPolicyTemplateStream",()=>t2,"estimateAttachmentImpactCall",()=>rl,"exchangeLoginCode",()=>oz,"exchangeMcpOAuthToken",()=>oO,"fetchAvailableSearchProviders",()=>rD,"fetchDiscoverableMCPServers",()=>r$,"fetchMCPAccessGroups",()=>rE,"fetchMCPClientIp",()=>rS,"fetchMCPServerHealth",()=>rx,"fetchMCPServers",()=>rC,"fetchMCPSubmissions",()=>rR,"fetchMCPToolsets",()=>rT,"fetchMemoryList",()=>o7,"fetchOpenAPIRegistry",()=>rw,"fetchSearchTools",()=>rB,"fetchToolDetail",()=>oQ,"fetchToolPolicyOptions",()=>oK,"fetchToolsList",()=>oX,"formatDate",()=>b,"getAgentCreateMetadata",()=>R,"getAgentInfo",()=>ou,"getAgentsList",()=>oc,"getAllowedIPs",()=>ez,"getBudgetList",()=>tw,"getCacheSettingsCall",()=>tE,"getCallbackConfigsCall",()=>w,"getCallbacksCall",()=>t$,"getCategoryYaml",()=>ol,"getClaudeCodePluginsList",()=>oH,"getConfigFieldSetting",()=>tO,"getDefaultTeamSettings",()=>rY,"getEmailEventSettings",()=>r9,"getGeneralSettingsCall",()=>tC,"getGlobalLitellmHeaderName",()=>B,"getGuardrailInfo",()=>od,"getGuardrailProviderSpecificParams",()=>oi,"getGuardrailUISettings",()=>oa,"getGuardrailsList",()=>tH,"getGuardrailsUsageDetail",()=>tq,"getGuardrailsUsageLogs",()=>tJ,"getGuardrailsUsageOverview",()=>tG,"getInProductNudgesCall",()=>$,"getInternalUserSettings",()=>ry,"getLicenseInfo",()=>o$,"getMCPOAuthUserCredentialStatus",()=>o4,"getMCPSemanticFilterSettings",()=>tz,"getMajorAirlines",()=>os,"getModelCostMapReloadStatus",()=>q,"getModelCostMapSource",()=>G,"getOnboardingCredentials",()=>ej,"getOpenAPISchema",()=>D,"getPassThroughEndpointsCall",()=>tj,"getPoliciesList",()=>tK,"getPolicyAttachmentsList",()=>rt,"getPolicyInfo",()=>re,"getPolicyInfoWithGuardrails",()=>tY,"getPolicyTemplates",()=>tQ,"getPossibleUserRoles",()=>te,"getPromptInfo",()=>rc,"getPromptVersions",()=>ru,"getPromptsList",()=>rs,"getProviderCreateMetadata",()=>P,"getProxyBaseUrl",()=>j,"getProxyUISettings",()=>tB,"getPublicModelHubInfo",()=>L,"getRemainingUsers",()=>ow,"getResolvedGuardrails",()=>ra,"getRouterSettingsCall",()=>tx,"getSSOSettings",()=>ov,"getTeamPermissionsCall",()=>rZ,"getToolUsageLogs",()=>oY,"getUISettings",()=>tA,"getUiConfig",()=>z,"getUiSettings",()=>oL,"handleError",()=>F,"individualModelHealthCheckCall",()=>tR,"invitationCreateCall",()=>Z,"keyAliasesCall",()=>e9,"keyCreateCall",()=>er,"keyCreateForAgentCall",()=>eo,"keyCreateServiceAccountCall",()=>et,"keyDeleteCall",()=>ea,"keyInfoCall",()=>e6,"keyInfoV1Call",()=>e7,"keyListCall",()=>e5,"keyUpdateCall",()=>tl,"latestHealthChecksCall",()=>tM,"listGuardrailSubmissions",()=>tV,"listMCPTools",()=>rV,"listMCPUserCredentials",()=>o6,"listPolicyVersions",()=>t7,"loginCall",()=>oA,"makeAgentsPublicCall",()=>or,"makeMCPPublicCall",()=>oo,"makeModelGroupPublic",()=>A,"mcpHubPublicServersCall",()=>eM,"modelAvailableCall",()=>eV,"modelCostMap",()=>H,"modelCreateCall",()=>J,"modelDeleteCall",()=>K,"modelHubCall",()=>eA,"modelHubPublicModelsCall",()=>eR,"modelInfoCall",()=>eF,"modelInfoV1Call",()=>eP,"modelPatchUpdateCall",()=>tc,"organizationCreateCall",()=>eg,"organizationDailyActivityCall",()=>eE,"organizationDeleteCall",()=>ey,"organizationInfoCall",()=>em,"organizationListCall",()=>eh,"organizationMemberAddCall",()=>th,"organizationMemberDeleteCall",()=>tm,"organizationMemberUpdateCall",()=>tg,"organizationUpdateCall",()=>ev,"patchAgentCall",()=>of,"perUserAnalyticsCall",()=>oM,"proxyBaseUrl",()=>k,"ragIngestCall",()=>r5,"regenerateKeyCall",()=>eT,"registerClaudeCodePlugin",()=>oV,"registerMCPServer",()=>rP,"registerMcpOAuthClient",()=>ok,"rejectGuardrailSubmission",()=>tU,"rejectMCPServer",()=>rM,"reloadModelCostMap",()=>V,"resetEmailEventSettings",()=>oe,"resolvePoliciesCall",()=>ri,"scheduleModelCostMapReload",()=>W,"searchToolQueryCall",()=>oI,"serverRootPath",()=>x,"serviceHealthCheck",()=>tb,"sessionSpendLogsCall",()=>r1,"setCallbacksCall",()=>tP,"setGlobalLitellmHeaderName",()=>M,"skillHubPublicCall",()=>eB,"storeMCPOAuthUserCredential",()=>o1,"suggestPolicyTemplates",()=>t0,"switchToWorkerUrl",()=>O,"tagCreateCall",()=>rU,"tagDailyActivityCall",()=>eC,"tagDauCall",()=>o_,"tagDeleteCall",()=>rX,"tagDistinctCall",()=>oR,"tagInfoCall",()=>rq,"tagListCall",()=>rK,"tagMauCall",()=>oP,"tagUpdateCall",()=>rG,"tagWauCall",()=>oF,"tagsSpendLogsCall",()=>eU,"teamBulkMemberAddCall",()=>td,"teamCreateCall",()=>tt,"teamDailyActivityCall",()=>ex,"teamDeleteCall",()=>el,"teamInfoCall",()=>eu,"teamListCall",()=>ef,"teamMemberAddCall",()=>tu,"teamMemberDeleteCall",()=>tp,"teamMemberUpdateCall",()=>tf,"teamPermissionsUpdateCall",()=>r0,"teamSpendLogsCall",()=>eW,"teamUpdateCall",()=>ts,"testCacheConnectionCall",()=>tS,"testConnectionRequest",()=>e3,"testCustomCodeGuardrail",()=>om,"testMCPSemanticFilter",()=>tD,"testMCPToolsListRequest",()=>oE,"testPipelineCall",()=>rn,"testPoliciesAndGuardrails",()=>tX,"testPolicyTemplate",()=>t1,"testSearchToolConnection",()=>rH,"transformRequestCall",()=>eb,"uiAuditLogsCall",()=>ob,"uiSpendLogDetailsCall",()=>rv,"uiSpendLogsCall",()=>eK,"updateCacheSettingsCall",()=>tk,"updateConfigFieldSetting",()=>tI,"updateDefaultTeamSettings",()=>rQ,"updateEmailEventSettings",()=>r8,"updateGuardrailCall",()=>op,"updateInternalUserSettings",()=>rb,"updateMCPSemanticFilterSettings",()=>tL,"updateMCPServer",()=>rj,"updateMCPToolset",()=>r_,"updateMemory",()=>o9,"updatePassThroughEndpoint",()=>oC,"updatePolicyCall",()=>t3,"updatePolicyVersionStatus",()=>t9,"updatePromptCall",()=>rf,"updateSSOSettings",()=>oy,"updateSearchTool",()=>rz,"updateToolPolicy",()=>oZ,"updateUiSettings",()=>oD,"updateUsefulLinksCall",()=>eH,"usageAiChatStream",()=>t4,"userAgentSummaryCall",()=>oN,"userBulkUpdateUserCall",()=>ty,"userCreateCall",()=>en,"userDailyActivityAggregatedCall",()=>e8,"userDailyActivityCall",()=>e$,"userDeleteCall",()=>ei,"userFilterUICall",()=>eJ,"userGetInfoV2",()=>ec,"userListCall",()=>es,"userUpdateUserCall",()=>tv,"v2TeamListCall",()=>ed,"validateBlockedWordsFile",()=>og,"vectorStoreCreateCall",()=>r2,"vectorStoreDeleteCall",()=>r6,"vectorStoreInfoCall",()=>r3,"vectorStoreListCall",()=>r4,"vectorStoreSearchCall",()=>oT,"vectorStoreUpdateCall",()=>r7],764205);var t=e.i(247167),r=e.i(888259),o=e.i(268004);e.s(["default",()=>v,"jsonFields",()=>m],82946);var n=e.i(843476),a=e.i(271645),i=e.i(808613),l=e.i(311451),s=e.i(28651),c=e.i(199133),u=e.i(779241),d=e.i(827252),f=e.i(592968);let p=e=>e?e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()):e;function h(e,t){return e.length>t?e.substring(0,t)+"...":e}e.s(["formItemValidateJSON",0,(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject("Please enter valid JSON")}},"formatLabel",0,p,"truncateString",()=>h],122550);let m=["metadata","config","enforced_params","aliases"],g=(e,t)=>m.includes(e)||"json"===t.format,v=({schemaComponent:e,excludedFields:t=[],form:r,overrideLabels:o={},overrideTooltips:h={},customValidation:m={},defaultValues:v={}})=>{let[y,b]=(0,a.useState)(null),[w,$]=(0,a.useState)(null);return((0,a.useEffect)(()=>{(async()=>{try{let o=(await D()).components.schemas[e];if(!o)throw Error(`Schema component "${e}" not found`);b(o);let n={};Object.keys(o.properties).filter(e=>!t.includes(e)&&void 0!==v[e]).forEach(e=>{n[e]=v[e]}),r.setFieldsValue(n)}catch(e){console.error("Schema fetch error:",e),$(e instanceof Error?e.message:"Failed to fetch schema")}})()},[e,r,t]),w)?(0,n.jsxs)("div",{className:"text-red-500",children:["Error: ",w]}):y?.properties?(0,n.jsx)("div",{children:Object.entries(y.properties).filter(([e])=>!t.includes(e)).map(([e,t])=>{let r,a,b,w,$,C,x,E;return a=(e=>{if(e.type)return e.type;if(e.anyOf){let t=e.anyOf.map(e=>e.type);if(t.includes("number")||t.includes("integer"))return"number";t.includes("string")}return"string"})(t),b=y?.required?.includes(e),w=o[e]||t.title||p(e),$=h[e]||t.description,C=[],b&&C.push({required:!0,message:`${w} is required`}),m[e]&&C.push({validator:m[e]}),g(e,t)&&C.push({validator:async(e,t)=>{if(t&&!(e=>{if(!e)return!0;try{return JSON.parse(e),!0}catch{return!1}})(t))throw Error("Please enter valid JSON")}}),x=$?(0,n.jsxs)("span",{children:[w," ",(0,n.jsx)(f.Tooltip,{title:$,children:(0,n.jsx)(d.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}):w,r=g(e,t)?(0,n.jsx)(l.Input.TextArea,{rows:4,placeholder:"Enter as JSON",className:"font-mono"}):t.enum?(0,n.jsx)(c.Select,{children:t.enum.map(e=>(0,n.jsx)(c.Select.Option,{value:e,children:e},e))}):"number"===a||"integer"===a?(0,n.jsx)(s.InputNumber,{style:{width:"100%"},precision:"integer"===a?0:void 0}):"duration"===e?(0,n.jsx)(u.TextInput,{placeholder:"eg: 30s, 30h, 30d"}):(0,n.jsx)(u.TextInput,{placeholder:$||""}),(0,n.jsx)(i.Form.Item,{label:x,name:e,className:"mt-8",rules:C,initialValue:v[e],help:(0,n.jsx)("div",{className:"text-xs text-gray-500",children:(E=({max_budget:"Enter maximum budget in USD (e.g., 100.50)",budget_duration:"Select a time period for budget reset",tpm_limit:"Enter maximum tokens per minute (whole number)",rpm_limit:"Enter maximum requests per minute (whole number)",duration:"Enter duration (e.g., 30s, 24h, 7d)",metadata:'Enter JSON object with key-value pairs\nExample: {"team": "research", "project": "nlp"}',config:'Enter configuration as JSON object\nExample: {"setting": "value"}',permissions:"Enter comma-separated permission strings",enforced_params:'Enter parameters as JSON object\nExample: {"param": "value"}',blocked:"Enter true/false or specific block conditions",aliases:'Enter aliases as JSON object\nExample: {"alias1": "value1", "alias2": "value2"}',models:"Select one or more model names",key_alias:"Enter a unique identifier for this key",tags:"Enter comma-separated tag strings"})[e]||({string:"Text input",number:"Numeric input",integer:"Whole number input",boolean:"True/False value"})[a]||"Text input",g(e,t)?`${E} -Must be valid JSON format`:t.enum?`Select from available options -Allowed values: ${t.enum.join(", ")}`:E)}),children:r},e)})}):null};var y=e.i(727749);let b=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),o=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${o}`},w=async e=>{try{let t=k?`${k}/callbacks/configs`:"/callbacks/configs",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},$=async e=>{try{let t=k?`${k}/in_product_nudges`:"/in_product_nudges",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get in-product nudges:",e),e}},C=t.default.env.NEXT_PUBLIC_BASE_URL?t.default.env.NEXT_PUBLIC_BASE_URL:null,x="/",E="litellm_worker_url",S=window.localStorage.getItem(E),k=(()=>{if(!S)return null;try{let e=new URL(S);if("http:"===e.protocol||"https:"===e.protocol)return S}catch{}return window.localStorage.removeItem(E),null})()??C;console.log=function(){};let j=()=>{if(k)return k;let e=window.location;return e?.origin??""};function O(e){(!e||function(e){try{let t=new URL(e);return"http:"===t.protocol||"https:"===t.protocol}catch{return!1}}(e))&&(e?window.localStorage.setItem(E,e):window.localStorage.removeItem(E),k=e??C)}let T="POST",I="DELETE",_=0,F=async e=>{let t=Date.now();if(t-_>6e4){if(("string"==typeof e?e:JSON.stringify(e)).includes("Authentication Error - Expired Key")){y.default.info("UI Session Expired. Logging out."),_=t,(0,o.clearTokenCookies)();let e=window.location;e&&(window.location.href=e.pathname)}_=t}else console.log("Error suppressed to prevent spam:",e)},P=async()=>{let e=k?`${k}/public/providers/fields`:"/public/providers/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch provider create metadata:",t.status,e),Error("Failed to load provider configuration")}return await t.json()},R=async()=>{let e=k?`${k}/public/agents/fields`:"/public/agents/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch agent create metadata:",t.status,e),Error("Failed to load agent configuration")}return await t.json()},N="Authorization";function M(e="Authorization"){console.log(`setGlobalLitellmHeaderName: ${e}`),N=e}function B(){return N}let A=async(e,t)=>{let r=k?`${k}/model_group/make_public`:"/model_group/make_public";return(await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model_groups:t})})).json()},z=async()=>{console.log("Getting UI config");let e=C?`${C}/litellm/.well-known/litellm-ui-config`:"/litellm/.well-known/litellm-ui-config",r=await fetch(e),o=await r.json();return console.log("jsonData in getUiConfig:",o),((e,r=null)=>{if(window.localStorage.getItem(E))return;let o=window.location,n=t.default.env.NEXT_PUBLIC_BASE_URL?t.default.env.NEXT_PUBLIC_BASE_URL:o?.origin??null,a=r||n;if(console.log("proxyBaseUrl:",k),console.log("serverRootPath:",e),!a)return console.log("Updated proxyBaseUrl:",k=k??null);e.length>0&&!a.endsWith(e)&&"/"!=e&&(a+=e),console.log("Updated proxyBaseUrl:",k=a)})(o.server_root_path,o.proxy_base_url),o},L=async()=>{let e=k?`${k}/public/model_hub/info`:"/public/model_hub/info",t=await fetch(e);return await t.json()},D=async()=>{let e=k?`${k}/openapi.json`:"/openapi.json",t=await fetch(e);return await t.json()},H=async()=>{try{let e=k?`${k}/public/litellm_model_cost_map`:"/public/litellm_model_cost_map",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}}),r=await t.json();return console.log(`received litellm model cost data: ${r}`),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},V=async e=>{try{let t=k?`${k}/reload/model_cost_map`:"/reload/model_cost_map",r=await fetch(t,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await r.json();return console.log(`Model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to reload model cost map:",e),e}},W=async(e,t)=>{try{let r=k?`${k}/schedule/model_cost_map_reload?hours=${t}`:`/schedule/model_cost_map_reload?hours=${t}`,o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await o.json();return console.log(`Schedule model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to schedule model cost map reload:",e),e}},U=async e=>{try{let t=k?`${k}/schedule/model_cost_map_reload`:"/schedule/model_cost_map_reload",r=await fetch(t,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await r.json();return console.log(`Cancel model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to cancel model cost map reload:",e),e}},G=async e=>{try{let t=k?`${k}/model/cost_map/source`:"/model/cost_map/source",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw Error(`HTTP ${r.status}: ${e}`)}let o=await r.json();return console.log("Model cost map source info:",o),o}catch(e){throw console.error("Failed to get model cost map source info:",e),e}},q=async e=>{try{let t=k?`${k}/schedule/model_cost_map_reload/status`:"/schedule/model_cost_map_reload/status";console.log("Fetching status from URL:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){console.error(`Status request failed with status: ${r.status}`);let e=await r.text();throw console.error("Error response:",e),Error(`HTTP ${r.status}: ${e}`)}let o=await r.json();return console.log("Model cost map reload status:",o),o}catch(e){throw console.error("Failed to get model cost map reload status:",e),e}},J=async(e,t)=>{try{let o=k?`${k}/model/new`:"/model/new",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("API Response:",a),r.default.destroy(),y.default.success(`Model ${t.model_name} created successfully`),a}catch(e){throw console.error("Failed to create key:",e),e}},K=async(e,t)=>{console.log(`model_id in model delete call: ${t}`);try{let r=k?`${k}/model/delete`:"/model/delete",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},X=async(e,t)=>{if(console.log(`budget_id in budget delete call: ${t}`),null!=e)try{let r=k?`${k}/budget/delete`:"/budget/delete",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},Y=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let r=k?`${k}/budget/new`:"/budget/new",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let r=k?`${k}/budget/update`:"/budget/update",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},Z=async(e,t)=>{try{let r=k?`${k}/invitation/new`:"/invitation/new",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},ee=async e=>{try{let t=k?`${k}/alerting/settings`:"/alerting/settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},et=async(e,t)=>{try{for(let e of(console.log("Form Values in keyCreateServiceAccountCall:",t),t.description&&(t.metadata||(t.metadata={}),t.metadata.description=t.description,delete t.description,t.metadata=JSON.stringify(t.metadata)),m))if(t[e]){console.log(`formValues.${e}:`,t[e]);try{t[e]=JSON.parse(t[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",t);let r=k?`${k}/key/service-account/generate`:"/key/service-account/generate",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw F(e),console.error("Error response from the server:",e),Error(e)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},er=async(e,t,r)=>{try{for(let e of(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),m))if(r[e]){console.log(`formValues.${e}:`,r[e]);try{r[e]=JSON.parse(r[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",r);let o=k?`${k}/key/generate`:"/key/generate",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!n.ok){let e=await n.text();throw F(e),console.error("Error response from the server:",e),Error(e)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},eo=async(e,t,r,o,n,a)=>{let i=k?`${k}/key/generate`:"/key/generate",l={agent_id:t,key_alias:r,models:o.length>0?o:[]};a&&(l.team_id=a),n&&Object.keys(n).length>0&&(l.metadata=n);let s=await fetch(i,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!s.ok)throw F(await s.text()),Error("Failed to create key for agent");return s.json()},en=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),r.auto_create_key=!1,r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",r);let o=k?`${k}/user/new`:"/user/new",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!n.ok){let e=await n.text();throw F(e),console.error("Error response from the server:",e),Error(e)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ea=async(e,t)=>{try{let r=k?`${k}/key/delete`:"/key/delete";console.log("in keyDeleteCall:",t);let o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t)=>{try{let r=k?`${k}/user/delete`:"/user/delete";console.log("in userDeleteCall:",t);let o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log(n),n}catch(e){throw console.error("Failed to delete user(s):",e),e}},el=async(e,t)=>{try{let r=k?`${k}/team/delete`:"/team/delete";console.log("in teamDeleteCall:",t);let o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log(n),n}catch(e){throw console.error("Failed to delete key:",e),e}},es=async(e,t=null,r=null,o=null,n=null,a=null,i=null,l=null,s=null,c=null,u=null)=>{try{let d=k?`${k}/user/list`:"/user/list";console.log("in userListCall");let f=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");f.append("user_ids",e)}r&&f.append("page",r.toString()),o&&f.append("page_size",o.toString()),n&&f.append("user_email",n),a&&f.append("role",a),i&&f.append("team",i),l&&f.append("sso_user_ids",l),s&&f.append("sort_by",s),c&&f.append("sort_order",c),u&&u.length>0&&f.append("organization_ids",u.join(","));let p=f.toString();p&&(d+=`?${p}`);let h=await fetch(d,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!h.ok){let e=await h.json(),t=oB(e);throw F(t),Error(t)}let m=await h.json();return console.log("/user/list API Response:",m),m}catch(e){throw console.error("Failed to create key:",e),e}},ec=async(e,t)=>{try{let r=k?`${k}/v2/user/info`:"/v2/user/info";t&&(r+=`?user_id=${encodeURIComponent(t)}`);let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch user info v2:",e),e}},eu=async(e,t)=>{try{let r=k?`${k}/team/info`:"/team/info";t&&(r=`${r}?team_id=${encodeURIComponent(t)}`),console.log("in teamInfoCall");let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t,r=null,o=null,n=null,a=1,i=10,l=null,s=null)=>{try{let a=k?`${k}/v2/team/list`:"/v2/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),o&&i.append("team_id",o.toString()),n&&i.append("team_alias",n.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=oB(e);throw F(t),Error(t)}let c=await s.json();return console.log("/v2/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ef=async(e,t,r=null,o=null,n=null)=>{try{let a=k?`${k}/team/list`:"/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),o&&i.append("team_id",o.toString()),n&&i.append("team_alias",n.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=oB(e);throw F(t),Error(t)}let c=await s.json();return console.log("/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ep=async e=>{try{let t=k?`${k}/team/available`:"/team/available";console.log("in availableTeamListCall");let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("/team/available_teams API Response:",o),o}catch(e){throw e}},eh=async(e,t=null,r=null)=>{try{let o=k?`${k}/organization/list`:"/organization/list",n=new URLSearchParams;t&&n.append("org_id",t.toString()),r&&n.append("org_alias",r.toString());let a=n.toString();a&&(o+=`?${a}`);let i=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=oB(e);throw F(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},em=async(e,t)=>{try{let r=k?`${k}/organization/info`:"/organization/info";t&&(r=`${r}?organization_id=${t}`),console.log("in teamInfoCall");let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eg=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let r=k?`${k}/organization/new`:"/organization/new",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},ev=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let r=k?`${k}/organization/update`:"/organization/update",o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Update Team Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},ey=async(e,t)=>{try{let r=k?`${k}/organization/delete`:"/organization/delete",o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!o.ok){let e=await o.text();throw F(e),Error(`Error deleting organization: ${e}`)}return await o.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},eb=async(e,t)=>{try{let r=k?`${k}/utils/transform_request`:"/utils/transform_request",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},ew=async({accessToken:e,endpoint:t,startTime:r,endTime:o,page:n=1,extraQueryParams:a})=>{try{let i,l,s,c,u=(i=t.startsWith("/")?t:`/${t}`,l=k?`${k}${i}`:i,(s=new URLSearchParams).append("start_date",b(r)),s.append("end_date",b(o)),s.append("page_size","1000"),s.append("page",n.toString()),s.append("timezone",new Date().getTimezoneOffset().toString()),a&&Object.entries(a).forEach(([e,t])=>{((e,t,r)=>{if(null!=r){if(Array.isArray(r)){r.length>0&&e.append(t,r.join(","));return}e.append(t,`${r}`)}})(s,e,t)}),(c=s.toString())?`${l}?${c}`:l),d=await fetch(u,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!d.ok){let e=await d.json(),t=oB(e);throw F(t),Error(t)}return await d.json()}catch(e){throw console.error(`Failed to fetch daily activity (${t}):`,e),e}},e$=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/user/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{user_id:n}}),eC=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/tag/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{tags:n}}),ex=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/team/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{team_ids:n,exclude_team_ids:"litellm-dashboard"}}),eE=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/organization/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{organization_ids:n}}),eS=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/customer/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{end_user_ids:n}}),ek=async(e,t,r,o=1,n=null)=>ew({accessToken:e,endpoint:"/agent/daily/activity",startTime:t,endTime:r,page:o,extraQueryParams:{agent_ids:n}}),ej=async e=>{try{let t=k?`${k}/onboarding/get_token`:"/onboarding/get_token";t+=`?invite_link=${e}`;let r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},eO=async(e,t,r,o)=>{let n=k?`${k}/onboarding/claim_token`:"/onboarding/claim_token";try{let a=await fetch(n,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:r,password:o})});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to delete key:",e),e}},eT=async(e,t,r)=>{try{let o=k?`${k}/key/${t}/regenerate`:`/key/${t}/regenerate`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("Regenerate key Response:",a),a}catch(e){throw console.error("Failed to regenerate key:",e),e}},eI=!1,e_=null,eF=async(e,t,r,o=1,n=50,a,i,l,s,c)=>{try{console.log("modelInfoCall:",e,t,r,o,n,a,i,l,s,c);let u=k?`${k}/v2/model/info`:"/v2/model/info",d=new URLSearchParams;d.append("include_team_models","true"),d.append("page",o.toString()),d.append("size",n.toString()),a&&a.trim()&&d.append("search",a.trim()),i&&i.trim()&&d.append("modelId",i.trim()),l&&l.trim()&&d.append("teamId",l.trim()),s&&s.trim()&&d.append("sortBy",s.trim()),c&&c.trim()&&d.append("sortOrder",c.trim()),d.toString()&&(u+=`?${d.toString()}`);let f=await fetch(u,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw e+=`error shown=${eI}`,eI||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),y.default.info(e),eI=!0,e_&&clearTimeout(e_),e_=setTimeout(()=>{eI=!1},1e4)),Error("Network response was not ok")}let p=await f.json();return console.log("modelInfoCall:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},eP=async(e,t)=>{try{let r=k?`${k}/v1/model/info`:"/v1/model/info";r+=`?litellm_model_id=${t}`;let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("modelInfoV1Call:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eR=async()=>{let e=k?`${k}/public/model_hub`:"/public/model_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`modelHubPublicModelsCall failed with status ${t.status}`),[])},eN=async()=>{let e=k?`${k}/public/agent_hub`:"/public/agent_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`agentHubPublicModelsCall failed with status ${t.status}`),[])},eM=async()=>{let e=k?`${k}/public/mcp_hub`:"/public/mcp_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`mcpHubPublicServersCall failed with status ${t.status}`),[])},eB=async()=>{let e=k?`${k}/public/skill_hub`:"/public/skill_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`skillHubPublicCall failed with status ${t.status}`),{plugins:[]})},eA=async e=>{try{let t=k?`${k}/model_group/info`:"/model_group/info",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("modelHubCall:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ez=async e=>{try{let t=k?`${k}/get/allowed_ips`:"/get/allowed_ips",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("getAllowedIPs:",o),o.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},eL=async(e,t)=>{try{let r=k?`${k}/add/allowed_ip`:"/add/allowed_ip",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("addAllowedIP:",n),n}catch(e){throw console.error("Failed to add allowed IP:",e),e}},eD=async(e,t)=>{try{let r=k?`${k}/delete/allowed_ip`:"/delete/allowed_ip",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("deleteAllowedIP:",n),n}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},eH=async(e,t)=>{try{let r=k?`${k}/model_hub/update_useful_links`:"/model_hub/update_useful_links",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({useful_links:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},eV=async(e,t,r,o=!1,n=null,a=!1,i=!1,l)=>{console.log("in /models calls, globalLitellmHeaderName",N);try{let t=k?`${k}/models`:"/models",r=new URLSearchParams;r.append("include_model_access_groups","True"),!0===o&&r.append("return_wildcard_routes","True"),!0===i&&r.append("only_model_access_groups","True"),n&&r.append("team_id",n.toString()),l&&r.append("scope",l),r.toString()&&(t+=`?${r.toString()}`);let a=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},eW=async e=>{try{let t=k?`${k}/global/spend/teams`:"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let r=await fetch(`${t}`,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eU=async(e,t,r,o)=>{try{let n=k?`${k}/global/spend/tags`:"/global/spend/tags";t&&r&&(n=`${n}?start_date=${t}&end_date=${r}`),o&&(n+=`&tags=${o.join(",")}`),console.log("in tagsSpendLogsCall:",n);let a=await fetch(`${n}`,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to create key:",e),e}},eG=async e=>{try{let t=k?`${k}/global/spend/all_tag_names`:"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let r=await fetch(`${t}`,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eq=async e=>{try{let t=k?`${k}/customer/list`:"/customer/list";console.log("in customer/list",t);let r=await fetch(`${t}`,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to fetch end users:",e),e}},eJ=async(e,t)=>{try{let r=k?`${k}/user/filter/ui`:"/user/filter/ui",o=new URLSearchParams;t.get("user_email")&&o.append("user_email",t.get("user_email")),t.get("user_id")&&o.append("user_id",t.get("user_id")),t.get("team_id")&&o.append("team_id",t.get("team_id"));let n=o.toString(),a=n?`${r}?${n}`:r,i=await fetch(a,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=oB(e);throw F(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eK=async({accessToken:e,start_date:t,end_date:r,page:o=1,page_size:n=50,params:a={}})=>{try{let i=k?`${k}/spend/logs/ui`:"/spend/logs/ui",l=new URLSearchParams;for(let[e,i]of(l.append("start_date",t),l.append("end_date",r),l.append("page",o.toString()),l.append("page_size",n.toString()),Object.entries(a)))null!=i&&("min_spend"===e||"max_spend"===e?l.append(e,i.toString()):"string"==typeof i&&""!==i&&l.append(e,String(i)));let s=l.toString();s&&(i+=`?${s}`);let c=await fetch(i,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!c.ok){let e=await c.json(),t=oB(e);throw F(t),Error(t)}let u=await c.json();return console.log("Spend Logs Response:",u),u}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},eX=async e=>{try{let t=k?`${k}/global/spend/logs`:"/global/spend/logs",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eY=async e=>{try{let t=k?`${k}/global/spend/keys?limit=5`:"/global/spend/keys?limit=5",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eQ=async(e,t,r,o)=>{try{let n=k?`${k}/global/spend/end_users`:"/global/spend/end_users",a="";a=t?JSON.stringify({api_key:t,startTime:r,endTime:o}):JSON.stringify({startTime:r,endTime:o});let i={method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:a},l=await fetch(n,i);if(!l.ok){let e=await l.json(),t=oB(e);throw F(t),Error(t)}let s=await l.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eZ=async(e,t,r,o)=>{try{let n=k?`${k}/global/spend/provider`:"/global/spend/provider";r&&o&&(n+=`?start_date=${r}&end_date=${o}`),t&&(n+=`&api_key=${t}`);let a={method:"GET",headers:{[N]:`Bearer ${e}`}},i=await fetch(n,a);if(!i.ok){let e=await i.json(),t=oB(e);throw F(t),Error(t)}let l=await i.json();return console.log(l),l}catch(e){throw console.error("Failed to fetch spend data:",e),e}},e0=async(e,t,r)=>{try{let o=k?`${k}/global/activity`:"/global/activity";t&&r&&(o+=`?start_date=${t}&end_date=${r}`);let n={method:"GET",headers:{[N]:`Bearer ${e}`}},a=await fetch(o,n);if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},e1=async(e,t,r)=>{try{let o=k?`${k}/global/activity/cache_hits`:"/global/activity/cache_hits";t&&r&&(o+=`?start_date=${t}&end_date=${r}`);let n={method:"GET",headers:{[N]:`Bearer ${e}`}},a=await fetch(o,n);if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},e2=async(e,t,r)=>{try{let o=k?`${k}/global/activity/model`:"/global/activity/model";t&&r&&(o+=`?start_date=${t}&end_date=${r}`);let n={method:"GET",headers:{[N]:`Bearer ${e}`}},a=await fetch(o,n);if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},e4=async e=>{try{let t=k?`${k}/global/spend/models?limit=5`:"/global/spend/models?limit=5",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},e6=async(e,t)=>{try{let r=k?`${k}/v2/key/info`:"/v2/key/info",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!o.ok){let e=await o.text();if(e.includes("Invalid proxy server token passed"))throw Error("Invalid proxy server token passed");throw F(e),Error("Network response was not ok")}let n=await o.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},e3=async(e,t,r,o)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let n=k?`${k}/health/test_connection`:"/health/test_connection",a=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({litellm_params:t,model_info:r,mode:o})}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||"error"===l.status)&&"error"!==l.status)return{status:"error",message:l.error?.message||`Connection test failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("Model connection test error:",e),e}},e7=async(e,t)=>{try{console.log("entering keyInfoV1Call");let r=k?`${k}/key/info`:"/key/info";r=`${r}?key=${t}`;let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(console.log("response",o),!o.ok){let e=await o.text();F(e),y.default.fromBackend("Failed to fetch key info - "+e)}let n=await o.json();return console.log("data",n),n}catch(e){throw console.error("Failed to fetch key info:",e),e}},e5=async(e,t,r,o,n,a,i,l,s=null,c=null,u=null,d=null)=>{try{let f=k?`${k}/key/list`:"/key/list";console.log("in keyListCall");let p=new URLSearchParams;r&&p.append("team_id",r.toString()),t&&p.append("organization_id",t.toString()),o&&p.append("key_alias",o),a&&p.append("key_hash",a),n&&p.append("user_id",n.toString()),i&&p.append("page",i.toString()),l&&p.append("size",l.toString()),s&&p.append("sort_by",s),c&&p.append("sort_order",c),u&&p.append("expand",u),d&&p.append("status",d),p.append("return_full_object","true"),p.append("include_team_keys","true"),p.append("include_created_by_keys","true");let h=p.toString();h&&(f+=`?${h}`);let m=await fetch(f,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!m.ok){let e=await m.json(),t=oB(e);throw F(t),Error(t)}let g=await m.json();return console.log("/team/list API Response:",g),g}catch(e){throw console.error("Failed to create key:",e),e}},e9=async(e,t=1,r=50,o,n)=>{try{let a=new URLSearchParams(Object.entries({page:String(t),size:String(r),...o?{search:o}:{},...n?{team_id:n}:{}})),i=k?`${k}/key/aliases`:"/key/aliases";i=`${i}?${a}`;let l=await fetch(i,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=oB(e);throw F(t),Error(t)}let s=await l.json();return console.log("/key/aliases API Response:",s),s}catch(e){throw console.error("Failed to fetch key aliases:",e),e}},e8=async(e,t,r,o=null)=>{try{let n=k?`${k}/user/daily/activity/aggregated`:"/user/daily/activity/aggregated",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),o=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${o}`};a.append("start_date",i(t)),a.append("end_date",i(r)),a.append("timezone",new Date().getTimezoneOffset().toString()),o&&a.append("user_id",o);let l=a.toString();l&&(n+=`?${l}`);let s=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=oB(e);throw F(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch aggregated user daily activity:",e),e}},te=async e=>{try{let t=k?`${k}/user/available_roles`:"/user/available_roles",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("response from user/available_role",o),o}catch(e){throw e}},tt=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=k?`${k}/team/new`:"/team/new",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},tr=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=k?`${k}/credentials`:"/credentials",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},to=async e=>{try{let t=k?`${k}/credentials`:"/credentials";console.log("in credentialListCall");let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("/credentials API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},tn=async(e,t,r)=>{try{let o=k?`${k}/credentials`:"/credentials";t?o+=`/by_name/${t}`:r&&(o+=`/by_model/${r}`),console.log("in credentialListCall");let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ta=async(e,t)=>{try{let r=k?`${k}/credentials/${t}`:`/credentials/${t}`;console.log("in credentialDeleteCall:",t);let o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log(n),n}catch(e){throw console.error("Failed to delete key:",e),e}},ti=async(e,t,r)=>{try{if(console.log("Form Values in credentialUpdateCall:",r),r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let o=k?`${k}/credentials/${t}`:`/credentials/${t}`,n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},tl=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let r=k?`${k}/key/update`:"/key/update",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw F(e),console.error("Error response from the server:",e),Error(e)}let n=await o.json();return console.log("Update key Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},ts=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let r=k?`${k}/team/update`:"/team/update",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw F(e),console.error("Error response from the server:",e),y.default.fromBackend("Failed to update team settings: "+e),Error(e)}let n=await o.json();return console.log("Update Team Response:",n),n}catch(e){throw console.error("Failed to update team:",e),e}},tc=async(e,t,r)=>{try{console.log("Form Values in modelUpateCall:",t);let o=k?`${k}/model/${r}/update`:`/model/${r}/update`,n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw F(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await n.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},tu=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let o=k?`${k}/team/member_add`:"/team/member_add",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:r})});if(!n.ok){let e=await n.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",o=Error(r);throw o.raw=t,o}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},td=async(e,t,r,o,n)=>{try{console.log("Bulk add team members:",{teamId:t,members:r,maxBudgetInTeam:o});let a=k?`${k}/team/bulk_member_add`:"/team/bulk_member_add",i={team_id:t};n?i.all_users=!0:i.members=r,null!=o&&(i.max_budget_in_team=o);let l=await fetch(a,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to bulk add team members",o=Error(r);throw o.raw=t,o}let s=await l.json();return console.log("Bulk team member add API Response:",s),s}catch(e){throw console.error("Failed to bulk add team members:",e),e}},tf=async(e,t,r)=>{try{console.log("Form Values in teamMemberUpdateCall:",r),console.log("Budget value:",r.max_budget_in_team),console.log("TPM limit:",r.tpm_limit),console.log("RPM limit:",r.rpm_limit);let o=k?`${k}/team/member_update`:"/team/member_update",n={team_id:t,role:r.role,user_id:r.user_id};void 0!==r.user_email&&(n.user_email=r.user_email),void 0!==r.max_budget_in_team&&null!==r.max_budget_in_team&&(n.max_budget_in_team=r.max_budget_in_team),void 0!==r.tpm_limit&&null!==r.tpm_limit&&(n.tpm_limit=r.tpm_limit),void 0!==r.rpm_limit&&null!==r.rpm_limit&&(n.rpm_limit=r.rpm_limit),void 0!==r.allowed_models&&(n.allowed_models=r.allowed_models),console.log("Final request body:",n);let a=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok){let e=await a.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",o=Error(r);throw o.raw=t,o}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to update team member:",e),e}},tp=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let o=k?`${k}/team/member_delete`:"/team/member_delete",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==r.user_email&&{user_email:r.user_email},...void 0!==r.user_id&&{user_id:r.user_id}})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},th=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let o=k?`${k}/organization/member_add`:"/organization/member_add",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:r})});if(!n.ok){let e=await n.text();throw F(e),console.error("Error response from the server:",e),Error(e)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create organization member:",e),e}},tm=async(e,t,r)=>{try{console.log("Form Values in organizationMemberDeleteCall:",r);let o=k?`${k}/organization/member_delete`:"/organization/member_delete",n=await fetch(o,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to delete organization member:",e),e}},tg=async(e,t,r)=>{try{console.log("Form Values in organizationMemberUpdateCall:",r);let o=k?`${k}/organization/member_update`:"/organization/member_update",n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to update organization member:",e),e}},tv=async(e,t,r)=>{try{console.log("Form Values in userUpdateUserCall:",t);let o=k?`${k}/user/update`:"/user/update",n={...t};null!==r&&(n.user_role=r),n=JSON.stringify(n);let a=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:n});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},ty=async(e,t,r,o=!1)=>{try{let n;console.log("Form Values in userUpdateUserCall:",t);let a=k?`${k}/user/bulk_update`:"/user/bulk_update";if(o)n=JSON.stringify({all_users:!0,user_updates:t});else if(r&&r.length>0){let e=[];for(let o of r)e.push({user_id:o,...t});n=JSON.stringify({users:e})}else throw Error("Must provide either userIds or set allUsers=true");let i=await fetch(a,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:n});if(!i.ok){let e=await i.json(),t=oB(e);throw F(t),Error(t)}let l=await i.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},tb=async(e,t)=>{try{let r=k?`${k}/health/services?service=${t}`:`/health/services?service=${t}`;console.log("Checking Slack Budget Alerts service health");let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw F(e),Error(e)}return await o.json()}catch(e){throw console.error("Failed to perform health check:",e),e}},tw=async e=>{try{let t=k?`${k}/budget/list`:"/budget/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},t$=async(e,t,r)=>{try{let t=k?`${k}/get/config/callbacks`:"/get/config/callbacks",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tC=async e=>{try{let t=k?`${k}/config/list?config_type=general_settings`:"/config/list?config_type=general_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tx=async e=>{try{let t=k?`${k}/router/settings`:"/router/settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get router settings:",e),e}},tE=async e=>{try{let t=k?`${k}/cache/settings`:"/cache/settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get cache settings:",e),e}},tS=async(e,t)=>{try{let r=k?`${k}/cache/settings/test`:"/cache/settings/test",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test cache connection:",e),e}},tk=async(e,t)=>{try{let r=k?`${k}/cache/settings`:"/cache/settings",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update cache settings:",e),e}},tj=async(e,t)=>{try{let r=k?`${k}/config/pass_through_endpoint`:"/config/pass_through_endpoint";t&&(r+=`/team/${t}`);let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tO=async(e,t)=>{try{let r=k?`${k}/config/field/info?field_name=${t}`:`/config/field/info?field_name=${t}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tT=async(e,t)=>{try{let r=k?`${k}/config/pass_through_endpoint`:"/config/pass_through_endpoint",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tI=async(e,t,r)=>{try{let o=k?`${k}/config/field/update`:"/config/field/update",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:r,config_type:"general_settings"})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return y.default.success("Successfully updated value!"),a}catch(e){throw console.error("Failed to set callbacks:",e),e}},t_=async(e,t)=>{try{let r=k?`${k}/config/field/delete`:"/config/field/delete",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return y.default.success("Field reset on proxy"),n}catch(e){throw console.error("Failed to get callbacks:",e),e}},tF=async(e,t)=>{try{let r=k?`${k}/config/pass_through_endpoint?endpoint_id=${t}`:`/config/pass_through_endpoint?endpoint_id=${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tP=async(e,t)=>{try{let r=k?`${k}/config/update`:"/config/update",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tR=async(e,t)=>{try{let r=k?`${k}/health?model_id=${encodeURIComponent(t)}`:`/health?model_id=${encodeURIComponent(t)}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to call /health for model id ${t}:`,e),e}},tN=async e=>{try{let t=k?`${k}/cache/ping`:"/cache/ping",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},tM=async e=>{try{let t=k?`${k}/health/latest`:"/health/latest",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /health/latest:",e),e}},tB=async e=>{try{console.log("Getting proxy UI settings"),console.log("proxyBaseUrl in getProxyUISettings:",k);let t=k?`${k}/sso/get/ui_settings`:"/sso/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tA=async e=>{try{let t=k?`${k}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);return console.error("Failed to get UI settings:",t),null}return await r.json()}catch(e){return console.error("Failed to get UI settings:",e),null}},tz=async e=>{try{let t=k?`${k}/get/mcp_semantic_filter_settings`:"/get/mcp_semantic_filter_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get MCP semantic filter settings:",e),e}},tL=async(e,t)=>{try{let r=k?`${k}/update/mcp_semantic_filter_settings`:"/update/mcp_semantic_filter_settings",o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update MCP semantic filter settings:",e),e}},tD=async(e,t,r)=>{try{let o=k?`${k}/v1/responses`:"/v1/responses",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model:t,input:[{role:"user",content:r,type:"message"}],tools:[{type:"mcp",server_url:"litellm_proxy",require_approval:"never"}],tool_choice:"required"})}),a=n.headers.get("x-litellm-semantic-filter"),i=n.headers.get("x-litellm-semantic-filter-tools");if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return{data:await n.json(),headers:{filter:a,tools:i}}}catch(e){throw console.error("Failed to test MCP semantic filter:",e),e}},tH=async e=>{try{let t=k?`${k}/v2/guardrails/list`:"/v2/guardrails/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(`v2 guardrails/list returned ${r.status}`);return await r.json()}catch(t){console.log("v2/guardrails/list failed, falling back to v1:",t);try{let t=k?`${k}/guardrails/list`:"/guardrails/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get guardrails list:",e),e}}},tV=async(e,t)=>{let r=k?`${k}/guardrails/submissions`:"/guardrails/submissions",o=new URLSearchParams;t?.status&&o.set("status",t.status),t?.team_id&&o.set("team_id",t.team_id),t?.team_guardrail!==void 0&&o.set("team_guardrail",String(t.team_guardrail)),t?.search&&o.set("search",t.search);let n=o.toString()?`${r}?${o.toString()}`:r,a=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=oB(await a.json().catch(()=>({})));throw F(e),Error(e)}return a.json()},tW=async(e,t)=>{let r=k?`${k}/guardrails/submissions/${encodeURIComponent(t)}/approve`:`/guardrails/submissions/${encodeURIComponent(t)}/approve`,o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=oB(await o.json().catch(()=>({})));throw F(e),Error(e)}return o.json()},tU=async(e,t)=>{let r=k?`${k}/guardrails/submissions/${encodeURIComponent(t)}/reject`:`/guardrails/submissions/${encodeURIComponent(t)}/reject`,o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=oB(await o.json().catch(()=>({})));throw F(e),Error(e)}return o.json()},tG=async(e,t,r)=>{try{let o=k?`${k}/guardrails/usage/overview`:"/guardrails/usage/overview",n=new URLSearchParams;t&&n.append("start_date",t),r&&n.append("end_date",r),n.toString()&&(o+=`?${n.toString()}`);let a=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json();throw Error(oB(e))}return a.json()}catch(e){throw console.error("Failed to get guardrails usage overview:",e),e}},tq=async(e,t,r,o)=>{try{let n=k?`${k}/guardrails/usage/detail/${encodeURIComponent(t)}`:`/guardrails/usage/detail/${encodeURIComponent(t)}`,a=new URLSearchParams;r&&a.append("start_date",r),o&&a.append("end_date",o),a.toString()&&(n+=`?${a.toString()}`);let i=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json();throw Error(oB(e))}return i.json()}catch(e){throw console.error("Failed to get guardrails usage detail:",e),e}},tJ=async(e,t)=>{try{let r=k?`${k}/guardrails/usage/logs`:"/guardrails/usage/logs",o=new URLSearchParams;t.guardrailId&&o.append("guardrail_id",t.guardrailId),t.policyId&&o.append("policy_id",t.policyId),null!=t.page&&o.append("page",String(t.page)),null!=t.pageSize&&o.append("page_size",String(t.pageSize)),t.action&&o.append("action",t.action),t.startDate&&o.append("start_date",t.startDate),t.endDate&&o.append("end_date",t.endDate),o.toString()&&(r+=`?${o.toString()}`);let n=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json();throw Error(oB(e))}return n.json()}catch(e){throw console.error("Failed to get guardrails usage logs:",e),e}},tK=async e=>{try{let t=k?`${k}/policies/list`:"/policies/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policies list:",e),e}},tX=async(e,t,r)=>{try{let o=k?`${k}/utils/test_policies_and_guardrails`:"/utils/test_policies_and_guardrails",n=await fetch(o,{method:"POST",signal:r,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({policy_names:t.policy_names??null,guardrail_names:t.guardrail_names??null,inputs:t.inputs??null,inputs_list:t.inputs_list??null,request_data:t.request_data??{},input_type:t.input_type??"request",agent_id:t.agent_id??null})});if(!n.ok){let e=await n.text(),t="Failed to test policies and guardrails";try{let r=JSON.parse(e);r.detail?t="string"==typeof r.detail?r.detail:JSON.stringify(r.detail):r.message&&(t=r.message)}catch{t=e||t}throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test policies and guardrails:",e),e}},tY=async(e,t)=>{try{let r=k?`${k}/policy/info/${t}`:`/policy/info/${t}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to get policy info for ${t}:`,e),e}},tQ=async e=>{try{let t=k?`${k}/policy/templates`:"/policy/templates",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy templates:",e),e}},tZ=async(e,t,r,o,n)=>{try{let a=k?`${k}/policy/templates/enrich`:"/policy/templates/enrich",i={template_id:t,parameters:r};o&&(i.model=o),n&&(i.competitors=n);let l=await fetch(a,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.json(),t=oB(e);throw F(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to enrich policy template:",e),e}},t0=async(e,t,r,o)=>{try{let n=k?`${k}/policy/templates/suggest`:"/policy/templates/suggest",a=await fetch(n,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({attack_examples:t.filter(e=>e.trim()),description:r,model:o})});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}return a.json()}catch(e){throw console.error("Failed to suggest policy templates:",e),e}},t1=async(e,t,r)=>{try{let o=k?`${k}/policy/templates/test`:"/policy/templates/test",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail_definitions:t,text:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to test policy template:",e),e}},t2=async(e,t,r,o,n,a,i,l,s)=>{let c=k?`${k}/policy/templates/enrich/stream`:"/policy/templates/enrich/stream",u={template_id:t,parameters:r,model:o};l?.instruction&&(u.instruction=l.instruction),l?.existingCompetitors&&(u.competitors=l.existingCompetitors);let d=await fetch(c,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(u)});if(!d.ok){let e=oB(await d.json());throw F(e),Error(e)}let f=d.body?.getReader();if(!f)throw Error("No response body");let p=new TextDecoder,h="";for(;;){let{done:e,value:t}=await f.read();if(e)break;let r=(h+=p.decode(t,{stream:!0})).split("\n");for(let e of(h=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"competitor"===t.type?n(t.name):"status"===t.type?s?.(t.message):"done"===t.type?a(t):"error"===t.type&&i?.(t.message)}catch{}}},t4=async(e,t,r,o,n,a,i,l,s)=>{let c=k?`${k}/usage/ai/chat`:"/usage/ai/chat",u=await fetch(c,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({messages:t,model:r}),signal:s});if(!u.ok){let e=oB(await u.json());throw F(e),Error(e)}let d=u.body?.getReader();if(!d)throw Error("No response body");let f=new TextDecoder,p="";for(;;){let{done:e,value:t}=await d.read();if(e)break;let r=(p+=f.decode(t,{stream:!0})).split("\n");for(let e of(p=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"chunk"===t.type?o(t.content):"status"===t.type?i?.(t.message):"tool_call"===t.type?l?.(t):"done"===t.type?n():"error"===t.type&&a?.(t.message)}catch{}}},t6=async(e,t)=>{try{let r=k?`${k}/policies`:"/policies",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create policy:",e),e}},t3=async(e,t,r)=>{try{let o=k?`${k}/policies/${t}`:`/policies/${t}`,n=await fetch(o,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update policy:",e),e}},t7=async(e,t)=>{try{let r=encodeURIComponent(t),o=k?`${k}/policies/name/${r}/versions`:`/policies/name/${r}/versions`,n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to list policy versions:",e),e}},t5=async(e,t,r)=>{try{let o=encodeURIComponent(t),n=k?`${k}/policies/name/${o}/versions`:`/policies/name/${o}/versions`,a=await fetch(n,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({source_policy_id:r??void 0})});if(!a.ok){let e=await a.json(),t=oB(e);throw F(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create policy version:",e),e}},t9=async(e,t,r)=>{try{let o=k?`${k}/policies/${t}/status`:`/policies/${t}/status`,n=await fetch(o,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({version_status:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update policy version status:",e),e}},t8=async(e,t)=>{try{let r=k?`${k}/policies/${t}`:`/policies/${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to delete policy:",e),e}},re=async(e,t)=>{try{let r=k?`${k}/policies/${t}`:`/policies/${t}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to get policy info:",e),e}},rt=async e=>{try{let t=k?`${k}/policies/attachments/list`:"/policies/attachments/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy attachments list:",e),e}},rr=async(e,t)=>{try{let r=k?`${k}/policies/attachments`:"/policies/attachments",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create policy attachment:",e),e}},ro=async(e,t)=>{try{let r=k?`${k}/policies/attachments/${t}`:`/policies/attachments/${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to delete policy attachment:",e),e}},rn=async(e,t,r)=>{try{let o=k?`${k}/policies/test-pipeline`:"/policies/test-pipeline",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({pipeline:t,test_messages:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test pipeline:",e),e}},ra=async(e,t)=>{try{let r=k?`${k}/policies/${t}/resolved-guardrails`:`/policies/${t}/resolved-guardrails`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to get resolved guardrails:",e),e}},ri=async(e,t)=>{try{let r=k?`${k}/policies/resolve`:"/policies/resolve",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to resolve policies:",e),e}},rl=async(e,t)=>{try{let r=k?`${k}/policies/attachments/estimate-impact`:"/policies/attachments/estimate-impact",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to estimate attachment impact:",e),e}},rs=async(e,t)=>{try{let r=k?`${k}/prompts/list`:"/prompts/list";t&&(r+=`?environment=${encodeURIComponent(t)}`);let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to get prompts list:",e),e}},rc=async(e,t,r)=>{try{let o=k?`${k}/prompts/${t}/info`:`/prompts/${t}/info`;r&&(o+=`?environment=${encodeURIComponent(r)}`);let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt info:",e),e}},ru=async(e,t,r)=>{try{let o=k?`${k}/prompts/${t}/versions`:`/prompts/${t}/versions`;r&&(o+=`?environment=${encodeURIComponent(r)}`);let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=oB(e);throw 404!==n.status&&F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt versions:",e),e}},rd=async(e,t)=>{try{let r=k?`${k}/prompts`:"/prompts",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create prompt:",e),e}},rf=async(e,t,r)=>{try{let o=k?`${k}/prompts/${t}`:`/prompts/${t}`,n=await fetch(o,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update prompt:",e),e}},rp=async(e,t)=>{try{let r=k?`${k}/prompts/${t}`:`/prompts/${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to delete prompt:",e),e}},rh=async(e,t)=>{try{let r=new FormData;r.append("file",t);let o=k?`${k}/utils/dotprompt_json_converter`:"/utils/dotprompt_json_converter",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`},body:r});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to convert prompt file:",e),e}},rm=async(e,t)=>{try{let r=k?`${k}/v1/agents`:"/v1/agents",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Create agent response:",n),n}catch(e){throw console.error("Failed to create agent:",e),e}},rg=async(e,t)=>{try{let r=k?`${k}/guardrails`:"/guardrails",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail:t})});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Create guardrail response:",n),n}catch(e){throw console.error("Failed to create guardrail:",e),e}},rv=async(e,t,r)=>{try{let o=k?`${k}/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`:`/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`;console.log("Fetching log details from:",o);let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("Fetched log details:",a),a}catch(e){throw console.error("Failed to fetch log details:",e),e}},ry=async e=>{try{let t=k?`${k}/get/internal_user_settings`:"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched SSO settings:",o),o}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},rb=async(e,t)=>{try{let r=k?`${k}/update/internal_user_settings`:"/update/internal_user_settings";console.log("Updating internal user settings:",t);let o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Updated internal user settings:",n),y.default.success("Internal user settings updated successfully"),n}catch(e){throw console.error("Failed to update internal user settings:",e),e}},rw=async e=>{try{let t=k?`${k}/v1/mcp/openapi-registry`:"/v1/mcp/openapi-registry",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json();throw Error(oB(e))}return await r.json()}catch(e){throw console.error("Failed to fetch OpenAPI registry:",e),e}},r$=async e=>{try{let t=k?`${k}/v1/mcp/discover`:"/v1/mcp/discover",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch discoverable MCP servers:",e),e}},rC=async(e,t)=>{try{let r=k?`${k}/v1/mcp/server`:"/v1/mcp/server";if(t){let e=new URLSearchParams;e.append("team_id",t),r=`${r}?${e.toString()}`}console.log("Fetching MCP servers from:",r);let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Fetched MCP servers:",n),n}catch(e){throw console.error("Failed to fetch MCP servers:",e),e}},rx=async(e,t)=>{try{let r=k?`${k}/v1/mcp/server/health`:"/v1/mcp/server/health";if(t&&t.length>0){let e=new URLSearchParams;t.forEach(t=>e.append("server_ids",t)),r=`${r}?${e.toString()}`}console.log("Fetching MCP server health from:",r);let o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Fetched MCP server health:",n),n}catch(e){throw console.error("Failed to fetch MCP server health:",e),e}},rE=async e=>{try{let t=k?`${k}/v1/mcp/access_groups`:"/v1/mcp/access_groups";console.log("Fetching MCP access groups from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched MCP access groups:",o),o.access_groups||[]}catch(e){throw console.error("Failed to fetch MCP access groups:",e),e}},rS=async e=>{try{let t=k?`${k}/v1/mcp/network/client-ip`:"/v1/mcp/network/client-ip",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`}});if(!r.ok)return null;return(await r.json()).ip||null}catch{return null}},rk=async(e,t)=>{try{console.log("Form Values in createMCPServer:",t);let r=k?`${k}/v1/mcp/server`:"/v1/mcp/server",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},rj=async(e,t)=>{try{let r=k?`${k}/v1/mcp/server`:"/v1/mcp/server",o=await fetch(r,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update MCP server:",e),e}},rO=async(e,t)=>{try{let r=(k?`${k}`:"")+`/v1/mcp/server/${t}`;console.log("in deleteMCPServer:",t);let o=await fetch(r,{method:I,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}}catch(e){throw console.error("Failed to delete key:",e),e}},rT=async e=>{try{let t=(k?`${k}`:"")+"/v1/mcp/toolset",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch MCP toolsets:",e),e}},rI=async(e,t)=>{try{let r=(k?`${k}`:"")+"/v1/mcp/toolset",o=await fetch(r,{method:T,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to create MCP toolset:",e),e}},r_=async(e,t)=>{try{let r=(k?`${k}`:"")+"/v1/mcp/toolset",o=await fetch(r,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update MCP toolset:",e),e}},rF=async(e,t)=>{try{let r=(k?`${k}`:"")+`/v1/mcp/toolset/${t}`,o=await fetch(r,{method:I,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}}catch(e){throw console.error("Failed to delete MCP toolset:",e),e}},rP=async(e,t)=>{try{let r=(k?`${k}`:"")+"/v1/mcp/server/register",o=await fetch(r,{method:T,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to register MCP server:",e),e}},rR=async e=>{try{let t=(k?`${k}`:"")+"/v1/mcp/server/submissions",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json().catch(()=>({})),t=oB(e);throw F(t),Error(t)}return r.json()}catch(e){throw console.error("Failed to fetch MCP submissions:",e),e}},rN=async(e,t)=>{try{let r=(k?`${k}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/approve`,o=await fetch(r,{method:"PUT",headers:{[N]:`Bearer ${e}`}});if(!o.ok){let e=await o.json().catch(()=>({})),t=oB(e);throw F(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to approve MCP server:",e),e}},rM=async(e,t,r)=>{try{let o=(k?`${k}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/reject`,n=await fetch(o,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({review_notes:r??null})});if(!n.ok){let e=await n.json().catch(()=>({})),t=oB(e);throw F(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to reject MCP server:",e),e}},rB=async e=>{try{let t=k?`${k}/search_tools/list`:"/search_tools/list";console.log("Fetching search tools from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched search tools:",o),o}catch(e){throw console.error("Failed to fetch search tools:",e),e}},rA=async(e,t)=>{try{console.log("Creating search tool with values:",t);let r=k?`${k}/search_tools`:"/search_tools",o=await fetch(r,{method:T,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Created search tool:",n),n}catch(e){throw console.error("Failed to create search tool:",e),e}},rz=async(e,t,r)=>{try{console.log("Updating search tool with ID:",t,"values:",r);let o=k?`${k}/search_tools/${t}`:`/search_tools/${t}`,n=await fetch(o,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("Updated search tool:",a),a}catch(e){throw console.error("Failed to update search tool:",e),e}},rL=async(e,t)=>{try{let r=(k?`${k}`:"")+`/search_tools/${t}`;console.log("Deleting search tool:",t);let o=await fetch(r,{method:I,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Deleted search tool:",n),n}catch(e){throw console.error("Failed to delete search tool:",e),e}},rD=async e=>{try{let t=k?`${k}/search_tools/ui/available_providers`:"/search_tools/ui/available_providers";console.log("Fetching available search providers from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched available search providers:",o),o}catch(e){throw console.error("Failed to fetch available search providers:",e),e}},rH=async(e,t)=>{try{let r=k?`${k}/search_tools/test_connection`:"/search_tools/test_connection";console.log("Testing search tool connection:",r);let o=await fetch(r,{method:T,headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({litellm_params:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Test connection response:",n),n}catch(e){throw console.error("Failed to test search tool connection:",e),e}},rV=async(e,t,r)=>{try{let o=k?`${k}/mcp-rest/tools/list?server_id=${t}`:`/mcp-rest/tools/list?server_id=${t}`;console.log("Fetching MCP tools from:",o);let n={[N]:`Bearer ${e}`,"Content-Type":"application/json",...r},a=await fetch(o,{method:"GET",headers:n}),i=await a.json();if(console.log("Fetched MCP tools response:",i),!a.ok){if(i.error&&i.message)throw Error(i.message);throw Error("Failed to fetch MCP tools")}return i}catch(e){return console.error("Failed to fetch MCP tools:",e),{tools:[],error:"network_error",message:e instanceof Error?e.message:"Failed to fetch MCP tools",stack_trace:null}}},rW=async(e,t,r,o,n)=>{try{let a=k?`${k}/mcp-rest/tools/call`:"/mcp-rest/tools/call";console.log("Calling MCP tool:",r,"with arguments:",o,"for server:",t);let i={[N]:`Bearer ${e}`,"Content-Type":"application/json",...n?.customHeaders||{}},l={server_id:t,name:r,arguments:o};n?.guardrails&&n.guardrails.length>0&&(l.litellm_metadata={guardrails:n.guardrails});let s=await fetch(a,{method:"POST",headers:i,body:JSON.stringify(l)});if(!s.ok){let e="Network response was not ok",t=null,r=await s.text();try{let o=JSON.parse(r);o.detail?"string"==typeof o.detail?e=o.detail:"object"==typeof o.detail&&(e=o.detail.message||o.detail.error||"An error occurred",t=o.detail):e=o.message||o.error||e}catch(t){console.error("Failed to parse JSON error response:",t),r&&(e=r)}let o=Error(e);throw o.status=s.status,o.statusText=s.statusText,o.details=t,F(e),o}let c=await s.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),console.error("Error type:",typeof e),e instanceof Error&&(console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}},rU=async(e,t)=>{try{let r=k?`${k}/tag/new`:"/tag/new",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify(t)});if(!o.ok){let e=await o.text();await F(e);return}return await o.json()}catch(e){throw console.error("Error creating tag:",e),e}},rG=async(e,t)=>{try{let r=k?`${k}/tag/update`:"/tag/update",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify(t)});if(!o.ok){let e=await o.text();await F(e);return}return await o.json()}catch(e){throw console.error("Error updating tag:",e),e}},rq=async(e,t)=>{try{let r=k?`${k}/tag/info`:"/tag/info",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({names:t})});if(!o.ok){let e=await o.text();return await F(e),{}}return await o.json()}catch(e){throw console.error("Error getting tag info:",e),e}},rJ=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),o=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${o}`},rK=async(e,t,r)=>{try{let o=k?`${k}/tag/list`:"/tag/list";if(t&&r){let e=new URLSearchParams({start_date:rJ(t),end_date:rJ(r)});o=`${o}?${e.toString()}`}let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`}});if(!n.ok){let e=await n.text();return await F(e),{}}return await n.json()}catch(e){throw console.error("Error listing tags:",e),e}},rX=async(e,t)=>{try{let r=k?`${k}/tag/delete`:"/tag/delete",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({name:t})});if(!o.ok){let e=await o.text();await F(e);return}return await o.json()}catch(e){throw console.error("Error deleting tag:",e),e}},rY=async e=>{try{let t=k?`${k}/get/default_team_settings`:"/get/default_team_settings";console.log("Fetching default team settings from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched default team settings:",o),o}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},rQ=async(e,t)=>{try{let r=k?`${k}/update/default_team_settings`:"/update/default_team_settings";console.log("Updating default team settings:",t);let o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}let n=await o.json();return console.log("Updated default team settings:",n),n}catch(e){throw console.error("Failed to update default team settings:",e),e}},rZ=async(e,t)=>{try{let r=k?`${k}/team/permissions_list?team_id=${t}`:`/team/permissions_list?team_id=${t}`,o=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`}});if(!o.ok){let e=await o.json(),t=oB(e);return console.error("Available permissions fetch failed:",t),{all_available_permissions:[],team_member_permissions:[]}}return await o.json()}catch(e){throw console.error("Failed to get team permissions:",e),e}},r0=async(e,t,r)=>{try{let o=k?`${k}/team/permissions_update`:"/team/permissions_update",n=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({team_id:t,team_member_permissions:r})});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to update team permissions:",e),e}},r1=async(e,t)=>{try{let r=k?`${k}/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`:`/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch session logs:",e),e}},r2=async(e,t)=>{try{let r=k?`${k}/vector_store/new`:"/vector_store/new",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify(t)});if(!o.ok){let e=await o.json();throw Error(e.detail||"Failed to create vector store")}return await o.json()}catch(e){throw console.error("Error creating vector store:",e),e}},r4=async(e,t=1,r=100)=>{try{let t=k?`${k}/vector_store/list`:"/vector_store/list",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`}});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to list vector stores")}return await r.json()}catch(e){throw console.error("Error listing vector stores:",e),e}},r6=async(e,t)=>{try{let r=k?`${k}/vector_store/delete`:"/vector_store/delete",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!o.ok){let e=await o.json();throw Error(e.detail||"Failed to delete vector store")}return await o.json()}catch(e){throw console.error("Error deleting vector store:",e),e}},r3=async(e,t)=>{try{let r=k?`${k}/vector_store/info`:"/vector_store/info",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!o.ok){let e=await o.json();throw Error(e.detail||"Failed to get vector store info")}return await o.json()}catch(e){throw console.error("Error getting vector store info:",e),e}},r7=async(e,t)=>{try{let r=k?`${k}/vector_store/update`:"/vector_store/update",o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[N]:`Bearer ${e}`},body:JSON.stringify(t)});if(!o.ok){let e=await o.json();throw Error(e.detail||"Failed to update vector store")}return await o.json()}catch(e){throw console.error("Error updating vector store:",e),e}},r5=async(e,t,r,o,n,a,i)=>{try{let l=k?`${k}/rag/ingest`:"/rag/ingest",s=new FormData;s.append("file",t);let c={ingest_options:{vector_store:{custom_llm_provider:r,...o&&{vector_store_id:o},...i&&i}}};(n||a)&&(c.ingest_options.litellm_vector_store_params={},n&&(c.ingest_options.litellm_vector_store_params.vector_store_name=n),a&&(c.ingest_options.litellm_vector_store_params.vector_store_description=a)),s.append("request",JSON.stringify(c));let u=await fetch(l,{method:"POST",headers:{[N]:`Bearer ${e}`},body:s});if(!u.ok){let e=await u.json();throw Error(e.error?.message||e.detail||"Failed to ingest document")}return await u.json()}catch(e){throw console.error("Error ingesting document:",e),e}},r9=async e=>{try{let t=k?`${k}/email/event_settings`:"/email/event_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error("Failed to get email event settings")}let o=await r.json();return console.log("Email event settings response:",o),o}catch(e){throw console.error("Failed to get email event settings:",e),e}},r8=async(e,t)=>{try{let r=k?`${k}/email/event_settings`:"/email/event_settings",o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text();throw F(e),Error("Failed to update email event settings")}let n=await o.json();return console.log("Update email event settings response:",n),n}catch(e){throw console.error("Failed to update email event settings:",e),e}},oe=async e=>{try{let t=k?`${k}/email/event_settings/reset`:"/email/event_settings/reset",r=await fetch(t,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error("Failed to reset email event settings")}let o=await r.json();return console.log("Reset email event settings response:",o),o}catch(e){throw console.error("Failed to reset email event settings:",e),e}},ot=async(e,t)=>{try{let r=k?`${k}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Delete agent response:",n),n}catch(e){throw console.error("Failed to delete agent:",e),e}},or=async(e,t)=>{try{let r=k?`${k}/v1/agents/make_public`:"/v1/agents/make_public",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({agent_ids:t})});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Make agents public response:",n),n}catch(e){throw console.error("Failed to make agents public:",e),e}},oo=async(e,t)=>{try{let r=k?`${k}/v1/mcp/make_public`:"/v1/mcp/make_public",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({mcp_server_ids:t})});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Make agents public response:",n),n}catch(e){throw console.error("Failed to make agents public:",e),e}},on=async(e,t)=>{try{let r=k?`${k}/guardrails/${t}`:`/guardrails/${t}`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw F(e),Error(e)}let n=await o.json();return console.log("Delete guardrail response:",n),n}catch(e){throw console.error("Failed to delete guardrail:",e),e}},oa=async e=>{try{let t=k?`${k}/guardrails/ui/add_guardrail_settings`:"/guardrails/ui/add_guardrail_settings",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error("Failed to get guardrail UI settings")}let o=await r.json();return console.log("Guardrail UI settings response:",o),o}catch(e){throw console.error("Failed to get guardrail UI settings:",e),e}},oi=async e=>{try{let t=k?`${k}/guardrails/ui/provider_specific_params`:"/guardrails/ui/provider_specific_params",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw F(e),Error("Failed to get guardrail provider specific parameters")}let o=await r.json();return console.log("Guardrail provider specific params response:",o),o}catch(e){throw console.error("Failed to get guardrail provider specific parameters:",e),e}},ol=async(e,t)=>{try{let r=encodeURIComponent(t),o=k?`${k}/guardrails/ui/category_yaml/${r}`:`/guardrails/ui/category_yaml/${r}`;console.log(`Fetching category YAML from: ${o}`);let n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw console.error(`Failed to get category YAML. Status: ${n.status}, Error:`,e),F(e),Error(`Failed to get category YAML: ${n.status} ${e}`)}let a=await n.json();return console.log("Category YAML response:",a),a}catch(e){throw console.error("Failed to get category YAML:",e),e}},os=async e=>{try{let t=k?`${k}/guardrails/ui/major_airlines`:"/guardrails/ui/major_airlines",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw console.error(`Failed to get major airlines. Status: ${r.status}, Error:`,e),F(e),Error(`Failed to get major airlines: ${r.status} ${e}`)}return await r.json()}catch(e){throw console.error("Failed to get major airlines:",e),e}},oc=async(e,t=!1)=>{try{let r=t?"?health_check=true":"",o=k?`${k}/v1/agents${r}`:`/v1/agents${r}`,n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw F(e),Error("Failed to get agents list")}let a=await n.json();return console.log("Agents list response:",a),{agents:a}}catch(e){throw console.error("Failed to get agents list:",e),e}},ou=async(e,t)=>{try{let r=k?`${k}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw F(e),Error("Failed to get agent info")}let n=await o.json();return console.log("Agent info response:",n),n}catch(e){throw console.error("Failed to get agent info:",e),e}},od=async(e,t)=>{try{let r=k?`${k}/guardrails/${t}/info`:`/guardrails/${t}/info`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw F(e),Error("Failed to get guardrail info")}let n=await o.json();return console.log("Guardrail info response:",n),n}catch(e){throw console.error("Failed to get guardrail info:",e),e}},of=async(e,t,r)=>{try{let o=k?`${k}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.text();throw F(e),Error("Failed to patch agent")}let a=await n.json();return console.log("Patch agent response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},op=async(e,t,r)=>{try{let o=k?`${k}/guardrails/${t}`:`/guardrails/${t}`,n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.text();throw F(e),Error("Failed to update guardrail")}let a=await n.json();return console.log("Update guardrail response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},oh=async(e,t,r,o,n)=>{try{let a=k?`${k}/guardrails/apply_guardrail`:"/guardrails/apply_guardrail",i={guardrail_name:t,text:r};o&&(i.language=o),n&&n.length>0&&(i.entities=n);let l=await fetch(a,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t="Failed to apply guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw F(e),Error(t)}let s=await l.json();return console.log("Apply guardrail response:",s),s}catch(e){throw console.error("Failed to apply guardrail:",e),e}},om=async(e,t)=>{try{let r=k?`${k}/guardrails/test_custom_code`:"/guardrails/test_custom_code",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text(),t="Failed to test custom code guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw F(e),Error(t)}let n=await o.json();return console.log("Test custom code guardrail response:",n),n}catch(e){throw console.error("Failed to test custom code guardrail:",e),e}},og=async(e,t)=>{try{let r=k?`${k}/guardrails/validate_blocked_words_file`:"/guardrails/validate_blocked_words_file",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({file_content:t})});if(!o.ok){let e=await o.text();throw F(e),Error("Failed to validate blocked words file")}let n=await o.json();return console.log("Validate blocked words file response:",n),n}catch(e){throw console.error("Failed to validate blocked words file:",e),e}},ov=async e=>{try{let t=k?`${k}/get/sso_settings`:"/get/sso_settings";console.log("Fetching SSO configuration from:",t);let r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}let o=await r.json();return console.log("Fetched SSO configuration:",o),o}catch(e){throw console.error("Failed to fetch SSO configuration:",e),e}},oy=async(e,t)=>{try{let r=k?`${k}/update/sso_settings`:"/update/sso_settings";console.log("Updating SSO configuration:",t);let o=await fetch(r,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.json(),t="object"==typeof e?.detail?e.detail?.error||e.detail?.message:e?.detail,r="string"==typeof t&&t.length>0?t:oB(e);F(r);let n=Error(r);throw e?.detail!==void 0&&(n.detail=e.detail),n.rawError=e,n}let n=await o.json();return console.log("Updated SSO configuration:",n),n}catch(e){throw console.error("Failed to update SSO configuration:",e),e}},ob=async({accessToken:e,page:t=1,page_size:r=50,params:o={}})=>{try{let n=k?`${k}/audit`:"/audit",a=new URLSearchParams;for(let[e,n]of(a.append("page",t.toString()),a.append("page_size",r.toString()),Object.entries(o)))null!=n&&""!==n&&a.append(e,String(n));n+=`?${a.toString()}`;let i=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=oB(e);throw F(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to fetch audit logs:",e),e}},ow=async e=>{try{let t=k?`${k}/user/available_users`:"/user/available_users",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw F(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch remaining users:",e),e}},o$=async e=>{try{let t=k?`${k}/health/license`:"/health/license",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw F(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch license info:",e),e}},oC=async(e,t,r)=>{try{let o=k?`${k}/config/pass_through_endpoint/${encodeURIComponent(t)}`:`/config/pass_through_endpoint/${encodeURIComponent(t)}`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.json(),t=oB(e);throw F(t),Error(t)}let a=await n.json();return y.default.success("Pass through endpoint updated successfully"),a}catch(e){throw console.error("Failed to update pass through endpoint:",e),e}},ox=async(e,t)=>{try{let r=k?`${k}/config/callback/delete`:"/config/callback/delete",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({callback_name:t})});if(!o.ok){let e=await o.json(),t=oB(e);throw F(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to delete specific callback:",e),e}},oE=async(e,t,r)=>{try{console.log("Testing MCP tools list with config:",JSON.stringify(t));let o=k?`${k}/mcp-rest/test/tools/list`:"/mcp-rest/test/tools/list",n={"Content-Type":"application/json"};e&&(n["x-litellm-api-key"]=e),r?n.Authorization=`Bearer ${r}`:e&&(n[N]=`Bearer ${e}`);let a=await fetch(o,{method:"POST",headers:n,body:JSON.stringify(t)}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||l.error)&&!l.error)return{tools:[],error:"request_failed",message:l.message||`MCP tools list failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("MCP tools list test error:",e),e}},oS=async(e,t)=>{let r=k?`${k}/v1/mcp/server/oauth/session`:"/v1/mcp/server/oauth/session",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)}),n=await o.json();if(!o.ok)throw Error(oB(n)||n?.error||"Failed to cache MCP server");return n},ok=async(e,t,r)=>{let o=j(),n=encodeURIComponent(t.trim()),a=`${o}/v1/mcp/server/oauth/${n}/register`,i=await fetch(a,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json, text/event-stream"},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw Error(oB(l)||l?.detail||"Failed to register OAuth client");return l},oj=({serverId:e,clientId:t,redirectUri:r,state:o,codeChallenge:n,scope:a})=>{let i=j(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/authorize`,c=new URLSearchParams({redirect_uri:r,state:o,response_type:"code",code_challenge:n,code_challenge_method:"S256"});return t&&t.trim().length>0&&c.set("client_id",t),a&&a.trim().length>0&&c.set("scope",a),`${s}?${c.toString()}`},oO=async({serverId:e,code:t,clientId:r,clientSecret:o,codeVerifier:n,redirectUri:a,accessToken:i})=>{let l=j(),s=encodeURIComponent(e.trim()),c=`${l}/v1/mcp/server/oauth/${s}/token`,u=new URLSearchParams;u.set("grant_type","authorization_code"),u.set("code",t),r&&r.trim().length>0&&u.set("client_id",r),o&&o.trim().length>0&&u.set("client_secret",o),u.set("code_verifier",n),u.set("redirect_uri",a);let d={"Content-Type":"application/x-www-form-urlencoded"};i&&(d.Authorization=`Bearer ${i}`);let f=await fetch(c,{method:"POST",headers:d,body:u.toString()}),p=await f.json();if(!f.ok)throw Error(oB(p)||p?.detail||"OAuth token exchange failed");return p},oT=async(e,t,r)=>{try{let o=`${j()}/v1/vector_stores/${t}/search`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r})});if(!n.ok){let e=await n.text();return await F(e),null}return await n.json()}catch(e){throw console.error("Error testing vector store search:",e),e}},oI=async(e,t,r,o)=>{try{let n=`${j()}/v1/search/${t}`,a=await fetch(n,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r,max_results:o||5})});if(!a.ok){let e=await a.text();return await F(e),null}return await a.json()}catch(e){throw console.error("Error querying search tool:",e),e}},o_=async(e,t,r,o)=>{try{let n,a,i,l=k?`${k}/tag/dau`:"/tag/dau",s=new URLSearchParams;s.append("end_date",(n=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${n}-${a}-${i}`)),o&&o.length>0?o.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=oB(e);throw F(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch DAU:",e),e}},oF=async(e,t,r,o)=>{try{let n,a,i,l=k?`${k}/tag/wau`:"/tag/wau",s=new URLSearchParams;s.append("end_date",(n=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${n}-${a}-${i}`)),o&&o.length>0?o.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=oB(e);throw F(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch WAU:",e),e}},oP=async(e,t,r,o)=>{try{let n,a,i,l=k?`${k}/tag/mau`:"/tag/mau",s=new URLSearchParams;s.append("end_date",(n=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${n}-${a}-${i}`)),o&&o.length>0?o.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=oB(e);throw F(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch MAU:",e),e}},oR=async e=>{try{let t=k?`${k}/tag/distinct`:"/tag/distinct",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=oB(e);throw F(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch distinct tags:",e),e}},oN=async(e,t,r,o)=>{try{let n=k?`${k}/tag/summary`:"/tag/summary",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),o=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${o}`};a.append("start_date",i(t)),a.append("end_date",i(r)),o&&o.length>0&&o.forEach(e=>{a.append("tag_filters",e)});let l=a.toString();l&&(n+=`?${l}`);let s=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=oB(e);throw F(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch user agent summary:",e),e}},oM=async(e,t=1,r=50,o)=>{try{let n=k?`${k}/tag/user-agent/per-user-analytics`:"/tag/user-agent/per-user-analytics",a=new URLSearchParams;a.append("page",t.toString()),a.append("page_size",r.toString()),o&&o.length>0&&o.forEach(e=>{a.append("tag_filters",e)});let i=a.toString();i&&(n+=`?${i}`);let l=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=oB(e);throw F(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to fetch per-user analytics:",e),e}},oB=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg||JSON.stringify(e)).join("; "):"string"==typeof t?t:void 0;return e?.error&&(e.error.message||("string"==typeof e.error?e.error:void 0))||e?.message||r||JSON.stringify(e)},oA=async(e,t,r)=>{let n=j(),a=r?"/v3/login":"/v2/login",i=n?`${n}${a}`:a,l=JSON.stringify({username:e,password:t}),s=await fetch(i,{method:"POST",body:l,credentials:"include",headers:{"Content-Type":"application/json"}});if(!s.ok)throw Error(oB(await s.json()));let c=await s.json();if(r&&c.code){let e=n?`${n}/v3/login/exchange`:"/v3/login/exchange",t=await fetch(e,{method:"POST",body:JSON.stringify({code:c.code}),credentials:"include",headers:{"Content-Type":"application/json"}});if(!t.ok)throw Error(oB(await t.json()));let r=await t.json();return r.token&&(0,o.storeLoginToken)(r.token),r}return c.token&&(0,o.storeLoginToken)(c.token),c},oz=async(e,t)=>{let r=t||j(),o=await fetch(`${r}/v3/login/exchange`,{method:"POST",body:JSON.stringify({code:e}),headers:{"Content-Type":"application/json"}});if(!o.ok)throw Error(oB(await o.json()));let n=await o.json();return n.token&&(document.cookie=`token=${n.token}; path=/; SameSite=Lax`),n.token},oL=async()=>{let e=j(),t=e?`${e}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET"});if(!r.ok)throw Error(oB(await r.json()));return await r.json()},oD=async(e,t)=>{let r=j(),o=r?`${r}/update/ui_settings`:"/update/ui_settings",n=await fetch(o,{method:"PATCH",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(oB(await n.json()));return await n.json()},oH=async(e,t=!1)=>{try{let r=j(),o=r?`${r}/claude-code/plugins?enabled_only=${t}`:`/claude-code/plugins?enabled_only=${t}`,n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text(),t=oB(JSON.parse(e));throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch Claude Code plugins list:",e),e}},oV=async(e,t)=>{try{let r=j(),o=r?`${r}/claude-code/plugins`:"/claude-code/plugins",n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text(),t=oB(JSON.parse(e));throw F(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to register Claude Code plugin:",e),e}},oW=async(e,t)=>{try{let r=j(),o=r?`${r}/claude-code/plugins/${t}/enable`:`/claude-code/plugins/${t}/enable`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text(),t=oB(JSON.parse(e));throw F(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to enable plugin "${t}":`,e),e}},oU=async(e,t)=>{try{let r=j(),o=r?`${r}/claude-code/plugins/${t}/disable`:`/claude-code/plugins/${t}/disable`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text(),t=oB(JSON.parse(e));throw F(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to disable plugin "${t}":`,e),e}},oG=async(e,t)=>{try{let r=j(),o=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,n=await fetch(o,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text(),t=oB(JSON.parse(e));throw F(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to delete plugin "${t}":`,e),e}},oq=async(e,t)=>{let r=k?`${k}/compliance/eu-ai-act`:"/compliance/eu-ai-act",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(await o.text());return o.json()},oJ=async(e,t)=>{let r=k?`${k}/compliance/gdpr`:"/compliance/gdpr",o=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(await o.text());return o.json()},oK=async e=>{let t=k?`${k}/v1/tool/policy/options`:"/v1/tool/policy/options",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return r.json()},oX=async e=>{let t=k?`${k}/v1/tool/list`:"/v1/tool/list",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return(await r.json()).tools??[]},oY=async(e,t,r)=>{let o=encodeURIComponent(t),n=k?`${k}/v1/tool/${o}/logs`:`/v1/tool/${o}/logs`,a=new URLSearchParams;null!=r.page&&a.append("page",String(r.page)),null!=r.pageSize&&a.append("page_size",String(r.pageSize)),r.startDate&&a.append("start_date",r.startDate),r.endDate&&a.append("end_date",r.endDate);let i=a.toString()?`${n}?${a.toString()}`:n,l=await fetch(i,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok)throw Error(oB(await l.json().catch(()=>({}))));return l.json()},oQ=async(e,t)=>{let r=encodeURIComponent(t),o=k?`${k}/v1/tool/${r}/detail`:`/v1/tool/${r}/detail`,n=await fetch(o,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok)throw Error(await n.text());return n.json()},oZ=async(e,t,r,o)=>{let n=k?`${k}/v1/tool/policy`:"/v1/tool/policy",a={tool_name:t};null!=r.input_policy&&(a.input_policy=r.input_policy),null!=r.output_policy&&(a.output_policy=r.output_policy),o?.team_id!=null&&(a.team_id=o.team_id||void 0),o?.key_hash!=null&&(a.key_hash=o.key_hash||void 0),o?.key_alias!=null&&(a.key_alias=o.key_alias||void 0);let i=await fetch(n,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw Error(await i.text());return i.json()},o0=async(e,t,r)=>{let o=encodeURIComponent(t),n=new URLSearchParams;null!=r.team_id&&""!==r.team_id&&n.set("team_id",r.team_id),null!=r.key_hash&&""!==r.key_hash&&n.set("key_hash",r.key_hash);let a=n.toString(),i=k?`${k}/v1/tool/${o}/overrides${a?`?${a}`:""}`:`/v1/tool/${o}/overrides${a?`?${a}`:""}`,l=await fetch(i,{method:"DELETE",headers:{[N]:`Bearer ${e}`}});if(!l.ok)throw Error(await l.text());return l.json()},o1=async(e,t,r)=>{let o=k?`${k}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,n=await fetch(o,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!n.ok){let e=await n.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to store OAuth credential")}return n.json()},o2=async(e,t)=>{let r=k?`${k}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,o=await fetch(r,{method:"DELETE",headers:{[N]:`Bearer ${e}`}});if(!o.ok){let e=await o.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to revoke OAuth credential")}return o.json()},o4=async(e,t)=>{let r=k?`${k}/v1/mcp/server/${t}/oauth-user-credential/status`:`/v1/mcp/server/${t}/oauth-user-credential/status`,o=await fetch(r,{method:"GET",headers:{[N]:`Bearer ${e}`}});return o.ok?o.json():{server_id:t,has_credential:!1,is_expired:!1}},o6=async e=>{let t=k?`${k}/v1/mcp/user-credentials`:"/v1/mcp/user-credentials",r=await fetch(t,{method:"GET",headers:{[N]:`Bearer ${e}`}});return r.ok?r.json():[]},o3=e=>e.split("/").map(encodeURIComponent).join("/"),o7=async(e,t={})=>{let r=k?`${k}/v1/memory`:"/v1/memory",o=new URLSearchParams;t.keyPrefix?o.append("key_prefix",t.keyPrefix):t.key&&o.append("key",t.key),null!=t.page&&o.append("page",String(t.page)),null!=t.pageSize&&o.append("page_size",String(t.pageSize));let n=o.toString()?`${r}?${o.toString()}`:r,a=await fetch(n,{method:"GET",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok)throw Error(await a.text());return a.json()},o5=async(e,t)=>{let r=k?`${k}/v1/memory`:"/v1/memory",o={key:t.key,value:t.value};void 0!==t.metadata&&(o.metadata=t.metadata);let n=await fetch(r,{method:"POST",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!n.ok)throw Error(await n.text());return n.json()},o9=async(e,t,r)=>{let o=o3(t),n=k?`${k}/v1/memory/${o}`:`/v1/memory/${o}`,a=await fetch(n,{method:"PUT",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!a.ok)throw Error(await a.text());return a.json()},o8=async(e,t)=>{let r=o3(t),o=k?`${k}/v1/memory/${r}`:`/v1/memory/${r}`,n=await fetch(o,{method:"DELETE",headers:{[N]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok)throw Error(await n.text())}},266027,869230,469637,e=>{"use strict";let t;var r=e.i(175555),o=e.i(540143),n=e.i(286491),a=e.i(915823),i=e.i(793803),l=e.i(619273),s=e.i(180166),c=class extends a.Subscribable{constructor(e,t){super(),this.options=t,this.#e=e,this.#t=null,this.#r=(0,i.pendingThenable)(),this.bindMethods(),this.setOptions(t)}#e;#o=void 0;#n=void 0;#a=void 0;#i;#l;#r;#t;#s;#c;#u;#d;#f;#p;#h=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){1===this.listeners.size&&(this.#o.addObserver(this),u(this.#o,this.options)?this.#m():this.updateResult(),this.#g())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return d(this.#o,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return d(this.#o,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#v(),this.#y(),this.#o.removeObserver(this)}setOptions(e){let t=this.options,r=this.#o;if(this.options=this.#e.defaultQueryOptions(e),void 0!==this.options.enabled&&"boolean"!=typeof this.options.enabled&&"function"!=typeof this.options.enabled&&"boolean"!=typeof(0,l.resolveEnabled)(this.options.enabled,this.#o))throw Error("Expected enabled to be a boolean or a callback that returns a boolean");this.#b(),this.#o.setOptions(this.options),t._defaulted&&!(0,l.shallowEqualObjects)(this.options,t)&&this.#e.getQueryCache().notify({type:"observerOptionsUpdated",query:this.#o,observer:this});let o=this.hasListeners();o&&f(this.#o,r,this.options,t)&&this.#m(),this.updateResult(),o&&(this.#o!==r||(0,l.resolveEnabled)(this.options.enabled,this.#o)!==(0,l.resolveEnabled)(t.enabled,this.#o)||(0,l.resolveStaleTime)(this.options.staleTime,this.#o)!==(0,l.resolveStaleTime)(t.staleTime,this.#o))&&this.#w();let n=this.#$();o&&(this.#o!==r||(0,l.resolveEnabled)(this.options.enabled,this.#o)!==(0,l.resolveEnabled)(t.enabled,this.#o)||n!==this.#p)&&this.#C(n)}getOptimisticResult(e){var t,r;let o=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(o,e);return t=this,r=n,(0,l.shallowEqualObjects)(t.getCurrentResult(),r)||(this.#a=n,this.#l=this.options,this.#i=this.#o.state),n}getCurrentResult(){return this.#a}trackResult(e,t){return new Proxy(e,{get:(e,r)=>(this.trackProp(r),t?.(r),"promise"===r&&(this.trackProp("data"),this.options.experimental_prefetchInRender||"pending"!==this.#r.status||this.#r.reject(Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(e,r))})}trackProp(e){this.#h.add(e)}getCurrentQuery(){return this.#o}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),r=this.#e.getQueryCache().build(this.#e,t);return r.fetch().then(()=>this.createResult(r,t))}fetch(e){return this.#m({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#a))}#m(e){this.#b();let t=this.#o.fetch(this.options,e);return e?.throwOnError||(t=t.catch(l.noop)),t}#w(){this.#v();let e=(0,l.resolveStaleTime)(this.options.staleTime,this.#o);if(l.isServer||this.#a.isStale||!(0,l.isValidTimeout)(e))return;let t=(0,l.timeUntilStale)(this.#a.dataUpdatedAt,e);this.#d=s.timeoutManager.setTimeout(()=>{this.#a.isStale||this.updateResult()},t+1)}#$(){return("function"==typeof this.options.refetchInterval?this.options.refetchInterval(this.#o):this.options.refetchInterval)??!1}#C(e){this.#y(),this.#p=e,!l.isServer&&!1!==(0,l.resolveEnabled)(this.options.enabled,this.#o)&&(0,l.isValidTimeout)(this.#p)&&0!==this.#p&&(this.#f=s.timeoutManager.setInterval(()=>{(this.options.refetchIntervalInBackground||r.focusManager.isFocused())&&this.#m()},this.#p))}#g(){this.#w(),this.#C(this.#$())}#v(){this.#d&&(s.timeoutManager.clearTimeout(this.#d),this.#d=void 0)}#y(){this.#f&&(s.timeoutManager.clearInterval(this.#f),this.#f=void 0)}createResult(e,t){let r,o=this.#o,a=this.options,s=this.#a,c=this.#i,d=this.#l,h=e!==o?e.state:this.#n,{state:m}=e,g={...m},v=!1;if(t._optimisticResults){let r=this.hasListeners(),i=!r&&u(e,t),l=r&&f(e,o,t,a);(i||l)&&(g={...g,...(0,n.fetchState)(m.data,e.options)}),"isRestoring"===t._optimisticResults&&(g.fetchStatus="idle")}let{error:y,errorUpdatedAt:b,status:w}=g;r=g.data;let $=!1;if(void 0!==t.placeholderData&&void 0===r&&"pending"===w){let e;s?.isPlaceholderData&&t.placeholderData===d?.placeholderData?(e=s.data,$=!0):e="function"==typeof t.placeholderData?t.placeholderData(this.#u?.state.data,this.#u):t.placeholderData,void 0!==e&&(w="success",r=(0,l.replaceData)(s?.data,e,t),v=!0)}if(t.select&&void 0!==r&&!$)if(s&&r===c?.data&&t.select===this.#s)r=this.#c;else try{this.#s=t.select,r=t.select(r),r=(0,l.replaceData)(s?.data,r,t),this.#c=r,this.#t=null}catch(e){this.#t=e}this.#t&&(y=this.#t,r=this.#c,b=Date.now(),w="error");let C="fetching"===g.fetchStatus,x="pending"===w,E="error"===w,S=x&&C,k=void 0!==r,j={status:w,fetchStatus:g.fetchStatus,isPending:x,isSuccess:"success"===w,isError:E,isInitialLoading:S,isLoading:S,data:r,dataUpdatedAt:g.dataUpdatedAt,error:y,errorUpdatedAt:b,failureCount:g.fetchFailureCount,failureReason:g.fetchFailureReason,errorUpdateCount:g.errorUpdateCount,isFetched:g.dataUpdateCount>0||g.errorUpdateCount>0,isFetchedAfterMount:g.dataUpdateCount>h.dataUpdateCount||g.errorUpdateCount>h.errorUpdateCount,isFetching:C,isRefetching:C&&!x,isLoadingError:E&&!k,isPaused:"paused"===g.fetchStatus,isPlaceholderData:v,isRefetchError:E&&k,isStale:p(e,t),refetch:this.refetch,promise:this.#r,isEnabled:!1!==(0,l.resolveEnabled)(t.enabled,e)};if(this.options.experimental_prefetchInRender){let t=void 0!==j.data,r="error"===j.status&&!t,n=e=>{r?e.reject(j.error):t&&e.resolve(j.data)},a=()=>{n(this.#r=j.promise=(0,i.pendingThenable)())},l=this.#r;switch(l.status){case"pending":e.queryHash===o.queryHash&&n(l);break;case"fulfilled":(r||j.data!==l.value)&&a();break;case"rejected":r&&j.error===l.reason||a()}}return j}updateResult(){let e=this.#a,t=this.createResult(this.#o,this.options);if(this.#i=this.#o.state,this.#l=this.options,void 0!==this.#i.data&&(this.#u=this.#o),(0,l.shallowEqualObjects)(t,e))return;this.#a=t;let r=()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,r="function"==typeof t?t():t;if("all"===r||!r&&!this.#h.size)return!0;let o=new Set(r??this.#h);return this.options.throwOnError&&o.add("error"),Object.keys(this.#a).some(t=>this.#a[t]!==e[t]&&o.has(t))};this.#x({listeners:r()})}#b(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#o)return;let t=this.#o;this.#o=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#g()}#x(e){o.notifyManager.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#a)}),this.#e.getQueryCache().notify({query:this.#o,type:"observerResultsUpdated"})})}};function u(e,t){return!1!==(0,l.resolveEnabled)(t.enabled,e)&&void 0===e.state.data&&("error"!==e.state.status||!1!==t.retryOnMount)||void 0!==e.state.data&&d(e,t,t.refetchOnMount)}function d(e,t,r){if(!1!==(0,l.resolveEnabled)(t.enabled,e)&&"static"!==(0,l.resolveStaleTime)(t.staleTime,e)){let o="function"==typeof r?r(e):r;return"always"===o||!1!==o&&p(e,t)}return!1}function f(e,t,r,o){return(e!==t||!1===(0,l.resolveEnabled)(o.enabled,e))&&(!r.suspense||"error"!==e.state.status)&&p(e,r)}function p(e,t){return!1!==(0,l.resolveEnabled)(t.enabled,e)&&e.isStaleByTime((0,l.resolveStaleTime)(t.staleTime,e))}e.s(["QueryObserver",()=>c],869230),e.i(247167);var h=e.i(271645),m=e.i(912598);e.i(843476);var g=h.createContext((t=!1,{clearReset:()=>{t=!1},reset:()=>{t=!0},isReset:()=>t})),v=h.createContext(!1);v.Provider;var y=(e,t,r)=>t.fetchOptimistic(e).catch(()=>{r.clearReset()});function b(e,t,r){let n,a=h.useContext(v),i=h.useContext(g),s=(0,m.useQueryClient)(r),c=s.defaultQueryOptions(e);s.getDefaultOptions().queries?._experimental_beforeQuery?.(c);let u=s.getQueryCache().get(c.queryHash);if(c._optimisticResults=a?"isRestoring":"optimistic",c.suspense){let e=e=>"static"===e?e:Math.max(e??1e3,1e3),t=c.staleTime;c.staleTime="function"==typeof t?(...r)=>e(t(...r)):e(t),"number"==typeof c.gcTime&&(c.gcTime=Math.max(c.gcTime,1e3))}n=u?.state.error&&"function"==typeof c.throwOnError?(0,l.shouldThrowError)(c.throwOnError,[u.state.error,u]):c.throwOnError,(c.suspense||c.experimental_prefetchInRender||n)&&!i.isReset()&&(c.retryOnMount=!1),h.useEffect(()=>{i.clearReset()},[i]);let d=!s.getQueryCache().get(c.queryHash),[f]=h.useState(()=>new t(s,c)),p=f.getOptimisticResult(c),b=!a&&!1!==e.subscribed;if(h.useSyncExternalStore(h.useCallback(e=>{let t=b?f.subscribe(o.notifyManager.batchCalls(e)):l.noop;return f.updateResult(),t},[f,b]),()=>f.getCurrentResult(),()=>f.getCurrentResult()),h.useEffect(()=>{f.setOptions(c)},[c,f]),c?.suspense&&p.isPending)throw y(c,f,i);if((({result:e,errorResetBoundary:t,throwOnError:r,query:o,suspense:n})=>e.isError&&!t.isReset()&&!e.isFetching&&o&&(n&&void 0===e.data||(0,l.shouldThrowError)(r,[e.error,o])))({result:p,errorResetBoundary:i,throwOnError:c.throwOnError,query:u,suspense:c.suspense}))throw p.error;if(s.getDefaultOptions().queries?._experimental_afterQuery?.(c,p),c.experimental_prefetchInRender&&!l.isServer&&p.isLoading&&p.isFetching&&!a){let e=d?y(c,f,i):u?.promise;e?.catch(l.noop).finally(()=>{f.updateResult()})}return c.notifyOnChangeProps?p:f.trackResult(p)}function w(e,t){return b(e,c,t)}e.s(["useBaseQuery",()=>b],469637),e.s(["useQuery",()=>w],266027)},243652,e=>{"use strict";function t(e){let t=[e];return{all:t,lists:()=>[...t,"list"],list:e=>[...t,"list",{params:e}],details:()=>[...t,"detail"],detail:e=>[...t,"detail",e]}}e.s(["createQueryKeys",()=>t])},947293,e=>{"use strict";class t extends Error{}function r(e,r){let o;if("string"!=typeof e)throw new t("Invalid token specified: must be a string");r||(r={});let n=+(!0!==r.header),a=e.split(".")[n];if("string"!=typeof a)throw new t(`Invalid token specified: missing part #${n+1}`);try{o=function(e){let t=e.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw Error("base64 string is not of the correct length")}try{var r;return r=t,decodeURIComponent(atob(r).replace(/(.)/g,(e,t)=>{let r=t.charCodeAt(0).toString(16).toUpperCase();return r.length<2&&(r="0"+r),"%"+r}))}catch(e){return atob(t)}}(a)}catch(e){throw new t(`Invalid token specified: invalid base64 for part #${n+1} (${e.message})`)}try{return JSON.parse(o)}catch(e){throw new t(`Invalid token specified: invalid json for part #${n+1} (${e.message})`)}}t.prototype.name="InvalidTokenError",e.s(["jwtDecode",()=>r])},612256,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let o=(0,e.i(243652).createQueryKeys)("uiConfig");e.s(["useUIConfig",0,()=>(0,r.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,t.getUiConfig)(),staleTime:864e5,gcTime:864e5})])}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0377ae18aae60c57.js b/litellm/proxy/_experimental/out/_next/static/chunks/0377ae18aae60c57.js deleted file mode 100644 index 66e4d15294f..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0377ae18aae60c57.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,362133,457202,439061,182399,234779,374615,330995,592143,372943,899268,87316,655900,299023,25652,882293,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M908 640H804V488c0-4.4-3.6-8-8-8H548v-96h108c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16H368c-8.8 0-16 7.2-16 16v288c0 8.8 7.2 16 16 16h108v96H228c-4.4 0-8 3.6-8 8v152H116c-8.8 0-16 7.2-16 16v288c0 8.8 7.2 16 16 16h288c8.8 0 16-7.2 16-16V656c0-8.8-7.2-16-16-16H292v-88h440v88H620c-8.8 0-16 7.2-16 16v288c0 8.8 7.2 16 16 16h288c8.8 0 16-7.2 16-16V656c0-8.8-7.2-16-16-16zm-564 76v168H176V716h168zm84-408V140h168v168H428zm420 576H680V716h168v168z"}}]},name:"apartment",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["ApartmentOutlined",0,r],362133);let i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M296 250c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H296zm184 144H296c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zm-48 458H208V148h560v320c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V108c0-17.7-14.3-32-32-32H168c-17.7 0-32 14.3-32 32v784c0 17.7 14.3 32 32 32h264c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm440-88H728v-36.6c46.3-13.8 80-56.6 80-107.4 0-61.9-50.1-112-112-112s-112 50.1-112 112c0 50.7 33.7 93.6 80 107.4V764H520c-8.8 0-16 7.2-16 16v152c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16V780c0-8.8-7.2-16-16-16zM646 620c0-27.6 22.4-50 50-50s50 22.4 50 50-22.4 50-50 50-50-22.4-50-50zm180 266H566v-60h260v60z"}}]},name:"audit",theme:"outlined"};var n=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:i}))});e.s(["AuditOutlined",0,n],457202);let o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M766.4 744.3c43.7 0 79.4-36.2 79.4-80.5 0-53.5-79.4-140.8-79.4-140.8S687 610.3 687 663.8c0 44.3 35.7 80.5 79.4 80.5zm-377.1-44.1c7.1 7.1 18.6 7.1 25.6 0l256.1-256c7.1-7.1 7.1-18.6 0-25.6l-256-256c-.6-.6-1.3-1.2-2-1.7l-78.2-78.2a9.11 9.11 0 00-12.8 0l-48 48a9.11 9.11 0 000 12.8l67.2 67.2-207.8 207.9c-7.1 7.1-7.1 18.6 0 25.6l255.9 256zm12.9-448.6l178.9 178.9H223.4l178.8-178.9zM904 816H120c-4.4 0-8 3.6-8 8v80c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-80c0-4.4-3.6-8-8-8z"}}]},name:"bg-colors",theme:"outlined"};var d=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:o}))});e.s(["BgColorsOutlined",0,d],439061);let c={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M856 376H648V168c0-8.8-7.2-16-16-16H168c-8.8 0-16 7.2-16 16v464c0 8.8 7.2 16 16 16h208v208c0 8.8 7.2 16 16 16h464c8.8 0 16-7.2 16-16V392c0-8.8-7.2-16-16-16zm-480 16v188H220V220h360v156H392c-8.8 0-16 7.2-16 16zm204 52v136H444V444h136zm224 360H444V648h188c8.8 0 16-7.2 16-16V444h156v360z"}}]},name:"block",theme:"outlined"};var m=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:c}))});e.s(["BlockOutlined",0,m],182399);let u={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-260 72h96v209.9L621.5 312 572 347.4V136zm220 752H232V136h280v296.9c0 3.3 1 6.6 3 9.3a15.9 15.9 0 0022.3 3.7l83.8-59.9 81.4 59.4c2.7 2 6 3.1 9.4 3.1 8.8 0 16-7.2 16-16V136h64v752z"}}]},name:"book",theme:"outlined"};var g=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:u}))});e.s(["BookOutlined",0,g],234779);let x={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-792 72h752v120H136V232zm752 560H136V440h752v352zm-237-64h165c4.4 0 8-3.6 8-8v-72c0-4.4-3.6-8-8-8H651c-4.4 0-8 3.6-8 8v72c0 4.4 3.6 8 8 8z"}}]},name:"credit-card",theme:"outlined"};var p=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:x}))});e.s(["CreditCardOutlined",0,p],374615);var h=e.i(366845);e.s(["FolderOutlined",()=>h.default],330995);var f=e.i(609587);e.s(["ConfigProvider",()=>f.default],592143);var y=e.i(8211),b=e.i(343794),v=e.i(529681),j=e.i(242064),N=e.i(704914),k=e.i(876556),w=e.i(290224),O=e.i(251224),_=function(e,t){var a={};for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&0>t.indexOf(s)&&(a[s]=e[s]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,s=Object.getOwnPropertySymbols(e);lt.indexOf(s[l])&&Object.prototype.propertyIsEnumerable.call(e,s[l])&&(a[s[l]]=e[s[l]]);return a};function L({suffixCls:e,tagName:t,displayName:s}){return s=>a.forwardRef((l,r)=>a.createElement(s,Object.assign({ref:r,suffixCls:e,tagName:t},l)))}let C=a.forwardRef((e,t)=>{let{prefixCls:s,suffixCls:l,className:r,tagName:i}=e,n=_(e,["prefixCls","suffixCls","className","tagName"]),{getPrefixCls:o}=a.useContext(j.ConfigContext),d=o("layout",s),[c,m,u]=(0,O.default)(d),g=l?`${d}-${l}`:d;return c(a.createElement(i,Object.assign({className:(0,b.default)(s||g,r,m,u),ref:t},n)))}),S=a.forwardRef((e,t)=>{let{direction:s}=a.useContext(j.ConfigContext),[l,r]=a.useState([]),{prefixCls:i,className:n,rootClassName:o,children:d,hasSider:c,tagName:m,style:u}=e,g=_(e,["prefixCls","className","rootClassName","children","hasSider","tagName","style"]),x=(0,v.default)(g,["suffixCls"]),{getPrefixCls:p,className:h,style:f}=(0,j.useComponentConfig)("layout"),L=p("layout",i),C="boolean"==typeof c?c:!!l.length||(0,k.default)(d).some(e=>e.type===w.default),[S,M,P]=(0,O.default)(L),H=(0,b.default)(L,{[`${L}-has-sider`]:C,[`${L}-rtl`]:"rtl"===s},h,n,o,M,P),z=a.useMemo(()=>({siderHook:{addSider:e=>{r(t=>[].concat((0,y.default)(t),[e]))},removeSider:e=>{r(t=>t.filter(t=>t!==e))}}}),[]);return S(a.createElement(N.LayoutContext.Provider,{value:z},a.createElement(m,Object.assign({ref:t,className:H,style:Object.assign(Object.assign({},f),u)},x),d)))}),M=L({tagName:"div",displayName:"Layout"})(S),P=L({suffixCls:"header",tagName:"header",displayName:"Header"})(C),H=L({suffixCls:"footer",tagName:"footer",displayName:"Footer"})(C),z=L({suffixCls:"content",tagName:"main",displayName:"Content"})(C);M.Header=P,M.Footer=H,M.Content=z,M.Sider=w.default,M._InternalSiderContext=w.SiderContext,e.s(["Layout",0,M],372943);var T=e.i(60699);e.s(["Menu",()=>T.default],899268);var R=e.i(475254);let E=(0,R.default)("calendar",[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}]]);e.s(["Calendar",()=>E],87316);var U=e.i(399219);e.s(["ChevronUp",()=>U.default],655900);let V=(0,R.default)("minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);e.s(["Minus",()=>V],299023);let A=(0,R.default)("trending-up",[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]]);e.s(["TrendingUp",()=>A],25652);let B=(0,R.default)("user-check",[["path",{d:"m16 11 2 2 4-4",key:"9rsbq5"}],["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]]);e.s(["UserCheck",()=>B],882293)},761911,98740,e=>{"use strict";let t=(0,e.i(475254).default)("users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]]);e.s(["default",()=>t],98740),e.s(["Users",()=>t],761911)},111672,e=>{"use strict";var t=e.i(247167),a=e.i(843476),s=e.i(109799),l=e.i(785242),r=e.i(135214),i=e.i(218129),n=e.i(362133),o=e.i(477189),d=e.i(457202),c=e.i(299251),m=e.i(153702),u=e.i(439061),g=e.i(182399),x=e.i(234779),p=e.i(374615),h=e.i(210612),f=e.i(19732),y=e.i(872934),b=e.i(993914),v=e.i(330995),j=e.i(438957),N=e.i(777579),k=e.i(788191),w=e.i(983561),O=e.i(602073),_=e.i(928685),L=e.i(313603),C=e.i(232164),S=e.i(645526),M=e.i(366308),P=e.i(771674),H=e.i(592143),z=e.i(372943),T=e.i(899268),R=e.i(271645),E=e.i(708347),U=e.i(844444),V=e.i(371401);e.i(389083);var A=e.i(878894),B=e.i(87316);e.i(664659),e.i(655900);var $=e.i(531278),I=e.i(299023),D=e.i(25652),K=e.i(882293),F=e.i(761911),W=e.i(764205);let G=(...e)=>e.filter(Boolean).join(" ");function q({accessToken:e,width:t=220}){let s=(0,V.useDisableUsageIndicator)(),[l,r]=(0,R.useState)(!1),[i,n]=(0,R.useState)(!1),[o,d]=(0,R.useState)(null),[c,m]=(0,R.useState)(null),[u,g]=(0,R.useState)(!1),[x,p]=(0,R.useState)(null);(0,R.useEffect)(()=>{(async()=>{if(e){g(!0),p(null);try{let[t,a]=await Promise.all([(0,W.getRemainingUsers)(e),(0,W.getLicenseInfo)(e).catch(()=>null)]);d(t),m(a)}catch(e){console.error("Failed to fetch usage data:",e),p("Failed to load usage data")}finally{g(!1)}}})()},[e]);let h=c?.expiration_date?(e=>{if(!e)return null;let t=new Date(e+"T00:00:00Z"),a=new Date;return a.setHours(0,0,0,0),Math.ceil((t.getTime()-a.getTime())/864e5)})(c.expiration_date):null,f=null!==h&&h<0,y=null!==h&&h>=0&&h<30,{isOverLimit:b,isNearLimit:v,usagePercentage:j,userMetrics:N,teamMetrics:k}=(e=>{if(!e)return{isOverLimit:!1,isNearLimit:!1,usagePercentage:0,userMetrics:{isOverLimit:!1,isNearLimit:!1,usagePercentage:0},teamMetrics:{isOverLimit:!1,isNearLimit:!1,usagePercentage:0}};let t=e.total_users?e.total_users_used/e.total_users*100:0,a=t>100,s=t>=80&&t<=100,l=e.total_teams?e.total_teams_used/e.total_teams*100:0,r=l>100,i=l>=80&&l<=100,n=a||r;return{isOverLimit:n,isNearLimit:(s||i)&&!n,usagePercentage:Math.max(t,l),userMetrics:{isOverLimit:a,isNearLimit:s,usagePercentage:t},teamMetrics:{isOverLimit:r,isNearLimit:i,usagePercentage:l}}})(o),w=b||v||f||y,O=b||f,_=(v||y)&&!O;return s||!e||o?.total_users===null&&o?.total_teams===null?null:(0,a.jsx)("div",{className:"fixed bottom-4 left-4 z-50",style:{width:`${Math.min(t,220)}px`},children:(0,a.jsx)(()=>i?(0,a.jsx)("button",{onClick:()=>n(!1),className:G("bg-white border border-gray-200 rounded-lg shadow-sm p-3 hover:shadow-md transition-all w-full"),title:"Show usage details",children:(0,a.jsxs)("div",{className:"flex items-center gap-2",children:[(0,a.jsx)(F.Users,{className:"h-4 w-4 flex-shrink-0"}),w&&(0,a.jsx)("span",{className:"flex-shrink-0",children:O?(0,a.jsx)(A.AlertTriangle,{className:"h-3 w-3"}):_?(0,a.jsx)(D.TrendingUp,{className:"h-3 w-3"}):null}),(0,a.jsxs)("div",{className:"flex items-center gap-2 text-sm font-medium truncate",children:[o&&null!==o.total_users&&(0,a.jsxs)("span",{className:G("flex-shrink-0 px-1.5 py-0.5 rounded text-xs border",N.isOverLimit&&"bg-red-50 text-red-700 border-red-200",N.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!N.isOverLimit&&!N.isNearLimit&&"bg-gray-50 text-gray-700 border-gray-200"),children:["U: ",o.total_users_used,"/",o.total_users]}),o&&null!==o.total_teams&&(0,a.jsxs)("span",{className:G("flex-shrink-0 px-1.5 py-0.5 rounded text-xs border",k.isOverLimit&&"bg-red-50 text-red-700 border-red-200",k.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!k.isOverLimit&&!k.isNearLimit&&"bg-gray-50 text-gray-700 border-gray-200"),children:["T: ",o.total_teams_used,"/",o.total_teams]}),c?.expiration_date&&null!==h&&(0,a.jsx)("span",{className:G("flex-shrink-0 px-1.5 py-0.5 rounded text-xs border",f&&"bg-red-50 text-red-700 border-red-200",y&&"bg-yellow-50 text-yellow-700 border-yellow-200",!f&&!y&&"bg-gray-50 text-gray-700 border-gray-200"),children:h<0?"Exp!":`${h}d`}),!o||null===o.total_users&&null===o.total_teams&&!c&&(0,a.jsx)("span",{className:"truncate",children:"Usage"})]})]})}):u?(0,a.jsx)("div",{className:"bg-white border border-gray-200 rounded-lg shadow-sm p-4 w-full",children:(0,a.jsxs)("div",{className:"flex items-center justify-center gap-2 py-2",children:[(0,a.jsx)($.Loader2,{className:"h-4 w-4 animate-spin"}),(0,a.jsx)("span",{className:"text-sm text-gray-500 truncate",children:"Loading..."})]})}):x||!o?(0,a.jsx)("div",{className:"bg-white border border-gray-200 rounded-lg shadow-sm p-4 group w-full",children:(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,a.jsx)("div",{className:"flex-1 min-w-0",children:(0,a.jsx)("span",{className:"text-sm text-gray-500 truncate block",children:x||"No data"})}),(0,a.jsx)("button",{onClick:()=>n(!0),className:"opacity-0 group-hover:opacity-100 p-1 hover:bg-gray-100 rounded transition-all flex-shrink-0",title:"Minimize",children:(0,a.jsx)(I.Minus,{className:"h-3 w-3 text-gray-400"})})]})}):(0,a.jsxs)("div",{className:G("bg-white border rounded-lg shadow-sm p-3 transition-all duration-200 group w-full"),children:[(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2 mb-3",children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 min-w-0 flex-1",children:[(0,a.jsx)(F.Users,{className:"h-4 w-4 flex-shrink-0"}),(0,a.jsx)("span",{className:"font-medium text-sm truncate",children:"Usage"})]}),(0,a.jsx)("button",{onClick:()=>n(!0),className:"opacity-0 group-hover:opacity-100 p-1 hover:bg-gray-100 rounded transition-all flex-shrink-0",title:"Minimize",children:(0,a.jsx)(I.Minus,{className:"h-3 w-3 text-gray-400"})})]}),(0,a.jsxs)("div",{className:"space-y-3 text-sm",children:[c?.has_license&&c.expiration_date&&(0,a.jsxs)("div",{className:G("space-y-1 border rounded-md p-2",f&&"border-red-200 bg-red-50",y&&"border-yellow-200 bg-yellow-50"),children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-600 mb-1",children:[(0,a.jsx)(B.Calendar,{className:"h-3 w-3"}),(0,a.jsx)("span",{className:"font-medium",children:"License"}),(0,a.jsx)("span",{className:G("ml-1 px-1.5 py-0.5 rounded border",f&&"bg-red-50 text-red-700 border-red-200",y&&"bg-yellow-50 text-yellow-700 border-yellow-200",!f&&!y&&"bg-gray-50 text-gray-600 border-gray-200"),children:f?"Expired":y?"Expiring soon":"OK"})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Status:"}),(0,a.jsx)("span",{className:G("font-medium text-right",f&&"text-red-600",y&&"text-yellow-600"),children:(e=>{if(null===e)return"No expiration";if(e<0)return"Expired";if(0===e)return"Expires today";if(1===e)return"1 day remaining";if(e<30)return`${e} days remaining`;if(e<60)return"1 month remaining";let t=Math.floor(e/30);return`${t} months remaining`})(h)})]}),c.license_type&&(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Type:"}),(0,a.jsx)("span",{className:"font-medium text-right capitalize",children:c.license_type})]})]}),null!==o.total_users&&(0,a.jsxs)("div",{className:G("space-y-1 border rounded-md p-2",N.isOverLimit&&"border-red-200 bg-red-50",N.isNearLimit&&"border-yellow-200 bg-yellow-50"),children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-600 mb-1",children:[(0,a.jsx)(F.Users,{className:"h-3 w-3"}),(0,a.jsx)("span",{className:"font-medium",children:"Users"}),(0,a.jsx)("span",{className:G("ml-1 px-1.5 py-0.5 rounded border",N.isOverLimit&&"bg-red-50 text-red-700 border-red-200",N.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!N.isOverLimit&&!N.isNearLimit&&"bg-gray-50 text-gray-600 border-gray-200"),children:N.isOverLimit?"Over limit":N.isNearLimit?"Near limit":"OK"})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Used:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[o.total_users_used,"/",o.total_users]})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Remaining:"}),(0,a.jsx)("span",{className:G("font-medium text-right",N.isOverLimit&&"text-red-600",N.isNearLimit&&"text-yellow-600"),children:o.total_users_remaining})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Usage:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[Math.round(N.usagePercentage),"%"]})]}),(0,a.jsx)("div",{className:"w-full bg-gray-200 rounded-full h-2",children:(0,a.jsx)("div",{className:G("h-2 rounded-full transition-all duration-300",N.isOverLimit&&"bg-red-500",N.isNearLimit&&"bg-yellow-500",!N.isOverLimit&&!N.isNearLimit&&"bg-green-500"),style:{width:`${Math.min(N.usagePercentage,100)}%`}})})]}),null!==o.total_teams&&(0,a.jsxs)("div",{className:G("space-y-1 border rounded-md p-2",k.isOverLimit&&"border-red-200 bg-red-50",k.isNearLimit&&"border-yellow-200 bg-yellow-50"),children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-600 mb-1",children:[(0,a.jsx)(K.UserCheck,{className:"h-3 w-3"}),(0,a.jsx)("span",{className:"font-medium",children:"Teams"}),(0,a.jsx)("span",{className:G("ml-1 px-1.5 py-0.5 rounded border",k.isOverLimit&&"bg-red-50 text-red-700 border-red-200",k.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!k.isOverLimit&&!k.isNearLimit&&"bg-gray-50 text-gray-600 border-gray-200"),children:k.isOverLimit?"Over limit":k.isNearLimit?"Near limit":"OK"})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Used:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[o.total_teams_used,"/",o.total_teams]})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Remaining:"}),(0,a.jsx)("span",{className:G("font-medium text-right",k.isOverLimit&&"text-red-600",k.isNearLimit&&"text-yellow-600"),children:o.total_teams_remaining})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Usage:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[Math.round(k.usagePercentage),"%"]})]}),(0,a.jsx)("div",{className:"w-full bg-gray-200 rounded-full h-2",children:(0,a.jsx)("div",{className:G("h-2 rounded-full transition-all duration-300",k.isOverLimit&&"bg-red-500",k.isNearLimit&&"bg-yellow-500",!k.isOverLimit&&!k.isNearLimit&&"bg-green-500"),style:{width:`${Math.min(k.usagePercentage,100)}%`}})})]})]})]}),{})})}let{Sider:Y}=z.Layout,X={"api-reference":"api-reference"},Z=[{groupLabel:"AI GATEWAY",items:[{key:"api-keys",page:"api-keys",label:"Virtual Keys",icon:(0,a.jsx)(j.KeyOutlined,{})},{key:"llm-playground",page:"llm-playground",label:"Playground",icon:(0,a.jsx)(k.PlayCircleOutlined,{}),roles:E.rolesWithWriteAccess},{key:"models",page:"models",label:"Models + Endpoints",icon:(0,a.jsx)(g.BlockOutlined,{}),roles:E.rolesAllowedToViewWriteScopedPages},{key:"agentic",page:"agentic",label:"Agentic",icon:(0,a.jsx)(w.RobotOutlined,{}),children:[{key:"agents",page:"agents",label:"Agents",icon:(0,a.jsx)(w.RobotOutlined,{}),roles:E.rolesAllowedToViewWriteScopedPages},{key:"workflows",page:"workflows",label:"Workflow Runs",icon:(0,a.jsx)(n.ApartmentOutlined,{})},{key:"memory",page:"memory",label:"Memory",icon:(0,a.jsx)(x.BookOutlined,{})}]},{key:"mcp-servers",page:"mcp-servers",label:"MCP Servers",icon:(0,a.jsx)(M.ToolOutlined,{})},{key:"skills",page:"skills",label:"Skills",icon:(0,a.jsx)(i.ApiOutlined,{}),roles:E.all_admin_roles},{key:"guardrails",page:"guardrails",label:"Guardrails",icon:(0,a.jsx)(O.SafetyOutlined,{})},{key:"policies",page:"policies",label:(0,a.jsx)("span",{className:"flex items-center gap-4",children:"Policies"}),icon:(0,a.jsx)(d.AuditOutlined,{}),roles:E.all_admin_roles},{key:"tools",page:"tools",label:"Tools",icon:(0,a.jsx)(M.ToolOutlined,{}),children:[{key:"search-tools",page:"search-tools",label:"Search Tools",icon:(0,a.jsx)(_.SearchOutlined,{})},{key:"vector-stores",page:"vector-stores",label:"Vector Stores",icon:(0,a.jsx)(h.DatabaseOutlined,{})},{key:"tool-policies",page:"tool-policies",label:"Tool Policies",icon:(0,a.jsx)(O.SafetyOutlined,{})}]}]},{groupLabel:"OBSERVABILITY",items:[{key:"new_usage",page:"new_usage",icon:(0,a.jsx)(m.BarChartOutlined,{}),roles:[...E.all_admin_roles,...E.internalUserRoles],label:"Usage"},{key:"logs",page:"logs",label:"Logs",icon:(0,a.jsx)(N.LineChartOutlined,{})},{key:"guardrails-monitor",page:"guardrails-monitor",label:"Guardrails Monitor",icon:(0,a.jsx)(O.SafetyOutlined,{}),roles:[...E.all_admin_roles,...E.internalUserRoles]}]},{groupLabel:"ACCESS CONTROL",items:[{key:"teams",page:"teams",label:"Teams",icon:(0,a.jsx)(S.TeamOutlined,{})},{key:"projects",page:"projects",label:(0,a.jsxs)("span",{className:"flex items-center gap-2",children:["Projects ",(0,a.jsx)(U.default,{})]}),icon:(0,a.jsx)(v.FolderOutlined,{}),roles:E.all_admin_roles},{key:"users",page:"users",label:"Internal Users",icon:(0,a.jsx)(P.UserOutlined,{}),roles:E.all_admin_roles},{key:"organizations",page:"organizations",label:"Organizations",icon:(0,a.jsx)(c.BankOutlined,{}),roles:E.all_admin_roles},{key:"access-groups",page:"access-groups",label:"Access Groups",icon:(0,a.jsx)(g.BlockOutlined,{}),roles:E.all_admin_roles},{key:"budgets",page:"budgets",label:"Budgets",icon:(0,a.jsx)(p.CreditCardOutlined,{}),roles:E.all_admin_roles}]},{groupLabel:"DEVELOPER TOOLS",items:[{key:"api-reference",page:"api-reference",label:"API Reference",icon:(0,a.jsx)(i.ApiOutlined,{})},{key:"model-hub-table",page:"model-hub-table",label:"AI Hub",icon:(0,a.jsx)(o.AppstoreOutlined,{})},{key:"learning-resources",page:"learning-resources",label:"Learning Resources",icon:(0,a.jsx)(x.BookOutlined,{}),external_url:"https://models.litellm.ai/cookbook"},{key:"experimental",page:"experimental",label:"Experimental",icon:(0,a.jsx)(f.ExperimentOutlined,{}),children:[{key:"caching",page:"caching",label:"Caching",icon:(0,a.jsx)(h.DatabaseOutlined,{}),roles:E.all_admin_roles},{key:"prompts",page:"prompts",label:"Prompts",icon:(0,a.jsx)(b.FileTextOutlined,{}),roles:E.all_admin_roles},{key:"transform-request",page:"transform-request",label:"API Playground",icon:(0,a.jsx)(i.ApiOutlined,{}),roles:[...E.all_admin_roles,...E.internalUserRoles]},{key:"tag-management",page:"tag-management",label:"Tag Management",icon:(0,a.jsx)(C.TagsOutlined,{}),roles:E.all_admin_roles},{key:"4",page:"usage",label:"Old Usage",icon:(0,a.jsx)(m.BarChartOutlined,{})}]}]},{groupLabel:"SETTINGS",roles:E.all_admin_roles,items:[{key:"settings",page:"settings",label:(0,a.jsxs)("span",{className:"flex items-center gap-2",children:["Settings ",(0,a.jsx)(U.default,{})]}),icon:(0,a.jsx)(L.SettingOutlined,{}),roles:E.all_admin_roles,children:[{key:"router-settings",page:"router-settings",label:"Router Settings",icon:(0,a.jsx)(L.SettingOutlined,{}),roles:E.all_admin_roles},{key:"logging-and-alerts",page:"logging-and-alerts",label:"Logging & Alerts",icon:(0,a.jsx)(L.SettingOutlined,{}),roles:E.all_admin_roles},{key:"admin-panel",page:"admin-panel",label:(0,a.jsxs)("span",{className:"flex items-center gap-2",children:["Admin Settings ",(0,a.jsx)(U.default,{dot:!0,children:(0,a.jsx)("span",{})})]}),icon:(0,a.jsx)(L.SettingOutlined,{}),roles:E.all_admin_roles},{key:"cost-tracking",page:"cost-tracking",label:"Cost Tracking",icon:(0,a.jsx)(m.BarChartOutlined,{}),roles:E.all_admin_roles},{key:"ui-theme",page:"ui-theme",label:"UI Theme",icon:(0,a.jsx)(u.BgColorsOutlined,{}),roles:E.all_admin_roles}]}]}];e.s(["default",0,({setPage:e,defaultSelectedKey:i,collapsed:n=!1,enabledPagesInternalUsers:o,enableProjectsUI:d,disableAgentsForInternalUsers:c,allowAgentsForTeamAdmins:m,disableVectorStoresForInternalUsers:u,allowVectorStoresForTeamAdmins:g})=>{let x,{userId:p,accessToken:h,userRole:f}=(0,r.default)(),{data:b}=(0,s.useOrganizations)(),{data:v}=(0,l.useTeams)(),j=(0,R.useMemo)(()=>!!p&&!!b&&b.some(e=>e.members?.some(e=>e.user_id===p&&"org_admin"===e.user_role)),[p,b]),N=(0,R.useMemo)(()=>(0,E.isUserTeamAdminForAnyTeam)(v??null,p??""),[v,p]),k=t=>{if(X[t])return void e(t);let a=new URLSearchParams(window.location.search);a.set("page",t),window.history.pushState(null,"",`?${a.toString()}`),e(t)},w=(e,s,l)=>{let r;if(l)return(0,a.jsxs)("a",{href:l,target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),style:{color:"inherit",textDecoration:"none"},children:[e," ",(0,a.jsx)(y.ExportOutlined,{style:{fontSize:10,marginLeft:4}})]});let i=X[s],n=i?function(e){let a=(t.default.env.NEXT_PUBLIC_BASE_URL??"").replace(/^\/+|\/+$/g,""),s=a?`/${a}/`:"/";if(W.serverRootPath&&"/"!==W.serverRootPath){let e=W.serverRootPath.replace(/\/+$/,""),t=s.replace(/^\/+/,"");s=`${e}/${t}`}return`${s}${e}`}(i):((r=new URLSearchParams(window.location.search)).set("page",s),`?${r.toString()}`);return(0,a.jsx)("a",{href:n,onClick:e=>{e.metaKey||e.ctrlKey||e.shiftKey||1===e.button?e.stopPropagation():e.preventDefault()},style:{color:"inherit",textDecoration:"none"},children:e})},O=e=>{let t=(0,E.isAdminRole)(f);return null!=o&&console.log("[LeftNav] Filtering with enabled pages:",{userRole:f,isAdmin:t,enabledPagesInternalUsers:o}),e.map(e=>({...e,children:e.children?O(e.children):void 0})).filter(e=>{if("organizations"===e.key||"users"===e.key){if(!(!e.roles||e.roles.includes(f)||j))return!1;if(!t&&null!=o){let t=o.includes(e.page);return console.log(`[LeftNav] Page "${e.page}" (${e.key}): ${t?"VISIBLE":"HIDDEN"}`),t}return!0}if("projects"===e.key&&!d||!t&&"agents"===e.key&&c&&!(m&&N)||!t&&"vector-stores"===e.key&&u&&!(g&&N)||e.roles&&!e.roles.includes(f))return!1;if(!t&&null!=o){if(e.children&&e.children.length>0&&e.children.some(e=>o.includes(e.page)))return console.log(`[LeftNav] Parent "${e.page}" (${e.key}): VISIBLE (has visible children)`),!0;let t=o.includes(e.page);return console.log(`[LeftNav] Page "${e.page}" (${e.key}): ${t?"VISIBLE":"HIDDEN"}`),t}return!0})},_=(e=>{for(let t of Z)for(let a of t.items){if(a.page===e)return a.key;if(a.children){let t=a.children.find(t=>t.page===e);if(t)return t.key}}return"api-keys"})(i);return(0,a.jsx)(z.Layout,{children:(0,a.jsxs)(Y,{theme:"light",width:220,collapsed:n,collapsedWidth:80,collapsible:!0,trigger:null,style:{transition:"all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",position:"relative"},children:[(0,a.jsx)(H.ConfigProvider,{theme:{components:{Menu:{iconSize:15,fontSize:13,itemMarginInline:4,itemPaddingInline:8,itemHeight:30,itemBorderRadius:6,subMenuItemBorderRadius:6,groupTitleFontSize:10,groupTitleLineHeight:1.5}}},children:(0,a.jsx)(T.Menu,{mode:"inline",selectedKeys:[_],defaultOpenKeys:[],inlineCollapsed:n,className:"custom-sidebar-menu",style:{borderRight:0,backgroundColor:"transparent",fontSize:"13px",paddingTop:"4px"},items:(x=[],Z.forEach(e=>{if(e.roles&&!e.roles.includes(f))return;let t=O(e.items);0!==t.length&&x.push({type:"group",label:n?null:(0,a.jsx)("span",{style:{fontSize:"10px",fontWeight:600,color:"#6b7280",letterSpacing:"0.05em",padding:"12px 0 4px 12px",display:"block",marginBottom:"2px"},children:e.groupLabel}),children:t.map(e=>({key:e.key,icon:e.icon,label:w(e.label,e.page,e.external_url),children:e.children?.map(e=>({key:e.key,icon:e.icon,label:w(e.label,e.page,e.external_url),onClick:()=>{e.external_url?window.open(e.external_url,"_blank"):k(e.page)}})),onClick:e.children?void 0:()=>{e.external_url?window.open(e.external_url,"_blank"):k(e.page)}}))})}),x)})}),(0,E.isAdminRole)(f)&&!n&&(0,a.jsx)(q,{accessToken:h,width:220})]})})},"menuGroups",()=>Z],111672)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/04711b0f8ffa7bbd.js b/litellm/proxy/_experimental/out/_next/static/chunks/04711b0f8ffa7bbd.js new file mode 100644 index 00000000000..6cfa66f43a4 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/04711b0f8ffa7bbd.js @@ -0,0 +1,7 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,309821,e=>{"use strict";e.i(247167);var t=e.i(271645);e.i(262370);var r=e.i(135551),n=e.i(201072),o=e.i(121229),i=e.i(726289),l=e.i(864517),a=e.i(343794),s=e.i(529681),c=e.i(242064),u=e.i(931067),d=e.i(209428),p=e.i(703923),f={percent:0,prefixCls:"rc-progress",strokeColor:"#2db7f5",strokeLinecap:"round",strokeWidth:1,trailColor:"#D9D9D9",trailWidth:1,gapPosition:"bottom"},g=function(){var e=(0,t.useRef)([]),r=(0,t.useRef)(null);return(0,t.useEffect)(function(){var t=Date.now(),n=!1;e.current.forEach(function(e){if(e){n=!0;var o=e.style;o.transitionDuration=".3s, .3s, .3s, .06s",r.current&&t-r.current<100&&(o.transitionDuration="0s, 0s")}}),n&&(r.current=Date.now())}),e.current},m=e.i(410160),b=e.i(392221),h=e.i(654310),v=0,y=(0,h.default)();let $=function(e){var r=t.useState(),n=(0,b.default)(r,2),o=n[0],i=n[1];return t.useEffect(function(){var e;i("rc_progress_".concat((y?(e=v,v+=1):e="TEST_OR_SSR",e)))},[]),e||o};var C=function(e){var r=e.bg,n=e.children;return t.createElement("div",{style:{width:"100%",height:"100%",background:r}},n)};function k(e,t){return Object.keys(e).map(function(r){var n=parseFloat(r),o="".concat(Math.floor(n*t),"%");return"".concat(e[r]," ").concat(o)})}var x=t.forwardRef(function(e,r){var n=e.prefixCls,o=e.color,i=e.gradientId,l=e.radius,a=e.style,s=e.ptg,c=e.strokeLinecap,u=e.strokeWidth,d=e.size,p=e.gapDegree,f=o&&"object"===(0,m.default)(o),g=d/2,b=t.createElement("circle",{className:"".concat(n,"-circle-path"),r:l,cx:g,cy:g,stroke:f?"#FFF":void 0,strokeLinecap:c,strokeWidth:u,opacity:+(0!==s),style:a,ref:r});if(!f)return b;var h="".concat(i,"-conic"),v=k(o,(360-p)/360),y=k(o,1),$="conic-gradient(from ".concat(p?"".concat(180+p/2,"deg"):"0deg",", ").concat(v.join(", "),")"),x="linear-gradient(to ".concat(p?"bottom":"top",", ").concat(y.join(", "),")");return t.createElement(t.Fragment,null,t.createElement("mask",{id:h},b),t.createElement("foreignObject",{x:0,y:0,width:d,height:d,mask:"url(#".concat(h,")")},t.createElement(C,{bg:x},t.createElement(C,{bg:$}))))}),S=function(e,t,r,n,o,i,l,a,s,c){var u=arguments.length>10&&void 0!==arguments[10]?arguments[10]:0,d=(100-n)/100*t;return"round"===s&&100!==n&&(d+=c/2)>=t&&(d=t-.01),{stroke:"string"==typeof a?a:void 0,strokeDasharray:"".concat(t,"px ").concat(e),strokeDashoffset:d+u,transform:"rotate(".concat(o+r/100*360*((360-i)/360)+(0===i?0:({bottom:0,top:180,left:90,right:-90})[l]),"deg)"),transformOrigin:"".concat(50,"px ").concat(50,"px"),transition:"stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s",fillOpacity:0}},O=["id","prefixCls","steps","strokeWidth","trailWidth","gapDegree","gapPosition","trailColor","strokeLinecap","style","className","strokeColor","percent"];function w(e){var t=null!=e?e:[];return Array.isArray(t)?t:[t]}let E=function(e){var r,n,o,i,l=(0,d.default)((0,d.default)({},f),e),s=l.id,c=l.prefixCls,b=l.steps,h=l.strokeWidth,v=l.trailWidth,y=l.gapDegree,C=void 0===y?0:y,k=l.gapPosition,E=l.trailColor,j=l.strokeLinecap,N=l.style,I=l.className,P=l.strokeColor,D=l.percent,R=(0,p.default)(l,O),z=$(s),A="".concat(z,"-gradient"),M=50-h/2,T=2*Math.PI*M,W=C>0?90+C/2:-90,B=(360-C)/360*T,F="object"===(0,m.default)(b)?b:{count:b,gap:2},X=F.count,L=F.gap,H=w(D),_=w(P),q=_.find(function(e){return e&&"object"===(0,m.default)(e)}),G=q&&"object"===(0,m.default)(q)?"butt":j,V=S(T,B,0,100,W,C,k,E,G,h),K=g();return t.createElement("svg",(0,u.default)({className:(0,a.default)("".concat(c,"-circle"),I),viewBox:"0 0 ".concat(100," ").concat(100),style:N,id:s,role:"presentation"},R),!X&&t.createElement("circle",{className:"".concat(c,"-circle-trail"),r:M,cx:50,cy:50,stroke:E,strokeLinecap:G,strokeWidth:v||h,style:V}),X?(r=Math.round(X*(H[0]/100)),n=100/X,o=0,Array(X).fill(null).map(function(e,i){var l=i<=r-1?_[0]:E,a=l&&"object"===(0,m.default)(l)?"url(#".concat(A,")"):void 0,s=S(T,B,o,n,W,C,k,l,"butt",h,L);return o+=(B-s.strokeDashoffset+L)*100/B,t.createElement("circle",{key:i,className:"".concat(c,"-circle-path"),r:M,cx:50,cy:50,stroke:a,strokeWidth:h,opacity:1,style:s,ref:function(e){K[i]=e}})})):(i=0,H.map(function(e,r){var n=_[r]||_[_.length-1],o=S(T,B,i,e,W,C,k,n,G,h);return i+=e,t.createElement(x,{key:r,color:n,ptg:e,radius:M,prefixCls:c,gradientId:A,style:o,strokeLinecap:G,strokeWidth:h,gapDegree:C,ref:function(e){K[r]=e},size:100})}).reverse()))};var j=e.i(491816);e.i(765846);var N=e.i(896091);function I(e){return!e||e<0?0:e>100?100:e}function P({success:e,successPercent:t}){let r=t;return e&&"progress"in e&&(r=e.progress),e&&"percent"in e&&(r=e.percent),r}let D=(e,t,r)=>{var n,o,i,l;let a=-1,s=-1;if("step"===t){let t=r.steps,n=r.strokeWidth;"string"==typeof e||void 0===e?(a="small"===e?2:14,s=null!=n?n:8):"number"==typeof e?[a,s]=[e,e]:[a=14,s=8]=Array.isArray(e)?e:[e.width,e.height],a*=t}else if("line"===t){let t=null==r?void 0:r.strokeWidth;"string"==typeof e||void 0===e?s=t||("small"===e?6:8):"number"==typeof e?[a,s]=[e,e]:[a=-1,s=8]=Array.isArray(e)?e:[e.width,e.height]}else("circle"===t||"dashboard"===t)&&("string"==typeof e||void 0===e?[a,s]="small"===e?[60,60]:[120,120]:"number"==typeof e?[a,s]=[e,e]:Array.isArray(e)&&(a=null!=(o=null!=(n=e[0])?n:e[1])?o:120,s=null!=(l=null!=(i=e[0])?i:e[1])?l:120));return[a,s]},R=e=>{let{prefixCls:r,trailColor:n=null,strokeLinecap:o="round",gapPosition:i,gapDegree:l,width:s=120,type:c,children:u,success:d,size:p=s,steps:f}=e,[g,m]=D(p,"circle"),{strokeWidth:b}=e;void 0===b&&(b=Math.max(3/g*100,6));let h=t.useMemo(()=>l||0===l?l:"dashboard"===c?75:void 0,[l,c]),v=(({percent:e,success:t,successPercent:r})=>{let n=I(P({success:t,successPercent:r}));return[n,I(I(e)-n)]})(e),y="[object Object]"===Object.prototype.toString.call(e.strokeColor),$=(({success:e={},strokeColor:t})=>{let{strokeColor:r}=e;return[r||N.presetPrimaryColors.green,t||null]})({success:d,strokeColor:e.strokeColor}),C=(0,a.default)(`${r}-inner`,{[`${r}-circle-gradient`]:y}),k=t.createElement(E,{steps:f,percent:f?v[1]:v,strokeWidth:b,trailWidth:b,strokeColor:f?$[1]:$,strokeLinecap:o,trailColor:n,prefixCls:r,gapDegree:h,gapPosition:i||"dashboard"===c&&"bottom"||void 0}),x=g<=20,S=t.createElement("div",{className:C,style:{width:g,height:m,fontSize:.15*g+6}},k,!x&&u);return x?t.createElement(j.default,{title:u},S):S};e.i(296059);var z=e.i(694758),A=e.i(915654),M=e.i(183293),T=e.i(246422),W=e.i(838378);let B="--progress-line-stroke-color",F="--progress-percent",X=e=>{let t=e?"100%":"-100%";return new z.Keyframes(`antProgress${e?"RTL":"LTR"}Active`,{"0%":{transform:`translateX(${t}) scaleX(0)`,opacity:.1},"20%":{transform:`translateX(${t}) scaleX(0)`,opacity:.5},to:{transform:"translateX(0) scaleX(1)",opacity:0}})},L=(0,T.genStyleHooks)("Progress",e=>{let t=e.calc(e.marginXXS).div(2).equal(),r=(0,W.mergeToken)(e,{progressStepMarginInlineEnd:t,progressStepMinWidth:t,progressActiveMotionDuration:"2.4s"});return[(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:Object.assign(Object.assign({},(0,M.resetComponent)(e)),{display:"inline-block","&-rtl":{direction:"rtl"},"&-line":{position:"relative",width:"100%",fontSize:e.fontSize},[`${t}-outer`]:{display:"inline-flex",alignItems:"center",width:"100%"},[`${t}-inner`]:{position:"relative",display:"inline-block",width:"100%",flex:1,overflow:"hidden",verticalAlign:"middle",backgroundColor:e.remainingColor,borderRadius:e.lineBorderRadius},[`${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.defaultColor}},[`${t}-success-bg, ${t}-bg`]:{position:"relative",background:e.defaultColor,borderRadius:e.lineBorderRadius,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`},[`${t}-layout-bottom`]:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",[`${t}-text`]:{width:"max-content",marginInlineStart:0,marginTop:e.marginXXS}},[`${t}-bg`]:{overflow:"hidden","&::after":{content:'""',background:{_multi_value_:!0,value:["inherit",`var(${B})`]},height:"100%",width:`calc(1 / var(${F}) * 100%)`,display:"block"},[`&${t}-bg-inner`]:{minWidth:"max-content","&::after":{content:"none"},[`${t}-text-inner`]:{color:e.colorWhite,[`&${t}-text-bright`]:{color:"rgba(0, 0, 0, 0.45)"}}}},[`${t}-success-bg`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,backgroundColor:e.colorSuccess},[`${t}-text`]:{display:"inline-block",marginInlineStart:e.marginXS,color:e.colorText,lineHeight:1,width:"2em",whiteSpace:"nowrap",textAlign:"start",verticalAlign:"middle",wordBreak:"normal",[r]:{fontSize:e.fontSize},[`&${t}-text-outer`]:{width:"max-content"},[`&${t}-text-outer${t}-text-start`]:{width:"max-content",marginInlineStart:0,marginInlineEnd:e.marginXS}},[`${t}-text-inner`]:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%",marginInlineStart:0,padding:`0 ${(0,A.unit)(e.paddingXXS)}`,[`&${t}-text-start`]:{justifyContent:"start"},[`&${t}-text-end`]:{justifyContent:"end"}},[`&${t}-status-active`]:{[`${t}-bg::before`]:{position:"absolute",inset:0,backgroundColor:e.colorBgContainer,borderRadius:e.lineBorderRadius,opacity:0,animationName:X(),animationDuration:e.progressActiveMotionDuration,animationTimingFunction:e.motionEaseOutQuint,animationIterationCount:"infinite",content:'""'}},[`&${t}-rtl${t}-status-active`]:{[`${t}-bg::before`]:{animationName:X(!0)}},[`&${t}-status-exception`]:{[`${t}-bg`]:{backgroundColor:e.colorError},[`${t}-text`]:{color:e.colorError}},[`&${t}-status-exception ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorError}},[`&${t}-status-success`]:{[`${t}-bg`]:{backgroundColor:e.colorSuccess},[`${t}-text`]:{color:e.colorSuccess}},[`&${t}-status-success ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorSuccess}}})}})(r),(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:{[`${t}-circle-trail`]:{stroke:e.remainingColor},[`&${t}-circle ${t}-inner`]:{position:"relative",lineHeight:1,backgroundColor:"transparent"},[`&${t}-circle ${t}-text`]:{position:"absolute",insetBlockStart:"50%",insetInlineStart:0,width:"100%",margin:0,padding:0,color:e.circleTextColor,fontSize:e.circleTextFontSize,lineHeight:1,whiteSpace:"normal",textAlign:"center",transform:"translateY(-50%)",[r]:{fontSize:e.circleIconFontSize}},[`${t}-circle&-status-exception`]:{[`${t}-text`]:{color:e.colorError}},[`${t}-circle&-status-success`]:{[`${t}-text`]:{color:e.colorSuccess}}},[`${t}-inline-circle`]:{lineHeight:1,[`${t}-inner`]:{verticalAlign:"bottom"}}}})(r),(e=>{let{componentCls:t}=e;return{[t]:{[`${t}-steps`]:{display:"inline-block","&-outer":{display:"flex",flexDirection:"row",alignItems:"center"},"&-item":{flexShrink:0,minWidth:e.progressStepMinWidth,marginInlineEnd:e.progressStepMarginInlineEnd,backgroundColor:e.remainingColor,transition:`all ${e.motionDurationSlow}`,"&-active":{backgroundColor:e.defaultColor}}}}}})(r),(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:{[`${t}-small&-line, ${t}-small&-line ${t}-text ${r}`]:{fontSize:e.fontSizeSM}}}})(r)]},e=>({circleTextColor:e.colorText,defaultColor:e.colorInfo,remainingColor:e.colorFillSecondary,lineBorderRadius:100,circleTextFontSize:"1em",circleIconFontSize:`${e.fontSize/e.fontSizeSM}em`}));var H=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let _=e=>{let{prefixCls:r,direction:n,percent:o,size:i,strokeWidth:l,strokeColor:s,strokeLinecap:c="round",children:u,trailColor:d=null,percentPosition:p,success:f}=e,{align:g,type:m}=p,b=s&&"string"!=typeof s?((e,t)=>{let{from:r=N.presetPrimaryColors.blue,to:n=N.presetPrimaryColors.blue,direction:o="rtl"===t?"to left":"to right"}=e,i=H(e,["from","to","direction"]);if(0!==Object.keys(i).length){let e,t=(e=[],Object.keys(i).forEach(t=>{let r=Number.parseFloat(t.replace(/%/g,""));Number.isNaN(r)||e.push({key:r,value:i[t]})}),(e=e.sort((e,t)=>e.key-t.key)).map(({key:e,value:t})=>`${t} ${e}%`).join(", ")),r=`linear-gradient(${o}, ${t})`;return{background:r,[B]:r}}let l=`linear-gradient(${o}, ${r}, ${n})`;return{background:l,[B]:l}})(s,n):{[B]:s,background:s},h="square"===c||"butt"===c?0:void 0,[v,y]=D(null!=i?i:[-1,l||("small"===i?6:8)],"line",{strokeWidth:l}),$=Object.assign(Object.assign({width:`${I(o)}%`,height:y,borderRadius:h},b),{[F]:I(o)/100}),C=P(e),k={width:`${I(C)}%`,height:y,borderRadius:h,backgroundColor:null==f?void 0:f.strokeColor},x=t.createElement("div",{className:`${r}-inner`,style:{backgroundColor:d||void 0,borderRadius:h}},t.createElement("div",{className:(0,a.default)(`${r}-bg`,`${r}-bg-${m}`),style:$},"inner"===m&&u),void 0!==C&&t.createElement("div",{className:`${r}-success-bg`,style:k})),S="outer"===m&&"start"===g,O="outer"===m&&"end"===g;return"outer"===m&&"center"===g?t.createElement("div",{className:`${r}-layout-bottom`},x,u):t.createElement("div",{className:`${r}-outer`,style:{width:v<0?"100%":v}},S&&u,x,O&&u)},q=e=>{let{size:r,steps:n,rounding:o=Math.round,percent:i=0,strokeWidth:l=8,strokeColor:s,trailColor:c=null,prefixCls:u,children:d}=e,p=o(i/100*n),[f,g]=D(null!=r?r:["small"===r?2:14,l],"step",{steps:n,strokeWidth:l}),m=f/n,b=Array.from({length:n});for(let e=0;et.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let V=["normal","exception","active","success"],K=t.forwardRef((e,u)=>{let d,{prefixCls:p,className:f,rootClassName:g,steps:m,strokeColor:b,percent:h=0,size:v="default",showInfo:y=!0,type:$="line",status:C,format:k,style:x,percentPosition:S={}}=e,O=G(e,["prefixCls","className","rootClassName","steps","strokeColor","percent","size","showInfo","type","status","format","style","percentPosition"]),{align:w="end",type:E="outer"}=S,j=Array.isArray(b)?b[0]:b,N="string"==typeof b||Array.isArray(b)?b:void 0,z=t.useMemo(()=>{if(j){let e="string"==typeof j?j:Object.values(j)[0];return new r.FastColor(e).isLight()}return!1},[b]),A=t.useMemo(()=>{var t,r;let n=P(e);return Number.parseInt(void 0!==n?null==(t=null!=n?n:0)?void 0:t.toString():null==(r=null!=h?h:0)?void 0:r.toString(),10)},[h,e.success,e.successPercent]),M=t.useMemo(()=>!V.includes(C)&&A>=100?"success":C||"normal",[C,A]),{getPrefixCls:T,direction:W,progress:B}=t.useContext(c.ConfigContext),F=T("progress",p),[X,H,K]=L(F),U="line"===$,Q=U&&!m,Y=t.useMemo(()=>{let r;if(!y)return null;let s=P(e),c=k||(e=>`${e}%`),u=U&&z&&"inner"===E;return"inner"===E||k||"exception"!==M&&"success"!==M?r=c(I(h),I(s)):"exception"===M?r=U?t.createElement(i.default,null):t.createElement(l.default,null):"success"===M&&(r=U?t.createElement(n.default,null):t.createElement(o.default,null)),t.createElement("span",{className:(0,a.default)(`${F}-text`,{[`${F}-text-bright`]:u,[`${F}-text-${w}`]:Q,[`${F}-text-${E}`]:Q}),title:"string"==typeof r?r:void 0},r)},[y,h,A,M,$,F,k]);"line"===$?d=m?t.createElement(q,Object.assign({},e,{strokeColor:N,prefixCls:F,steps:"object"==typeof m?m.count:m}),Y):t.createElement(_,Object.assign({},e,{strokeColor:j,prefixCls:F,direction:W,percentPosition:{align:w,type:E}}),Y):("circle"===$||"dashboard"===$)&&(d=t.createElement(R,Object.assign({},e,{strokeColor:j,prefixCls:F,progressStatus:M}),Y));let J=(0,a.default)(F,`${F}-status-${M}`,{[`${F}-${"dashboard"===$&&"circle"||$}`]:"line"!==$,[`${F}-inline-circle`]:"circle"===$&&D(v,"circle")[0]<=20,[`${F}-line`]:Q,[`${F}-line-align-${w}`]:Q,[`${F}-line-position-${E}`]:Q,[`${F}-steps`]:m,[`${F}-show-info`]:y,[`${F}-${v}`]:"string"==typeof v,[`${F}-rtl`]:"rtl"===W},null==B?void 0:B.className,f,g,H,K);return X(t.createElement("div",Object.assign({ref:u,style:Object.assign(Object.assign({},null==B?void 0:B.style),x),className:J,role:"progressbar","aria-valuenow":A,"aria-valuemin":0,"aria-valuemax":100},(0,s.default)(O,["trailColor","strokeWidth","width","gapDegree","gapPosition","strokeLinecap","success","successPercent"])),d))});e.s(["default",0,K],309821)},91874,e=>{"use strict";var t=e.i(931067),r=e.i(209428),n=e.i(211577),o=e.i(392221),i=e.i(703923),l=e.i(343794),a=e.i(914949),s=e.i(271645),c=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],u=(0,s.forwardRef)(function(e,u){var d=e.prefixCls,p=void 0===d?"rc-checkbox":d,f=e.className,g=e.style,m=e.checked,b=e.disabled,h=e.defaultChecked,v=e.type,y=void 0===v?"checkbox":v,$=e.title,C=e.onChange,k=(0,i.default)(e,c),x=(0,s.useRef)(null),S=(0,s.useRef)(null),O=(0,a.default)(void 0!==h&&h,{value:m}),w=(0,o.default)(O,2),E=w[0],j=w[1];(0,s.useImperativeHandle)(u,function(){return{focus:function(e){var t;null==(t=x.current)||t.focus(e)},blur:function(){var e;null==(e=x.current)||e.blur()},input:x.current,nativeElement:S.current}});var N=(0,l.default)(p,f,(0,n.default)((0,n.default)({},"".concat(p,"-checked"),E),"".concat(p,"-disabled"),b));return s.createElement("span",{className:N,title:$,style:g,ref:S},s.createElement("input",(0,t.default)({},k,{className:"".concat(p,"-input"),ref:x,onChange:function(t){b||("checked"in e||j(t.target.checked),null==C||C({target:(0,r.default)((0,r.default)({},e),{},{type:y,checked:t.target.checked}),stopPropagation:function(){t.stopPropagation()},preventDefault:function(){t.preventDefault()},nativeEvent:t.nativeEvent}))},disabled:b,checked:!!E,type:y})),s.createElement("span",{className:"".concat(p,"-inner")}))});e.s(["default",0,u])},681216,e=>{"use strict";var t=e.i(271645),r=e.i(963188);function n(e){let n=t.default.useRef(null),o=()=>{r.default.cancel(n.current),n.current=null};return[()=>{o(),n.current=(0,r.default)(()=>{n.current=null})},t=>{n.current&&(t.stopPropagation(),o()),null==e||e(t)}]}e.s(["default",()=>n])},421512,236836,e=>{"use strict";let t=e.i(271645).default.createContext(null);e.s(["default",0,t],421512),e.i(296059);var r=e.i(915654),n=e.i(183293),o=e.i(246422),i=e.i(838378);function l(e,t){return(e=>{let{checkboxCls:t}=e,o=`${t}-wrapper`;return[{[`${t}-group`]:Object.assign(Object.assign({},(0,n.resetComponent)(e)),{display:"inline-flex",flexWrap:"wrap",columnGap:e.marginXS,[`> ${e.antCls}-row`]:{flex:1}}),[o]:Object.assign(Object.assign({},(0,n.resetComponent)(e)),{display:"inline-flex",alignItems:"baseline",cursor:"pointer","&:after":{display:"inline-block",width:0,overflow:"hidden",content:"'\\a0'"},[`& + ${o}`]:{marginInlineStart:0},[`&${o}-in-form-item`]:{'input[type="checkbox"]':{width:14,height:14}}}),[t]:Object.assign(Object.assign({},(0,n.resetComponent)(e)),{position:"relative",whiteSpace:"nowrap",lineHeight:1,cursor:"pointer",borderRadius:e.borderRadiusSM,alignSelf:"center",[`${t}-input`]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0,margin:0,[`&:focus-visible + ${t}-inner`]:(0,n.genFocusOutline)(e)},[`${t}-inner`]:{boxSizing:"border-box",display:"block",width:e.checkboxSize,height:e.checkboxSize,direction:"ltr",backgroundColor:e.colorBgContainer,border:`${(0,r.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,borderCollapse:"separate",transition:`all ${e.motionDurationSlow}`,"&:after":{boxSizing:"border-box",position:"absolute",top:"50%",insetInlineStart:"25%",display:"table",width:e.calc(e.checkboxSize).div(14).mul(5).equal(),height:e.calc(e.checkboxSize).div(14).mul(8).equal(),border:`${(0,r.unit)(e.lineWidthBold)} solid ${e.colorWhite}`,borderTop:0,borderInlineStart:0,transform:"rotate(45deg) scale(0) translate(-50%,-50%)",opacity:0,content:'""',transition:`all ${e.motionDurationFast} ${e.motionEaseInBack}, opacity ${e.motionDurationFast}`}},"& + span":{paddingInlineStart:e.paddingXS,paddingInlineEnd:e.paddingXS}})},{[` + ${o}:not(${o}-disabled), + ${t}:not(${t}-disabled) + `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${o}:not(${o}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` + ${o}-checked:not(${o}-disabled), + ${t}-checked:not(${t}-disabled) + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorBorder}`,"&:after":{top:"50%",insetInlineStart:"50%",width:e.calc(e.fontSizeLG).div(2).equal(),height:e.calc(e.fontSizeLG).div(2).equal(),backgroundColor:e.colorPrimary,border:0,transform:"translate(-50%, -50%) scale(1)",opacity:1,content:'""'}},[`&:hover ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${o}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,i.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let a=(0,o.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[l(t,e)]);e.s(["default",0,a,"getStyle",()=>l],236836)},536916,374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),n=e.i(91874),o=e.i(611935),i=e.i(121872),l=e.i(26905),a=e.i(242064),s=e.i(937328),c=e.i(321883),u=e.i(62139),d=e.i(421512),p=e.i(236836),f=e.i(681216),g=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let m=t.forwardRef((e,m)=>{var b;let{prefixCls:h,className:v,rootClassName:y,children:$,indeterminate:C=!1,style:k,onMouseEnter:x,onMouseLeave:S,skipGroup:O=!1,disabled:w}=e,E=g(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:j,direction:N,checkbox:I}=t.useContext(a.ConfigContext),P=t.useContext(d.default),{isFormItemInput:D}=t.useContext(u.FormItemInputContext),R=t.useContext(s.default),z=null!=(b=(null==P?void 0:P.disabled)||w)?b:R,A=t.useRef(E.value),M=t.useRef(null),T=(0,o.composeRef)(m,M);t.useEffect(()=>{null==P||P.registerValue(E.value)},[]),t.useEffect(()=>{if(!O)return E.value!==A.current&&(null==P||P.cancelValue(A.current),null==P||P.registerValue(E.value),A.current=E.value),()=>null==P?void 0:P.cancelValue(E.value)},[E.value]),t.useEffect(()=>{var e;(null==(e=M.current)?void 0:e.input)&&(M.current.input.indeterminate=C)},[C]);let W=j("checkbox",h),B=(0,c.default)(W),[F,X,L]=(0,p.default)(W,B),H=Object.assign({},E);P&&!O&&(H.onChange=(...e)=>{E.onChange&&E.onChange.apply(E,e),P.toggleOption&&P.toggleOption({label:$,value:E.value})},H.name=P.name,H.checked=P.value.includes(E.value));let _=(0,r.default)(`${W}-wrapper`,{[`${W}-rtl`]:"rtl"===N,[`${W}-wrapper-checked`]:H.checked,[`${W}-wrapper-disabled`]:z,[`${W}-wrapper-in-form-item`]:D},null==I?void 0:I.className,v,y,L,B,X),q=(0,r.default)({[`${W}-indeterminate`]:C},l.TARGET_CLS,X),[G,V]=(0,f.default)(H.onClick);return F(t.createElement(i.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:_,style:Object.assign(Object.assign({},null==I?void 0:I.style),k),onMouseEnter:x,onMouseLeave:S,onClick:G},t.createElement(n.default,Object.assign({},H,{onClick:V,prefixCls:W,className:q,disabled:z,ref:T})),null!=$&&t.createElement("span",{className:`${W}-label`},$))))});var b=e.i(8211),h=e.i(529681),v=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let y=t.forwardRef((e,n)=>{let{defaultValue:o,children:i,options:l=[],prefixCls:s,className:u,rootClassName:f,style:g,onChange:y}=e,$=v(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:C,direction:k}=t.useContext(a.ConfigContext),[x,S]=t.useState($.value||o||[]),[O,w]=t.useState([]);t.useEffect(()=>{"value"in $&&S($.value||[])},[$.value]);let E=t.useMemo(()=>l.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[l]),j=e=>{w(t=>t.filter(t=>t!==e))},N=e=>{w(t=>[].concat((0,b.default)(t),[e]))},I=e=>{let t=x.indexOf(e.value),r=(0,b.default)(x);-1===t?r.push(e.value):r.splice(t,1),"value"in $||S(r),null==y||y(r.filter(e=>O.includes(e)).sort((e,t)=>E.findIndex(t=>t.value===e)-E.findIndex(e=>e.value===t)))},P=C("checkbox",s),D=`${P}-group`,R=(0,c.default)(P),[z,A,M]=(0,p.default)(P,R),T=(0,h.default)($,["value","disabled"]),W=l.length?E.map(e=>t.createElement(m,{prefixCls:P,key:e.value.toString(),disabled:"disabled"in e?e.disabled:$.disabled,value:e.value,checked:x.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${D}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):i,B=t.useMemo(()=>({toggleOption:I,value:x,disabled:$.disabled,name:$.name,registerValue:N,cancelValue:j}),[I,x,$.disabled,$.name,N,j]),F=(0,r.default)(D,{[`${D}-rtl`]:"rtl"===k},u,f,M,R,A);return z(t.createElement("div",Object.assign({className:F,style:g},T,{ref:n}),t.createElement(d.default.Provider,{value:B},W)))});m.Group=y,m.__ANT_CHECKBOX=!0,e.s(["default",0,m],374276),e.s(["Checkbox",0,m],536916)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0493aafc4891dd29.js b/litellm/proxy/_experimental/out/_next/static/chunks/0493aafc4891dd29.js deleted file mode 100644 index 90c97f4525a..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0493aafc4891dd29.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,312361,e=>{"use strict";e.i(247167);var t=e.i(271645),n=e.i(343794),r=e.i(242064),i=e.i(517455);e.i(296059);var a=e.i(915654),l=e.i(183293),o=e.i(246422),c=e.i(838378);let s=(0,o.genStyleHooks)("Divider",e=>{let t=(0,c.mergeToken)(e,{dividerHorizontalWithTextGutterMargin:e.margin,sizePaddingEdgeHorizontal:0});return[(e=>{let{componentCls:t,sizePaddingEdgeHorizontal:n,colorSplit:r,lineWidth:i,textPaddingInline:o,orientationMargin:c,verticalMarginInline:s}=e;return{[t]:Object.assign(Object.assign({},(0,l.resetComponent)(e)),{borderBlockStart:`${(0,a.unit)(i)} solid ${r}`,"&-vertical":{position:"relative",top:"-0.06em",display:"inline-block",height:"0.9em",marginInline:s,marginBlock:0,verticalAlign:"middle",borderTop:0,borderInlineStart:`${(0,a.unit)(i)} solid ${r}`},"&-horizontal":{display:"flex",clear:"both",width:"100%",minWidth:"100%",margin:`${(0,a.unit)(e.marginLG)} 0`},[`&-horizontal${t}-with-text`]:{display:"flex",alignItems:"center",margin:`${(0,a.unit)(e.dividerHorizontalWithTextGutterMargin)} 0`,color:e.colorTextHeading,fontWeight:500,fontSize:e.fontSizeLG,whiteSpace:"nowrap",textAlign:"center",borderBlockStart:`0 ${r}`,"&::before, &::after":{position:"relative",width:"50%",borderBlockStart:`${(0,a.unit)(i)} solid transparent`,borderBlockStartColor:"inherit",borderBlockEnd:0,transform:"translateY(50%)",content:"''"}},[`&-horizontal${t}-with-text-start`]:{"&::before":{width:`calc(${c} * 100%)`},"&::after":{width:`calc(100% - ${c} * 100%)`}},[`&-horizontal${t}-with-text-end`]:{"&::before":{width:`calc(100% - ${c} * 100%)`},"&::after":{width:`calc(${c} * 100%)`}},[`${t}-inner-text`]:{display:"inline-block",paddingBlock:0,paddingInline:o},"&-dashed":{background:"none",borderColor:r,borderStyle:"dashed",borderWidth:`${(0,a.unit)(i)} 0 0`},[`&-horizontal${t}-with-text${t}-dashed`]:{"&::before, &::after":{borderStyle:"dashed none none"}},[`&-vertical${t}-dashed`]:{borderInlineStartWidth:i,borderInlineEnd:0,borderBlockStart:0,borderBlockEnd:0},"&-dotted":{background:"none",borderColor:r,borderStyle:"dotted",borderWidth:`${(0,a.unit)(i)} 0 0`},[`&-horizontal${t}-with-text${t}-dotted`]:{"&::before, &::after":{borderStyle:"dotted none none"}},[`&-vertical${t}-dotted`]:{borderInlineStartWidth:i,borderInlineEnd:0,borderBlockStart:0,borderBlockEnd:0},[`&-plain${t}-with-text`]:{color:e.colorText,fontWeight:"normal",fontSize:e.fontSize},[`&-horizontal${t}-with-text-start${t}-no-default-orientation-margin-start`]:{"&::before":{width:0},"&::after":{width:"100%"},[`${t}-inner-text`]:{paddingInlineStart:n}},[`&-horizontal${t}-with-text-end${t}-no-default-orientation-margin-end`]:{"&::before":{width:"100%"},"&::after":{width:0},[`${t}-inner-text`]:{paddingInlineEnd:n}}})}})(t),(e=>{let{componentCls:t}=e;return{[t]:{"&-horizontal":{[`&${t}`]:{"&-sm":{marginBlock:e.marginXS},"&-md":{marginBlock:e.margin}}}}}})(t)]},e=>({textPaddingInline:"1em",orientationMargin:.05,verticalMarginInline:e.marginXS}),{unitless:{orientationMargin:!0}});var d=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let u={small:"sm",middle:"md"};e.s(["Divider",0,e=>{let{getPrefixCls:a,direction:l,className:o,style:c}=(0,r.useComponentConfig)("divider"),{prefixCls:g,type:m="horizontal",orientation:p="center",orientationMargin:h,className:f,rootClassName:b,children:$,dashed:y,variant:S="solid",plain:v,style:k,size:C}=e,w=d(e,["prefixCls","type","orientation","orientationMargin","className","rootClassName","children","dashed","variant","plain","style","size"]),I=a("divider",g),[x,O,E]=s(I),z=u[(0,i.default)(C)],j=!!$,N=t.useMemo(()=>"left"===p?"rtl"===l?"end":"start":"right"===p?"rtl"===l?"start":"end":p,[l,p]),P="start"===N&&null!=h,T="end"===N&&null!=h,M=(0,n.default)(I,o,O,E,`${I}-${m}`,{[`${I}-with-text`]:j,[`${I}-with-text-${N}`]:j,[`${I}-dashed`]:!!y,[`${I}-${S}`]:"solid"!==S,[`${I}-plain`]:!!v,[`${I}-rtl`]:"rtl"===l,[`${I}-no-default-orientation-margin-start`]:P,[`${I}-no-default-orientation-margin-end`]:T,[`${I}-${z}`]:!!z},f,b),B=t.useMemo(()=>"number"==typeof h?h:/^\d+$/.test(h)?Number(h):h,[h]);return x(t.createElement("div",Object.assign({className:M,style:Object.assign(Object.assign({},c),k)},w,{role:"separator"}),$&&"vertical"!==m&&t.createElement("span",{className:`${I}-inner-text`,style:{marginInlineStart:P?B:void 0,marginInlineEnd:T?B:void 0}},$)))}],312361)},801312,e=>{"use strict";e.i(247167);var t=e.i(931067),n=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"}}]},name:"left",theme:"outlined"};var i=e.i(9583),a=n.forwardRef(function(e,a){return n.createElement(i.default,(0,t.default)({},e,{ref:a,icon:r}))});e.s(["default",0,a],801312)},475254,e=>{"use strict";var t=e.i(271645);let n=e=>{let t=e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase());return t.charAt(0).toUpperCase()+t.slice(1)},r=(...e)=>e.filter((e,t,n)=>!!e&&""!==e.trim()&&n.indexOf(e)===t).join(" ").trim();var i={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"};let a=(0,t.forwardRef)(({color:e="currentColor",size:n=24,strokeWidth:a=2,absoluteStrokeWidth:l,className:o="",children:c,iconNode:s,...d},u)=>(0,t.createElement)("svg",{ref:u,...i,width:n,height:n,stroke:e,strokeWidth:l?24*Number(a)/Number(n):a,className:r("lucide",o),...!c&&!(e=>{for(let t in e)if(t.startsWith("aria-")||"role"===t||"title"===t)return!0})(d)&&{"aria-hidden":"true"},...d},[...s.map(([e,n])=>(0,t.createElement)(e,n)),...Array.isArray(c)?c:[c]])),l=(e,i)=>{let l=(0,t.forwardRef)(({className:l,...o},c)=>(0,t.createElement)(a,{ref:c,iconNode:i,className:r(`lucide-${n(e).replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`,`lucide-${e}`,l),...o}));return l.displayName=n(e),l};e.s(["default",()=>l],475254)},262218,e=>{"use strict";e.i(247167);var t=e.i(271645),n=e.i(343794),r=e.i(529681),i=e.i(702779),a=e.i(563113),l=e.i(763731),o=e.i(121872),c=e.i(242064);e.i(296059);var s=e.i(915654);e.i(262370);var d=e.i(135551),u=e.i(183293),g=e.i(246422),m=e.i(838378);let p=e=>{let{lineWidth:t,fontSizeIcon:n,calc:r}=e,i=e.fontSizeSM;return(0,m.mergeToken)(e,{tagFontSize:i,tagLineHeight:(0,s.unit)(r(e.lineHeightSM).mul(i).equal()),tagIconSize:r(n).sub(r(t).mul(2)).equal(),tagPaddingHorizontal:8,tagBorderlessBg:e.defaultBg})},h=e=>({defaultBg:new d.FastColor(e.colorFillQuaternary).onBackground(e.colorBgContainer).toHexString(),defaultColor:e.colorText}),f=(0,g.genStyleHooks)("Tag",e=>(e=>{let{paddingXXS:t,lineWidth:n,tagPaddingHorizontal:r,componentCls:i,calc:a}=e,l=a(r).sub(n).equal(),o=a(t).sub(n).equal();return{[i]:Object.assign(Object.assign({},(0,u.resetComponent)(e)),{display:"inline-block",height:"auto",marginInlineEnd:e.marginXS,paddingInline:l,fontSize:e.tagFontSize,lineHeight:e.tagLineHeight,whiteSpace:"nowrap",background:e.defaultBg,border:`${(0,s.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,opacity:1,transition:`all ${e.motionDurationMid}`,textAlign:"start",position:"relative",[`&${i}-rtl`]:{direction:"rtl"},"&, a, a:hover":{color:e.defaultColor},[`${i}-close-icon`]:{marginInlineStart:o,fontSize:e.tagIconSize,color:e.colorIcon,cursor:"pointer",transition:`all ${e.motionDurationMid}`,"&:hover":{color:e.colorTextHeading}},[`&${i}-has-color`]:{borderColor:"transparent",[`&, a, a:hover, ${e.iconCls}-close, ${e.iconCls}-close:hover`]:{color:e.colorTextLightSolid}},"&-checkable":{backgroundColor:"transparent",borderColor:"transparent",cursor:"pointer",[`&:not(${i}-checkable-checked):hover`]:{color:e.colorPrimary,backgroundColor:e.colorFillSecondary},"&:active, &-checked":{color:e.colorTextLightSolid},"&-checked":{backgroundColor:e.colorPrimary,"&:hover":{backgroundColor:e.colorPrimaryHover}},"&:active":{backgroundColor:e.colorPrimaryActive}},"&-hidden":{display:"none"},[`> ${e.iconCls} + span, > span + ${e.iconCls}`]:{marginInlineStart:l}}),[`${i}-borderless`]:{borderColor:"transparent",background:e.tagBorderlessBg}}})(p(e)),h);var b=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let $=t.forwardRef((e,r)=>{let{prefixCls:i,style:a,className:l,checked:o,children:s,icon:d,onChange:u,onClick:g}=e,m=b(e,["prefixCls","style","className","checked","children","icon","onChange","onClick"]),{getPrefixCls:p,tag:h}=t.useContext(c.ConfigContext),$=p("tag",i),[y,S,v]=f($),k=(0,n.default)($,`${$}-checkable`,{[`${$}-checkable-checked`]:o},null==h?void 0:h.className,l,S,v);return y(t.createElement("span",Object.assign({},m,{ref:r,style:Object.assign(Object.assign({},a),null==h?void 0:h.style),className:k,onClick:e=>{null==u||u(!o),null==g||g(e)}}),d,t.createElement("span",null,s)))});var y=e.i(403541);let S=(0,g.genSubStyleComponent)(["Tag","preset"],e=>{let t;return t=p(e),(0,y.genPresetColor)(t,(e,{textColor:n,lightBorderColor:r,lightColor:i,darkColor:a})=>({[`${t.componentCls}${t.componentCls}-${e}`]:{color:n,background:i,borderColor:r,"&-inverse":{color:t.colorTextLightSolid,background:a,borderColor:a},[`&${t.componentCls}-borderless`]:{borderColor:"transparent"}}}))},h),v=(e,t,n)=>{let r="string"!=typeof n?n:n.charAt(0).toUpperCase()+n.slice(1);return{[`${e.componentCls}${e.componentCls}-${t}`]:{color:e[`color${n}`],background:e[`color${r}Bg`],borderColor:e[`color${r}Border`],[`&${e.componentCls}-borderless`]:{borderColor:"transparent"}}}},k=(0,g.genSubStyleComponent)(["Tag","status"],e=>{let t=p(e);return[v(t,"success","Success"),v(t,"processing","Info"),v(t,"error","Error"),v(t,"warning","Warning")]},h);var C=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let w=t.forwardRef((e,s)=>{let{prefixCls:d,className:u,rootClassName:g,style:m,children:p,icon:h,color:b,onClose:$,bordered:y=!0,visible:v}=e,w=C(e,["prefixCls","className","rootClassName","style","children","icon","color","onClose","bordered","visible"]),{getPrefixCls:I,direction:x,tag:O}=t.useContext(c.ConfigContext),[E,z]=t.useState(!0),j=(0,r.default)(w,["closeIcon","closable"]);t.useEffect(()=>{void 0!==v&&z(v)},[v]);let N=(0,i.isPresetColor)(b),P=(0,i.isPresetStatusColor)(b),T=N||P,M=Object.assign(Object.assign({backgroundColor:b&&!T?b:void 0},null==O?void 0:O.style),m),B=I("tag",d),[H,L,R]=f(B),q=(0,n.default)(B,null==O?void 0:O.className,{[`${B}-${b}`]:T,[`${B}-has-color`]:b&&!T,[`${B}-hidden`]:!E,[`${B}-rtl`]:"rtl"===x,[`${B}-borderless`]:!y},u,g,L,R),G=e=>{e.stopPropagation(),null==$||$(e),e.defaultPrevented||z(!1)},[,A]=(0,a.useClosable)((0,a.pickClosable)(e),(0,a.pickClosable)(O),{closable:!1,closeIconRender:e=>{let r=t.createElement("span",{className:`${B}-close-icon`,onClick:G},e);return(0,l.replaceElement)(e,r,e=>({onClick:t=>{var n;null==(n=null==e?void 0:e.onClick)||n.call(e,t),G(t)},className:(0,n.default)(null==e?void 0:e.className,`${B}-close-icon`)}))}}),W="function"==typeof w.onClick||p&&"a"===p.type,D=h||null,X=D?t.createElement(t.Fragment,null,D,p&&t.createElement("span",null,p)):p,F=t.createElement("span",Object.assign({},j,{ref:s,className:q,style:M}),X,A,N&&t.createElement(S,{key:"preset",prefixCls:B}),P&&t.createElement(k,{key:"status",prefixCls:B}));return H(W?t.createElement(o.default,{component:"Tag"},F):F)});w.CheckableTag=$,e.s(["Tag",0,w],262218)},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},790848,e=>{"use strict";e.i(247167);var t=e.i(271645),n=e.i(739295),r=e.i(343794),i=e.i(931067),a=e.i(211577),l=e.i(392221),o=e.i(703923),c=e.i(914949),s=e.i(404948),d=["prefixCls","className","checked","defaultChecked","disabled","loadingIcon","checkedChildren","unCheckedChildren","onClick","onChange","onKeyDown"],u=t.forwardRef(function(e,n){var u,g=e.prefixCls,m=void 0===g?"rc-switch":g,p=e.className,h=e.checked,f=e.defaultChecked,b=e.disabled,$=e.loadingIcon,y=e.checkedChildren,S=e.unCheckedChildren,v=e.onClick,k=e.onChange,C=e.onKeyDown,w=(0,o.default)(e,d),I=(0,c.default)(!1,{value:h,defaultValue:f}),x=(0,l.default)(I,2),O=x[0],E=x[1];function z(e,t){var n=O;return b||(E(n=e),null==k||k(n,t)),n}var j=(0,r.default)(m,p,(u={},(0,a.default)(u,"".concat(m,"-checked"),O),(0,a.default)(u,"".concat(m,"-disabled"),b),u));return t.createElement("button",(0,i.default)({},w,{type:"button",role:"switch","aria-checked":O,disabled:b,className:j,ref:n,onKeyDown:function(e){e.which===s.default.LEFT?z(!1,e):e.which===s.default.RIGHT&&z(!0,e),null==C||C(e)},onClick:function(e){var t=z(!O,e);null==v||v(t,e)}}),$,t.createElement("span",{className:"".concat(m,"-inner")},t.createElement("span",{className:"".concat(m,"-inner-checked")},y),t.createElement("span",{className:"".concat(m,"-inner-unchecked")},S)))});u.displayName="Switch";var g=e.i(121872),m=e.i(242064),p=e.i(937328),h=e.i(517455);e.i(296059);var f=e.i(915654);e.i(262370);var b=e.i(135551),$=e.i(183293),y=e.i(246422),S=e.i(838378);let v=(0,y.genStyleHooks)("Switch",e=>{let t=(0,S.mergeToken)(e,{switchDuration:e.motionDurationMid,switchColor:e.colorPrimary,switchDisabledOpacity:e.opacityLoading,switchLoadingIconSize:e.calc(e.fontSizeIcon).mul(.75).equal(),switchLoadingIconColor:`rgba(0, 0, 0, ${e.opacityLoading})`,switchHandleActiveInset:"-30%"});return[(e=>{let{componentCls:t,trackHeight:n,trackMinWidth:r}=e;return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,$.resetComponent)(e)),{position:"relative",display:"inline-block",boxSizing:"border-box",minWidth:r,height:n,lineHeight:(0,f.unit)(n),verticalAlign:"middle",background:e.colorTextQuaternary,border:"0",borderRadius:100,cursor:"pointer",transition:`all ${e.motionDurationMid}`,userSelect:"none",[`&:hover:not(${t}-disabled)`]:{background:e.colorTextTertiary}}),(0,$.genFocusStyle)(e)),{[`&${t}-checked`]:{background:e.switchColor,[`&:hover:not(${t}-disabled)`]:{background:e.colorPrimaryHover}},[`&${t}-loading, &${t}-disabled`]:{cursor:"not-allowed",opacity:e.switchDisabledOpacity,"*":{boxShadow:"none",cursor:"not-allowed"}},[`&${t}-rtl`]:{direction:"rtl"}})}})(t),(e=>{let{componentCls:t,trackHeight:n,trackPadding:r,innerMinMargin:i,innerMaxMargin:a,handleSize:l,calc:o}=e,c=`${t}-inner`,s=(0,f.unit)(o(l).add(o(r).mul(2)).equal()),d=(0,f.unit)(o(a).mul(2).equal());return{[t]:{[c]:{display:"block",overflow:"hidden",borderRadius:100,height:"100%",paddingInlineStart:a,paddingInlineEnd:i,transition:`padding-inline-start ${e.switchDuration} ease-in-out, padding-inline-end ${e.switchDuration} ease-in-out`,[`${c}-checked, ${c}-unchecked`]:{display:"block",color:e.colorTextLightSolid,fontSize:e.fontSizeSM,transition:`margin-inline-start ${e.switchDuration} ease-in-out, margin-inline-end ${e.switchDuration} ease-in-out`,pointerEvents:"none",minHeight:n},[`${c}-checked`]:{marginInlineStart:`calc(-100% + ${s} - ${d})`,marginInlineEnd:`calc(100% - ${s} + ${d})`},[`${c}-unchecked`]:{marginTop:o(n).mul(-1).equal(),marginInlineStart:0,marginInlineEnd:0}},[`&${t}-checked ${c}`]:{paddingInlineStart:i,paddingInlineEnd:a,[`${c}-checked`]:{marginInlineStart:0,marginInlineEnd:0},[`${c}-unchecked`]:{marginInlineStart:`calc(100% - ${s} + ${d})`,marginInlineEnd:`calc(-100% + ${s} - ${d})`}},[`&:not(${t}-disabled):active`]:{[`&:not(${t}-checked) ${c}`]:{[`${c}-unchecked`]:{marginInlineStart:o(r).mul(2).equal(),marginInlineEnd:o(r).mul(-1).mul(2).equal()}},[`&${t}-checked ${c}`]:{[`${c}-checked`]:{marginInlineStart:o(r).mul(-1).mul(2).equal(),marginInlineEnd:o(r).mul(2).equal()}}}}}})(t),(e=>{let{componentCls:t,trackPadding:n,handleBg:r,handleShadow:i,handleSize:a,calc:l}=e,o=`${t}-handle`;return{[t]:{[o]:{position:"absolute",top:n,insetInlineStart:n,width:a,height:a,transition:`all ${e.switchDuration} ease-in-out`,"&::before":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,backgroundColor:r,borderRadius:l(a).div(2).equal(),boxShadow:i,transition:`all ${e.switchDuration} ease-in-out`,content:'""'}},[`&${t}-checked ${o}`]:{insetInlineStart:`calc(100% - ${(0,f.unit)(l(a).add(n).equal())})`},[`&:not(${t}-disabled):active`]:{[`${o}::before`]:{insetInlineEnd:e.switchHandleActiveInset,insetInlineStart:0},[`&${t}-checked ${o}::before`]:{insetInlineEnd:0,insetInlineStart:e.switchHandleActiveInset}}}}})(t),(e=>{let{componentCls:t,handleSize:n,calc:r}=e;return{[t]:{[`${t}-loading-icon${e.iconCls}`]:{position:"relative",top:r(r(n).sub(e.fontSize)).div(2).equal(),color:e.switchLoadingIconColor,verticalAlign:"top"},[`&${t}-checked ${t}-loading-icon`]:{color:e.switchColor}}}})(t),(e=>{let{componentCls:t,trackHeightSM:n,trackPadding:r,trackMinWidthSM:i,innerMinMarginSM:a,innerMaxMarginSM:l,handleSizeSM:o,calc:c}=e,s=`${t}-inner`,d=(0,f.unit)(c(o).add(c(r).mul(2)).equal()),u=(0,f.unit)(c(l).mul(2).equal());return{[t]:{[`&${t}-small`]:{minWidth:i,height:n,lineHeight:(0,f.unit)(n),[`${t}-inner`]:{paddingInlineStart:l,paddingInlineEnd:a,[`${s}-checked, ${s}-unchecked`]:{minHeight:n},[`${s}-checked`]:{marginInlineStart:`calc(-100% + ${d} - ${u})`,marginInlineEnd:`calc(100% - ${d} + ${u})`},[`${s}-unchecked`]:{marginTop:c(n).mul(-1).equal(),marginInlineStart:0,marginInlineEnd:0}},[`${t}-handle`]:{width:o,height:o},[`${t}-loading-icon`]:{top:c(c(o).sub(e.switchLoadingIconSize)).div(2).equal(),fontSize:e.switchLoadingIconSize},[`&${t}-checked`]:{[`${t}-inner`]:{paddingInlineStart:a,paddingInlineEnd:l,[`${s}-checked`]:{marginInlineStart:0,marginInlineEnd:0},[`${s}-unchecked`]:{marginInlineStart:`calc(100% - ${d} + ${u})`,marginInlineEnd:`calc(-100% + ${d} - ${u})`}},[`${t}-handle`]:{insetInlineStart:`calc(100% - ${(0,f.unit)(c(o).add(r).equal())})`}},[`&:not(${t}-disabled):active`]:{[`&:not(${t}-checked) ${s}`]:{[`${s}-unchecked`]:{marginInlineStart:c(e.marginXXS).div(2).equal(),marginInlineEnd:c(e.marginXXS).mul(-1).div(2).equal()}},[`&${t}-checked ${s}`]:{[`${s}-checked`]:{marginInlineStart:c(e.marginXXS).mul(-1).div(2).equal(),marginInlineEnd:c(e.marginXXS).div(2).equal()}}}}}}})(t)]},e=>{let{fontSize:t,lineHeight:n,controlHeight:r,colorWhite:i}=e,a=t*n,l=r/2,o=a-4,c=l-4;return{trackHeight:a,trackHeightSM:l,trackMinWidth:2*o+8,trackMinWidthSM:2*c+4,trackPadding:2,handleBg:i,handleSize:o,handleSizeSM:c,handleShadow:`0 2px 4px 0 ${new b.FastColor("#00230b").setA(.2).toRgbString()}`,innerMinMargin:o/2,innerMaxMargin:o+2+4,innerMinMarginSM:c/2,innerMaxMarginSM:c+2+4}});var k=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let C=t.forwardRef((e,i)=>{let{prefixCls:a,size:l,disabled:o,loading:s,className:d,rootClassName:f,style:b,checked:$,value:y,defaultChecked:S,defaultValue:C,onChange:w}=e,I=k(e,["prefixCls","size","disabled","loading","className","rootClassName","style","checked","value","defaultChecked","defaultValue","onChange"]),[x,O]=(0,c.default)(!1,{value:null!=$?$:y,defaultValue:null!=S?S:C}),{getPrefixCls:E,direction:z,switch:j}=t.useContext(m.ConfigContext),N=t.useContext(p.default),P=(null!=o?o:N)||s,T=E("switch",a),M=t.createElement("div",{className:`${T}-handle`},s&&t.createElement(n.default,{className:`${T}-loading-icon`})),[B,H,L]=v(T),R=(0,h.default)(l),q=(0,r.default)(null==j?void 0:j.className,{[`${T}-small`]:"small"===R,[`${T}-loading`]:s,[`${T}-rtl`]:"rtl"===z},d,f,H,L),G=Object.assign(Object.assign({},null==j?void 0:j.style),b);return B(t.createElement(g.default,{component:"Switch",disabled:P},t.createElement(u,Object.assign({},I,{checked:x,onChange:(...e)=>{O(e[0]),null==w||w.apply(void 0,e)},prefixCls:T,className:q,style:G,disabled:P,ref:i,loadingIcon:M}))))});C.__ANT_SWITCH=!0,e.s(["Switch",0,C],790848)},38243,908286,e=>{"use strict";e.i(247167);var t=e.i(271645),n=e.i(343794),r=e.i(876556);function i(e){return["small","middle","large"].includes(e)}function a(e){return!!e&&"number"==typeof e&&!Number.isNaN(e)}e.s(["isPresetSize",()=>i,"isValidGapNumber",()=>a],908286);var l=e.i(242064),o=e.i(249616),c=e.i(372409),s=e.i(246422);let d=(0,s.genStyleHooks)(["Space","Addon"],e=>[(e=>{let{componentCls:t,borderRadius:n,paddingSM:r,colorBorder:i,paddingXS:a,fontSizeLG:l,fontSizeSM:o,borderRadiusLG:s,borderRadiusSM:d,colorBgContainerDisabled:u,lineWidth:g}=e;return{[t]:[{display:"inline-flex",alignItems:"center",gap:0,paddingInline:r,margin:0,background:u,borderWidth:g,borderStyle:"solid",borderColor:i,borderRadius:n,"&-large":{fontSize:l,borderRadius:s},"&-small":{paddingInline:a,borderRadius:d,fontSize:o},"&-compact-last-item":{borderEndStartRadius:0,borderStartStartRadius:0},"&-compact-first-item":{borderEndEndRadius:0,borderStartEndRadius:0},"&-compact-item:not(:first-child):not(:last-child)":{borderRadius:0},"&-compact-item:not(:last-child)":{borderInlineEndWidth:0}},(0,c.genCompactItemStyle)(e,{focus:!1})]}})(e)]);var u=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let g=t.default.forwardRef((e,r)=>{let{className:i,children:a,style:c,prefixCls:s}=e,g=u(e,["className","children","style","prefixCls"]),{getPrefixCls:m,direction:p}=t.default.useContext(l.ConfigContext),h=m("space-addon",s),[f,b,$]=d(h),{compactItemClassnames:y,compactSize:S}=(0,o.useCompactItemContext)(h,p),v=(0,n.default)(h,b,y,$,{[`${h}-${S}`]:S},i);return f(t.default.createElement("div",Object.assign({ref:r,className:v,style:c},g),a))}),m=t.default.createContext({latestIndex:0}),p=m.Provider,h=({className:e,index:n,children:r,split:i,style:a})=>{let{latestIndex:l}=t.useContext(m);return null==r?null:t.createElement(t.Fragment,null,t.createElement("div",{className:e,style:a},r),n{let t=(0,f.mergeToken)(e,{spaceGapSmallSize:e.paddingXS,spaceGapMiddleSize:e.padding,spaceGapLargeSize:e.paddingLG});return[(e=>{let{componentCls:t,antCls:n}=e;return{[t]:{display:"inline-flex","&-rtl":{direction:"rtl"},"&-vertical":{flexDirection:"column"},"&-align":{flexDirection:"column","&-center":{alignItems:"center"},"&-start":{alignItems:"flex-start"},"&-end":{alignItems:"flex-end"},"&-baseline":{alignItems:"baseline"}},[`${t}-item:empty`]:{display:"none"},[`${t}-item > ${n}-badge-not-a-wrapper:only-child`]:{display:"block"}}}})(t),(e=>{let{componentCls:t}=e;return{[t]:{"&-gap-row-small":{rowGap:e.spaceGapSmallSize},"&-gap-row-middle":{rowGap:e.spaceGapMiddleSize},"&-gap-row-large":{rowGap:e.spaceGapLargeSize},"&-gap-col-small":{columnGap:e.spaceGapSmallSize},"&-gap-col-middle":{columnGap:e.spaceGapMiddleSize},"&-gap-col-large":{columnGap:e.spaceGapLargeSize}}}})(t)]},()=>({}),{resetStyle:!1});var $=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n};let y=t.forwardRef((e,o)=>{var c;let{getPrefixCls:s,direction:d,size:u,className:g,style:m,classNames:f,styles:y}=(0,l.useComponentConfig)("space"),{size:S=null!=u?u:"small",align:v,className:k,rootClassName:C,children:w,direction:I="horizontal",prefixCls:x,split:O,style:E,wrap:z=!1,classNames:j,styles:N}=e,P=$(e,["size","align","className","rootClassName","children","direction","prefixCls","split","style","wrap","classNames","styles"]),[T,M]=Array.isArray(S)?S:[S,S],B=i(M),H=i(T),L=a(M),R=a(T),q=(0,r.default)(w,{keepEmpty:!0}),G=void 0===v&&"horizontal"===I?"center":v,A=s("space",x),[W,D,X]=b(A),F=(0,n.default)(A,g,D,`${A}-${I}`,{[`${A}-rtl`]:"rtl"===d,[`${A}-align-${G}`]:G,[`${A}-gap-row-${M}`]:B,[`${A}-gap-col-${T}`]:H},k,C,X),K=(0,n.default)(`${A}-item`,null!=(c=null==j?void 0:j.item)?c:f.item),U=Object.assign(Object.assign({},y.item),null==N?void 0:N.item),V=q.map((e,n)=>{let r=(null==e?void 0:e.key)||`${K}-${n}`;return t.createElement(h,{className:K,key:r,index:n,split:O,style:U},e)}),Q=t.useMemo(()=>({latestIndex:q.reduce((e,t,n)=>null!=t?n:e,0)}),[q]);if(0===q.length)return null;let _={};return z&&(_.flexWrap="wrap"),!H&&R&&(_.columnGap=T),!B&&L&&(_.rowGap=M),W(t.createElement("div",Object.assign({ref:o,className:F,style:Object.assign(Object.assign(Object.assign({},_),m),E)},P),t.createElement(p,{value:Q},V)))});y.Compact=o.default,y.Addon=g,e.s(["default",0,y],38243)},770914,e=>{"use strict";var t=e.i(38243);e.s(["Space",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),n=e.i(266027);let r=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,n.useQuery)({queryKey:r.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let n=t.forwardRef(function(e,n){return t.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:n},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,n],250980)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0549bc9afa7d4888.js b/litellm/proxy/_experimental/out/_next/static/chunks/0549bc9afa7d4888.js deleted file mode 100644 index feba90545f9..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0549bc9afa7d4888.js +++ /dev/null @@ -1,41 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,464571,e=>{"use strict";var t=e.i(920228);e.s(["Button",()=>t.default])},486794,(e,t,n)=>{t.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],l=0;l{"use strict";var l=e.r(486794),r={"text/plain":"Text","text/html":"Url",default:"Text"};t.exports=function(e,t){var n,o,a,i,c,s,u,d,p=!1;t||(t={}),a=t.debug||!1;try{if(c=l(),s=document.createRange(),u=document.getSelection(),(d=document.createElement("span")).textContent=e,d.ariaHidden="true",d.style.all="unset",d.style.position="fixed",d.style.top=0,d.style.clip="rect(0, 0, 0, 0)",d.style.whiteSpace="pre",d.style.webkitUserSelect="text",d.style.MozUserSelect="text",d.style.msUserSelect="text",d.style.userSelect="text",d.addEventListener("copy",function(n){if(n.stopPropagation(),t.format)if(n.preventDefault(),void 0===n.clipboardData){a&&console.warn("unable to use e.clipboardData"),a&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var l=r[t.format]||r.default;window.clipboardData.setData(l,e)}else n.clipboardData.clearData(),n.clipboardData.setData(t.format,e);t.onCopy&&(n.preventDefault(),t.onCopy(n.clipboardData))}),document.body.appendChild(d),s.selectNodeContents(d),u.addRange(s),!document.execCommand("copy"))throw Error("copy command was unsuccessful");p=!0}catch(l){a&&console.error("unable to copy using execCommand: ",l),a&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),p=!0}catch(l){a&&console.error("unable to copy using clipboardData: ",l),a&&console.error("falling back to prompt"),n="message"in t?t.message:"Copy to clipboard: #{key}, Enter",o=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C",i=n.replace(/#{\s*key\s*}/g,o),window.prompt(i,e)}}finally{u&&("function"==typeof u.removeRange?u.removeRange(s):u.removeAllRanges()),d&&document.body.removeChild(d),c()}return p}},898586,401361,335771,e=>{"use strict";e.i(247167);var t=e.i(271645),n=e.i(8211),l=e.i(931067);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M257.7 752c2 0 4-.2 6-.5L431.9 722c2-.4 3.9-1.3 5.3-2.8l423.9-423.9a9.96 9.96 0 000-14.1L694.9 114.9c-1.9-1.9-4.4-2.9-7.1-2.9s-5.2 1-7.1 2.9L256.8 538.8c-1.5 1.5-2.4 3.3-2.8 5.3l-29.5 168.2a33.5 33.5 0 009.4 29.8c6.6 6.4 14.9 9.9 23.8 9.9zm67.4-174.4L687.8 215l73.3 73.3-362.7 362.6-88.9 15.7 15.6-89zM880 836H144c-17.7 0-32 14.3-32 32v36c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-36c0-17.7-14.3-32-32-32z"}}]},name:"edit",theme:"outlined"};var o=e.i(9583),a=t.forwardRef(function(e,n){return t.createElement(o.default,(0,l.default)({},e,{ref:n,icon:r}))});e.s(["default",0,a],401361);var i=e.i(343794),c=e.i(430073),s=e.i(876556),u=e.i(174428),d=e.i(914949),p=e.i(529681),f=e.i(611935),m=e.i(735049),g=e.i(242064),b=e.i(929447),y=e.i(491816);let v={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M864 170h-60c-4.4 0-8 3.6-8 8v518H310v-73c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 000 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-75h498c35.3 0 64-28.7 64-64V178c0-4.4-3.6-8-8-8z"}}]},name:"enter",theme:"outlined"};var h=t.forwardRef(function(e,n){return t.createElement(o.default,(0,l.default)({},e,{ref:n,icon:v}))}),x=e.i(404948),O=e.i(763731),E=e.i(635432),S=e.i(183293),w=e.i(246422);e.i(765846);var j=e.i(896091);let C=(0,w.genStyleHooks)("Typography",e=>{let t,{componentCls:n,titleMarginTop:l}=e;return{[n]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({color:e.colorText,wordBreak:"break-word",lineHeight:e.lineHeight,[`&${n}-secondary`]:{color:e.colorTextDescription},[`&${n}-success`]:{color:e.colorSuccessText},[`&${n}-warning`]:{color:e.colorWarningText},[`&${n}-danger`]:{color:e.colorErrorText,"a&:active, a&:focus":{color:e.colorErrorTextActive},"a&:hover":{color:e.colorErrorTextHover}},[`&${n}-disabled`]:{color:e.colorTextDisabled,cursor:"not-allowed",userSelect:"none"},[` - div&, - p - `]:{marginBottom:"1em"}},(t={},[1,2,3,4,5].forEach(n=>{t[` - h${n}&, - div&-h${n}, - div&-h${n} > textarea, - h${n} - `]=((e,t,n,l)=>{let{titleMarginBottom:r,fontWeightStrong:o}=l;return{marginBottom:r,color:n,fontWeight:o,fontSize:e,lineHeight:t}})(e[`fontSizeHeading${n}`],e[`lineHeightHeading${n}`],e.colorTextHeading,e)}),t)),{[` - & + h1${n}, - & + h2${n}, - & + h3${n}, - & + h4${n}, - & + h5${n} - `]:{marginTop:l},[` - div, - ul, - li, - p, - h1, - h2, - h3, - h4, - h5`]:{[` - + h1, - + h2, - + h3, - + h4, - + h5 - `]:{marginTop:l}}}),{code:{margin:"0 0.2em",paddingInline:"0.4em",paddingBlock:"0.2em 0.1em",fontSize:"85%",fontFamily:e.fontFamilyCode,background:"rgba(150, 150, 150, 0.1)",border:"1px solid rgba(100, 100, 100, 0.2)",borderRadius:3},kbd:{margin:"0 0.2em",paddingInline:"0.4em",paddingBlock:"0.15em 0.1em",fontSize:"90%",fontFamily:e.fontFamilyCode,background:"rgba(150, 150, 150, 0.06)",border:"1px solid rgba(100, 100, 100, 0.2)",borderBottomWidth:2,borderRadius:3},mark:{padding:0,backgroundColor:j.gold[2]},"u, ins":{textDecoration:"underline",textDecorationSkipInk:"auto"},"s, del":{textDecoration:"line-through"},strong:{fontWeight:e.fontWeightStrong},"ul, ol":{marginInline:0,marginBlock:"0 1em",padding:0,li:{marginInline:"20px 0",marginBlock:0,paddingInline:"4px 0",paddingBlock:0}},ul:{listStyleType:"circle",ul:{listStyleType:"disc"}},ol:{listStyleType:"decimal"},"pre, blockquote":{margin:"1em 0"},pre:{padding:"0.4em 0.6em",whiteSpace:"pre-wrap",wordWrap:"break-word",background:"rgba(150, 150, 150, 0.1)",border:"1px solid rgba(100, 100, 100, 0.2)",borderRadius:3,fontFamily:e.fontFamilyCode,code:{display:"inline",margin:0,padding:0,fontSize:"inherit",fontFamily:"inherit",background:"transparent",border:0}},blockquote:{paddingInline:"0.6em 0",paddingBlock:0,borderInlineStart:"4px solid rgba(100, 100, 100, 0.2)",opacity:.85}}),(e=>{let{componentCls:t}=e;return{"a&, a":Object.assign(Object.assign({},(0,S.operationUnit)(e)),{userSelect:"text",[`&[disabled], &${t}-disabled`]:{color:e.colorTextDisabled,cursor:"not-allowed","&:active, &:hover":{color:e.colorTextDisabled},"&:active":{pointerEvents:"none"}}})}})(e)),{[` - ${n}-expand, - ${n}-collapse, - ${n}-edit, - ${n}-copy - `]:Object.assign(Object.assign({},(0,S.operationUnit)(e)),{marginInlineStart:e.marginXXS})}),(e=>{let{componentCls:t,paddingSM:n}=e;return{"&-edit-content":{position:"relative","div&":{insetInlineStart:e.calc(e.paddingSM).mul(-1).equal(),insetBlockStart:e.calc(n).div(-2).add(1).equal(),marginBottom:e.calc(n).div(2).sub(2).equal()},[`${t}-edit-content-confirm`]:{position:"absolute",insetInlineEnd:e.calc(e.marginXS).add(2).equal(),insetBlockEnd:e.marginXS,color:e.colorIcon,fontWeight:"normal",fontSize:e.fontSize,fontStyle:"normal",pointerEvents:"none"},textarea:{margin:"0!important",MozTransition:"none",height:"1em"}}}})(e)),{[`${e.componentCls}-copy-success`]:{[` - &, - &:hover, - &:focus`]:{color:e.colorSuccess}},[`${e.componentCls}-copy-icon-only`]:{marginInlineStart:0}}),{[` - a&-ellipsis, - span&-ellipsis - `]:{display:"inline-block",maxWidth:"100%"},"&-ellipsis-single-line":{whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis","a&, span&":{verticalAlign:"bottom"},"> code":{paddingBlock:0,maxWidth:"calc(100% - 1.2em)",display:"inline-block",overflow:"hidden",textOverflow:"ellipsis",verticalAlign:"bottom",boxSizing:"content-box"}},"&-ellipsis-multiple-line":{display:"-webkit-box",overflow:"hidden",WebkitLineClamp:3,WebkitBoxOrient:"vertical"}}),{"&-rtl":{direction:"rtl"}})}},()=>({titleMarginTop:"1.2em",titleMarginBottom:"0.5em"})),k=e=>{let{prefixCls:n,"aria-label":l,className:r,style:o,direction:a,maxLength:c,autoSize:s=!0,value:u,onSave:d,onCancel:p,onEnd:f,component:m,enterIcon:g=t.createElement(h,null)}=e,b=t.useRef(null),y=t.useRef(!1),v=t.useRef(null),[S,w]=t.useState(u);t.useEffect(()=>{w(u)},[u]),t.useEffect(()=>{var e;if(null==(e=b.current)?void 0:e.resizableTextArea){let{textArea:e}=b.current.resizableTextArea;e.focus();let{length:t}=e.value;e.setSelectionRange(t,t)}},[]);let j=()=>{d(S.trim())},[k,R,$]=C(n),T=(0,i.default)(n,`${n}-edit-content`,{[`${n}-rtl`]:"rtl"===a,[`${n}-${m}`]:!!m},r,R,$);return k(t.createElement("div",{className:T,style:o},t.createElement(E.default,{ref:b,maxLength:c,value:S,onChange:({target:e})=>{w(e.value.replace(/[\n\r]/g,""))},onKeyDown:({keyCode:e})=>{y.current||(v.current=e)},onKeyUp:({keyCode:e,ctrlKey:t,altKey:n,metaKey:l,shiftKey:r})=>{v.current!==e||y.current||t||n||l||r||(e===x.default.ENTER?(j(),null==f||f()):e===x.default.ESC&&p())},onCompositionStart:()=>{y.current=!0},onCompositionEnd:()=>{y.current=!1},onBlur:()=>{j()},"aria-label":l,rows:1,autoSize:s}),null!==g?(0,O.cloneElement)(g,{className:`${n}-edit-content-confirm`}):null))};var R=e.i(844343),$=e.i(175066);function T(e,n){return t.useMemo(()=>{let t=!!e;return[t,Object.assign(Object.assign({},n),t&&"object"==typeof e?e:null)]},[e])}var I=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let D=t.forwardRef((e,n)=>{let{prefixCls:l,component:r="article",className:o,rootClassName:a,setContentRef:c,children:s,direction:u,style:d}=e,p=I(e,["prefixCls","component","className","rootClassName","setContentRef","children","direction","style"]),{getPrefixCls:m,direction:b,className:y,style:v}=(0,g.useComponentConfig)("typography"),h=c?(0,f.composeRef)(n,c):n,x=m("typography",l),[O,E,S]=C(x),w=(0,i.default)(x,y,{[`${x}-rtl`]:"rtl"===(null!=u?u:b)},o,a,E,S),j=Object.assign(Object.assign({},v),d);return O(t.createElement(r,Object.assign({className:w,style:j,ref:h},p),s))});var P=e.i(121229),B=e.i(190144),M=e.i(739295);function H(e){return!1===e?[!1,!1]:Array.isArray(e)?e:[e]}function z(e,t,n){return!0===e||void 0===e?t:e||n&&t}let A=e=>["string","number"].includes(typeof e),W=({prefixCls:e,copied:n,locale:l,iconOnly:r,tooltips:o,icon:a,tabIndex:c,onCopy:s,loading:u})=>{let d=H(o),p=H(a),{copied:f,copy:m}=null!=l?l:{},g=n?f:m,b=z(d[+!!n],g),v="string"==typeof b?b:g;return t.createElement(y.default,{title:b},t.createElement("button",{type:"button",className:(0,i.default)(`${e}-copy`,{[`${e}-copy-success`]:n,[`${e}-copy-icon-only`]:r}),onClick:s,"aria-label":v,tabIndex:c},n?z(p[1],t.createElement(P.default,null),!0):z(p[0],u?t.createElement(M.default,null):t.createElement(B.default,null),!0)))},L=t.forwardRef(({style:e,children:n},l)=>{let r=t.useRef(null);return t.useImperativeHandle(l,()=>({isExceed:()=>{let e=r.current;return e.scrollHeight>e.clientHeight},getHeight:()=>r.current.clientHeight})),t.createElement("span",{"aria-hidden":!0,ref:r,style:Object.assign({position:"fixed",display:"block",left:0,top:0,pointerEvents:"none",backgroundColor:"rgba(255, 0, 0, 0.65)"},e)},n)});function N(e,t){let n=0,l=[];for(let r=0;rt){let e=t-n;return l.push(String(o).slice(0,e)),l}l.push(o),n=a}return e}let U={display:"-webkit-box",overflow:"hidden",WebkitBoxOrient:"vertical"};function F(e){let{enableMeasure:l,width:r,text:o,children:a,rows:i,expanded:c,miscDeps:d,onEllipsis:p}=e,f=t.useMemo(()=>(0,s.default)(o),[o]),m=t.useMemo(()=>f.reduce((e,t)=>e+(A(t)?String(t).length:1),0),[o]),g=t.useMemo(()=>a(f,!1),[o]),[b,y]=t.useState(null),v=t.useRef(null),h=t.useRef(null),x=t.useRef(null),O=t.useRef(null),E=t.useRef(null),[S,w]=t.useState(!1),[j,C]=t.useState(0),[k,R]=t.useState(0),[$,T]=t.useState(null);(0,u.default)(()=>{l&&r&&m?C(1):C(0)},[r,o,i,l,f]),(0,u.default)(()=>{var e,t,n,l;if(1===j)C(2),T(h.current&&getComputedStyle(h.current).whiteSpace);else if(2===j){let r=!!(null==(e=x.current)?void 0:e.isExceed());C(r?3:4),y(r?[0,m]:null),w(r),R(Math.max((null==(t=x.current)?void 0:t.getHeight())||0,(1===i?0:(null==(n=O.current)?void 0:n.getHeight())||0)+((null==(l=E.current)?void 0:l.getHeight())||0))+1),p(r)}},[j]);let I=b?Math.ceil((b[0]+b[1])/2):0;(0,u.default)(()=>{var e;let[t,n]=b||[0,0];if(t!==n){let l=((null==(e=v.current)?void 0:e.getHeight())||0)>k,r=I;n-t==1&&(r=l?t:n),y(l?[t,r]:[r,n])}},[b,I]);let D=t.useMemo(()=>{if(!l)return a(f,!1);if(3!==j||!b||b[0]!==b[1]){let e=a(f,!1);return[4,0].includes(j)?e:t.createElement("span",{style:Object.assign(Object.assign({},U),{WebkitLineClamp:i})},e)}return a(c?f:N(f,b[0]),S)},[c,j,b,f].concat((0,n.default)(d))),P={width:r,margin:0,padding:0,whiteSpace:"nowrap"===$?"normal":"inherit"};return t.createElement(t.Fragment,null,D,2===j&&t.createElement(t.Fragment,null,t.createElement(L,{style:Object.assign(Object.assign(Object.assign({},P),U),{WebkitLineClamp:i}),ref:x},g),t.createElement(L,{style:Object.assign(Object.assign(Object.assign({},P),U),{WebkitLineClamp:i-1}),ref:O},g),t.createElement(L,{style:Object.assign(Object.assign(Object.assign({},P),U),{WebkitLineClamp:1}),ref:E},a([],!0))),3===j&&b&&b[0]!==b[1]&&t.createElement(L,{style:Object.assign(Object.assign({},P),{top:400}),ref:v},a(N(f,I),!0)),1===j&&t.createElement("span",{style:{whiteSpace:"inherit"},ref:h}))}let q=({enableEllipsis:e,isEllipsis:n,children:l,tooltipProps:r})=>(null==r?void 0:r.title)&&e?t.createElement(y.default,Object.assign({open:!!n&&void 0},r),l):l;var X=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let K=["delete","mark","code","underline","strong","keyboard","italic"],V=t.forwardRef((e,l)=>{var r;let o,v,h,{prefixCls:x,className:O,style:E,type:S,disabled:w,children:j,ellipsis:C,editable:I,copyable:P,component:B,title:M}=e,H=X(e,["prefixCls","className","style","type","disabled","children","ellipsis","editable","copyable","component","title"]),{getPrefixCls:z,direction:L}=t.useContext(g.ConfigContext),[N]=(0,b.default)("Text"),U=t.useRef(null),V=t.useRef(null),_=z("typography",x),G=(0,p.default)(H,K),[J,Q]=T(I),[Y,Z]=(0,d.default)(!1,{value:Q.editing}),{triggerType:ee=["icon"]}=Q,et=e=>{var t;e&&(null==(t=Q.onStart)||t.call(Q)),Z(e)},en=(o=(0,t.useRef)(void 0),(0,t.useEffect)(()=>{o.current=Y}),o.current);(0,u.default)(()=>{var e;!Y&&en&&(null==(e=V.current)||e.focus())},[Y]);let el=e=>{null==e||e.preventDefault(),et(!0)},[er,eo]=T(P),{copied:ea,copyLoading:ei,onClick:ec}=(({copyConfig:e,children:n})=>{let[l,r]=t.useState(!1),[o,a]=t.useState(!1),i=t.useRef(null),c=()=>{i.current&&clearTimeout(i.current)},s={};e.format&&(s.format=e.format),t.useEffect(()=>c,[]);let u=(0,$.default)(t=>{var l,o,u,d;return l=void 0,o=void 0,u=void 0,d=function*(){var l;null==t||t.preventDefault(),null==t||t.stopPropagation(),a(!0);try{let o="function"==typeof e.text?yield e.text():e.text;(0,R.default)(o||((e,t=!1)=>t&&null==e?[]:Array.isArray(e)?e:[e])(n,!0).join("")||"",s),a(!1),r(!0),c(),i.current=setTimeout(()=>{r(!1)},3e3),null==(l=e.onCopy)||l.call(e,t)}catch(e){throw a(!1),e}},new(u||(u=Promise))(function(e,t){function n(e){try{a(d.next(e))}catch(e){t(e)}}function r(e){try{a(d.throw(e))}catch(e){t(e)}}function a(t){var l;t.done?e(t.value):((l=t.value)instanceof u?l:new u(function(e){e(l)})).then(n,r)}a((d=d.apply(l,o||[])).next())})});return{copied:l,copyLoading:o,onClick:u}})({copyConfig:eo,children:j}),[es,eu]=t.useState(!1),[ed,ep]=t.useState(!1),[ef,em]=t.useState(!1),[eg,eb]=t.useState(!1),[ey,ev]=t.useState(!0),[eh,ex]=T(C,{expandable:!1,symbol:e=>e?null==N?void 0:N.collapse:null==N?void 0:N.expand}),[eO,eE]=(0,d.default)(ex.defaultExpanded||!1,{value:ex.expanded}),eS=eh&&(!eO||"collapsible"===ex.expandable),{rows:ew=1}=ex,ej=t.useMemo(()=>eS&&(void 0!==ex.suffix||ex.onEllipsis||ex.expandable||J||er),[eS,ex,J,er]);(0,u.default)(()=>{eh&&!ej&&(eu((0,m.isStyleSupport)("webkitLineClamp")),ep((0,m.isStyleSupport)("textOverflow")))},[ej,eh]);let[eC,ek]=t.useState(eS),eR=t.useMemo(()=>!ej&&(1===ew?ed:es),[ej,ed,es]);(0,u.default)(()=>{ek(eR&&eS)},[eR,eS]);let e$=eS&&(eC?eg:ef),eT=eS&&1===ew&&eC,eI=eS&&ew>1&&eC,[eD,eP]=t.useState(0),eB=e=>{var t;em(e),ef!==e&&(null==(t=ex.onEllipsis)||t.call(ex,e))};t.useEffect(()=>{let e=U.current;if(eh&&eC&&e){let t,n,l,r=(t=document.createElement("em"),e.appendChild(t),n=e.getBoundingClientRect(),l=t.getBoundingClientRect(),e.removeChild(t),n.left>l.left||l.right>n.right||n.top>l.top||l.bottom>n.bottom);eg!==r&&eb(r)}},[eh,eC,j,eI,ey,eD]),t.useEffect(()=>{let e=U.current;if("u"{ev(!!e.offsetParent)});return t.observe(e),()=>{t.disconnect()}},[eC,eS]);let eM=(v=ex.tooltip,h=Q.text,(0,t.useMemo)(()=>!0===v?{title:null!=h?h:j}:(0,t.isValidElement)(v)?{title:v}:"object"==typeof v?Object.assign({title:null!=h?h:j},v):{title:v},[v,h,j])),eH=t.useMemo(()=>{if(eh&&!eC)return[Q.text,j,M,eM.title].find(A)},[eh,eC,M,eM.title,e$]);return Y?t.createElement(k,{value:null!=(r=Q.text)?r:"string"==typeof j?j:"",onSave:e=>{var t;null==(t=Q.onChange)||t.call(Q,e),et(!1)},onCancel:()=>{var e;null==(e=Q.onCancel)||e.call(Q),et(!1)},onEnd:Q.onEnd,prefixCls:_,className:O,style:E,direction:L,component:B,maxLength:Q.maxLength,autoSize:Q.autoSize,enterIcon:Q.enterIcon}):t.createElement(c.default,{onResize:({offsetWidth:e})=>{eP(e)},disabled:!eS},r=>t.createElement(q,{tooltipProps:eM,enableEllipsis:eS,isEllipsis:e$},t.createElement(D,Object.assign({className:(0,i.default)({[`${_}-${S}`]:S,[`${_}-disabled`]:w,[`${_}-ellipsis`]:eh,[`${_}-ellipsis-single-line`]:eT,[`${_}-ellipsis-multiple-line`]:eI},O),prefixCls:x,style:Object.assign(Object.assign({},E),{WebkitLineClamp:eI?ew:void 0}),component:B,ref:(0,f.composeRef)(r,U,l),direction:L,onClick:ee.includes("text")?el:void 0,"aria-label":null==eH?void 0:eH.toString(),title:M},G),t.createElement(F,{enableMeasure:eS&&!eC,text:j,rows:ew,width:eD,onEllipsis:eB,expanded:eO,miscDeps:[ea,eO,ei,J,er,N].concat((0,n.default)(K.map(t=>e[t])))},(n,l)=>{let r;return function({mark:e,code:n,underline:l,delete:r,strong:o,keyboard:a,italic:i},c){let s=c;function u(e,n){n&&(s=t.createElement(e,{},s))}return u("strong",o),u("u",l),u("del",r),u("code",n),u("mark",e),u("kbd",a),u("i",i),s}(e,t.createElement(t.Fragment,null,n.length>0&&l&&!eO&&eH?t.createElement("span",{key:"show-content","aria-hidden":!0},n):n,[(r=l)&&!eO&&t.createElement("span",{"aria-hidden":!0,key:"ellipsis"},"..."),ex.suffix,[r&&(()=>{let{expandable:e,symbol:n}=ex;return e?t.createElement("button",{type:"button",key:"expand",className:`${_}-${eO?"collapse":"expand"}`,onClick:e=>{var t,n;eE((t={expanded:!eO}).expanded),null==(n=ex.onExpand)||n.call(ex,e,t)},"aria-label":eO?N.collapse:null==N?void 0:N.expand},"function"==typeof n?n(eO):n):null})(),(()=>{if(!J)return;let{icon:e,tooltip:n,tabIndex:l}=Q,r=(0,s.default)(n)[0]||(null==N?void 0:N.edit),o="string"==typeof r?r:"";return ee.includes("icon")?t.createElement(y.default,{key:"edit",title:!1===n?"":r},t.createElement("button",{type:"button",ref:V,className:`${_}-edit`,onClick:el,"aria-label":o,tabIndex:l},e||t.createElement(a,{role:"button"}))):null})(),er?t.createElement(W,Object.assign({key:"copy"},eo,{prefixCls:_,copied:ea,locale:N,onCopy:ec,loading:ei,iconOnly:null==j})):null]]))}))))});var _=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let G=t.forwardRef((e,n)=>{let{ellipsis:l,rel:r,children:o,navigate:a}=e,i=_(e,["ellipsis","rel","children","navigate"]),c=Object.assign(Object.assign({},i),{rel:void 0===r&&"_blank"===i.target?"noopener noreferrer":r});return t.createElement(V,Object.assign({},c,{ref:n,ellipsis:!!l,component:"a"}),o)});var J=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let Q=t.forwardRef((e,n)=>{let{children:l}=e,r=J(e,["children"]);return t.createElement(V,Object.assign({ref:n},r,{component:"div"}),l)});var Y=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let Z=t.forwardRef((e,n)=>{let{ellipsis:l,children:r}=e,o=Y(e,["ellipsis","children"]),a=t.useMemo(()=>l&&"object"==typeof l?(0,p.default)(l,["expandable","rows"]):l,[l]);return t.createElement(V,Object.assign({ref:n},o,{ellipsis:a,component:"span"}),r)});var ee=function(e,t){var n={};for(var l in e)Object.prototype.hasOwnProperty.call(e,l)&&0>t.indexOf(l)&&(n[l]=e[l]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,l=Object.getOwnPropertySymbols(e);rt.indexOf(l[r])&&Object.prototype.propertyIsEnumerable.call(e,l[r])&&(n[l[r]]=e[l[r]]);return n};let et=[1,2,3,4,5],en=t.forwardRef((e,n)=>{let{level:l=1,children:r}=e,o=ee(e,["level","children"]),a=et.includes(l)?`h${l}`:"h1";return t.createElement(V,Object.assign({ref:n},o,{component:a}),r)});e.s(["default",0,en],335771),D.Text=Z,D.Link=G,D.Title=en,D.Paragraph=Q,e.s(["Typography",0,D],898586)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/36ccc2b555a26ad4.js b/litellm/proxy/_experimental/out/_next/static/chunks/05d4ceb8d45fdc83.js similarity index 96% rename from litellm/proxy/_experimental/out/_next/static/chunks/36ccc2b555a26ad4.js rename to litellm/proxy/_experimental/out/_next/static/chunks/05d4ceb8d45fdc83.js index d601999bfa6..b544627b867 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/36ccc2b555a26ad4.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/05d4ceb8d45fdc83.js @@ -1,4 +1,4 @@ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,429427,371330,80758,402155,368578,544508,746725,835696,941444,914189,394487,e=>{"use strict";let t;e.i(247167);var r=e.i(271645);let n="u">typeof document?r.default.useLayoutEffect:()=>{},o=e=>{var t;return null!=(t=null==e?void 0:e.ownerDocument)?t:document},a=e=>e&&"window"in e&&e.window===e?e:o(e).defaultView||window;"u">typeof Element&&Element.prototype;let s=["input:not([disabled]):not([type=hidden])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable^="false"])',"permission"];s.join(":not([hidden]),"),s.push('[tabindex]:not([tabindex="-1"]):not([disabled])'),s.join(':not([hidden]):not([tabindex="-1"]),');let l=null;function i(e){return e.nativeEvent=e,e.isDefaultPrevented=()=>e.defaultPrevented,e.isPropagationStopped=()=>e.cancelBubble,e.persist=()=>{},e}function u(e){let t=(0,r.useRef)({isFocused:!1,observer:null});return n(()=>{let e=t.current;return()=>{e.observer&&(e.observer.disconnect(),e.observer=null)}},[]),(0,r.useCallback)(r=>{if(r.target instanceof HTMLButtonElement||r.target instanceof HTMLInputElement||r.target instanceof HTMLTextAreaElement||r.target instanceof HTMLSelectElement){t.current.isFocused=!0;let n=r.target;n.addEventListener("focusout",r=>{if(t.current.isFocused=!1,n.disabled){let t=i(r);null==e||e(t)}t.current.observer&&(t.current.observer.disconnect(),t.current.observer=null)},{once:!0}),t.current.observer=new MutationObserver(()=>{if(t.current.isFocused&&n.disabled){var e;null==(e=t.current.observer)||e.disconnect();let r=n===document.activeElement?null:document.activeElement;n.dispatchEvent(new FocusEvent("blur",{relatedTarget:r})),n.dispatchEvent(new FocusEvent("focusout",{bubbles:!0,relatedTarget:r}))}}),t.current.observer.observe(n,{attributes:!0,attributeFilter:["disabled"]})}},[e])}function c(e){var t;if("u"e.test(t.brand))||e.test(window.navigator.userAgent)}function d(e){var t;return"u">typeof window&&null!=window.navigator&&e.test((null==(t=window.navigator.userAgentData)?void 0:t.platform)||window.navigator.platform)}function f(e){let t=null;return()=>(null==t&&(t=e()),t)}let p=f(function(){return d(/^Mac/i)}),m=f(function(){return d(/^iPhone/i)}),v=f(function(){return d(/^iPad/i)||p()&&navigator.maxTouchPoints>1}),b=f(function(){return m()||v()});f(function(){return p()||b()});let g=f(function(){return c(/AppleWebKit/i)&&!h()}),h=f(function(){return c(/Chrome/i)}),y=f(function(){return c(/Android/i)}),E=f(function(){return c(/Firefox/i)});function w(e,t,r=!0){var n,o;let{metaKey:a,ctrlKey:s,altKey:i,shiftKey:u}=t;E()&&(null==(o=window.event)||null==(n=o.type)?void 0:n.startsWith("key"))&&"_blank"===e.target&&(p()?a=!0:s=!0);let c=g()&&p()&&!v()&&1?new KeyboardEvent("keydown",{keyIdentifier:"Enter",metaKey:a,ctrlKey:s,altKey:i,shiftKey:u}):new MouseEvent("click",{metaKey:a,ctrlKey:s,altKey:i,shiftKey:u,detail:1,bubbles:!0,cancelable:!0});if(w.isOpening=r,function(){if(null==l){l=!1;try{document.createElement("div").focus({get preventScroll(){return l=!0,!0}})}catch{}}return l}())e.focus({preventScroll:!0});else{let t=function(e){let t=e.parentNode,r=[],n=document.scrollingElement||document.documentElement;for(;t instanceof HTMLElement&&t!==n;)(t.offsetHeighttypeof window&&window.document&&window.document.createElement,new WeakMap;r.default.useId;let x=null,F=new Set,P=new Map,k=!1,L=!1,N={Tab:!0,Escape:!0};function C(e,t){for(let r of F)r(e,t)}function I(e){k=!0,w.isOpening||e.metaKey||!p()&&e.altKey||e.ctrlKey||"Control"===e.key||"Shift"===e.key||"Meta"===e.key||(x="keyboard",C("keyboard",e))}function S(e){x="pointer","pointerType"in e&&e.pointerType,("mousedown"===e.type||"pointerdown"===e.type)&&(k=!0,C("pointer",e))}function A(e){w.isOpening||(""!==e.pointerType||!e.isTrusted)&&(y()&&e.pointerType?"click"!==e.type||1!==e.buttons:0!==e.detail||e.pointerType)||(k=!0,x="virtual")}function M(e){e.target!==window&&e.target!==document&&e.isTrusted&&(k||L||(x="virtual",C("virtual",e)),k=!1,L=!1)}function R(){k=!1,L=!0}function O(e){if("u"typeof PointerEvent&&(r.addEventListener("pointerdown",S,!0),r.addEventListener("pointermove",S,!0),r.addEventListener("pointerup",S,!0)),t.addEventListener("beforeunload",()=>{D(e)},{once:!0}),P.set(t,{focus:n})}let D=(e,t)=>{let r=a(e),n=o(e);t&&n.removeEventListener("DOMContentLoaded",t),P.has(r)&&(r.HTMLElement.prototype.focus=P.get(r).focus,n.removeEventListener("keydown",I,!0),n.removeEventListener("keyup",I,!0),n.removeEventListener("click",A,!0),r.removeEventListener("focus",M,!0),r.removeEventListener("blur",R,!1),"u">typeof PointerEvent&&(n.removeEventListener("pointerdown",S,!0),n.removeEventListener("pointermove",S,!0),n.removeEventListener("pointerup",S,!0)),P.delete(r))};function H(){return"pointer"!==x}"u">typeof document&&("loading"!==(t=o(void 0)).readyState?O(void 0):t.addEventListener("DOMContentLoaded",()=>{O(void 0)}));let j=new Set(["checkbox","radio","range","color","file","image","button","submit","reset"]);function K(e,t){return!!t&&!!e&&e.contains(t)}function W(){let e=(0,r.useRef)(new Map),t=(0,r.useCallback)((t,r,n,o)=>{let a=(null==o?void 0:o.once)?(...t)=>{e.current.delete(n),n(...t)}:n;e.current.set(n,{type:r,eventTarget:t,fn:a,options:o}),t.addEventListener(r,a,o)},[]),n=(0,r.useCallback)((t,r,n,o)=>{var a;let s=(null==(a=e.current.get(n))?void 0:a.fn)||n;t.removeEventListener(r,s,o),e.current.delete(n)},[]),o=(0,r.useCallback)(()=>{e.current.forEach((e,t)=>{n(e.eventTarget,e.type,t,e.options)})},[n]);return(0,r.useEffect)(()=>o,[o]),{addGlobalListener:t,removeGlobalListener:n,removeAllGlobalListeners:o}}function B(e={}){var t;let{autoFocus:n=!1,isTextInput:s,within:l}=e,c=(0,r.useRef)({isFocused:!1,isFocusVisible:n||H()}),[d,f]=(0,r.useState)(!1),[p,m]=(0,r.useState)(()=>c.current.isFocused&&c.current.isFocusVisible),v=(0,r.useCallback)(()=>m(c.current.isFocused&&c.current.isFocusVisible),[]),b=(0,r.useCallback)(e=>{c.current.isFocused=e,f(e),v()},[v]);t={isTextInput:s},O(),(0,r.useEffect)(()=>{let e=(e,r)=>{var n;let s,l,i,u,d;n=!!(null==t?void 0:t.isTextInput),s=o(null==r?void 0:r.target),l="u">typeof window?a(null==r?void 0:r.target).HTMLInputElement:HTMLInputElement,i="u">typeof window?a(null==r?void 0:r.target).HTMLTextAreaElement:HTMLTextAreaElement,u="u">typeof window?a(null==r?void 0:r.target).HTMLElement:HTMLElement,d="u">typeof window?a(null==r?void 0:r.target).KeyboardEvent:KeyboardEvent,(n=n||s.activeElement instanceof l&&!j.has(s.activeElement.type)||s.activeElement instanceof i||s.activeElement instanceof u&&s.activeElement.isContentEditable)&&"keyboard"===e&&r instanceof d&&!N[r.key]||(e=>{c.current.isFocusVisible=e,v()})(H())};return F.add(e),()=>{F.delete(e)}},[]);let{focusProps:g}=function(e){let{isDisabled:t,onFocus:n,onBlur:a,onFocusChange:s}=e,l=(0,r.useCallback)(e=>{if(e.target===e.currentTarget)return a&&a(e),s&&s(!1),!0},[a,s]),i=u(l),c=(0,r.useCallback)(e=>{var t;let r=o(e.target),a=r?((e=document)=>e.activeElement)(r):((e=document)=>e.activeElement)();e.target===e.currentTarget&&a===(t=e.nativeEvent,t.target)&&(n&&n(e),s&&s(!0),i(e))},[s,n,i]);return{focusProps:{onFocus:!t&&(n||s||a)?c:void 0,onBlur:!t&&(a||s)?l:void 0}}}({isDisabled:l,onFocusChange:b}),{focusWithinProps:h}=function(e){let{isDisabled:t,onBlurWithin:n,onFocusWithin:a,onFocusWithinChange:s}=e,l=(0,r.useRef)({isFocusWithin:!1}),{addGlobalListener:c,removeAllGlobalListeners:d}=W(),f=(0,r.useCallback)(e=>{e.currentTarget.contains(e.target)&&l.current.isFocusWithin&&!e.currentTarget.contains(e.relatedTarget)&&(l.current.isFocusWithin=!1,d(),n&&n(e),s&&s(!1))},[n,s,l,d]),p=u(f),m=(0,r.useCallback)(e=>{var t;if(!e.currentTarget.contains(e.target))return;let r=o(e.target),n=((e=document)=>e.activeElement)(r);if(!l.current.isFocusWithin&&n===(t=e.nativeEvent,t.target)){a&&a(e),s&&s(!0),l.current.isFocusWithin=!0,p(e);let t=e.currentTarget;c(r,"focus",e=>{if(l.current.isFocusWithin&&!K(t,e.target)){let n=new r.defaultView.FocusEvent("blur",{relatedTarget:e.target});Object.defineProperty(n,"target",{value:t}),Object.defineProperty(n,"currentTarget",{value:t}),f(i(n))}},{capture:!0})}},[a,s,p,c,f]);return t?{focusWithinProps:{onFocus:void 0,onBlur:void 0}}:{focusWithinProps:{onFocus:m,onBlur:f}}}({isDisabled:!l,onFocusWithinChange:b});return{isFocused:d,isFocusVisible:p,focusProps:l?h:g}}e.s(["useFocusRing",()=>B],429427);let V=!1,_=0;function G(e){"touch"===e.pointerType&&(V=!0,setTimeout(()=>{V=!1},50))}function U(){if("u">typeof document)return 0===_&&"u">typeof PointerEvent&&document.addEventListener("pointerup",G),_++,()=>{!(--_>0)&&"u">typeof PointerEvent&&document.removeEventListener("pointerup",G)}}function $(e){let{onHoverStart:t,onHoverChange:n,onHoverEnd:a,isDisabled:s}=e,[l,i]=(0,r.useState)(!1),u=(0,r.useRef)({isHovered:!1,ignoreEmulatedMouseEvents:!1,pointerType:"",target:null}).current;(0,r.useEffect)(U,[]);let{addGlobalListener:c,removeAllGlobalListeners:d}=W(),{hoverProps:f,triggerHoverEnd:p}=(0,r.useMemo)(()=>{let e=(e,t)=>{let r=u.target;u.pointerType="",u.target=null,"touch"!==t&&u.isHovered&&r&&(u.isHovered=!1,d(),a&&a({type:"hoverend",target:r,pointerType:t}),n&&n(!1),i(!1))},r={};return"u">typeof PointerEvent&&(r.onPointerEnter=r=>{V&&"mouse"===r.pointerType||((r,a)=>{if(u.pointerType=a,s||"touch"===a||u.isHovered||!r.currentTarget.contains(r.target))return;u.isHovered=!0;let l=r.currentTarget;u.target=l,c(o(r.target),"pointerover",t=>{u.isHovered&&u.target&&!K(u.target,t.target)&&e(t,t.pointerType)},{capture:!0}),t&&t({type:"hoverstart",target:l,pointerType:a}),n&&n(!0),i(!0)})(r,r.pointerType)},r.onPointerLeave=t=>{!s&&t.currentTarget.contains(t.target)&&e(t,t.pointerType)}),{hoverProps:r,triggerHoverEnd:e}},[t,n,a,s,u,c,d]);return(0,r.useEffect)(()=>{s&&p({currentTarget:u.target},u.pointerType)},[s]),{hoverProps:f,isHovered:l}}e.s(["useHover",()=>$],371330);var q=Object.defineProperty,X=(e,t,r)=>{let n;return(n="symbol"!=typeof t?t+"":t)in e?q(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r,r};let Y=new class{constructor(){X(this,"current",this.detect()),X(this,"handoffState","pending"),X(this,"currentId",0)}set(e){this.current!==e&&(this.handoffState="pending",this.currentId=0,this.current=e)}reset(){this.set(this.detect())}nextId(){return++this.currentId}get isServer(){return"server"===this.current}get isClient(){return"client"===this.current}detect(){return"u"setTimeout(()=>{throw e}))}function J(){let e=[],t={addEventListener:(e,r,n,o)=>(e.addEventListener(r,n,o),t.add(()=>e.removeEventListener(r,n,o))),requestAnimationFrame(...e){let r=requestAnimationFrame(...e);return t.add(()=>cancelAnimationFrame(r))},nextFrame:(...e)=>t.requestAnimationFrame(()=>t.requestAnimationFrame(...e)),setTimeout(...e){let r=setTimeout(...e);return t.add(()=>clearTimeout(r))},microTask(...e){let r={current:!0};return Z(()=>{r.current&&e[0]()}),t.add(()=>{r.current=!1})},style(e,t,r){let n=e.style.getPropertyValue(t);return Object.assign(e.style,{[t]:r}),this.add(()=>{Object.assign(e.style,{[t]:n})})},group(e){let t=J();return e(t),this.add(()=>t.dispose())},add:t=>(e.includes(t)||e.push(t),()=>{let r=e.indexOf(t);if(r>=0)for(let t of e.splice(r,1))t()}),dispose(){for(let t of e.splice(0))t()}};return t}function Q(){let[e]=(0,r.useState)(J);return(0,r.useEffect)(()=>()=>e.dispose(),[e]),e}e.s(["env",()=>Y],80758),e.s(["getOwnerDocument",()=>z],402155),e.s(["microTask",()=>Z],368578),e.s(["disposables",()=>J],544508),e.s(["useDisposables",()=>Q],746725);let ee=(e,t)=>{Y.isServer?(0,r.useEffect)(e,t):(0,r.useLayoutEffect)(e,t)};function et(e){let t=(0,r.useRef)(e);return ee(()=>{t.current=e},[e]),t}e.s(["useIsoMorphicEffect",()=>ee],835696),e.s(["useLatestValue",()=>et],941444);let er=function(e){let t=et(e);return r.default.useCallback((...e)=>t.current(...e),[t])};function en({disabled:e=!1}={}){let t=(0,r.useRef)(null),[n,o]=(0,r.useState)(!1),a=Q(),s=er(()=>{t.current=null,o(!1),a.dispose()}),l=er(e=>{if(a.dispose(),null===t.current){t.current=e.currentTarget,o(!0);{let r=z(e.currentTarget);a.addEventListener(r,"pointerup",s,!1),a.addEventListener(r,"pointermove",e=>{if(t.current){var r,n;let a,s;o((a=e.width/2,s=e.height/2,r={top:e.clientY-s,right:e.clientX+a,bottom:e.clientY+s,left:e.clientX-a},n=t.current.getBoundingClientRect(),!(!r||!n||r.rightn.right||r.bottomn.bottom)))}},!1),a.addEventListener(r,"pointercancel",s,!1)}}});return{pressed:n,pressProps:e?{}:{onPointerDown:l,onPointerUp:s,onClick:s}}}e.s(["useEvent",()=>er],914189),e.s(["useActivePress",()=>en],394487)},144279,294316,e=>{"use strict";var t=e.i(271645);function r(e,r){return(0,t.useMemo)(()=>{var t;if(e.type)return e.type;let n=null!=(t=e.as)?t:"button";if("string"==typeof n&&"button"===n.toLowerCase()||(null==r?void 0:r.tagName)==="BUTTON"&&!r.hasAttribute("type"))return"button"},[e.type,e.as,r])}e.s(["useResolveButtonType",()=>r],144279);var n=e.i(914189);let o=Symbol();function a(e,t=!0){return Object.assign(e,{[o]:t})}function s(...e){let r=(0,t.useRef)(e);(0,t.useEffect)(()=>{r.current=e},[e]);let a=(0,n.useEvent)(e=>{for(let t of r.current)null!=t&&("function"==typeof t?t(e):t.current=e)});return e.every(e=>null==e||(null==e?void 0:e[o]))?void 0:a}e.s(["optionalRef",()=>a,"useSyncRefs",()=>s],294316)},553521,e=>{"use strict";var t=e.i(271645),r=e.i(835696);function n(){let e=(0,t.useRef)(!1);return(0,r.useIsoMorphicEffect)(()=>(e.current=!0,()=>{e.current=!1}),[]),e}e.s(["useIsMounted",()=>n])},732607,e=>{"use strict";function t(...e){return Array.from(new Set(e.flatMap(e=>"string"==typeof e?e.split(" "):[]))).filter(Boolean).join(" ")}e.s(["classNames",()=>t])},397701,e=>{"use strict";function t(e,r,...n){if(e in r){let t=r[e];return"function"==typeof t?t(...n):t}let o=Error(`Tried to handle "${e}" but there is no handler defined. Only defined handlers are: ${Object.keys(r).map(e=>`"${e}"`).join(", ")}.`);throw Error.captureStackTrace&&Error.captureStackTrace(o,t),o}e.s(["match",()=>t])},700020,e=>{"use strict";let t,r;var n=e.i(271645),o=e.i(732607),a=e.i(397701),s=((t=s||{})[t.None=0]="None",t[t.RenderStrategy=1]="RenderStrategy",t[t.Static=2]="Static",t),l=((r=l||{})[r.Unmount=0]="Unmount",r[r.Hidden=1]="Hidden",r);function i(){let e,t,r=(e=(0,n.useRef)([]),t=(0,n.useCallback)(t=>{for(let r of e.current)null!=r&&("function"==typeof r?r(t):r.current=t)},[]),(...r)=>{if(!r.every(e=>null==e))return e.current=r,t});return(0,n.useCallback)(e=>(function({ourProps:e,theirProps:t,slot:r,defaultTag:n,features:o,visible:s=!0,name:l,mergeRefs:i}){i=null!=i?i:c;let f=d(t,e);if(s)return u(f,r,n,l,i);let p=null!=o?o:0;if(2&p){let{static:e=!1,...t}=f;if(e)return u(t,r,n,l,i)}if(1&p){let{unmount:e=!0,...t}=f;return(0,a.match)(+!e,{0:()=>null,1:()=>u({...t,hidden:!0,style:{display:"none"}},r,n,l,i)})}return u(f,r,n,l,i)})({mergeRefs:r,...e}),[r])}function u(e,t={},r,a,s){let{as:l=r,children:i,refName:c="ref",...f}=v(e,["unmount","static"]),p=void 0!==e.ref?{[c]:e.ref}:{},b="function"==typeof i?i(t):i;"className"in f&&f.className&&"function"==typeof f.className&&(f.className=f.className(t)),f["aria-labelledby"]&&f["aria-labelledby"]===f.id&&(f["aria-labelledby"]=void 0);let g={};if(t){let e=!1,r=[];for(let[n,o]of Object.entries(t))"boolean"==typeof o&&(e=!0),!0===o&&r.push(n.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`));if(e)for(let e of(g["data-headlessui-state"]=r.join(" "),r))g[`data-${e}`]=""}if(l===n.Fragment&&(Object.keys(m(f)).length>0||Object.keys(m(g)).length>0))if(!(0,n.isValidElement)(b)||Array.isArray(b)&&b.length>1){if(Object.keys(m(f)).length>0)throw Error(['Passing props on "Fragment"!',"",`The current component <${a} /> is rendering a "Fragment".`,"However we need to passthrough the following props:",Object.keys(m(f)).concat(Object.keys(m(g))).map(e=>` - ${e}`).join(` `),"","You can apply a few solutions:",['Add an `as="..."` prop, to ensure that we render an actual element instead of a "Fragment".',"Render a single element as the child so that we can forward the props onto that element."].map(e=>` - ${e}`).join(` `)].join(` -`))}else{var h;let e=b.props,t=null==e?void 0:e.className,r="function"==typeof t?(...e)=>(0,o.classNames)(t(...e),f.className):(0,o.classNames)(t,f.className),a=d(b.props,m(v(f,["ref"])));for(let e in g)e in a&&delete g[e];return(0,n.cloneElement)(b,Object.assign({},a,g,p,{ref:s((h=b,n.default.version.split(".")[0]>="19"?h.props.ref:h.ref),p.ref)},r?{className:r}:{}))}return(0,n.createElement)(l,Object.assign({},v(f,["ref"]),l!==n.Fragment&&p,l!==n.Fragment&&g),b)}function c(...e){return e.every(e=>null==e)?void 0:t=>{for(let r of e)null!=r&&("function"==typeof r?r(t):r.current=t)}}function d(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];if(t.disabled||t["aria-disabled"])for(let e in r)/^(on(?:Click|Pointer|Mouse|Key)(?:Down|Up|Press)?)$/.test(e)&&(r[e]=[e=>{var t;return null==(t=null==e?void 0:e.preventDefault)?void 0:t.call(e)}]);for(let e in r)Object.assign(t,{[e](t,...n){for(let o of r[e]){if((t instanceof Event||(null==t?void 0:t.nativeEvent)instanceof Event)&&t.defaultPrevented)return;o(t,...n)}}});return t}function f(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];for(let e in r)Object.assign(t,{[e](...t){for(let n of r[e])null==n||n(...t)}});return t}function p(e){var t;return Object.assign((0,n.forwardRef)(e),{displayName:null!=(t=e.displayName)?t:e.name})}function m(e){let t=Object.assign({},e);for(let e in t)void 0===t[e]&&delete t[e];return t}function v(e,t=[]){let r=Object.assign({},e);for(let e of t)e in r&&delete r[e];return r}e.s(["RenderFeatures",()=>s,"RenderStrategy",()=>l,"compact",()=>m,"forwardRefWithAs",()=>p,"mergeProps",()=>f,"useRender",()=>i])},2788,e=>{"use strict";let t;var r=e.i(700020),n=((t=n||{})[t.None=1]="None",t[t.Focusable=2]="Focusable",t[t.Hidden=4]="Hidden",t);let o=(0,r.forwardRefWithAs)(function(e,t){var n;let{features:o=1,...a}=e,s={ref:t,"aria-hidden":(2&o)==2||(null!=(n=a["aria-hidden"])?n:void 0),hidden:(4&o)==4||void 0,style:{position:"fixed",top:1,left:1,width:1,height:0,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",borderWidth:"0",...(4&o)==4&&(2&o)!=2&&{display:"none"}}};return(0,r.useRender)()({ourProps:s,theirProps:a,slot:{},defaultTag:"span",name:"Hidden"})});e.s(["Hidden",()=>o,"HiddenFeatures",()=>n])},640497,e=>{"use strict";var t=e.i(271645),r=e.i(553521),n=e.i(2788);function o({onFocus:e}){let[o,a]=(0,t.useState)(!0),s=(0,r.useIsMounted)();return o?t.default.createElement(n.Hidden,{as:"button",type:"button",features:n.HiddenFeatures.Focusable,onFocus:t=>{t.preventDefault();let r,n=50;r=requestAnimationFrame(function t(){if(n--<=0){r&&cancelAnimationFrame(r);return}if(e()){if(cancelAnimationFrame(r),!s.current)return;a(!1);return}r=requestAnimationFrame(t)})}}):null}e.s(["FocusSentinel",()=>o])},652265,e=>{"use strict";let t,r,n,o,a;e.i(544508);var s=e.i(397701),l=e.i(402155);let i=["[contentEditable=true]","[tabindex]","a[href]","area[href]","button:not([disabled])","iframe","input:not([disabled])","select:not([disabled])","textarea:not([disabled])"].map(e=>`${e}:not([tabindex='-1'])`).join(","),u=["[data-autofocus]"].map(e=>`${e}:not([tabindex='-1'])`).join(",");var c=((t=c||{})[t.First=1]="First",t[t.Previous=2]="Previous",t[t.Next=4]="Next",t[t.Last=8]="Last",t[t.WrapAround=16]="WrapAround",t[t.NoScroll=32]="NoScroll",t[t.AutoFocus=64]="AutoFocus",t),d=((r=d||{})[r.Error=0]="Error",r[r.Overflow=1]="Overflow",r[r.Success=2]="Success",r[r.Underflow=3]="Underflow",r),f=((n=f||{})[n.Previous=-1]="Previous",n[n.Next=1]="Next",n);function p(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(i)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}var m=((o=m||{})[o.Strict=0]="Strict",o[o.Loose=1]="Loose",o);function v(e,t=0){var r;return e!==(null==(r=(0,l.getOwnerDocument)(e))?void 0:r.body)&&(0,s.match)(t,{0:()=>e.matches(i),1(){let t=e;for(;null!==t;){if(t.matches(i))return!0;t=t.parentElement}return!1}})}var b=((a=b||{})[a.Keyboard=0]="Keyboard",a[a.Mouse=1]="Mouse",a);function g(e,t=e=>e){return e.slice().sort((e,r)=>{let n=t(e),o=t(r);if(null===n||null===o)return 0;let a=n.compareDocumentPosition(o);return a&Node.DOCUMENT_POSITION_FOLLOWING?-1:a&Node.DOCUMENT_POSITION_PRECEDING?1:0})}function h(e,t){return y(p(),t,{relativeTo:e})}function y(e,t,{sorted:r=!0,relativeTo:n=null,skipElements:o=[]}={}){var a,s,l;let i=Array.isArray(e)?e.length>0?e[0].ownerDocument:document:e.ownerDocument,c=Array.isArray(e)?r?g(e):e:64&t?function(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(u)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}(e):p(e);o.length>0&&c.length>1&&(c=c.filter(e=>!o.some(t=>null!=t&&"current"in t?(null==t?void 0:t.current)===e:t===e))),n=null!=n?n:i.activeElement;let d=(()=>{if(5&t)return 1;if(10&t)return -1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),f=(()=>{if(1&t)return 0;if(2&t)return Math.max(0,c.indexOf(n))-1;if(4&t)return Math.max(0,c.indexOf(n))+1;if(8&t)return c.length-1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),m=32&t?{preventScroll:!0}:{},v=0,b=c.length,h;do{if(v>=b||v+b<=0)return 0;let e=f+v;if(16&t)e=(e+b)%b;else{if(e<0)return 3;if(e>=b)return 1}null==(h=c[e])||h.focus(m),v+=d}while(h!==i.activeElement)return 6&t&&null!=(l=null==(s=null==(a=h)?void 0:a.matches)?void 0:s.call(a,"textarea,input"))&&l&&h.select(),2}"u">typeof window&&"u">typeof document&&(document.addEventListener("keydown",e=>{e.metaKey||e.altKey||e.ctrlKey||(document.documentElement.dataset.headlessuiFocusVisible="")},!0),document.addEventListener("click",e=>{1===e.detail?delete document.documentElement.dataset.headlessuiFocusVisible:0===e.detail&&(document.documentElement.dataset.headlessuiFocusVisible="")},!0)),e.s(["Focus",()=>c,"FocusResult",()=>d,"FocusableMode",()=>m,"focusFrom",()=>h,"focusIn",()=>y,"getFocusableElements",()=>p,"isFocusableElement",()=>v,"sortByDomNode",()=>g])},963703,e=>{"use strict";var t=e.i(271645);let r=t.createContext(null);function n({children:e}){let n=t.useRef({groups:new Map,get(e,t){var r;let n=this.groups.get(e);n||(n=new Map,this.groups.set(e,n));let o=null!=(r=n.get(t))?r:0;return n.set(t,o+1),[Array.from(n.keys()).indexOf(t),function(){let e=n.get(t);e>1?n.set(t,e-1):n.delete(t)}]}});return t.createElement(r.Provider,{value:n},e)}function o(e){let n=t.useContext(r);if(!n)throw Error("You must wrap your component in a ");let o=t.useId(),[a,s]=n.current.get(e,o);return t.useEffect(()=>s,[]),a}e.s(["StableCollection",()=>n,"useStableCollectionIndex",()=>o])},998348,e=>{"use strict";let t;var r=((t=r||{}).Space=" ",t.Enter="Enter",t.Escape="Escape",t.Backspace="Backspace",t.Delete="Delete",t.ArrowLeft="ArrowLeft",t.ArrowUp="ArrowUp",t.ArrowRight="ArrowRight",t.ArrowDown="ArrowDown",t.Home="Home",t.End="End",t.PageUp="PageUp",t.PageDown="PageDown",t.Tab="Tab",t);e.s(["Keys",()=>r])},970554,e=>{"use strict";let t,r,n;var o=e.i(429427),a=e.i(371330),s=e.i(271645),l=e.i(394487),i=e.i(914189),u=e.i(835696),c=e.i(941444),d=e.i(144279),f=e.i(294316),p=e.i(640497),m=e.i(2788),v=e.i(652265),b=e.i(397701),g=e.i(368578),h=e.i(402155),y=e.i(700020),E=e.i(963703),w=e.i(998348),T=((t=T||{})[t.Forwards=0]="Forwards",t[t.Backwards=1]="Backwards",t),x=((r=x||{})[r.Less=-1]="Less",r[r.Equal=0]="Equal",r[r.Greater=1]="Greater",r),F=((n=F||{})[n.SetSelectedIndex=0]="SetSelectedIndex",n[n.RegisterTab=1]="RegisterTab",n[n.UnregisterTab=2]="UnregisterTab",n[n.RegisterPanel=3]="RegisterPanel",n[n.UnregisterPanel=4]="UnregisterPanel",n);let P={0(e,t){var r;let n=(0,v.sortByDomNode)(e.tabs,e=>e.current),o=(0,v.sortByDomNode)(e.panels,e=>e.current),a=n.filter(e=>{var t;return!(null!=(t=e.current)&&t.hasAttribute("disabled"))}),s={...e,tabs:n,panels:o};if(t.index<0||t.index>n.length-1){let r=(0,b.match)(Math.sign(t.index-e.selectedIndex),{[-1]:()=>1,0:()=>(0,b.match)(Math.sign(t.index),{[-1]:()=>0,0:()=>0,1:()=>1}),1:()=>0});if(0===a.length)return s;let o=(0,b.match)(r,{0:()=>n.indexOf(a[0]),1:()=>n.indexOf(a[a.length-1])});return{...s,selectedIndex:-1===o?e.selectedIndex:o}}let l=n.slice(0,t.index),i=[...n.slice(t.index),...l].find(e=>a.includes(e));if(!i)return s;let u=null!=(r=n.indexOf(i))?r:e.selectedIndex;return -1===u&&(u=e.selectedIndex),{...s,selectedIndex:u}},1(e,t){if(e.tabs.includes(t.tab))return e;let r=e.tabs[e.selectedIndex],n=(0,v.sortByDomNode)([...e.tabs,t.tab],e=>e.current),o=e.selectedIndex;return e.info.current.isControlled||-1===(o=n.indexOf(r))&&(o=e.selectedIndex),{...e,tabs:n,selectedIndex:o}},2:(e,t)=>({...e,tabs:e.tabs.filter(e=>e!==t.tab)}),3:(e,t)=>e.panels.includes(t.panel)?e:{...e,panels:(0,v.sortByDomNode)([...e.panels,t.panel],e=>e.current)},4:(e,t)=>({...e,panels:e.panels.filter(e=>e!==t.panel)})},k=(0,s.createContext)(null);function L(e){let t=(0,s.useContext)(k);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,L),t}return t}k.displayName="TabsDataContext";let N=(0,s.createContext)(null);function C(e){let t=(0,s.useContext)(N);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,C),t}return t}function I(e,t){return(0,b.match)(t.type,P,e,t)}N.displayName="TabsActionsContext";let S=y.RenderFeatures.RenderStrategy|y.RenderFeatures.Static,A=Object.assign((0,y.forwardRefWithAs)(function(e,t){var r,n;let c=(0,s.useId)(),{id:p=`headlessui-tabs-tab-${c}`,disabled:m=!1,autoFocus:T=!1,...x}=e,{orientation:F,activation:P,selectedIndex:k,tabs:N,panels:I}=L("Tab"),S=C("Tab"),A=L("Tab"),[M,R]=(0,s.useState)(null),O=(0,s.useRef)(null),D=(0,f.useSyncRefs)(O,t,R);(0,u.useIsoMorphicEffect)(()=>S.registerTab(O),[S,O]);let H=(0,E.useStableCollectionIndex)("tabs"),j=N.indexOf(O);-1===j&&(j=H);let K=j===k,W=(0,i.useEvent)(e=>{var t;let r=e();if(r===v.FocusResult.Success&&"auto"===P){let e=null==(t=(0,h.getOwnerDocument)(O))?void 0:t.activeElement,r=A.tabs.findIndex(t=>t.current===e);-1!==r&&S.change(r)}return r}),B=(0,i.useEvent)(e=>{let t=N.map(e=>e.current).filter(Boolean);if(e.key===w.Keys.Space||e.key===w.Keys.Enter){e.preventDefault(),e.stopPropagation(),S.change(j);return}switch(e.key){case w.Keys.Home:case w.Keys.PageUp:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.First));case w.Keys.End:case w.Keys.PageDown:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.Last))}if(W(()=>(0,b.match)(F,{vertical:()=>e.key===w.Keys.ArrowUp?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowDown?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error,horizontal:()=>e.key===w.Keys.ArrowLeft?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowRight?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error}))===v.FocusResult.Success)return e.preventDefault()}),V=(0,s.useRef)(!1),_=(0,i.useEvent)(()=>{var e;V.current||(V.current=!0,null==(e=O.current)||e.focus({preventScroll:!0}),S.change(j),(0,g.microTask)(()=>{V.current=!1}))}),G=(0,i.useEvent)(e=>{e.preventDefault()}),{isFocusVisible:U,focusProps:$}=(0,o.useFocusRing)({autoFocus:T}),{isHovered:q,hoverProps:X}=(0,a.useHover)({isDisabled:m}),{pressed:Y,pressProps:z}=(0,l.useActivePress)({disabled:m}),Z=(0,s.useMemo)(()=>({selected:K,hover:q,active:Y,focus:U,autofocus:T,disabled:m}),[K,q,U,Y,T,m]),J=(0,y.mergeProps)({ref:D,onKeyDown:B,onMouseDown:G,onClick:_,id:p,role:"tab",type:(0,d.useResolveButtonType)(e,M),"aria-controls":null==(n=null==(r=I[j])?void 0:r.current)?void 0:n.id,"aria-selected":K,tabIndex:K?0:-1,disabled:m||void 0,autoFocus:T},$,X,z);return(0,y.useRender)()({ourProps:J,theirProps:x,slot:Z,defaultTag:"button",name:"Tabs.Tab"})}),{Group:(0,y.forwardRefWithAs)(function(e,t){let{defaultIndex:r=0,vertical:n=!1,manual:o=!1,onChange:a,selectedIndex:l=null,...d}=e,m=n?"vertical":"horizontal",b=o?"manual":"auto",g=null!==l,h=(0,c.useLatestValue)({isControlled:g}),w=(0,f.useSyncRefs)(t),[T,x]=(0,s.useReducer)(I,{info:h,selectedIndex:null!=l?l:r,tabs:[],panels:[]}),F=(0,s.useMemo)(()=>({selectedIndex:T.selectedIndex}),[T.selectedIndex]),P=(0,c.useLatestValue)(a||(()=>{})),L=(0,c.useLatestValue)(T.tabs),C=(0,s.useMemo)(()=>({orientation:m,activation:b,...T}),[m,b,T]),S=(0,i.useEvent)(e=>(x({type:1,tab:e}),()=>x({type:2,tab:e}))),A=(0,i.useEvent)(e=>(x({type:3,panel:e}),()=>x({type:4,panel:e}))),M=(0,i.useEvent)(e=>{R.current!==e&&P.current(e),g||x({type:0,index:e})}),R=(0,c.useLatestValue)(g?e.selectedIndex:T.selectedIndex),O=(0,s.useMemo)(()=>({registerTab:S,registerPanel:A,change:M}),[]);(0,u.useIsoMorphicEffect)(()=>{x({type:0,index:null!=l?l:r})},[l]),(0,u.useIsoMorphicEffect)(()=>{if(void 0===R.current||T.tabs.length<=0)return;let e=(0,v.sortByDomNode)(T.tabs,e=>e.current);e.some((e,t)=>T.tabs[t]!==e)&&M(e.indexOf(T.tabs[R.current]))});let D=(0,y.useRender)();return s.default.createElement(E.StableCollection,null,s.default.createElement(N.Provider,{value:O},s.default.createElement(k.Provider,{value:C},C.tabs.length<=0&&s.default.createElement(p.FocusSentinel,{onFocus:()=>{var e,t;for(let r of L.current)if((null==(e=r.current)?void 0:e.tabIndex)===0)return null==(t=r.current)||t.focus(),!0;return!1}}),D({ourProps:{ref:w},theirProps:d,slot:F,defaultTag:"div",name:"Tabs"}))))}),List:(0,y.forwardRefWithAs)(function(e,t){let{orientation:r,selectedIndex:n}=L("Tab.List"),o=(0,f.useSyncRefs)(t),a=(0,s.useMemo)(()=>({selectedIndex:n}),[n]);return(0,y.useRender)()({ourProps:{ref:o,role:"tablist","aria-orientation":r},theirProps:e,slot:a,defaultTag:"div",name:"Tabs.List"})}),Panels:(0,y.forwardRefWithAs)(function(e,t){let{selectedIndex:r}=L("Tab.Panels"),n=(0,f.useSyncRefs)(t),o=(0,s.useMemo)(()=>({selectedIndex:r}),[r]);return(0,y.useRender)()({ourProps:{ref:n},theirProps:e,slot:o,defaultTag:"div",name:"Tabs.Panels"})}),Panel:(0,y.forwardRefWithAs)(function(e,t){var r,n,a,l;let i=(0,s.useId)(),{id:c=`headlessui-tabs-panel-${i}`,tabIndex:d=0,...p}=e,{selectedIndex:v,tabs:b,panels:g}=L("Tab.Panel"),h=C("Tab.Panel"),w=(0,s.useRef)(null),T=(0,f.useSyncRefs)(w,t);(0,u.useIsoMorphicEffect)(()=>h.registerPanel(w),[h,w]);let x=(0,E.useStableCollectionIndex)("panels"),F=g.indexOf(w);-1===F&&(F=x);let P=F===v,{isFocusVisible:k,focusProps:N}=(0,o.useFocusRing)(),I=(0,s.useMemo)(()=>({selected:P,focus:k}),[P,k]),A=(0,y.mergeProps)({ref:T,id:c,role:"tabpanel","aria-labelledby":null==(n=null==(r=b[F])?void 0:r.current)?void 0:n.id,tabIndex:P?d:-1},N),M=(0,y.useRender)();return P||null!=(a=p.unmount)&&!a||null!=(l=p.static)&&l?M({ourProps:A,theirProps:p,slot:I,defaultTag:"div",features:S,visible:P,name:"Tabs.Panel"}):s.default.createElement(m.Hidden,{"aria-hidden":"true",...A})})});e.s(["Tab",()=>A])},653824,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(444755),o=e.i(673706),a=e.i(271645);let s=(0,o.makeClassName)("TabGroup"),l=a.default.forwardRef((e,o)=>{let{defaultIndex:l,index:i,onIndexChange:u,children:c,className:d}=e,f=(0,t.__rest)(e,["defaultIndex","index","onIndexChange","children","className"]);return a.default.createElement(r.Tab.Group,Object.assign({as:"div",ref:o,defaultIndex:l,selectedIndex:i,onChange:u,className:(0,n.tremorTwMerge)(s("root"),"w-full",d)},f),c)});l.displayName="TabGroup",e.s(["TabGroup",()=>l],653824)},405371,910342,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(480731);let o=(0,r.createContext)(n.BaseColors.Blue);e.s(["default",()=>o],910342);var a=e.i(970554),s=e.i(444755);let l=(0,e.i(673706).makeClassName)("TabList"),i=(0,r.createContext)("line"),u={line:(0,s.tremorTwMerge)("flex border-b space-x-4","border-tremor-border","dark:border-dark-tremor-border"),solid:(0,s.tremorTwMerge)("inline-flex p-0.5 rounded-tremor-default space-x-1.5","bg-tremor-background-subtle","dark:bg-dark-tremor-background-subtle")},c=r.default.forwardRef((e,n)=>{let{color:c,variant:d="line",children:f,className:p}=e,m=(0,t.__rest)(e,["color","variant","children","className"]);return r.default.createElement(a.Tab.List,Object.assign({ref:n,className:(0,s.tremorTwMerge)(l("root"),"justify-start overflow-x-clip",u[d],p)},m),r.default.createElement(i.Provider,{value:d},r.default.createElement(o.Provider,{value:c},f)))});c.displayName="TabList",e.s(["TabVariantContext",()=>i,"default",()=>c],405371)},881073,e=>{"use strict";var t=e.i(405371);e.s(["TabList",()=>t.default])},197647,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(95779),o=e.i(444755),a=e.i(673706),s=e.i(271645),l=e.i(405371),i=e.i(910342);let u=(0,a.makeClassName)("Tab"),c=s.default.forwardRef((e,c)=>{let{icon:d,className:f,children:p}=e,m=(0,t.__rest)(e,["icon","className","children"]),v=(0,s.useContext)(l.TabVariantContext),b=(0,s.useContext)(i.default);return s.default.createElement(r.Tab,Object.assign({ref:c,className:(0,o.tremorTwMerge)(u("root"),"flex whitespace-nowrap truncate max-w-xs outline-none data-focus-visible:ring text-tremor-default transition duration-100",function(e,t){switch(e){case"line":return(0,o.tremorTwMerge)("data-[selected]:border-b-2 hover:border-b-2 border-transparent transition duration-100 -mb-px px-2 py-2","hover:border-tremor-content hover:text-tremor-content-emphasis text-tremor-content","[&:not([data-selected])]:dark:hover:border-dark-tremor-content-emphasis [&:not([data-selected])]:dark:hover:text-dark-tremor-content-emphasis [&:not([data-selected])]:dark:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.border).selectBorderColor:["data-[selected]:border-tremor-brand data-[selected]:text-tremor-brand","data-[selected]:dark:border-dark-tremor-brand data-[selected]:dark:text-dark-tremor-brand"]);case"solid":return(0,o.tremorTwMerge)("border-transparent border rounded-tremor-small px-2.5 py-1","data-[selected]:border-tremor-border data-[selected]:bg-tremor-background data-[selected]:shadow-tremor-input [&:not([data-selected])]:hover:text-tremor-content-emphasis data-[selected]:text-tremor-brand [&:not([data-selected])]:text-tremor-content","dark:data-[selected]:border-dark-tremor-border dark:data-[selected]:bg-dark-tremor-background dark:data-[selected]:shadow-dark-tremor-input dark:[&:not([data-selected])]:hover:text-dark-tremor-content-emphasis dark:data-[selected]:text-dark-tremor-brand dark:[&:not([data-selected])]:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.text).selectTextColor:"text-tremor-content dark:text-dark-tremor-content")}}(v,b),f,b&&(0,a.getColorClassNames)(b,n.colorPalette.text).selectTextColor)},m),d?s.default.createElement(d,{className:(0,o.tremorTwMerge)(u("icon"),"flex-none h-5 w-5",p?"mr-2":"")}):null,p?s.default.createElement("span",null,p):null)});c.displayName="Tab",e.s(["Tab",()=>c],197647)},751734,e=>{"use strict";let t=(0,e.i(271645).createContext)(0);e.s(["default",()=>t])},144582,e=>{"use strict";let t=(0,e.i(271645).createContext)({selectedValue:void 0,handleValueChange:void 0});e.s(["default",()=>t])},723731,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(751734),o=e.i(144582),a=e.i(444755),s=e.i(673706),l=e.i(271645);let i=(0,s.makeClassName)("TabPanels"),u=l.default.forwardRef((e,s)=>{let{children:u,className:c}=e,d=(0,t.__rest)(e,["children","className"]);return l.default.createElement(r.Tab.Panels,Object.assign({as:"div",ref:s,className:(0,a.tremorTwMerge)(i("root"),"w-full",c)},d),({selectedIndex:e})=>l.default.createElement(o.default.Provider,{value:{selectedValue:e}},l.default.Children.map(u,(e,t)=>l.default.createElement(n.default.Provider,{value:t},e))))});u.displayName="TabPanels",e.s(["TabPanels",()=>u],723731)},404206,e=>{"use strict";var t=e.i(290571),r=e.i(751734),n=e.i(144582),o=e.i(444755),a=e.i(673706),s=e.i(271645);let l=(0,a.makeClassName)("TabPanel"),i=s.default.forwardRef((e,a)=>{let{children:i,className:u}=e,c=(0,t.__rest)(e,["children","className"]),{selectedValue:d}=(0,s.useContext)(n.default),f=d===(0,s.useContext)(r.default);return s.default.createElement("div",Object.assign({ref:a,className:(0,o.tremorTwMerge)(l("root"),"w-full mt-2",f?"":"hidden",u),"aria-selected":f?"true":"false"},c),i)});i.displayName="TabPanel",e.s(["TabPanel",()=>i],404206)}]); \ No newline at end of file +`))}else{var h;let e=b.props,t=null==e?void 0:e.className,r="function"==typeof t?(...e)=>(0,o.classNames)(t(...e),f.className):(0,o.classNames)(t,f.className),a=d(b.props,m(v(f,["ref"])));for(let e in g)e in a&&delete g[e];return(0,n.cloneElement)(b,Object.assign({},a,g,p,{ref:s((h=b,n.default.version.split(".")[0]>="19"?h.props.ref:h.ref),p.ref)},r?{className:r}:{}))}return(0,n.createElement)(l,Object.assign({},v(f,["ref"]),l!==n.Fragment&&p,l!==n.Fragment&&g),b)}function c(...e){return e.every(e=>null==e)?void 0:t=>{for(let r of e)null!=r&&("function"==typeof r?r(t):r.current=t)}}function d(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];if(t.disabled||t["aria-disabled"])for(let e in r)/^(on(?:Click|Pointer|Mouse|Key)(?:Down|Up|Press)?)$/.test(e)&&(r[e]=[e=>{var t;return null==(t=null==e?void 0:e.preventDefault)?void 0:t.call(e)}]);for(let e in r)Object.assign(t,{[e](t,...n){for(let o of r[e]){if((t instanceof Event||(null==t?void 0:t.nativeEvent)instanceof Event)&&t.defaultPrevented)return;o(t,...n)}}});return t}function f(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];for(let e in r)Object.assign(t,{[e](...t){for(let n of r[e])null==n||n(...t)}});return t}function p(e){var t;return Object.assign((0,n.forwardRef)(e),{displayName:null!=(t=e.displayName)?t:e.name})}function m(e){let t=Object.assign({},e);for(let e in t)void 0===t[e]&&delete t[e];return t}function v(e,t=[]){let r=Object.assign({},e);for(let e of t)e in r&&delete r[e];return r}e.s(["RenderFeatures",()=>s,"RenderStrategy",()=>l,"compact",()=>m,"forwardRefWithAs",()=>p,"mergeProps",()=>f,"useRender",()=>i])},2788,e=>{"use strict";let t;var r=e.i(700020),n=((t=n||{})[t.None=1]="None",t[t.Focusable=2]="Focusable",t[t.Hidden=4]="Hidden",t);let o=(0,r.forwardRefWithAs)(function(e,t){var n;let{features:o=1,...a}=e,s={ref:t,"aria-hidden":(2&o)==2||(null!=(n=a["aria-hidden"])?n:void 0),hidden:(4&o)==4||void 0,style:{position:"fixed",top:1,left:1,width:1,height:0,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",borderWidth:"0",...(4&o)==4&&(2&o)!=2&&{display:"none"}}};return(0,r.useRender)()({ourProps:s,theirProps:a,slot:{},defaultTag:"span",name:"Hidden"})});e.s(["Hidden",()=>o,"HiddenFeatures",()=>n])},640497,e=>{"use strict";var t=e.i(271645),r=e.i(553521),n=e.i(2788);function o({onFocus:e}){let[o,a]=(0,t.useState)(!0),s=(0,r.useIsMounted)();return o?t.default.createElement(n.Hidden,{as:"button",type:"button",features:n.HiddenFeatures.Focusable,onFocus:t=>{t.preventDefault();let r,n=50;r=requestAnimationFrame(function t(){if(n--<=0){r&&cancelAnimationFrame(r);return}if(e()){if(cancelAnimationFrame(r),!s.current)return;a(!1);return}r=requestAnimationFrame(t)})}}):null}e.s(["FocusSentinel",()=>o])},652265,e=>{"use strict";let t,r,n,o,a;e.i(544508);var s=e.i(397701),l=e.i(402155);let i=["[contentEditable=true]","[tabindex]","a[href]","area[href]","button:not([disabled])","iframe","input:not([disabled])","select:not([disabled])","textarea:not([disabled])"].map(e=>`${e}:not([tabindex='-1'])`).join(","),u=["[data-autofocus]"].map(e=>`${e}:not([tabindex='-1'])`).join(",");var c=((t=c||{})[t.First=1]="First",t[t.Previous=2]="Previous",t[t.Next=4]="Next",t[t.Last=8]="Last",t[t.WrapAround=16]="WrapAround",t[t.NoScroll=32]="NoScroll",t[t.AutoFocus=64]="AutoFocus",t),d=((r=d||{})[r.Error=0]="Error",r[r.Overflow=1]="Overflow",r[r.Success=2]="Success",r[r.Underflow=3]="Underflow",r),f=((n=f||{})[n.Previous=-1]="Previous",n[n.Next=1]="Next",n);function p(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(i)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}var m=((o=m||{})[o.Strict=0]="Strict",o[o.Loose=1]="Loose",o);function v(e,t=0){var r;return e!==(null==(r=(0,l.getOwnerDocument)(e))?void 0:r.body)&&(0,s.match)(t,{0:()=>e.matches(i),1(){let t=e;for(;null!==t;){if(t.matches(i))return!0;t=t.parentElement}return!1}})}var b=((a=b||{})[a.Keyboard=0]="Keyboard",a[a.Mouse=1]="Mouse",a);function g(e,t=e=>e){return e.slice().sort((e,r)=>{let n=t(e),o=t(r);if(null===n||null===o)return 0;let a=n.compareDocumentPosition(o);return a&Node.DOCUMENT_POSITION_FOLLOWING?-1:a&Node.DOCUMENT_POSITION_PRECEDING?1:0})}function h(e,t){return y(p(),t,{relativeTo:e})}function y(e,t,{sorted:r=!0,relativeTo:n=null,skipElements:o=[]}={}){var a,s,l;let i=Array.isArray(e)?e.length>0?e[0].ownerDocument:document:e.ownerDocument,c=Array.isArray(e)?r?g(e):e:64&t?function(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(u)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}(e):p(e);o.length>0&&c.length>1&&(c=c.filter(e=>!o.some(t=>null!=t&&"current"in t?(null==t?void 0:t.current)===e:t===e))),n=null!=n?n:i.activeElement;let d=(()=>{if(5&t)return 1;if(10&t)return -1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),f=(()=>{if(1&t)return 0;if(2&t)return Math.max(0,c.indexOf(n))-1;if(4&t)return Math.max(0,c.indexOf(n))+1;if(8&t)return c.length-1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),m=32&t?{preventScroll:!0}:{},v=0,b=c.length,h;do{if(v>=b||v+b<=0)return 0;let e=f+v;if(16&t)e=(e+b)%b;else{if(e<0)return 3;if(e>=b)return 1}null==(h=c[e])||h.focus(m),v+=d}while(h!==i.activeElement)return 6&t&&null!=(l=null==(s=null==(a=h)?void 0:a.matches)?void 0:s.call(a,"textarea,input"))&&l&&h.select(),2}"u">typeof window&&"u">typeof document&&(document.addEventListener("keydown",e=>{e.metaKey||e.altKey||e.ctrlKey||(document.documentElement.dataset.headlessuiFocusVisible="")},!0),document.addEventListener("click",e=>{1===e.detail?delete document.documentElement.dataset.headlessuiFocusVisible:0===e.detail&&(document.documentElement.dataset.headlessuiFocusVisible="")},!0)),e.s(["Focus",()=>c,"FocusResult",()=>d,"FocusableMode",()=>m,"focusFrom",()=>h,"focusIn",()=>y,"getFocusableElements",()=>p,"isFocusableElement",()=>v,"sortByDomNode",()=>g])},963703,e=>{"use strict";var t=e.i(271645);let r=t.createContext(null);function n({children:e}){let n=t.useRef({groups:new Map,get(e,t){var r;let n=this.groups.get(e);n||(n=new Map,this.groups.set(e,n));let o=null!=(r=n.get(t))?r:0;return n.set(t,o+1),[Array.from(n.keys()).indexOf(t),function(){let e=n.get(t);e>1?n.set(t,e-1):n.delete(t)}]}});return t.createElement(r.Provider,{value:n},e)}function o(e){let n=t.useContext(r);if(!n)throw Error("You must wrap your component in a ");let o=t.useId(),[a,s]=n.current.get(e,o);return t.useEffect(()=>s,[]),a}e.s(["StableCollection",()=>n,"useStableCollectionIndex",()=>o])},998348,e=>{"use strict";let t;var r=((t=r||{}).Space=" ",t.Enter="Enter",t.Escape="Escape",t.Backspace="Backspace",t.Delete="Delete",t.ArrowLeft="ArrowLeft",t.ArrowUp="ArrowUp",t.ArrowRight="ArrowRight",t.ArrowDown="ArrowDown",t.Home="Home",t.End="End",t.PageUp="PageUp",t.PageDown="PageDown",t.Tab="Tab",t);e.s(["Keys",()=>r])},970554,e=>{"use strict";let t,r,n;var o=e.i(429427),a=e.i(371330),s=e.i(271645),l=e.i(394487),i=e.i(914189),u=e.i(835696),c=e.i(941444),d=e.i(144279),f=e.i(294316),p=e.i(640497),m=e.i(2788),v=e.i(652265),b=e.i(397701),g=e.i(368578),h=e.i(402155),y=e.i(700020),E=e.i(963703),w=e.i(998348),T=((t=T||{})[t.Forwards=0]="Forwards",t[t.Backwards=1]="Backwards",t),x=((r=x||{})[r.Less=-1]="Less",r[r.Equal=0]="Equal",r[r.Greater=1]="Greater",r),F=((n=F||{})[n.SetSelectedIndex=0]="SetSelectedIndex",n[n.RegisterTab=1]="RegisterTab",n[n.UnregisterTab=2]="UnregisterTab",n[n.RegisterPanel=3]="RegisterPanel",n[n.UnregisterPanel=4]="UnregisterPanel",n);let P={0(e,t){var r;let n=(0,v.sortByDomNode)(e.tabs,e=>e.current),o=(0,v.sortByDomNode)(e.panels,e=>e.current),a=n.filter(e=>{var t;return!(null!=(t=e.current)&&t.hasAttribute("disabled"))}),s={...e,tabs:n,panels:o};if(t.index<0||t.index>n.length-1){let r=(0,b.match)(Math.sign(t.index-e.selectedIndex),{[-1]:()=>1,0:()=>(0,b.match)(Math.sign(t.index),{[-1]:()=>0,0:()=>0,1:()=>1}),1:()=>0});if(0===a.length)return s;let o=(0,b.match)(r,{0:()=>n.indexOf(a[0]),1:()=>n.indexOf(a[a.length-1])});return{...s,selectedIndex:-1===o?e.selectedIndex:o}}let l=n.slice(0,t.index),i=[...n.slice(t.index),...l].find(e=>a.includes(e));if(!i)return s;let u=null!=(r=n.indexOf(i))?r:e.selectedIndex;return -1===u&&(u=e.selectedIndex),{...s,selectedIndex:u}},1(e,t){if(e.tabs.includes(t.tab))return e;let r=e.tabs[e.selectedIndex],n=(0,v.sortByDomNode)([...e.tabs,t.tab],e=>e.current),o=e.selectedIndex;return e.info.current.isControlled||-1===(o=n.indexOf(r))&&(o=e.selectedIndex),{...e,tabs:n,selectedIndex:o}},2:(e,t)=>({...e,tabs:e.tabs.filter(e=>e!==t.tab)}),3:(e,t)=>e.panels.includes(t.panel)?e:{...e,panels:(0,v.sortByDomNode)([...e.panels,t.panel],e=>e.current)},4:(e,t)=>({...e,panels:e.panels.filter(e=>e!==t.panel)})},k=(0,s.createContext)(null);function L(e){let t=(0,s.useContext)(k);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,L),t}return t}k.displayName="TabsDataContext";let N=(0,s.createContext)(null);function C(e){let t=(0,s.useContext)(N);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,C),t}return t}function I(e,t){return(0,b.match)(t.type,P,e,t)}N.displayName="TabsActionsContext";let S=y.RenderFeatures.RenderStrategy|y.RenderFeatures.Static,A=Object.assign((0,y.forwardRefWithAs)(function(e,t){var r,n;let c=(0,s.useId)(),{id:p=`headlessui-tabs-tab-${c}`,disabled:m=!1,autoFocus:T=!1,...x}=e,{orientation:F,activation:P,selectedIndex:k,tabs:N,panels:I}=L("Tab"),S=C("Tab"),A=L("Tab"),[M,R]=(0,s.useState)(null),O=(0,s.useRef)(null),D=(0,f.useSyncRefs)(O,t,R);(0,u.useIsoMorphicEffect)(()=>S.registerTab(O),[S,O]);let H=(0,E.useStableCollectionIndex)("tabs"),j=N.indexOf(O);-1===j&&(j=H);let K=j===k,W=(0,i.useEvent)(e=>{var t;let r=e();if(r===v.FocusResult.Success&&"auto"===P){let e=null==(t=(0,h.getOwnerDocument)(O))?void 0:t.activeElement,r=A.tabs.findIndex(t=>t.current===e);-1!==r&&S.change(r)}return r}),B=(0,i.useEvent)(e=>{let t=N.map(e=>e.current).filter(Boolean);if(e.key===w.Keys.Space||e.key===w.Keys.Enter){e.preventDefault(),e.stopPropagation(),S.change(j);return}switch(e.key){case w.Keys.Home:case w.Keys.PageUp:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.First));case w.Keys.End:case w.Keys.PageDown:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.Last))}if(W(()=>(0,b.match)(F,{vertical:()=>e.key===w.Keys.ArrowUp?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowDown?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error,horizontal:()=>e.key===w.Keys.ArrowLeft?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowRight?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error}))===v.FocusResult.Success)return e.preventDefault()}),V=(0,s.useRef)(!1),_=(0,i.useEvent)(()=>{var e;V.current||(V.current=!0,null==(e=O.current)||e.focus({preventScroll:!0}),S.change(j),(0,g.microTask)(()=>{V.current=!1}))}),G=(0,i.useEvent)(e=>{e.preventDefault()}),{isFocusVisible:U,focusProps:$}=(0,o.useFocusRing)({autoFocus:T}),{isHovered:q,hoverProps:X}=(0,a.useHover)({isDisabled:m}),{pressed:Y,pressProps:z}=(0,l.useActivePress)({disabled:m}),Z=(0,s.useMemo)(()=>({selected:K,hover:q,active:Y,focus:U,autofocus:T,disabled:m}),[K,q,U,Y,T,m]),J=(0,y.mergeProps)({ref:D,onKeyDown:B,onMouseDown:G,onClick:_,id:p,role:"tab",type:(0,d.useResolveButtonType)(e,M),"aria-controls":null==(n=null==(r=I[j])?void 0:r.current)?void 0:n.id,"aria-selected":K,tabIndex:K?0:-1,disabled:m||void 0,autoFocus:T},$,X,z);return(0,y.useRender)()({ourProps:J,theirProps:x,slot:Z,defaultTag:"button",name:"Tabs.Tab"})}),{Group:(0,y.forwardRefWithAs)(function(e,t){let{defaultIndex:r=0,vertical:n=!1,manual:o=!1,onChange:a,selectedIndex:l=null,...d}=e,m=n?"vertical":"horizontal",b=o?"manual":"auto",g=null!==l,h=(0,c.useLatestValue)({isControlled:g}),w=(0,f.useSyncRefs)(t),[T,x]=(0,s.useReducer)(I,{info:h,selectedIndex:null!=l?l:r,tabs:[],panels:[]}),F=(0,s.useMemo)(()=>({selectedIndex:T.selectedIndex}),[T.selectedIndex]),P=(0,c.useLatestValue)(a||(()=>{})),L=(0,c.useLatestValue)(T.tabs),C=(0,s.useMemo)(()=>({orientation:m,activation:b,...T}),[m,b,T]),S=(0,i.useEvent)(e=>(x({type:1,tab:e}),()=>x({type:2,tab:e}))),A=(0,i.useEvent)(e=>(x({type:3,panel:e}),()=>x({type:4,panel:e}))),M=(0,i.useEvent)(e=>{R.current!==e&&P.current(e),g||x({type:0,index:e})}),R=(0,c.useLatestValue)(g?e.selectedIndex:T.selectedIndex),O=(0,s.useMemo)(()=>({registerTab:S,registerPanel:A,change:M}),[]);(0,u.useIsoMorphicEffect)(()=>{x({type:0,index:null!=l?l:r})},[l]),(0,u.useIsoMorphicEffect)(()=>{if(void 0===R.current||T.tabs.length<=0)return;let e=(0,v.sortByDomNode)(T.tabs,e=>e.current);e.some((e,t)=>T.tabs[t]!==e)&&M(e.indexOf(T.tabs[R.current]))});let D=(0,y.useRender)();return s.default.createElement(E.StableCollection,null,s.default.createElement(N.Provider,{value:O},s.default.createElement(k.Provider,{value:C},C.tabs.length<=0&&s.default.createElement(p.FocusSentinel,{onFocus:()=>{var e,t;for(let r of L.current)if((null==(e=r.current)?void 0:e.tabIndex)===0)return null==(t=r.current)||t.focus(),!0;return!1}}),D({ourProps:{ref:w},theirProps:d,slot:F,defaultTag:"div",name:"Tabs"}))))}),List:(0,y.forwardRefWithAs)(function(e,t){let{orientation:r,selectedIndex:n}=L("Tab.List"),o=(0,f.useSyncRefs)(t),a=(0,s.useMemo)(()=>({selectedIndex:n}),[n]);return(0,y.useRender)()({ourProps:{ref:o,role:"tablist","aria-orientation":r},theirProps:e,slot:a,defaultTag:"div",name:"Tabs.List"})}),Panels:(0,y.forwardRefWithAs)(function(e,t){let{selectedIndex:r}=L("Tab.Panels"),n=(0,f.useSyncRefs)(t),o=(0,s.useMemo)(()=>({selectedIndex:r}),[r]);return(0,y.useRender)()({ourProps:{ref:n},theirProps:e,slot:o,defaultTag:"div",name:"Tabs.Panels"})}),Panel:(0,y.forwardRefWithAs)(function(e,t){var r,n,a,l;let i=(0,s.useId)(),{id:c=`headlessui-tabs-panel-${i}`,tabIndex:d=0,...p}=e,{selectedIndex:v,tabs:b,panels:g}=L("Tab.Panel"),h=C("Tab.Panel"),w=(0,s.useRef)(null),T=(0,f.useSyncRefs)(w,t);(0,u.useIsoMorphicEffect)(()=>h.registerPanel(w),[h,w]);let x=(0,E.useStableCollectionIndex)("panels"),F=g.indexOf(w);-1===F&&(F=x);let P=F===v,{isFocusVisible:k,focusProps:N}=(0,o.useFocusRing)(),I=(0,s.useMemo)(()=>({selected:P,focus:k}),[P,k]),A=(0,y.mergeProps)({ref:T,id:c,role:"tabpanel","aria-labelledby":null==(n=null==(r=b[F])?void 0:r.current)?void 0:n.id,tabIndex:P?d:-1},N),M=(0,y.useRender)();return P||null!=(a=p.unmount)&&!a||null!=(l=p.static)&&l?M({ourProps:A,theirProps:p,slot:I,defaultTag:"div",features:S,visible:P,name:"Tabs.Panel"}):s.default.createElement(m.Hidden,{"aria-hidden":"true",...A})})});e.s(["Tab",()=>A])},653824,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(444755),o=e.i(673706),a=e.i(271645);let s=(0,o.makeClassName)("TabGroup"),l=a.default.forwardRef((e,o)=>{let{defaultIndex:l,index:i,onIndexChange:u,children:c,className:d}=e,f=(0,t.__rest)(e,["defaultIndex","index","onIndexChange","children","className"]);return a.default.createElement(r.Tab.Group,Object.assign({as:"div",ref:o,defaultIndex:l,selectedIndex:i,onChange:u,className:(0,n.tremorTwMerge)(s("root"),"w-full",d)},f),c)});l.displayName="TabGroup",e.s(["TabGroup",()=>l],653824)},405371,910342,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(480731);let o=(0,r.createContext)(n.BaseColors.Blue);e.s(["default",()=>o],910342);var a=e.i(970554),s=e.i(444755);let l=(0,e.i(673706).makeClassName)("TabList"),i=(0,r.createContext)("line"),u={line:(0,s.tremorTwMerge)("flex border-b space-x-4","border-tremor-border","dark:border-dark-tremor-border"),solid:(0,s.tremorTwMerge)("inline-flex p-0.5 rounded-tremor-default space-x-1.5","bg-tremor-background-subtle","dark:bg-dark-tremor-background-subtle")},c=r.default.forwardRef((e,n)=>{let{color:c,variant:d="line",children:f,className:p}=e,m=(0,t.__rest)(e,["color","variant","children","className"]);return r.default.createElement(a.Tab.List,Object.assign({ref:n,className:(0,s.tremorTwMerge)(l("root"),"justify-start overflow-x-clip",u[d],p)},m),r.default.createElement(i.Provider,{value:d},r.default.createElement(o.Provider,{value:c},f)))});c.displayName="TabList",e.s(["TabVariantContext",()=>i,"default",()=>c],405371)},881073,e=>{"use strict";var t=e.i(405371);e.s(["TabList",()=>t.default])},197647,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(95779),o=e.i(444755),a=e.i(673706),s=e.i(271645),l=e.i(405371),i=e.i(910342);let u=(0,a.makeClassName)("Tab"),c=s.default.forwardRef((e,c)=>{let{icon:d,className:f,children:p}=e,m=(0,t.__rest)(e,["icon","className","children"]),v=(0,s.useContext)(l.TabVariantContext),b=(0,s.useContext)(i.default);return s.default.createElement(r.Tab,Object.assign({ref:c,className:(0,o.tremorTwMerge)(u("root"),"flex whitespace-nowrap truncate max-w-xs outline-none data-focus-visible:ring text-tremor-default transition duration-100",function(e,t){switch(e){case"line":return(0,o.tremorTwMerge)("data-[selected]:border-b-2 hover:border-b-2 border-transparent transition duration-100 -mb-px px-2 py-2","hover:border-tremor-content hover:text-tremor-content-emphasis text-tremor-content","[&:not([data-selected])]:dark:hover:border-dark-tremor-content-emphasis [&:not([data-selected])]:dark:hover:text-dark-tremor-content-emphasis [&:not([data-selected])]:dark:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.border).selectBorderColor:["data-[selected]:border-tremor-brand data-[selected]:text-tremor-brand","data-[selected]:dark:border-dark-tremor-brand data-[selected]:dark:text-dark-tremor-brand"]);case"solid":return(0,o.tremorTwMerge)("border-transparent border rounded-tremor-small px-2.5 py-1","data-[selected]:border-tremor-border data-[selected]:bg-tremor-background data-[selected]:shadow-tremor-input [&:not([data-selected])]:hover:text-tremor-content-emphasis data-[selected]:text-tremor-brand [&:not([data-selected])]:text-tremor-content","dark:data-[selected]:border-dark-tremor-border dark:data-[selected]:bg-dark-tremor-background dark:data-[selected]:shadow-dark-tremor-input dark:[&:not([data-selected])]:hover:text-dark-tremor-content-emphasis dark:data-[selected]:text-dark-tremor-brand dark:[&:not([data-selected])]:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.text).selectTextColor:"text-tremor-content dark:text-dark-tremor-content")}}(v,b),f,b&&(0,a.getColorClassNames)(b,n.colorPalette.text).selectTextColor)},m),d?s.default.createElement(d,{className:(0,o.tremorTwMerge)(u("icon"),"flex-none h-5 w-5",p?"mr-2":"")}):null,p?s.default.createElement("span",null,p):null)});c.displayName="Tab",e.s(["Tab",()=>c],197647)},751734,144582,e=>{"use strict";var t=e.i(271645);let r=(0,t.createContext)(0);e.s(["default",()=>r],751734);let n=(0,t.createContext)({selectedValue:void 0,handleValueChange:void 0});e.s(["default",()=>n],144582)},723731,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(751734),o=e.i(144582),a=e.i(444755),s=e.i(673706),l=e.i(271645);let i=(0,s.makeClassName)("TabPanels"),u=l.default.forwardRef((e,s)=>{let{children:u,className:c}=e,d=(0,t.__rest)(e,["children","className"]);return l.default.createElement(r.Tab.Panels,Object.assign({as:"div",ref:s,className:(0,a.tremorTwMerge)(i("root"),"w-full",c)},d),({selectedIndex:e})=>l.default.createElement(o.default.Provider,{value:{selectedValue:e}},l.default.Children.map(u,(e,t)=>l.default.createElement(n.default.Provider,{value:t},e))))});u.displayName="TabPanels",e.s(["TabPanels",()=>u],723731)},404206,e=>{"use strict";var t=e.i(290571),r=e.i(751734),n=e.i(144582),o=e.i(444755),a=e.i(673706),s=e.i(271645);let l=(0,a.makeClassName)("TabPanel"),i=s.default.forwardRef((e,a)=>{let{children:i,className:u}=e,c=(0,t.__rest)(e,["children","className"]),{selectedValue:d}=(0,s.useContext)(n.default),f=d===(0,s.useContext)(r.default);return s.default.createElement("div",Object.assign({ref:a,className:(0,o.tremorTwMerge)(l("root"),"w-full mt-2",f?"":"hidden",u),"aria-selected":f?"true":"false"},c),i)});i.displayName="TabPanel",e.s(["TabPanel",()=>i],404206)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/05e9ff30be0ddaae.js b/litellm/proxy/_experimental/out/_next/static/chunks/05e9ff30be0ddaae.js new file mode 100644 index 00000000000..f926944354f --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/05e9ff30be0ddaae.js @@ -0,0 +1,4 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,751734,144582,e=>{"use strict";var t=e.i(271645);let r=(0,t.createContext)(0);e.s(["default",()=>r],751734);let n=(0,t.createContext)({selectedValue:void 0,handleValueChange:void 0});e.s(["default",()=>n],144582)},404206,e=>{"use strict";var t=e.i(290571),r=e.i(751734),n=e.i(144582),o=e.i(444755),a=e.i(673706),s=e.i(271645);let l=(0,a.makeClassName)("TabPanel"),i=s.default.forwardRef((e,a)=>{let{children:i,className:u}=e,c=(0,t.__rest)(e,["children","className"]),{selectedValue:d}=(0,s.useContext)(n.default),f=d===(0,s.useContext)(r.default);return s.default.createElement("div",Object.assign({ref:a,className:(0,o.tremorTwMerge)(l("root"),"w-full mt-2",f?"":"hidden",u),"aria-selected":f?"true":"false"},c),i)});i.displayName="TabPanel",e.s(["TabPanel",()=>i],404206)},429427,371330,80758,402155,368578,544508,746725,835696,941444,914189,394487,e=>{"use strict";let t;e.i(247167);var r=e.i(271645);let n="u">typeof document?r.default.useLayoutEffect:()=>{},o=e=>{var t;return null!=(t=null==e?void 0:e.ownerDocument)?t:document},a=e=>e&&"window"in e&&e.window===e?e:o(e).defaultView||window;"u">typeof Element&&Element.prototype;let s=["input:not([disabled]):not([type=hidden])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable^="false"])',"permission"];s.join(":not([hidden]),"),s.push('[tabindex]:not([tabindex="-1"]):not([disabled])'),s.join(':not([hidden]):not([tabindex="-1"]),');let l=null;function i(e){return e.nativeEvent=e,e.isDefaultPrevented=()=>e.defaultPrevented,e.isPropagationStopped=()=>e.cancelBubble,e.persist=()=>{},e}function u(e){let t=(0,r.useRef)({isFocused:!1,observer:null});return n(()=>{let e=t.current;return()=>{e.observer&&(e.observer.disconnect(),e.observer=null)}},[]),(0,r.useCallback)(r=>{if(r.target instanceof HTMLButtonElement||r.target instanceof HTMLInputElement||r.target instanceof HTMLTextAreaElement||r.target instanceof HTMLSelectElement){t.current.isFocused=!0;let n=r.target;n.addEventListener("focusout",r=>{if(t.current.isFocused=!1,n.disabled){let t=i(r);null==e||e(t)}t.current.observer&&(t.current.observer.disconnect(),t.current.observer=null)},{once:!0}),t.current.observer=new MutationObserver(()=>{if(t.current.isFocused&&n.disabled){var e;null==(e=t.current.observer)||e.disconnect();let r=n===document.activeElement?null:document.activeElement;n.dispatchEvent(new FocusEvent("blur",{relatedTarget:r})),n.dispatchEvent(new FocusEvent("focusout",{bubbles:!0,relatedTarget:r}))}}),t.current.observer.observe(n,{attributes:!0,attributeFilter:["disabled"]})}},[e])}function c(e){var t;if("u"e.test(t.brand))||e.test(window.navigator.userAgent)}function d(e){var t;return"u">typeof window&&null!=window.navigator&&e.test((null==(t=window.navigator.userAgentData)?void 0:t.platform)||window.navigator.platform)}function f(e){let t=null;return()=>(null==t&&(t=e()),t)}let p=f(function(){return d(/^Mac/i)}),m=f(function(){return d(/^iPhone/i)}),v=f(function(){return d(/^iPad/i)||p()&&navigator.maxTouchPoints>1}),b=f(function(){return m()||v()});f(function(){return p()||b()});let g=f(function(){return c(/AppleWebKit/i)&&!h()}),h=f(function(){return c(/Chrome/i)}),y=f(function(){return c(/Android/i)}),E=f(function(){return c(/Firefox/i)});function w(e,t,r=!0){var n,o;let{metaKey:a,ctrlKey:s,altKey:i,shiftKey:u}=t;E()&&(null==(o=window.event)||null==(n=o.type)?void 0:n.startsWith("key"))&&"_blank"===e.target&&(p()?a=!0:s=!0);let c=g()&&p()&&!v()&&1?new KeyboardEvent("keydown",{keyIdentifier:"Enter",metaKey:a,ctrlKey:s,altKey:i,shiftKey:u}):new MouseEvent("click",{metaKey:a,ctrlKey:s,altKey:i,shiftKey:u,detail:1,bubbles:!0,cancelable:!0});if(w.isOpening=r,function(){if(null==l){l=!1;try{document.createElement("div").focus({get preventScroll(){return l=!0,!0}})}catch{}}return l}())e.focus({preventScroll:!0});else{let t=function(e){let t=e.parentNode,r=[],n=document.scrollingElement||document.documentElement;for(;t instanceof HTMLElement&&t!==n;)(t.offsetHeighttypeof window&&window.document&&window.document.createElement,new WeakMap;r.default.useId;let x=null,F=new Set,P=new Map,k=!1,L=!1,N={Tab:!0,Escape:!0};function C(e,t){for(let r of F)r(e,t)}function I(e){k=!0,w.isOpening||e.metaKey||!p()&&e.altKey||e.ctrlKey||"Control"===e.key||"Shift"===e.key||"Meta"===e.key||(x="keyboard",C("keyboard",e))}function S(e){x="pointer","pointerType"in e&&e.pointerType,("mousedown"===e.type||"pointerdown"===e.type)&&(k=!0,C("pointer",e))}function A(e){w.isOpening||(""!==e.pointerType||!e.isTrusted)&&(y()&&e.pointerType?"click"!==e.type||1!==e.buttons:0!==e.detail||e.pointerType)||(k=!0,x="virtual")}function M(e){e.target!==window&&e.target!==document&&e.isTrusted&&(k||L||(x="virtual",C("virtual",e)),k=!1,L=!1)}function R(){k=!1,L=!0}function O(e){if("u"typeof PointerEvent&&(r.addEventListener("pointerdown",S,!0),r.addEventListener("pointermove",S,!0),r.addEventListener("pointerup",S,!0)),t.addEventListener("beforeunload",()=>{D(e)},{once:!0}),P.set(t,{focus:n})}let D=(e,t)=>{let r=a(e),n=o(e);t&&n.removeEventListener("DOMContentLoaded",t),P.has(r)&&(r.HTMLElement.prototype.focus=P.get(r).focus,n.removeEventListener("keydown",I,!0),n.removeEventListener("keyup",I,!0),n.removeEventListener("click",A,!0),r.removeEventListener("focus",M,!0),r.removeEventListener("blur",R,!1),"u">typeof PointerEvent&&(n.removeEventListener("pointerdown",S,!0),n.removeEventListener("pointermove",S,!0),n.removeEventListener("pointerup",S,!0)),P.delete(r))};function H(){return"pointer"!==x}"u">typeof document&&("loading"!==(t=o(void 0)).readyState?O(void 0):t.addEventListener("DOMContentLoaded",()=>{O(void 0)}));let j=new Set(["checkbox","radio","range","color","file","image","button","submit","reset"]);function K(e,t){return!!t&&!!e&&e.contains(t)}function W(){let e=(0,r.useRef)(new Map),t=(0,r.useCallback)((t,r,n,o)=>{let a=(null==o?void 0:o.once)?(...t)=>{e.current.delete(n),n(...t)}:n;e.current.set(n,{type:r,eventTarget:t,fn:a,options:o}),t.addEventListener(r,a,o)},[]),n=(0,r.useCallback)((t,r,n,o)=>{var a;let s=(null==(a=e.current.get(n))?void 0:a.fn)||n;t.removeEventListener(r,s,o),e.current.delete(n)},[]),o=(0,r.useCallback)(()=>{e.current.forEach((e,t)=>{n(e.eventTarget,e.type,t,e.options)})},[n]);return(0,r.useEffect)(()=>o,[o]),{addGlobalListener:t,removeGlobalListener:n,removeAllGlobalListeners:o}}function B(e={}){var t;let{autoFocus:n=!1,isTextInput:s,within:l}=e,c=(0,r.useRef)({isFocused:!1,isFocusVisible:n||H()}),[d,f]=(0,r.useState)(!1),[p,m]=(0,r.useState)(()=>c.current.isFocused&&c.current.isFocusVisible),v=(0,r.useCallback)(()=>m(c.current.isFocused&&c.current.isFocusVisible),[]),b=(0,r.useCallback)(e=>{c.current.isFocused=e,f(e),v()},[v]);t={isTextInput:s},O(),(0,r.useEffect)(()=>{let e=(e,r)=>{var n;let s,l,i,u,d;n=!!(null==t?void 0:t.isTextInput),s=o(null==r?void 0:r.target),l="u">typeof window?a(null==r?void 0:r.target).HTMLInputElement:HTMLInputElement,i="u">typeof window?a(null==r?void 0:r.target).HTMLTextAreaElement:HTMLTextAreaElement,u="u">typeof window?a(null==r?void 0:r.target).HTMLElement:HTMLElement,d="u">typeof window?a(null==r?void 0:r.target).KeyboardEvent:KeyboardEvent,(n=n||s.activeElement instanceof l&&!j.has(s.activeElement.type)||s.activeElement instanceof i||s.activeElement instanceof u&&s.activeElement.isContentEditable)&&"keyboard"===e&&r instanceof d&&!N[r.key]||(e=>{c.current.isFocusVisible=e,v()})(H())};return F.add(e),()=>{F.delete(e)}},[]);let{focusProps:g}=function(e){let{isDisabled:t,onFocus:n,onBlur:a,onFocusChange:s}=e,l=(0,r.useCallback)(e=>{if(e.target===e.currentTarget)return a&&a(e),s&&s(!1),!0},[a,s]),i=u(l),c=(0,r.useCallback)(e=>{var t;let r=o(e.target),a=r?((e=document)=>e.activeElement)(r):((e=document)=>e.activeElement)();e.target===e.currentTarget&&a===(t=e.nativeEvent,t.target)&&(n&&n(e),s&&s(!0),i(e))},[s,n,i]);return{focusProps:{onFocus:!t&&(n||s||a)?c:void 0,onBlur:!t&&(a||s)?l:void 0}}}({isDisabled:l,onFocusChange:b}),{focusWithinProps:h}=function(e){let{isDisabled:t,onBlurWithin:n,onFocusWithin:a,onFocusWithinChange:s}=e,l=(0,r.useRef)({isFocusWithin:!1}),{addGlobalListener:c,removeAllGlobalListeners:d}=W(),f=(0,r.useCallback)(e=>{e.currentTarget.contains(e.target)&&l.current.isFocusWithin&&!e.currentTarget.contains(e.relatedTarget)&&(l.current.isFocusWithin=!1,d(),n&&n(e),s&&s(!1))},[n,s,l,d]),p=u(f),m=(0,r.useCallback)(e=>{var t;if(!e.currentTarget.contains(e.target))return;let r=o(e.target),n=((e=document)=>e.activeElement)(r);if(!l.current.isFocusWithin&&n===(t=e.nativeEvent,t.target)){a&&a(e),s&&s(!0),l.current.isFocusWithin=!0,p(e);let t=e.currentTarget;c(r,"focus",e=>{if(l.current.isFocusWithin&&!K(t,e.target)){let n=new r.defaultView.FocusEvent("blur",{relatedTarget:e.target});Object.defineProperty(n,"target",{value:t}),Object.defineProperty(n,"currentTarget",{value:t}),f(i(n))}},{capture:!0})}},[a,s,p,c,f]);return t?{focusWithinProps:{onFocus:void 0,onBlur:void 0}}:{focusWithinProps:{onFocus:m,onBlur:f}}}({isDisabled:!l,onFocusWithinChange:b});return{isFocused:d,isFocusVisible:p,focusProps:l?h:g}}e.s(["useFocusRing",()=>B],429427);let V=!1,_=0;function G(e){"touch"===e.pointerType&&(V=!0,setTimeout(()=>{V=!1},50))}function U(){if("u">typeof document)return 0===_&&"u">typeof PointerEvent&&document.addEventListener("pointerup",G),_++,()=>{!(--_>0)&&"u">typeof PointerEvent&&document.removeEventListener("pointerup",G)}}function $(e){let{onHoverStart:t,onHoverChange:n,onHoverEnd:a,isDisabled:s}=e,[l,i]=(0,r.useState)(!1),u=(0,r.useRef)({isHovered:!1,ignoreEmulatedMouseEvents:!1,pointerType:"",target:null}).current;(0,r.useEffect)(U,[]);let{addGlobalListener:c,removeAllGlobalListeners:d}=W(),{hoverProps:f,triggerHoverEnd:p}=(0,r.useMemo)(()=>{let e=(e,t)=>{let r=u.target;u.pointerType="",u.target=null,"touch"!==t&&u.isHovered&&r&&(u.isHovered=!1,d(),a&&a({type:"hoverend",target:r,pointerType:t}),n&&n(!1),i(!1))},r={};return"u">typeof PointerEvent&&(r.onPointerEnter=r=>{V&&"mouse"===r.pointerType||((r,a)=>{if(u.pointerType=a,s||"touch"===a||u.isHovered||!r.currentTarget.contains(r.target))return;u.isHovered=!0;let l=r.currentTarget;u.target=l,c(o(r.target),"pointerover",t=>{u.isHovered&&u.target&&!K(u.target,t.target)&&e(t,t.pointerType)},{capture:!0}),t&&t({type:"hoverstart",target:l,pointerType:a}),n&&n(!0),i(!0)})(r,r.pointerType)},r.onPointerLeave=t=>{!s&&t.currentTarget.contains(t.target)&&e(t,t.pointerType)}),{hoverProps:r,triggerHoverEnd:e}},[t,n,a,s,u,c,d]);return(0,r.useEffect)(()=>{s&&p({currentTarget:u.target},u.pointerType)},[s]),{hoverProps:f,isHovered:l}}e.s(["useHover",()=>$],371330);var q=Object.defineProperty,X=(e,t,r)=>{let n;return(n="symbol"!=typeof t?t+"":t)in e?q(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r,r};let Y=new class{constructor(){X(this,"current",this.detect()),X(this,"handoffState","pending"),X(this,"currentId",0)}set(e){this.current!==e&&(this.handoffState="pending",this.currentId=0,this.current=e)}reset(){this.set(this.detect())}nextId(){return++this.currentId}get isServer(){return"server"===this.current}get isClient(){return"client"===this.current}detect(){return"u"setTimeout(()=>{throw e}))}function J(){let e=[],t={addEventListener:(e,r,n,o)=>(e.addEventListener(r,n,o),t.add(()=>e.removeEventListener(r,n,o))),requestAnimationFrame(...e){let r=requestAnimationFrame(...e);return t.add(()=>cancelAnimationFrame(r))},nextFrame:(...e)=>t.requestAnimationFrame(()=>t.requestAnimationFrame(...e)),setTimeout(...e){let r=setTimeout(...e);return t.add(()=>clearTimeout(r))},microTask(...e){let r={current:!0};return Z(()=>{r.current&&e[0]()}),t.add(()=>{r.current=!1})},style(e,t,r){let n=e.style.getPropertyValue(t);return Object.assign(e.style,{[t]:r}),this.add(()=>{Object.assign(e.style,{[t]:n})})},group(e){let t=J();return e(t),this.add(()=>t.dispose())},add:t=>(e.includes(t)||e.push(t),()=>{let r=e.indexOf(t);if(r>=0)for(let t of e.splice(r,1))t()}),dispose(){for(let t of e.splice(0))t()}};return t}function Q(){let[e]=(0,r.useState)(J);return(0,r.useEffect)(()=>()=>e.dispose(),[e]),e}e.s(["env",()=>Y],80758),e.s(["getOwnerDocument",()=>z],402155),e.s(["microTask",()=>Z],368578),e.s(["disposables",()=>J],544508),e.s(["useDisposables",()=>Q],746725);let ee=(e,t)=>{Y.isServer?(0,r.useEffect)(e,t):(0,r.useLayoutEffect)(e,t)};function et(e){let t=(0,r.useRef)(e);return ee(()=>{t.current=e},[e]),t}e.s(["useIsoMorphicEffect",()=>ee],835696),e.s(["useLatestValue",()=>et],941444);let er=function(e){let t=et(e);return r.default.useCallback((...e)=>t.current(...e),[t])};function en({disabled:e=!1}={}){let t=(0,r.useRef)(null),[n,o]=(0,r.useState)(!1),a=Q(),s=er(()=>{t.current=null,o(!1),a.dispose()}),l=er(e=>{if(a.dispose(),null===t.current){t.current=e.currentTarget,o(!0);{let r=z(e.currentTarget);a.addEventListener(r,"pointerup",s,!1),a.addEventListener(r,"pointermove",e=>{if(t.current){var r,n;let a,s;o((a=e.width/2,s=e.height/2,r={top:e.clientY-s,right:e.clientX+a,bottom:e.clientY+s,left:e.clientX-a},n=t.current.getBoundingClientRect(),!(!r||!n||r.rightn.right||r.bottomn.bottom)))}},!1),a.addEventListener(r,"pointercancel",s,!1)}}});return{pressed:n,pressProps:e?{}:{onPointerDown:l,onPointerUp:s,onClick:s}}}e.s(["useEvent",()=>er],914189),e.s(["useActivePress",()=>en],394487)},397701,e=>{"use strict";function t(e,r,...n){if(e in r){let t=r[e];return"function"==typeof t?t(...n):t}let o=Error(`Tried to handle "${e}" but there is no handler defined. Only defined handlers are: ${Object.keys(r).map(e=>`"${e}"`).join(", ")}.`);throw Error.captureStackTrace&&Error.captureStackTrace(o,t),o}e.s(["match",()=>t])},652265,e=>{"use strict";let t,r,n,o,a;e.i(544508);var s=e.i(397701),l=e.i(402155);let i=["[contentEditable=true]","[tabindex]","a[href]","area[href]","button:not([disabled])","iframe","input:not([disabled])","select:not([disabled])","textarea:not([disabled])"].map(e=>`${e}:not([tabindex='-1'])`).join(","),u=["[data-autofocus]"].map(e=>`${e}:not([tabindex='-1'])`).join(",");var c=((t=c||{})[t.First=1]="First",t[t.Previous=2]="Previous",t[t.Next=4]="Next",t[t.Last=8]="Last",t[t.WrapAround=16]="WrapAround",t[t.NoScroll=32]="NoScroll",t[t.AutoFocus=64]="AutoFocus",t),d=((r=d||{})[r.Error=0]="Error",r[r.Overflow=1]="Overflow",r[r.Success=2]="Success",r[r.Underflow=3]="Underflow",r),f=((n=f||{})[n.Previous=-1]="Previous",n[n.Next=1]="Next",n);function p(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(i)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}var m=((o=m||{})[o.Strict=0]="Strict",o[o.Loose=1]="Loose",o);function v(e,t=0){var r;return e!==(null==(r=(0,l.getOwnerDocument)(e))?void 0:r.body)&&(0,s.match)(t,{0:()=>e.matches(i),1(){let t=e;for(;null!==t;){if(t.matches(i))return!0;t=t.parentElement}return!1}})}var b=((a=b||{})[a.Keyboard=0]="Keyboard",a[a.Mouse=1]="Mouse",a);function g(e,t=e=>e){return e.slice().sort((e,r)=>{let n=t(e),o=t(r);if(null===n||null===o)return 0;let a=n.compareDocumentPosition(o);return a&Node.DOCUMENT_POSITION_FOLLOWING?-1:a&Node.DOCUMENT_POSITION_PRECEDING?1:0})}function h(e,t){return y(p(),t,{relativeTo:e})}function y(e,t,{sorted:r=!0,relativeTo:n=null,skipElements:o=[]}={}){var a,s,l;let i=Array.isArray(e)?e.length>0?e[0].ownerDocument:document:e.ownerDocument,c=Array.isArray(e)?r?g(e):e:64&t?function(e=document.body){return null==e?[]:Array.from(e.querySelectorAll(u)).sort((e,t)=>Math.sign((e.tabIndex||Number.MAX_SAFE_INTEGER)-(t.tabIndex||Number.MAX_SAFE_INTEGER)))}(e):p(e);o.length>0&&c.length>1&&(c=c.filter(e=>!o.some(t=>null!=t&&"current"in t?(null==t?void 0:t.current)===e:t===e))),n=null!=n?n:i.activeElement;let d=(()=>{if(5&t)return 1;if(10&t)return -1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),f=(()=>{if(1&t)return 0;if(2&t)return Math.max(0,c.indexOf(n))-1;if(4&t)return Math.max(0,c.indexOf(n))+1;if(8&t)return c.length-1;throw Error("Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last")})(),m=32&t?{preventScroll:!0}:{},v=0,b=c.length,h;do{if(v>=b||v+b<=0)return 0;let e=f+v;if(16&t)e=(e+b)%b;else{if(e<0)return 3;if(e>=b)return 1}null==(h=c[e])||h.focus(m),v+=d}while(h!==i.activeElement)return 6&t&&null!=(l=null==(s=null==(a=h)?void 0:a.matches)?void 0:s.call(a,"textarea,input"))&&l&&h.select(),2}"u">typeof window&&"u">typeof document&&(document.addEventListener("keydown",e=>{e.metaKey||e.altKey||e.ctrlKey||(document.documentElement.dataset.headlessuiFocusVisible="")},!0),document.addEventListener("click",e=>{1===e.detail?delete document.documentElement.dataset.headlessuiFocusVisible:0===e.detail&&(document.documentElement.dataset.headlessuiFocusVisible="")},!0)),e.s(["Focus",()=>c,"FocusResult",()=>d,"FocusableMode",()=>m,"focusFrom",()=>h,"focusIn",()=>y,"getFocusableElements",()=>p,"isFocusableElement",()=>v,"sortByDomNode",()=>g])},144279,294316,e=>{"use strict";var t=e.i(271645);function r(e,r){return(0,t.useMemo)(()=>{var t;if(e.type)return e.type;let n=null!=(t=e.as)?t:"button";if("string"==typeof n&&"button"===n.toLowerCase()||(null==r?void 0:r.tagName)==="BUTTON"&&!r.hasAttribute("type"))return"button"},[e.type,e.as,r])}e.s(["useResolveButtonType",()=>r],144279);var n=e.i(914189);let o=Symbol();function a(e,t=!0){return Object.assign(e,{[o]:t})}function s(...e){let r=(0,t.useRef)(e);(0,t.useEffect)(()=>{r.current=e},[e]);let a=(0,n.useEvent)(e=>{for(let t of r.current)null!=t&&("function"==typeof t?t(e):t.current=e)});return e.every(e=>null==e||(null==e?void 0:e[o]))?void 0:a}e.s(["optionalRef",()=>a,"useSyncRefs",()=>s],294316)},732607,e=>{"use strict";function t(...e){return Array.from(new Set(e.flatMap(e=>"string"==typeof e?e.split(" "):[]))).filter(Boolean).join(" ")}e.s(["classNames",()=>t])},700020,e=>{"use strict";let t,r;var n=e.i(271645),o=e.i(732607),a=e.i(397701),s=((t=s||{})[t.None=0]="None",t[t.RenderStrategy=1]="RenderStrategy",t[t.Static=2]="Static",t),l=((r=l||{})[r.Unmount=0]="Unmount",r[r.Hidden=1]="Hidden",r);function i(){let e,t,r=(e=(0,n.useRef)([]),t=(0,n.useCallback)(t=>{for(let r of e.current)null!=r&&("function"==typeof r?r(t):r.current=t)},[]),(...r)=>{if(!r.every(e=>null==e))return e.current=r,t});return(0,n.useCallback)(e=>(function({ourProps:e,theirProps:t,slot:r,defaultTag:n,features:o,visible:s=!0,name:l,mergeRefs:i}){i=null!=i?i:c;let f=d(t,e);if(s)return u(f,r,n,l,i);let p=null!=o?o:0;if(2&p){let{static:e=!1,...t}=f;if(e)return u(t,r,n,l,i)}if(1&p){let{unmount:e=!0,...t}=f;return(0,a.match)(+!e,{0:()=>null,1:()=>u({...t,hidden:!0,style:{display:"none"}},r,n,l,i)})}return u(f,r,n,l,i)})({mergeRefs:r,...e}),[r])}function u(e,t={},r,a,s){let{as:l=r,children:i,refName:c="ref",...f}=v(e,["unmount","static"]),p=void 0!==e.ref?{[c]:e.ref}:{},b="function"==typeof i?i(t):i;"className"in f&&f.className&&"function"==typeof f.className&&(f.className=f.className(t)),f["aria-labelledby"]&&f["aria-labelledby"]===f.id&&(f["aria-labelledby"]=void 0);let g={};if(t){let e=!1,r=[];for(let[n,o]of Object.entries(t))"boolean"==typeof o&&(e=!0),!0===o&&r.push(n.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`));if(e)for(let e of(g["data-headlessui-state"]=r.join(" "),r))g[`data-${e}`]=""}if(l===n.Fragment&&(Object.keys(m(f)).length>0||Object.keys(m(g)).length>0))if(!(0,n.isValidElement)(b)||Array.isArray(b)&&b.length>1){if(Object.keys(m(f)).length>0)throw Error(['Passing props on "Fragment"!',"",`The current component <${a} /> is rendering a "Fragment".`,"However we need to passthrough the following props:",Object.keys(m(f)).concat(Object.keys(m(g))).map(e=>` - ${e}`).join(` +`),"","You can apply a few solutions:",['Add an `as="..."` prop, to ensure that we render an actual element instead of a "Fragment".',"Render a single element as the child so that we can forward the props onto that element."].map(e=>` - ${e}`).join(` +`)].join(` +`))}else{var h;let e=b.props,t=null==e?void 0:e.className,r="function"==typeof t?(...e)=>(0,o.classNames)(t(...e),f.className):(0,o.classNames)(t,f.className),a=d(b.props,m(v(f,["ref"])));for(let e in g)e in a&&delete g[e];return(0,n.cloneElement)(b,Object.assign({},a,g,p,{ref:s((h=b,n.default.version.split(".")[0]>="19"?h.props.ref:h.ref),p.ref)},r?{className:r}:{}))}return(0,n.createElement)(l,Object.assign({},v(f,["ref"]),l!==n.Fragment&&p,l!==n.Fragment&&g),b)}function c(...e){return e.every(e=>null==e)?void 0:t=>{for(let r of e)null!=r&&("function"==typeof r?r(t):r.current=t)}}function d(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];if(t.disabled||t["aria-disabled"])for(let e in r)/^(on(?:Click|Pointer|Mouse|Key)(?:Down|Up|Press)?)$/.test(e)&&(r[e]=[e=>{var t;return null==(t=null==e?void 0:e.preventDefault)?void 0:t.call(e)}]);for(let e in r)Object.assign(t,{[e](t,...n){for(let o of r[e]){if((t instanceof Event||(null==t?void 0:t.nativeEvent)instanceof Event)&&t.defaultPrevented)return;o(t,...n)}}});return t}function f(...e){if(0===e.length)return{};if(1===e.length)return e[0];let t={},r={};for(let n of e)for(let e in n)e.startsWith("on")&&"function"==typeof n[e]?(null!=r[e]||(r[e]=[]),r[e].push(n[e])):t[e]=n[e];for(let e in r)Object.assign(t,{[e](...t){for(let n of r[e])null==n||n(...t)}});return t}function p(e){var t;return Object.assign((0,n.forwardRef)(e),{displayName:null!=(t=e.displayName)?t:e.name})}function m(e){let t=Object.assign({},e);for(let e in t)void 0===t[e]&&delete t[e];return t}function v(e,t=[]){let r=Object.assign({},e);for(let e of t)e in r&&delete r[e];return r}e.s(["RenderFeatures",()=>s,"RenderStrategy",()=>l,"compact",()=>m,"forwardRefWithAs",()=>p,"mergeProps",()=>f,"useRender",()=>i])},2788,e=>{"use strict";let t;var r=e.i(700020),n=((t=n||{})[t.None=1]="None",t[t.Focusable=2]="Focusable",t[t.Hidden=4]="Hidden",t);let o=(0,r.forwardRefWithAs)(function(e,t){var n;let{features:o=1,...a}=e,s={ref:t,"aria-hidden":(2&o)==2||(null!=(n=a["aria-hidden"])?n:void 0),hidden:(4&o)==4||void 0,style:{position:"fixed",top:1,left:1,width:1,height:0,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",borderWidth:"0",...(4&o)==4&&(2&o)!=2&&{display:"none"}}};return(0,r.useRender)()({ourProps:s,theirProps:a,slot:{},defaultTag:"span",name:"Hidden"})});e.s(["Hidden",()=>o,"HiddenFeatures",()=>n])},998348,e=>{"use strict";let t;var r=((t=r||{}).Space=" ",t.Enter="Enter",t.Escape="Escape",t.Backspace="Backspace",t.Delete="Delete",t.ArrowLeft="ArrowLeft",t.ArrowUp="ArrowUp",t.ArrowRight="ArrowRight",t.ArrowDown="ArrowDown",t.Home="Home",t.End="End",t.PageUp="PageUp",t.PageDown="PageDown",t.Tab="Tab",t);e.s(["Keys",()=>r])},553521,e=>{"use strict";var t=e.i(271645),r=e.i(835696);function n(){let e=(0,t.useRef)(!1);return(0,r.useIsoMorphicEffect)(()=>(e.current=!0,()=>{e.current=!1}),[]),e}e.s(["useIsMounted",()=>n])},640497,e=>{"use strict";var t=e.i(271645),r=e.i(553521),n=e.i(2788);function o({onFocus:e}){let[o,a]=(0,t.useState)(!0),s=(0,r.useIsMounted)();return o?t.default.createElement(n.Hidden,{as:"button",type:"button",features:n.HiddenFeatures.Focusable,onFocus:t=>{t.preventDefault();let r,n=50;r=requestAnimationFrame(function t(){if(n--<=0){r&&cancelAnimationFrame(r);return}if(e()){if(cancelAnimationFrame(r),!s.current)return;a(!1);return}r=requestAnimationFrame(t)})}}):null}e.s(["FocusSentinel",()=>o])},963703,e=>{"use strict";var t=e.i(271645);let r=t.createContext(null);function n({children:e}){let n=t.useRef({groups:new Map,get(e,t){var r;let n=this.groups.get(e);n||(n=new Map,this.groups.set(e,n));let o=null!=(r=n.get(t))?r:0;return n.set(t,o+1),[Array.from(n.keys()).indexOf(t),function(){let e=n.get(t);e>1?n.set(t,e-1):n.delete(t)}]}});return t.createElement(r.Provider,{value:n},e)}function o(e){let n=t.useContext(r);if(!n)throw Error("You must wrap your component in a ");let o=t.useId(),[a,s]=n.current.get(e,o);return t.useEffect(()=>s,[]),a}e.s(["StableCollection",()=>n,"useStableCollectionIndex",()=>o])},970554,e=>{"use strict";let t,r,n;var o=e.i(429427),a=e.i(371330),s=e.i(271645),l=e.i(394487),i=e.i(914189),u=e.i(835696),c=e.i(941444),d=e.i(144279),f=e.i(294316),p=e.i(640497),m=e.i(2788),v=e.i(652265),b=e.i(397701),g=e.i(368578),h=e.i(402155),y=e.i(700020),E=e.i(963703),w=e.i(998348),T=((t=T||{})[t.Forwards=0]="Forwards",t[t.Backwards=1]="Backwards",t),x=((r=x||{})[r.Less=-1]="Less",r[r.Equal=0]="Equal",r[r.Greater=1]="Greater",r),F=((n=F||{})[n.SetSelectedIndex=0]="SetSelectedIndex",n[n.RegisterTab=1]="RegisterTab",n[n.UnregisterTab=2]="UnregisterTab",n[n.RegisterPanel=3]="RegisterPanel",n[n.UnregisterPanel=4]="UnregisterPanel",n);let P={0(e,t){var r;let n=(0,v.sortByDomNode)(e.tabs,e=>e.current),o=(0,v.sortByDomNode)(e.panels,e=>e.current),a=n.filter(e=>{var t;return!(null!=(t=e.current)&&t.hasAttribute("disabled"))}),s={...e,tabs:n,panels:o};if(t.index<0||t.index>n.length-1){let r=(0,b.match)(Math.sign(t.index-e.selectedIndex),{[-1]:()=>1,0:()=>(0,b.match)(Math.sign(t.index),{[-1]:()=>0,0:()=>0,1:()=>1}),1:()=>0});if(0===a.length)return s;let o=(0,b.match)(r,{0:()=>n.indexOf(a[0]),1:()=>n.indexOf(a[a.length-1])});return{...s,selectedIndex:-1===o?e.selectedIndex:o}}let l=n.slice(0,t.index),i=[...n.slice(t.index),...l].find(e=>a.includes(e));if(!i)return s;let u=null!=(r=n.indexOf(i))?r:e.selectedIndex;return -1===u&&(u=e.selectedIndex),{...s,selectedIndex:u}},1(e,t){if(e.tabs.includes(t.tab))return e;let r=e.tabs[e.selectedIndex],n=(0,v.sortByDomNode)([...e.tabs,t.tab],e=>e.current),o=e.selectedIndex;return e.info.current.isControlled||-1===(o=n.indexOf(r))&&(o=e.selectedIndex),{...e,tabs:n,selectedIndex:o}},2:(e,t)=>({...e,tabs:e.tabs.filter(e=>e!==t.tab)}),3:(e,t)=>e.panels.includes(t.panel)?e:{...e,panels:(0,v.sortByDomNode)([...e.panels,t.panel],e=>e.current)},4:(e,t)=>({...e,panels:e.panels.filter(e=>e!==t.panel)})},k=(0,s.createContext)(null);function L(e){let t=(0,s.useContext)(k);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,L),t}return t}k.displayName="TabsDataContext";let N=(0,s.createContext)(null);function C(e){let t=(0,s.useContext)(N);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,C),t}return t}function I(e,t){return(0,b.match)(t.type,P,e,t)}N.displayName="TabsActionsContext";let S=y.RenderFeatures.RenderStrategy|y.RenderFeatures.Static,A=Object.assign((0,y.forwardRefWithAs)(function(e,t){var r,n;let c=(0,s.useId)(),{id:p=`headlessui-tabs-tab-${c}`,disabled:m=!1,autoFocus:T=!1,...x}=e,{orientation:F,activation:P,selectedIndex:k,tabs:N,panels:I}=L("Tab"),S=C("Tab"),A=L("Tab"),[M,R]=(0,s.useState)(null),O=(0,s.useRef)(null),D=(0,f.useSyncRefs)(O,t,R);(0,u.useIsoMorphicEffect)(()=>S.registerTab(O),[S,O]);let H=(0,E.useStableCollectionIndex)("tabs"),j=N.indexOf(O);-1===j&&(j=H);let K=j===k,W=(0,i.useEvent)(e=>{var t;let r=e();if(r===v.FocusResult.Success&&"auto"===P){let e=null==(t=(0,h.getOwnerDocument)(O))?void 0:t.activeElement,r=A.tabs.findIndex(t=>t.current===e);-1!==r&&S.change(r)}return r}),B=(0,i.useEvent)(e=>{let t=N.map(e=>e.current).filter(Boolean);if(e.key===w.Keys.Space||e.key===w.Keys.Enter){e.preventDefault(),e.stopPropagation(),S.change(j);return}switch(e.key){case w.Keys.Home:case w.Keys.PageUp:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.First));case w.Keys.End:case w.Keys.PageDown:return e.preventDefault(),e.stopPropagation(),W(()=>(0,v.focusIn)(t,v.Focus.Last))}if(W(()=>(0,b.match)(F,{vertical:()=>e.key===w.Keys.ArrowUp?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowDown?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error,horizontal:()=>e.key===w.Keys.ArrowLeft?(0,v.focusIn)(t,v.Focus.Previous|v.Focus.WrapAround):e.key===w.Keys.ArrowRight?(0,v.focusIn)(t,v.Focus.Next|v.Focus.WrapAround):v.FocusResult.Error}))===v.FocusResult.Success)return e.preventDefault()}),V=(0,s.useRef)(!1),_=(0,i.useEvent)(()=>{var e;V.current||(V.current=!0,null==(e=O.current)||e.focus({preventScroll:!0}),S.change(j),(0,g.microTask)(()=>{V.current=!1}))}),G=(0,i.useEvent)(e=>{e.preventDefault()}),{isFocusVisible:U,focusProps:$}=(0,o.useFocusRing)({autoFocus:T}),{isHovered:q,hoverProps:X}=(0,a.useHover)({isDisabled:m}),{pressed:Y,pressProps:z}=(0,l.useActivePress)({disabled:m}),Z=(0,s.useMemo)(()=>({selected:K,hover:q,active:Y,focus:U,autofocus:T,disabled:m}),[K,q,U,Y,T,m]),J=(0,y.mergeProps)({ref:D,onKeyDown:B,onMouseDown:G,onClick:_,id:p,role:"tab",type:(0,d.useResolveButtonType)(e,M),"aria-controls":null==(n=null==(r=I[j])?void 0:r.current)?void 0:n.id,"aria-selected":K,tabIndex:K?0:-1,disabled:m||void 0,autoFocus:T},$,X,z);return(0,y.useRender)()({ourProps:J,theirProps:x,slot:Z,defaultTag:"button",name:"Tabs.Tab"})}),{Group:(0,y.forwardRefWithAs)(function(e,t){let{defaultIndex:r=0,vertical:n=!1,manual:o=!1,onChange:a,selectedIndex:l=null,...d}=e,m=n?"vertical":"horizontal",b=o?"manual":"auto",g=null!==l,h=(0,c.useLatestValue)({isControlled:g}),w=(0,f.useSyncRefs)(t),[T,x]=(0,s.useReducer)(I,{info:h,selectedIndex:null!=l?l:r,tabs:[],panels:[]}),F=(0,s.useMemo)(()=>({selectedIndex:T.selectedIndex}),[T.selectedIndex]),P=(0,c.useLatestValue)(a||(()=>{})),L=(0,c.useLatestValue)(T.tabs),C=(0,s.useMemo)(()=>({orientation:m,activation:b,...T}),[m,b,T]),S=(0,i.useEvent)(e=>(x({type:1,tab:e}),()=>x({type:2,tab:e}))),A=(0,i.useEvent)(e=>(x({type:3,panel:e}),()=>x({type:4,panel:e}))),M=(0,i.useEvent)(e=>{R.current!==e&&P.current(e),g||x({type:0,index:e})}),R=(0,c.useLatestValue)(g?e.selectedIndex:T.selectedIndex),O=(0,s.useMemo)(()=>({registerTab:S,registerPanel:A,change:M}),[]);(0,u.useIsoMorphicEffect)(()=>{x({type:0,index:null!=l?l:r})},[l]),(0,u.useIsoMorphicEffect)(()=>{if(void 0===R.current||T.tabs.length<=0)return;let e=(0,v.sortByDomNode)(T.tabs,e=>e.current);e.some((e,t)=>T.tabs[t]!==e)&&M(e.indexOf(T.tabs[R.current]))});let D=(0,y.useRender)();return s.default.createElement(E.StableCollection,null,s.default.createElement(N.Provider,{value:O},s.default.createElement(k.Provider,{value:C},C.tabs.length<=0&&s.default.createElement(p.FocusSentinel,{onFocus:()=>{var e,t;for(let r of L.current)if((null==(e=r.current)?void 0:e.tabIndex)===0)return null==(t=r.current)||t.focus(),!0;return!1}}),D({ourProps:{ref:w},theirProps:d,slot:F,defaultTag:"div",name:"Tabs"}))))}),List:(0,y.forwardRefWithAs)(function(e,t){let{orientation:r,selectedIndex:n}=L("Tab.List"),o=(0,f.useSyncRefs)(t),a=(0,s.useMemo)(()=>({selectedIndex:n}),[n]);return(0,y.useRender)()({ourProps:{ref:o,role:"tablist","aria-orientation":r},theirProps:e,slot:a,defaultTag:"div",name:"Tabs.List"})}),Panels:(0,y.forwardRefWithAs)(function(e,t){let{selectedIndex:r}=L("Tab.Panels"),n=(0,f.useSyncRefs)(t),o=(0,s.useMemo)(()=>({selectedIndex:r}),[r]);return(0,y.useRender)()({ourProps:{ref:n},theirProps:e,slot:o,defaultTag:"div",name:"Tabs.Panels"})}),Panel:(0,y.forwardRefWithAs)(function(e,t){var r,n,a,l;let i=(0,s.useId)(),{id:c=`headlessui-tabs-panel-${i}`,tabIndex:d=0,...p}=e,{selectedIndex:v,tabs:b,panels:g}=L("Tab.Panel"),h=C("Tab.Panel"),w=(0,s.useRef)(null),T=(0,f.useSyncRefs)(w,t);(0,u.useIsoMorphicEffect)(()=>h.registerPanel(w),[h,w]);let x=(0,E.useStableCollectionIndex)("panels"),F=g.indexOf(w);-1===F&&(F=x);let P=F===v,{isFocusVisible:k,focusProps:N}=(0,o.useFocusRing)(),I=(0,s.useMemo)(()=>({selected:P,focus:k}),[P,k]),A=(0,y.mergeProps)({ref:T,id:c,role:"tabpanel","aria-labelledby":null==(n=null==(r=b[F])?void 0:r.current)?void 0:n.id,tabIndex:P?d:-1},N),M=(0,y.useRender)();return P||null!=(a=p.unmount)&&!a||null!=(l=p.static)&&l?M({ourProps:A,theirProps:p,slot:I,defaultTag:"div",features:S,visible:P,name:"Tabs.Panel"}):s.default.createElement(m.Hidden,{"aria-hidden":"true",...A})})});e.s(["Tab",()=>A])},405371,910342,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(480731);let o=(0,r.createContext)(n.BaseColors.Blue);e.s(["default",()=>o],910342);var a=e.i(970554),s=e.i(444755);let l=(0,e.i(673706).makeClassName)("TabList"),i=(0,r.createContext)("line"),u={line:(0,s.tremorTwMerge)("flex border-b space-x-4","border-tremor-border","dark:border-dark-tremor-border"),solid:(0,s.tremorTwMerge)("inline-flex p-0.5 rounded-tremor-default space-x-1.5","bg-tremor-background-subtle","dark:bg-dark-tremor-background-subtle")},c=r.default.forwardRef((e,n)=>{let{color:c,variant:d="line",children:f,className:p}=e,m=(0,t.__rest)(e,["color","variant","children","className"]);return r.default.createElement(a.Tab.List,Object.assign({ref:n,className:(0,s.tremorTwMerge)(l("root"),"justify-start overflow-x-clip",u[d],p)},m),r.default.createElement(i.Provider,{value:d},r.default.createElement(o.Provider,{value:c},f)))});c.displayName="TabList",e.s(["TabVariantContext",()=>i,"default",()=>c],405371)},197647,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(95779),o=e.i(444755),a=e.i(673706),s=e.i(271645),l=e.i(405371),i=e.i(910342);let u=(0,a.makeClassName)("Tab"),c=s.default.forwardRef((e,c)=>{let{icon:d,className:f,children:p}=e,m=(0,t.__rest)(e,["icon","className","children"]),v=(0,s.useContext)(l.TabVariantContext),b=(0,s.useContext)(i.default);return s.default.createElement(r.Tab,Object.assign({ref:c,className:(0,o.tremorTwMerge)(u("root"),"flex whitespace-nowrap truncate max-w-xs outline-none data-focus-visible:ring text-tremor-default transition duration-100",function(e,t){switch(e){case"line":return(0,o.tremorTwMerge)("data-[selected]:border-b-2 hover:border-b-2 border-transparent transition duration-100 -mb-px px-2 py-2","hover:border-tremor-content hover:text-tremor-content-emphasis text-tremor-content","[&:not([data-selected])]:dark:hover:border-dark-tremor-content-emphasis [&:not([data-selected])]:dark:hover:text-dark-tremor-content-emphasis [&:not([data-selected])]:dark:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.border).selectBorderColor:["data-[selected]:border-tremor-brand data-[selected]:text-tremor-brand","data-[selected]:dark:border-dark-tremor-brand data-[selected]:dark:text-dark-tremor-brand"]);case"solid":return(0,o.tremorTwMerge)("border-transparent border rounded-tremor-small px-2.5 py-1","data-[selected]:border-tremor-border data-[selected]:bg-tremor-background data-[selected]:shadow-tremor-input [&:not([data-selected])]:hover:text-tremor-content-emphasis data-[selected]:text-tremor-brand [&:not([data-selected])]:text-tremor-content","dark:data-[selected]:border-dark-tremor-border dark:data-[selected]:bg-dark-tremor-background dark:data-[selected]:shadow-dark-tremor-input dark:[&:not([data-selected])]:hover:text-dark-tremor-content-emphasis dark:data-[selected]:text-dark-tremor-brand dark:[&:not([data-selected])]:text-dark-tremor-content",t?(0,a.getColorClassNames)(t,n.colorPalette.text).selectTextColor:"text-tremor-content dark:text-dark-tremor-content")}}(v,b),f,b&&(0,a.getColorClassNames)(b,n.colorPalette.text).selectTextColor)},m),d?s.default.createElement(d,{className:(0,o.tremorTwMerge)(u("icon"),"flex-none h-5 w-5",p?"mr-2":"")}):null,p?s.default.createElement("span",null,p):null)});c.displayName="Tab",e.s(["Tab",()=>c],197647)},653824,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(444755),o=e.i(673706),a=e.i(271645);let s=(0,o.makeClassName)("TabGroup"),l=a.default.forwardRef((e,o)=>{let{defaultIndex:l,index:i,onIndexChange:u,children:c,className:d}=e,f=(0,t.__rest)(e,["defaultIndex","index","onIndexChange","children","className"]);return a.default.createElement(r.Tab.Group,Object.assign({as:"div",ref:o,defaultIndex:l,selectedIndex:i,onChange:u,className:(0,n.tremorTwMerge)(s("root"),"w-full",d)},f),c)});l.displayName="TabGroup",e.s(["TabGroup",()=>l],653824)},881073,e=>{"use strict";var t=e.i(405371);e.s(["TabList",()=>t.default])},723731,e=>{"use strict";var t=e.i(290571),r=e.i(970554),n=e.i(751734),o=e.i(144582),a=e.i(444755),s=e.i(673706),l=e.i(271645);let i=(0,s.makeClassName)("TabPanels"),u=l.default.forwardRef((e,s)=>{let{children:u,className:c}=e,d=(0,t.__rest)(e,["children","className"]);return l.default.createElement(r.Tab.Panels,Object.assign({as:"div",ref:s,className:(0,a.tremorTwMerge)(i("root"),"w-full",c)},d),({selectedIndex:e})=>l.default.createElement(o.default.Provider,{value:{selectedValue:e}},l.default.Children.map(u,(e,t)=>l.default.createElement(n.default.Provider,{value:t},e))))});u.displayName="TabPanels",e.s(["TabPanels",()=>u],723731)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/05fcbaa2a2d4ce24.js b/litellm/proxy/_experimental/out/_next/static/chunks/05fcbaa2a2d4ce24.js deleted file mode 100644 index 3bd408347f0..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/05fcbaa2a2d4ce24.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,213205,e=>{"use strict";e.i(247167);var s=e.i(931067),t=e.i(271645);let l={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M678.3 642.4c24.2-13 51.9-20.4 81.4-20.4h.1c3 0 4.4-3.6 2.2-5.6a371.67 371.67 0 00-103.7-65.8c-.4-.2-.8-.3-1.2-.5C719.2 505 759.6 431.7 759.6 349c0-137-110.8-248-247.5-248S264.7 212 264.7 349c0 82.7 40.4 156 102.6 201.1-.4.2-.8.3-1.2.5-44.7 18.9-84.8 46-119.3 80.6a373.42 373.42 0 00-80.4 119.5A373.6 373.6 0 00137 888.8a8 8 0 008 8.2h59.9c4.3 0 7.9-3.5 8-7.8 2-77.2 32.9-149.5 87.6-204.3C357 628.2 432.2 597 512.2 597c56.7 0 111.1 15.7 158 45.1a8.1 8.1 0 008.1.3zM512.2 521c-45.8 0-88.9-17.9-121.4-50.4A171.2 171.2 0 01340.5 349c0-45.9 17.9-89.1 50.3-121.6S466.3 177 512.2 177s88.9 17.9 121.4 50.4A171.2 171.2 0 01683.9 349c0 45.9-17.9 89.1-50.3 121.6C601.1 503.1 558 521 512.2 521zM880 759h-84v-84c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v84h-84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h84v84c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-84h84c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"}}]},name:"user-add",theme:"outlined"};var a=e.i(9583),r=t.forwardRef(function(e,r){return t.createElement(a.default,(0,s.default)({},e,{ref:r,icon:l}))});e.s(["UserAddOutlined",0,r],213205)},355619,e=>{"use strict";var s=e.i(764205);let t=async(e,t,l)=>{try{if(null===e||null===t)return;if(null!==l){let a=(await (0,s.modelAvailableCall)(l,e,t,!0,null,!0)).data.map(e=>e.id),r=[],i=[];return a.forEach(e=>{e.endsWith("/*")?r.push(e):i.push(e)}),[...r,...i]}}catch(e){console.error("Error fetching user models:",e)}};e.s(["fetchAvailableModelsForTeamOrKey",0,t,"getModelDisplayName",0,e=>{if("all-proxy-models"===e)return"All Proxy Models";if(e.endsWith("/*")){let s=e.replace("/*","");return`All ${s} models`}return e},"unfurlWildcardModelsInList",0,(e,s)=>{let t=[],l=[];return console.log("teamModels",e),console.log("allModels",s),e.forEach(e=>{if(e.endsWith("/*")){let a=e.replace("/*",""),r=s.filter(e=>e.startsWith(a+"/"));l.push(...r),t.push(e)}else l.push(e)}),[...t,...l].filter((e,s,t)=>t.indexOf(e)===s)}])},860585,e=>{"use strict";var s=e.i(843476),t=e.i(199133);let{Option:l}=t.Select;e.s(["default",0,({value:e,onChange:a,className:r="",style:i={}})=>(0,s.jsxs)(t.Select,{style:{width:"100%",...i},value:e||void 0,onChange:a,className:r,placeholder:"n/a",allowClear:!0,children:[(0,s.jsx)(l,{value:"1h",children:"hourly"}),(0,s.jsx)(l,{value:"24h",children:"daily"}),(0,s.jsx)(l,{value:"7d",children:"weekly"}),(0,s.jsx)(l,{value:"30d",children:"monthly"})]}),"getBudgetDurationLabel",0,e=>e?({"1h":"hourly","24h":"daily","7d":"weekly","30d":"monthly"})[e]||e:"Not set"])},285027,e=>{"use strict";e.i(247167);var s=e.i(931067),t=e.i(271645);let l={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8zm475.7 440l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zm-783.5-27.9L512 239.9l339.8 588.2H172.2z"}}]},name:"warning",theme:"outlined"};var a=e.i(9583),r=t.forwardRef(function(e,r){return t.createElement(a.default,(0,s.default)({},e,{ref:r,icon:l}))});e.s(["WarningOutlined",0,r],285027)},447082,e=>{"use strict";var s=e.i(843476),t=e.i(271645),l=e.i(599724),a=e.i(464571),r=e.i(212931),i=e.i(291542),n=e.i(515831),d=e.i(898586),o=e.i(519756),c=e.i(737434),m=e.i(285027),u=e.i(993914),x=e.i(955135);e.i(247167);var h=e.i(931067);let p={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM472 744a40 40 0 1080 0 40 40 0 10-80 0zm16-104h48c4.4 0 8-3.6 8-8V448c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v184c0 4.4 3.6 8 8 8z"}}]},name:"file-exclamation",theme:"outlined"};var f=e.i(9583),g=t.forwardRef(function(e,s){return t.createElement(f.default,(0,h.default)({},e,{ref:s,icon:p}))}),j=e.i(764205),v=e.i(59935),y=e.i(220508),b=e.i(964306);let N=t.forwardRef(function(e,s){return t.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"}))});var w=e.i(237016),_=e.i(727749);e.s(["default",0,({accessToken:e,teams:h,possibleUIRoles:p,onUsersCreated:f})=>{let[C,S]=(0,t.useState)(!1),[k,I]=(0,t.useState)([]),[T,U]=(0,t.useState)(!1),[V,B]=(0,t.useState)(null),[O,M]=(0,t.useState)(null),[F,L]=(0,t.useState)(null),[z,P]=(0,t.useState)(null),[E,A]=(0,t.useState)(null),[R,D]=(0,t.useState)("http://localhost:4000");(0,t.useEffect)(()=>{(async()=>{try{let s=await (0,j.getProxyUISettings)(e);A(s)}catch(e){console.error("Error fetching UI settings:",e)}})(),D(new URL("/",window.location.href).toString())},[e]);let $=async()=>{U(!0);let s=k.map(e=>({...e,status:"pending"}));I(s);let t=!1;for(let l=0;le.trim()).filter(Boolean),0===s.teams.length&&delete s.teams),a.models&&"string"==typeof a.models&&""!==a.models.trim()&&(s.models=a.models.split(",").map(e=>e.trim()).filter(Boolean),0===s.models.length&&delete s.models),a.max_budget&&""!==a.max_budget.toString().trim()){let e=parseFloat(a.max_budget.toString());!isNaN(e)&&e>0&&(s.max_budget=e)}a.budget_duration&&""!==a.budget_duration.trim()&&(s.budget_duration=a.budget_duration.trim()),a.metadata&&"string"==typeof a.metadata&&""!==a.metadata.trim()&&(s.metadata=a.metadata.trim()),console.log("Sending user data:",s);let r=await (0,j.userCreateCall)(e,null,s);if(console.log("Full response:",r),r&&(r.key||r.user_id)){t=!0,console.log("Success case triggered");let s=r.data?.user_id||r.user_id;try{if(E?.SSO_ENABLED){let e=new URL("/ui",R).toString();I(s=>s.map((s,t)=>t===l?{...s,status:"success",key:r.key||r.user_id,invitation_link:e}:s))}else{let t=await (0,j.invitationCreateCall)(e,s),a=new URL(`/ui?invitation_id=${t.id}`,R).toString();I(e=>e.map((e,s)=>s===l?{...e,status:"success",key:r.key||r.user_id,invitation_link:a}:e))}}catch(e){console.error("Error creating invitation:",e),I(e=>e.map((e,s)=>s===l?{...e,status:"success",key:r.key||r.user_id,error:"User created but failed to generate invitation link"}:e))}}else{console.log("Error case triggered");let e=r?.error||"Failed to create user";console.log("Error message:",e),I(s=>s.map((s,t)=>t===l?{...s,status:"failed",error:e}:s))}}catch(s){console.error("Caught error:",s);let e=s?.response?.data?.error||s?.message||String(s);I(s=>s.map((s,t)=>t===l?{...s,status:"failed",error:e}:s))}}U(!1),t&&f&&f()},W=[{title:"Row",dataIndex:"rowNumber",key:"rowNumber",width:80},{title:"Email",dataIndex:"user_email",key:"user_email"},{title:"Role",dataIndex:"user_role",key:"user_role"},{title:"Teams",dataIndex:"teams",key:"teams"},{title:"Budget",dataIndex:"max_budget",key:"max_budget"},{title:"Status",key:"status",render:(e,t)=>t.isValid?t.status&&"pending"!==t.status?"success"===t.status?(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)(y.CheckCircleIcon,{className:"h-5 w-5 text-green-500 mr-2"}),(0,s.jsx)("span",{className:"text-green-500",children:"Success"})]}),t.invitation_link&&(0,s.jsx)("div",{className:"mt-1",children:(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)("span",{className:"text-xs text-gray-500 truncate max-w-[150px]",children:t.invitation_link}),(0,s.jsx)(w.CopyToClipboard,{text:t.invitation_link,onCopy:()=>_.default.success("Invitation link copied!"),children:(0,s.jsx)("button",{className:"ml-1 text-blue-500 text-xs hover:text-blue-700",children:"Copy"})})]})})]}):(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)(b.XCircleIcon,{className:"h-5 w-5 text-red-500 mr-2"}),(0,s.jsx)("span",{className:"text-red-500",children:"Failed"})]}),t.error&&(0,s.jsx)("span",{className:"text-sm text-red-500 ml-7",children:JSON.stringify(t.error)})]}):(0,s.jsx)("span",{className:"text-gray-500",children:"Pending"}):(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)(b.XCircleIcon,{className:"h-5 w-5 text-red-500 mr-2"}),(0,s.jsx)("span",{className:"text-red-500",children:"Invalid"})]}),t.error&&(0,s.jsx)("span",{className:"text-sm text-red-500 ml-7",children:t.error})]})}];return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.Button,{type:"primary",className:"mb-0",onClick:()=>S(!0),children:"+ Bulk Invite Users"}),(0,s.jsx)(r.Modal,{title:"Bulk Invite Users",open:C,width:800,onCancel:()=>S(!1),bodyStyle:{maxHeight:"70vh",overflow:"auto"},footer:null,children:(0,s.jsx)("div",{className:"flex flex-col",children:0===k.length?(0,s.jsxs)("div",{className:"mb-6",children:[(0,s.jsxs)("div",{className:"flex items-center mb-4",children:[(0,s.jsx)("div",{className:"w-8 h-8 rounded-full bg-blue-500 text-white flex items-center justify-center mr-3",children:"1"}),(0,s.jsx)("h3",{className:"text-lg font-medium",children:"Download and fill the template"})]}),(0,s.jsxs)("div",{className:"ml-11 mb-6",children:[(0,s.jsx)("p",{className:"mb-4",children:"Add multiple users at once by following these steps:"}),(0,s.jsxs)("ol",{className:"list-decimal list-inside space-y-2 ml-2 mb-4",children:[(0,s.jsx)("li",{children:"Download our CSV template"}),(0,s.jsx)("li",{children:"Add your users' information to the spreadsheet"}),(0,s.jsx)("li",{children:"Save the file and upload it here"}),(0,s.jsx)("li",{children:"After creation, download the results file containing the Virtual Keys for each user"})]}),(0,s.jsxs)("div",{className:"bg-gray-50 p-4 rounded-md border border-gray-200 mb-4",children:[(0,s.jsx)("h4",{className:"font-medium mb-2",children:"Template Column Names"}),(0,s.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:[(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-red-500 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"user_email"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:"User's email address (required)"})]})]}),(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-red-500 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"user_role"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:'User\'s role (one of: "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer")'})]})]}),(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-gray-300 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"teams"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:'Comma-separated team IDs (e.g., "team-1,team-2")'})]})]}),(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-gray-300 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"max_budget"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:'Maximum budget as a number (e.g., "100")'})]})]}),(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-gray-300 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"budget_duration"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:'Budget reset period (e.g., "30d", "1mo")'})]})]}),(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"w-3 h-3 rounded-full bg-gray-300 mt-1.5 mr-2 flex-shrink-0"}),(0,s.jsxs)("div",{children:[(0,s.jsx)("p",{className:"font-medium",children:"models"}),(0,s.jsx)("p",{className:"text-sm text-gray-600",children:'Comma-separated allowed models (e.g., "gpt-3.5-turbo,gpt-4")'})]})]})]})]}),(0,s.jsx)(a.Button,{type:"primary",size:"large",className:"w-full md:w-auto",icon:(0,s.jsx)(c.DownloadOutlined,{}),children:"Download CSV Template"})]}),(0,s.jsxs)("div",{className:"flex items-center mb-4",children:[(0,s.jsx)("div",{className:"w-8 h-8 rounded-full bg-blue-500 text-white flex items-center justify-center mr-3",children:"2"}),(0,s.jsx)("h3",{className:"text-lg font-medium",children:"Upload your completed CSV"})]}),(0,s.jsxs)("div",{className:"ml-11",children:[z?(0,s.jsxs)("div",{className:`mb-4 p-4 rounded-md border ${F?"bg-red-50 border-red-200":"bg-blue-50 border-blue-200"}`,children:[(0,s.jsxs)("div",{className:"flex items-center justify-between",children:[(0,s.jsxs)("div",{className:"flex items-center",children:[F?(0,s.jsx)(g,{className:"text-red-500 text-xl mr-3"}):(0,s.jsx)(u.FileTextOutlined,{className:"text-blue-500 text-xl mr-3"}),(0,s.jsxs)("div",{children:[(0,s.jsx)(d.Typography.Text,{strong:!0,className:F?"text-red-800":"text-blue-800",children:z.name}),(0,s.jsxs)(d.Typography.Text,{className:`block text-xs ${F?"text-red-600":"text-blue-600"}`,children:[(z.size/1024).toFixed(1)," KB • ",new Date().toLocaleDateString()]})]})]}),(0,s.jsx)(a.Button,{size:"small",onClick:()=>{P(null),I([]),B(null),M(null),L(null)},className:"flex items-center",icon:(0,s.jsx)(x.DeleteOutlined,{}),children:"Remove"})]}),F?(0,s.jsxs)("div",{className:"mt-3 text-red-600 text-sm flex items-start",children:[(0,s.jsx)(m.WarningOutlined,{className:"mr-2 mt-0.5"}),(0,s.jsx)("span",{children:F})]}):!O&&(0,s.jsxs)("div",{className:"mt-3 flex items-center",children:[(0,s.jsx)("div",{className:"w-full bg-gray-200 rounded-full h-1.5",children:(0,s.jsx)("div",{className:"bg-blue-500 h-1.5 rounded-full w-full animate-pulse"})}),(0,s.jsx)("span",{className:"ml-2 text-xs text-blue-600",children:"Processing..."})]})]}):(0,s.jsx)(n.Upload,{beforeUpload:e=>((B(null),M(null),L(null),P(e),"text/csv"===e.type||e.name.endsWith(".csv"))?e.size>5242880?L(`File is too large (${(e.size/1048576).toFixed(1)} MB). Please upload a CSV file smaller than 5MB.`):v.default.parse(e,{complete:e=>{if(!e.data||0===e.data.length){M("The CSV file appears to be empty. Please upload a file with data."),I([]);return}if(1===e.data.length){M("The CSV file only contains headers but no user data. Please add user data to your CSV."),I([]);return}let s=e.data[0];if(0===s.length||1===s.length&&""===s[0]){M("The CSV file doesn't contain any column headers. Please make sure your CSV has headers."),I([]);return}let t=["user_email","user_role"].filter(e=>!s.includes(e));if(t.length>0){M(`Your CSV is missing these required columns: ${t.join(", ")}. Please add these columns to your CSV file.`),I([]);return}try{let t=e.data.slice(1).map((e,t)=>{if(0===e.length||1===e.length&&""===e[0])return null;if(e.length=parseFloat(l.max_budget.toString())&&a.push("Max budget must be greater than 0")),l.budget_duration&&!l.budget_duration.match(/^\d+[dhmwy]$|^\d+mo$/)&&a.push(`Invalid budget duration format "${l.budget_duration}". Use format like "30d", "1mo", "2w", "6h"`),l.teams&&"string"==typeof l.teams&&h&&h.length>0){let e=h.map(e=>e.team_id),s=l.teams.split(",").map(e=>e.trim()).filter(s=>!e.includes(s));s.length>0&&a.push(`Unknown team(s): ${s.join(", ")}`)}return a.length>0&&(l.isValid=!1,l.error=a.join(", ")),l}).filter(Boolean),l=t.filter(e=>e.isValid);I(t),0===t.length?M("No valid data rows found in the CSV file. Please check your file format."):0===l.length?B("No valid users found in the CSV. Please check the errors below and fix your CSV file."):l.length{B(`Failed to parse CSV file: ${e.message}`),I([])},header:!1}):(L(`Invalid file type: ${e.name}. Please upload a CSV file (.csv extension).`),_.default.fromBackend("Invalid file type. Please upload a CSV file.")),!1),accept:".csv",maxCount:1,showUploadList:!1,children:(0,s.jsxs)("div",{className:"border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-blue-500 transition-colors cursor-pointer",children:[(0,s.jsx)(o.UploadOutlined,{className:"text-3xl text-gray-400 mb-2"}),(0,s.jsx)("p",{className:"mb-1",children:"Drag and drop your CSV file here"}),(0,s.jsx)("p",{className:"text-sm text-gray-500 mb-3",children:"or"}),(0,s.jsx)(a.Button,{size:"small",children:"Browse files"}),(0,s.jsx)("p",{className:"text-xs text-gray-500 mt-4",children:"Only CSV files (.csv) are supported"})]})}),O&&(0,s.jsx)("div",{className:"mb-4 p-4 bg-yellow-50 border border-yellow-200 rounded-md",children:(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)(N,{className:"h-5 w-5 text-yellow-500 mr-2 mt-0.5"}),(0,s.jsxs)("div",{children:[(0,s.jsx)(d.Typography.Text,{strong:!0,className:"text-yellow-800",children:"CSV Structure Error"}),(0,s.jsx)(d.Typography.Paragraph,{className:"text-yellow-700 mt-1 mb-0",children:O}),(0,s.jsx)(d.Typography.Paragraph,{className:"text-yellow-700 mt-2 mb-0",children:"Please download our template and ensure your CSV follows the required format."})]})]})})]})]}):(0,s.jsxs)("div",{className:"mb-6",children:[(0,s.jsxs)("div",{className:"flex items-center mb-4",children:[(0,s.jsx)("div",{className:"w-8 h-8 rounded-full bg-blue-500 text-white flex items-center justify-center mr-3",children:"3"}),(0,s.jsx)("h3",{className:"text-lg font-medium",children:k.some(e=>"success"===e.status||"failed"===e.status)?"User Creation Results":"Review and create users"})]}),V&&(0,s.jsx)("div",{className:"ml-11 mb-4 p-4 bg-red-50 border border-red-200 rounded-md",children:(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)(m.WarningOutlined,{className:"text-red-500 mr-2 mt-1"}),(0,s.jsxs)("div",{children:[(0,s.jsx)(l.Text,{className:"text-red-600 font-medium",children:V}),k.some(e=>!e.isValid)&&(0,s.jsxs)("ul",{className:"mt-2 list-disc list-inside text-red-600 text-sm",children:[(0,s.jsx)("li",{children:"Check the table below for specific errors in each row"}),(0,s.jsx)("li",{children:"Common issues include invalid email formats, missing required fields, or incorrect role values"}),(0,s.jsx)("li",{children:"Fix these issues in your CSV file and upload again"})]})]})]})}),(0,s.jsxs)("div",{className:"ml-11",children:[(0,s.jsxs)("div",{className:"flex justify-between items-center mb-3",children:[(0,s.jsx)("div",{className:"flex items-center",children:k.some(e=>"success"===e.status||"failed"===e.status)?(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)(l.Text,{className:"text-lg font-medium mr-3",children:"Creation Summary"}),(0,s.jsxs)(l.Text,{className:"text-sm bg-green-100 text-green-800 px-2 py-1 rounded mr-2",children:[k.filter(e=>"success"===e.status).length," Successful"]}),k.some(e=>"failed"===e.status)&&(0,s.jsxs)(l.Text,{className:"text-sm bg-red-100 text-red-800 px-2 py-1 rounded",children:[k.filter(e=>"failed"===e.status).length," Failed"]})]}):(0,s.jsxs)("div",{className:"flex items-center",children:[(0,s.jsx)(l.Text,{className:"text-lg font-medium mr-3",children:"User Preview"}),(0,s.jsxs)(l.Text,{className:"text-sm bg-blue-100 text-blue-800 px-2 py-1 rounded",children:[k.filter(e=>e.isValid).length," of ",k.length," users valid"]})]})}),!k.some(e=>"success"===e.status||"failed"===e.status)&&(0,s.jsxs)("div",{className:"flex space-x-3",children:[(0,s.jsx)(a.Button,{onClick:()=>{I([]),B(null)},children:"Back"}),(0,s.jsx)(a.Button,{type:"primary",onClick:$,disabled:0===k.filter(e=>e.isValid).length||T,children:T?"Creating...":`Create ${k.filter(e=>e.isValid).length} Users`})]})]}),k.some(e=>"success"===e.status)&&(0,s.jsx)("div",{className:"mb-4 p-4 bg-blue-50 border border-blue-200 rounded-md",children:(0,s.jsxs)("div",{className:"flex items-start",children:[(0,s.jsx)("div",{className:"mr-3 mt-1",children:(0,s.jsx)(y.CheckCircleIcon,{className:"h-5 w-5 text-blue-500"})}),(0,s.jsxs)("div",{children:[(0,s.jsx)(l.Text,{className:"font-medium text-blue-800",children:"User creation complete"}),(0,s.jsxs)(l.Text,{className:"block text-sm text-blue-700 mt-1",children:[(0,s.jsx)("span",{className:"font-medium",children:"Next step:"})," Download the credentials file containing Virtual Keys and invitation links. Users will need these Virtual Keys to make LLM requests through LiteLLM."]})]})]})}),(0,s.jsx)(i.Table,{dataSource:k,columns:W,size:"small",pagination:{pageSize:5},scroll:{y:300},rowClassName:e=>e.isValid?"":"bg-red-50"}),!k.some(e=>"success"===e.status||"failed"===e.status)&&(0,s.jsxs)("div",{className:"flex justify-end mt-4",children:[(0,s.jsx)(a.Button,{onClick:()=>{I([]),B(null)},className:"mr-3",children:"Back"}),(0,s.jsx)(a.Button,{type:"primary",onClick:$,disabled:0===k.filter(e=>e.isValid).length||T,children:T?"Creating...":`Create ${k.filter(e=>e.isValid).length} Users`})]}),k.some(e=>"success"===e.status||"failed"===e.status)&&(0,s.jsxs)("div",{className:"flex justify-end mt-4",children:[(0,s.jsx)(a.Button,{onClick:()=>{I([]),B(null)},className:"mr-3",children:"Start New Bulk Import"}),(0,s.jsx)(a.Button,{type:"primary",onClick:()=>{let e=k.map(e=>({user_email:e.user_email,user_role:e.user_role,status:e.status,key:e.key||"",invitation_link:e.invitation_link||"",error:e.error||""})),s=new Blob([v.default.unparse(e)],{type:"text/csv"}),t=window.URL.createObjectURL(s),l=document.createElement("a");l.href=t,l.download="bulk_users_results.csv",document.body.appendChild(l),l.click(),document.body.removeChild(l),window.URL.revokeObjectURL(t)},icon:(0,s.jsx)(c.DownloadOutlined,{}),children:"Download User Credentials"})]})]})]})})})]})}],447082)},371455,172372,e=>{"use strict";var s=e.i(843476),t=e.i(827252),l=e.i(213205),a=e.i(912598),r=e.i(109799),i=e.i(677667),n=e.i(130643),d=e.i(898667),o=e.i(35983),c=e.i(779241),m=e.i(560445),u=e.i(464571),x=e.i(536916),h=e.i(808613),p=e.i(311451),f=e.i(212931),g=e.i(199133),j=e.i(770914),v=e.i(592968),y=e.i(898586),b=e.i(271645),N=e.i(447082),w=e.i(663435),_=e.i(355619),C=e.i(727749),S=e.i(764205),k=e.i(237016),I=e.i(599724);function T({isInvitationLinkModalVisible:e,setIsInvitationLinkModalVisible:t,baseUrl:l,invitationLinkData:a,modalType:r="invitation"}){let{Title:i,Paragraph:n}=y.Typography,d=()=>{if(!l)return"";let e=new URL(l).pathname,s=e&&"/"!==e?`${e}/ui`:"ui";if(a?.has_user_setup_sso)return new URL(s,l).toString();let t=`${s}?invitation_id=${a?.id}`;return"resetPassword"===r&&(t+="&action=reset_password"),new URL(t,l).toString()};return(0,s.jsxs)(f.Modal,{title:"invitation"===r?"Invitation Link":"Reset Password Link",open:e,width:800,footer:null,onOk:()=>{t(!1)},onCancel:()=>{t(!1)},children:[(0,s.jsx)(n,{children:"invitation"===r?"Copy and send the generated link to onboard this user to the proxy.":"Copy and send the generated link to the user to reset their password."}),(0,s.jsxs)("div",{className:"flex justify-between pt-5 pb-2",children:[(0,s.jsx)(I.Text,{className:"text-base",children:"User ID"}),(0,s.jsx)(I.Text,{children:a?.user_id})]}),(0,s.jsxs)("div",{className:"flex justify-between pt-5 pb-2",children:[(0,s.jsx)(I.Text,{children:"invitation"===r?"Invitation Link":"Reset Password Link"}),(0,s.jsx)(I.Text,{children:(0,s.jsx)(I.Text,{children:d()})})]}),(0,s.jsx)("div",{className:"flex justify-end mt-5",children:(0,s.jsx)(k.CopyToClipboard,{text:d(),onCopy:()=>C.default.success("Copied!"),children:(0,s.jsx)(u.Button,{type:"primary",children:"invitation"===r?"Copy invitation link":"Copy password reset link"})})})]})}e.s(["default",()=>T],172372);let{Option:U}=g.Select,{Text:V,Link:B,Title:O}=y.Typography;e.s(["CreateUserButton",0,({userID:e,accessToken:y,teams:k,possibleUIRoles:I,onUserCreated:O,isEmbedded:M=!1})=>{let F=(0,a.useQueryClient)(),[L,z]=(0,b.useState)(null),[P]=h.Form.useForm(),[E,A]=(0,b.useState)(!1),[R,D]=(0,b.useState)(!1),[$,W]=(0,b.useState)([]),[K,q]=(0,b.useState)(!1),[H,G]=(0,b.useState)(null),[J,Q]=(0,b.useState)(null),{data:X=[]}=(0,r.useOrganizations)();(0,b.useMemo)(()=>{let e=X.flatMap(e=>e.teams||[]);return e.length>0?e:k||[]},[X,k]),(0,b.useEffect)(()=>{let s=async()=>{try{let s=await (0,S.modelAvailableCall)(y,e,"any"),t=[];for(let e=0;e{try{C.default.info("Making API Call"),M||A(!0),s.models&&0!==s.models.length||"proxy_admin"===s.user_role||(s.models=["no-default-models"]),s.organization_ids&&(s.organizations=s.organization_ids,delete s.organization_ids);let t=await (0,S.userCreateCall)(y,null,s);await F.invalidateQueries({queryKey:["userList"]}),D(!0);let l=t.data?.user_id||t.user_id;if(O&&M){O(l),P.resetFields();return}if(L?.SSO_ENABLED){let s={id:"u">typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let s=16*Math.random()|0;return("x"==e?s:3&s|8).toString(16)}),user_id:l,is_accepted:!1,accepted_at:null,expires_at:new Date(Date.now()+6048e5),created_at:new Date,created_by:e,updated_at:new Date,updated_by:e,has_user_setup_sso:!0};G(s),q(!0)}else(0,S.invitationCreateCall)(y,l).then(e=>{e.has_user_setup_sso=!1,G(e),q(!0)});C.default.success("API user Created"),P.resetFields(),localStorage.removeItem("userData"+e)}catch(s){let e=s.response?.data?.detail||s?.message||"Error creating the user";C.default.fromBackend(e),console.error("Error creating the user:",s)}};return M?(0,s.jsxs)(h.Form,{form:P,onFinish:Y,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{user_role:"internal_user_viewer",send_invite_email:!0},children:[(0,s.jsx)(m.Alert,{message:"Email invitations",description:(0,s.jsxs)(s.Fragment,{children:["New users receive an email invite only when an email integration (SMTP, Resend, or SendGrid) is configured."," ",(0,s.jsx)(B,{href:"https://docs.litellm.ai/docs/proxy/email",target:"_blank",children:"Learn how to set up email notifications"})]}),type:"info",showIcon:!0,className:"mb-4"}),(0,s.jsx)(h.Form.Item,{label:"User Email",name:"user_email",children:(0,s.jsx)(c.TextInput,{placeholder:""})}),(0,s.jsx)(h.Form.Item,{label:"User Role",name:"user_role",children:(0,s.jsx)(g.Select,{children:I&&Object.entries(I).map(([e,{ui_label:t,description:l}])=>(0,s.jsx)(o.SelectItem,{value:e,title:t,children:(0,s.jsxs)("div",{className:"flex",children:[t," ",(0,s.jsx)(V,{className:"ml-2",style:{color:"gray",fontSize:"12px"},children:l})]})},e))})}),(0,s.jsx)(h.Form.Item,{label:"Team",name:"team_id",children:(0,s.jsx)(w.default,{})}),(0,s.jsx)(h.Form.Item,{label:"Metadata",name:"metadata",children:(0,s.jsx)(p.Input.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,s.jsx)(h.Form.Item,{label:"Send invitation email",name:"send_invite_email",valuePropName:"checked",children:(0,s.jsx)(x.Checkbox,{})}),(0,s.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,s.jsx)(u.Button,{htmlType:"submit",children:"Create User"})})]}):(0,s.jsxs)("div",{className:"flex gap-2",children:[(0,s.jsx)(u.Button,{type:"primary",className:"mb-0",onClick:()=>A(!0),children:"+ Invite User"}),(0,s.jsx)(N.default,{accessToken:y,teams:k,possibleUIRoles:I}),(0,s.jsxs)(f.Modal,{title:"Invite User",open:E,width:800,footer:null,onOk:()=>{A(!1),P.resetFields()},onCancel:()=>{A(!1),D(!1),P.resetFields()},children:[(0,s.jsxs)(j.Space,{direction:"vertical",size:"middle",children:[(0,s.jsx)(V,{className:"mb-1",children:"Create a User who can own keys"}),(0,s.jsx)(m.Alert,{message:"Email invitations",description:(0,s.jsxs)(s.Fragment,{children:["New users receive an email invite only when an email integration (SMTP, Resend, or SendGrid) is configured."," ",(0,s.jsx)(B,{href:"https://docs.litellm.ai/docs/proxy/email",target:"_blank",children:"Learn how to set up email notifications"})]}),type:"info",showIcon:!0,className:"mb-4"})]}),(0,s.jsxs)(h.Form,{form:P,onFinish:Y,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{user_role:"internal_user_viewer",send_invite_email:!0},children:[(0,s.jsx)(h.Form.Item,{label:"User Email",name:"user_email",children:(0,s.jsx)(p.Input,{})}),(0,s.jsx)(h.Form.Item,{label:(0,s.jsxs)("span",{children:["Global Proxy Role"," ",(0,s.jsx)(v.Tooltip,{title:"This role is independent of any team/org specific roles. Configure Team / Organization Admins in the Settings",children:(0,s.jsx)(t.InfoCircleOutlined,{})})]}),name:"user_role",children:(0,s.jsx)(g.Select,{children:I&&Object.entries(I).map(([e,{ui_label:t,description:l}])=>(0,s.jsxs)(o.SelectItem,{value:e,title:t,children:[(0,s.jsx)(V,{children:t}),(0,s.jsxs)(V,{type:"secondary",children:[" - ",l]})]},e))})}),(0,s.jsx)(h.Form.Item,{label:"Team",className:"gap-2",name:"team_id",help:"If selected, user will be added as a 'user' role to the team.",children:(0,s.jsx)(w.default,{})}),(0,s.jsx)(h.Form.Item,{label:"Organization",name:"organization_ids",help:"The user will be added to the selected organization(s).",children:(0,s.jsx)(g.Select,{mode:"multiple",placeholder:"Select Organization",style:{width:"100%"},children:X.map(e=>(0,s.jsxs)(U,{value:e.organization_id,children:[e.organization_alias," (",e.organization_id,")"]},e.organization_id))})}),(0,s.jsx)(h.Form.Item,{label:"Metadata",name:"metadata",children:(0,s.jsx)(p.Input.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,s.jsx)(h.Form.Item,{label:"Send invitation email",name:"send_invite_email",valuePropName:"checked",children:(0,s.jsx)(x.Checkbox,{})}),(0,s.jsxs)(i.Accordion,{children:[(0,s.jsx)(d.AccordionHeader,{children:(0,s.jsx)(V,{strong:!0,children:"Personal Key Creation"})}),(0,s.jsx)(n.AccordionBody,{children:(0,s.jsx)(h.Form.Item,{className:"gap-2",label:(0,s.jsxs)("span",{children:["Models"," ",(0,s.jsx)(v.Tooltip,{title:"Models user has access to, outside of team scope.",children:(0,s.jsx)(t.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"models",help:"Models user has access to, outside of team scope.",children:(0,s.jsxs)(g.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:[(0,s.jsx)(g.Select.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),(0,s.jsx)(g.Select.Option,{value:"no-default-models",children:"No Default Models"},"no-default-models"),$.map(e=>(0,s.jsx)(g.Select.Option,{value:e,children:(0,_.getModelDisplayName)(e)},e))]})})})]}),(0,s.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,s.jsx)(u.Button,{type:"primary",icon:(0,s.jsx)(l.UserAddOutlined,{}),htmlType:"submit",children:"Invite User"})})]})]}),R&&(0,s.jsx)(T,{isInvitationLinkModalVisible:K,setIsInvitationLinkModalVisible:q,baseUrl:J||"",invitationLinkData:H})]})}],371455)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0606c92ecd600e0c.js b/litellm/proxy/_experimental/out/_next/static/chunks/0606c92ecd600e0c.js deleted file mode 100644 index 4d144c04ad4..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0606c92ecd600e0c.js +++ /dev/null @@ -1,420 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,492030,e=>{"use strict";var t=e.i(121229);e.s(["CheckOutlined",()=>t.default])},166406,e=>{"use strict";var t=e.i(190144);e.s(["CopyOutlined",()=>t.default])},447566,e=>{"use strict";e.i(247167);var t=e.i(931067),i=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 474H286.9l350.2-304c5.6-4.9 2.2-14-5.2-14h-88.5c-3.9 0-7.6 1.4-10.5 3.9L155 487.8a31.96 31.96 0 000 48.3L535.1 866c1.5 1.3 3.3 2 5.2 2h91.5c7.4 0 10.8-9.2 5.2-14L286.9 550H872c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"arrow-left",theme:"outlined"};var o=e.i(9583),r=i.forwardRef(function(e,r){return i.createElement(o.default,(0,t.default)({},e,{ref:r,icon:a}))});e.s(["ArrowLeftOutlined",0,r],447566)},596239,e=>{"use strict";e.i(247167);var t=e.i(931067),i=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M574 665.4a8.03 8.03 0 00-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 00-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 000 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 000 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 00-11.3 0L372.3 598.7a8.03 8.03 0 000 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"}}]},name:"link",theme:"outlined"};var o=e.i(9583),r=i.forwardRef(function(e,r){return i.createElement(o.default,(0,t.default)({},e,{ref:r,icon:a}))});e.s(["LinkOutlined",0,r],596239)},190272,785913,e=>{"use strict";var t,i,a=((t={}).AUDIO_SPEECH="audio_speech",t.AUDIO_TRANSCRIPTION="audio_transcription",t.IMAGE_GENERATION="image_generation",t.VIDEO_GENERATION="video_generation",t.CHAT="chat",t.RESPONSES="responses",t.IMAGE_EDITS="image_edits",t.ANTHROPIC_MESSAGES="anthropic_messages",t.EMBEDDING="embedding",t),o=((i={}).IMAGE="image",i.VIDEO="video",i.CHAT="chat",i.RESPONSES="responses",i.IMAGE_EDITS="image_edits",i.ANTHROPIC_MESSAGES="anthropic_messages",i.EMBEDDINGS="embeddings",i.SPEECH="speech",i.TRANSCRIPTION="transcription",i.A2A_AGENTS="a2a_agents",i.MCP="mcp",i.REALTIME="realtime",i);let r={image_generation:"image",video_generation:"video",chat:"chat",responses:"responses",image_edits:"image_edits",anthropic_messages:"anthropic_messages",audio_speech:"speech",audio_transcription:"transcription",embedding:"embeddings"};e.s(["EndpointType",()=>o,"getEndpointType",0,e=>{if(console.log("getEndpointType:",e),Object.values(a).includes(e)){let t=r[e];return console.log("endpointType:",t),t}return"chat"}],785913),e.s(["generateCodeSnippet",0,e=>{let t,{apiKeySource:i,accessToken:a,apiKey:r,inputMessage:n,chatHistory:s,selectedTags:l,selectedVectorStores:p,selectedGuardrails:d,selectedPolicies:c,selectedMCPServers:g,mcpServers:m,mcpServerToolRestrictions:u,selectedVoice:f,endpointType:_,selectedModel:h,selectedSdk:A,proxySettings:x}=e,b="session"===i?a:r,y=window.location.origin,I=x?.LITELLM_UI_API_DOC_BASE_URL;I&&I.trim()?y=I:x?.PROXY_BASE_URL&&(y=x.PROXY_BASE_URL);let v=n||"Your prompt here",C=v.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n"),E=s.filter(e=>!e.isImage).map(({role:e,content:t})=>({role:e,content:t})),O={};l.length>0&&(O.tags=l),p.length>0&&(O.vector_stores=p),d.length>0&&(O.guardrails=d),c.length>0&&(O.policies=c);let T=h||"your-model-name",S="azure"===A?`import openai - -client = openai.AzureOpenAI( - api_key="${b||"YOUR_LITELLM_API_KEY"}", - azure_endpoint="${y}", - api_version="2024-02-01" -)`:`import openai - -client = openai.OpenAI( - api_key="${b||"YOUR_LITELLM_API_KEY"}", - base_url="${y}" -)`;switch(_){case o.CHAT:{let e=Object.keys(O).length>0,i="";if(e){let e=JSON.stringify({metadata:O},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();i=`, - extra_body=${e}`}let a=E.length>0?E:[{role:"user",content:v}];t=` -import base64 - -# Helper function to encode images to base64 -def encode_image(image_path): - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -# Example with text only -response = client.chat.completions.create( - model="${T}", - messages=${JSON.stringify(a,null,4)}${i} -) - -print(response) - -# Example with image or PDF (uncomment and provide file path to use) -# base64_file = encode_image("path/to/your/file.jpg") # or .pdf -# response_with_file = client.chat.completions.create( -# model="${T}", -# messages=[ -# { -# "role": "user", -# "content": [ -# { -# "type": "text", -# "text": "${C}" -# }, -# { -# "type": "image_url", -# "image_url": { -# "url": f"data:image/jpeg;base64,{base64_file}" # or data:application/pdf;base64,{base64_file} -# } -# } -# ] -# } -# ]${i} -# ) -# print(response_with_file) -`;break}case o.RESPONSES:{let e=Object.keys(O).length>0,i="";if(e){let e=JSON.stringify({metadata:O},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();i=`, - extra_body=${e}`}let a=E.length>0?E:[{role:"user",content:v}];t=` -import base64 - -# Helper function to encode images to base64 -def encode_image(image_path): - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -# Example with text only -response = client.responses.create( - model="${T}", - input=${JSON.stringify(a,null,4)}${i} -) - -print(response.output_text) - -# Example with image or PDF (uncomment and provide file path to use) -# base64_file = encode_image("path/to/your/file.jpg") # or .pdf -# response_with_file = client.responses.create( -# model="${T}", -# input=[ -# { -# "role": "user", -# "content": [ -# {"type": "input_text", "text": "${C}"}, -# { -# "type": "input_image", -# "image_url": f"data:image/jpeg;base64,{base64_file}", # or data:application/pdf;base64,{base64_file} -# }, -# ], -# } -# ]${i} -# ) -# print(response_with_file.output_text) -`;break}case o.IMAGE:t="azure"===A?` -# NOTE: The Azure SDK does not have a direct equivalent to the multi-modal 'responses.create' method shown for OpenAI. -# This snippet uses 'client.images.generate' and will create a new image based on your prompt. -# It does not use the uploaded image, as 'client.images.generate' does not support image inputs in this context. -import os -import requests -import json -import time -from PIL import Image - -result = client.images.generate( - model="${T}", - prompt="${n}", - n=1 -) - -json_response = json.loads(result.model_dump_json()) - -# Set the directory for the stored image -image_dir = os.path.join(os.curdir, 'images') - -# If the directory doesn't exist, create it -if not os.path.isdir(image_dir): - os.mkdir(image_dir) - -# Initialize the image path -image_filename = f"generated_image_{int(time.time())}.png" -image_path = os.path.join(image_dir, image_filename) - -try: - # Retrieve the generated image - if json_response.get("data") && len(json_response["data"]) > 0 && json_response["data"][0].get("url"): - image_url = json_response["data"][0]["url"] - generated_image = requests.get(image_url).content - with open(image_path, "wb") as image_file: - image_file.write(generated_image) - - print(f"Image saved to {image_path}") - # Display the image - image = Image.open(image_path) - image.show() - else: - print("Could not find image URL in response.") - print("Full response:", json_response) -except Exception as e: - print(f"An error occurred: {e}") - print("Full response:", json_response) -`:` -import base64 -import os -import time -import json -from PIL import Image -import requests - -# Helper function to encode images to base64 -def encode_image(image_path): - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -# Helper function to create a file (simplified for this example) -def create_file(image_path): - # In a real implementation, this would upload the file to OpenAI - # For this example, we'll just return a placeholder ID - return f"file_{os.path.basename(image_path).replace('.', '_')}" - -# The prompt entered by the user -prompt = "${C}" - -# Encode images to base64 -base64_image1 = encode_image("body-lotion.png") -base64_image2 = encode_image("soap.png") - -# Create file IDs -file_id1 = create_file("body-lotion.png") -file_id2 = create_file("incense-kit.png") - -response = client.responses.create( - model="${T}", - input=[ - { - "role": "user", - "content": [ - {"type": "input_text", "text": prompt}, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image1}", - }, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image2}", - }, - { - "type": "input_image", - "file_id": file_id1, - }, - { - "type": "input_image", - "file_id": file_id2, - } - ], - } - ], - tools=[{"type": "image_generation"}], -) - -# Process the response -image_generation_calls = [ - output - for output in response.output - if output.type == "image_generation_call" -] - -image_data = [output.result for output in image_generation_calls] - -if image_data: - image_base64 = image_data[0] - image_filename = f"edited_image_{int(time.time())}.png" - with open(image_filename, "wb") as f: - f.write(base64.b64decode(image_base64)) - print(f"Image saved to {image_filename}") -else: - # If no image is generated, there might be a text response with an explanation - text_response = [output.text for output in response.output if hasattr(output, 'text')] - if text_response: - print("No image generated. Model response:") - print("\\n".join(text_response)) - else: - print("No image data found in response.") - print("Full response for debugging:") - print(response) -`;break;case o.IMAGE_EDITS:t="azure"===A?` -import base64 -import os -import time -import json -from PIL import Image -import requests - -# Helper function to encode images to base64 -def encode_image(image_path): - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -# The prompt entered by the user -prompt = "${C}" - -# Encode images to base64 -base64_image1 = encode_image("body-lotion.png") -base64_image2 = encode_image("soap.png") - -# Create file IDs -file_id1 = create_file("body-lotion.png") -file_id2 = create_file("incense-kit.png") - -response = client.responses.create( - model="${T}", - input=[ - { - "role": "user", - "content": [ - {"type": "input_text", "text": prompt}, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image1}", - }, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image2}", - }, - { - "type": "input_image", - "file_id": file_id1, - }, - { - "type": "input_image", - "file_id": file_id2, - } - ], - } - ], - tools=[{"type": "image_generation"}], -) - -# Process the response -image_generation_calls = [ - output - for output in response.output - if output.type == "image_generation_call" -] - -image_data = [output.result for output in image_generation_calls] - -if image_data: - image_base64 = image_data[0] - image_filename = f"edited_image_{int(time.time())}.png" - with open(image_filename, "wb") as f: - f.write(base64.b64decode(image_base64)) - print(f"Image saved to {image_filename}") -else: - # If no image is generated, there might be a text response with an explanation - text_response = [output.text for output in response.output if hasattr(output, 'text')] - if text_response: - print("No image generated. Model response:") - print("\\n".join(text_response)) - else: - print("No image data found in response.") - print("Full response for debugging:") - print(response) -`:` -import base64 -import os -import time - -# Helper function to encode images to base64 -def encode_image(image_path): - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -# Helper function to create a file (simplified for this example) -def create_file(image_path): - # In a real implementation, this would upload the file to OpenAI - # For this example, we'll just return a placeholder ID - return f"file_{os.path.basename(image_path).replace('.', '_')}" - -# The prompt entered by the user -prompt = "${C}" - -# Encode images to base64 -base64_image1 = encode_image("body-lotion.png") -base64_image2 = encode_image("soap.png") - -# Create file IDs -file_id1 = create_file("body-lotion.png") -file_id2 = create_file("incense-kit.png") - -response = client.responses.create( - model="${T}", - input=[ - { - "role": "user", - "content": [ - {"type": "input_text", "text": prompt}, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image1}", - }, - { - "type": "input_image", - "image_url": f"data:image/jpeg;base64,{base64_image2}", - }, - { - "type": "input_image", - "file_id": file_id1, - }, - { - "type": "input_image", - "file_id": file_id2, - } - ], - } - ], - tools=[{"type": "image_generation"}], -) - -# Process the response -image_generation_calls = [ - output - for output in response.output - if output.type == "image_generation_call" -] - -image_data = [output.result for output in image_generation_calls] - -if image_data: - image_base64 = image_data[0] - image_filename = f"edited_image_{int(time.time())}.png" - with open(image_filename, "wb") as f: - f.write(base64.b64decode(image_base64)) - print(f"Image saved to {image_filename}") -else: - # If no image is generated, there might be a text response with an explanation - text_response = [output.text for output in response.output if hasattr(output, 'text')] - if text_response: - print("No image generated. Model response:") - print("\\n".join(text_response)) - else: - print("No image data found in response.") - print("Full response for debugging:") - print(response) -`;break;case o.EMBEDDINGS:t=` -response = client.embeddings.create( - input="${n||"Your string here"}", - model="${T}", - encoding_format="base64" # or "float" -) - -print(response.data[0].embedding) -`;break;case o.TRANSCRIPTION:t=` -# Open the audio file -audio_file = open("path/to/your/audio/file.mp3", "rb") - -# Make the transcription request -response = client.audio.transcriptions.create( - model="${T}", - file=audio_file${n?`, - prompt="${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:""} -) - -print(response.text) -`;break;case o.SPEECH:t=` -# Make the text-to-speech request -response = client.audio.speech.create( - model="${T}", - input="${n||"Your text to convert to speech here"}", - voice="${f}" # Options: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer -) - -# Save the audio to a file -output_filename = "output_speech.mp3" -response.stream_to_file(output_filename) -print(f"Audio saved to {output_filename}") - -# Optional: Customize response format and speed -# response = client.audio.speech.create( -# model="${T}", -# input="${n||"Your text to convert to speech here"}", -# voice="alloy", -# response_format="mp3", # Options: mp3, opus, aac, flac, wav, pcm -# speed=1.0 # Range: 0.25 to 4.0 -# ) -# response.stream_to_file("output_speech.mp3") -`;break;default:t="\n# Code generation for this endpoint is not implemented yet."}return`${S} -${t}`}],190272)},652272,209261,e=>{"use strict";var t=e.i(843476),i=e.i(271645),a=e.i(447566),o=e.i(166406),r=e.i(492030),n=e.i(596239);let s=e=>"github"===e.source.source&&e.source.repo?`/plugin marketplace add ${e.source.repo}`:"url"===e.source.source&&e.source.url?`/plugin marketplace add ${e.source.url}`:`/plugin marketplace add ${e.name}`;e.s(["formatInstallCommand",0,s,"getCategoryBadgeColor",0,e=>{if(!e)return"gray";let t=e.toLowerCase();if(t.includes("development")||t.includes("dev"))return"blue";if(t.includes("productivity")||t.includes("workflow"))return"green";if(t.includes("learning")||t.includes("education"))return"purple";if(t.includes("security")||t.includes("safety"))return"red";if(t.includes("data")||t.includes("analytics"))return"orange";else if(t.includes("integration")||t.includes("api"))return"yellow";return"gray"},"isValidEmail",0,e=>!e||/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e),"isValidSemanticVersion",0,e=>!e||/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(e),"isValidUrl",0,e=>{if(!e)return!0;try{return new URL(e),!0}catch{return!1}},"parseKeywords",0,e=>e&&""!==e.trim()?e.split(",").map(e=>e.trim()).filter(e=>""!==e):[],"validatePluginName",0,e=>!!e&&""!==e.trim()&&/^[a-z0-9-]+$/.test(e)],209261),e.s(["default",0,({skill:e,onBack:l})=>{let p,[d,c]=(0,i.useState)("overview"),[g,m]=(0,i.useState)(null),u=(e,t)=>{navigator.clipboard.writeText(e),m(t),setTimeout(()=>m(null),2e3)},f="github"===(p=e.source).source&&p.repo?`https://github.com/${p.repo}`:"git-subdir"===p.source&&p.url?p.path?`${p.url}/tree/main/${p.path}`:p.url:"url"===p.source&&p.url?p.url:null,_=s(e),h=[...e.category?[{property:"Category",value:e.category}]:[],...e.domain?[{property:"Domain",value:e.domain}]:[],...e.namespace?[{property:"Namespace",value:e.namespace}]:[],...e.version?[{property:"Version",value:e.version}]:[],...e.author?.name?[{property:"Author",value:e.author.name}]:[],...e.created_at?[{property:"Added",value:new Date(e.created_at).toLocaleDateString()}]:[]];return(0,t.jsxs)("div",{style:{padding:"24px 32px 24px 0"},children:[(0,t.jsxs)("div",{onClick:l,style:{display:"inline-flex",alignItems:"center",gap:6,color:"#5f6368",cursor:"pointer",fontSize:14,marginBottom:24},children:[(0,t.jsx)(a.ArrowLeftOutlined,{style:{fontSize:11}}),(0,t.jsx)("span",{children:"Skills"})]}),(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsx)("h1",{style:{fontSize:28,fontWeight:400,color:"#202124",margin:0,lineHeight:1.2},children:e.name}),e.description&&(0,t.jsx)("p",{style:{fontSize:14,color:"#5f6368",margin:"8px 0 0 0",lineHeight:1.6},children:e.description})]}),(0,t.jsx)("div",{style:{borderBottom:"1px solid #dadce0",marginBottom:28,marginTop:24},children:(0,t.jsx)("div",{style:{display:"flex",gap:0},children:[{key:"overview",label:"Overview"},{key:"usage",label:"How to Use"}].map(e=>(0,t.jsx)("div",{onClick:()=>c(e.key),style:{padding:"12px 20px",fontSize:14,color:d===e.key?"#1a73e8":"#5f6368",borderBottom:d===e.key?"3px solid #1a73e8":"3px solid transparent",cursor:"pointer",fontWeight:d===e.key?500:400,marginBottom:-1},children:e.label},e.key))})}),"overview"===d&&(0,t.jsxs)("div",{style:{display:"flex",gap:64},children:[(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsx)("h2",{style:{fontSize:18,fontWeight:400,color:"#202124",margin:"0 0 4px 0"},children:"Skill Details"}),(0,t.jsx)("p",{style:{fontSize:13,color:"#5f6368",margin:"0 0 16px 0"},children:"Metadata registered with this skill"}),(0,t.jsxs)("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:14},children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{style:{borderBottom:"1px solid #dadce0"},children:[(0,t.jsx)("th",{style:{textAlign:"left",padding:"12px 0",color:"#5f6368",fontWeight:500,width:160},children:"Property"}),(0,t.jsx)("th",{style:{textAlign:"left",padding:"12px 0",color:"#5f6368",fontWeight:500},children:e.name})]})}),(0,t.jsx)("tbody",{children:h.map((e,i)=>(0,t.jsxs)("tr",{style:{borderBottom:"1px solid #f1f3f4"},children:[(0,t.jsx)("td",{style:{padding:"12px 0",color:"#3c4043"},children:e.property}),(0,t.jsx)("td",{style:{padding:"12px 0",color:"#202124"},children:e.value})]},i))})]})]}),(0,t.jsxs)("div",{style:{width:240,flexShrink:0},children:[(0,t.jsxs)("div",{style:{marginBottom:24},children:[(0,t.jsx)("div",{style:{fontSize:12,color:"#5f6368",marginBottom:4},children:"Status"}),(0,t.jsx)("span",{style:{fontSize:12,padding:"3px 10px",borderRadius:12,backgroundColor:e.enabled?"#e6f4ea":"#f1f3f4",color:e.enabled?"#137333":"#5f6368",fontWeight:500},children:e.enabled?"Public":"Draft"})]}),f&&(0,t.jsxs)("div",{style:{marginBottom:24},children:[(0,t.jsx)("div",{style:{fontSize:12,color:"#5f6368",marginBottom:4},children:"Source"}),(0,t.jsxs)("a",{href:f,target:"_blank",rel:"noopener noreferrer",style:{fontSize:13,color:"#1a73e8",wordBreak:"break-all",display:"flex",alignItems:"center",gap:4},children:[f.replace("https://",""),(0,t.jsx)(n.LinkOutlined,{style:{fontSize:11,flexShrink:0}})]})]}),e.keywords&&e.keywords.length>0&&(0,t.jsxs)("div",{style:{marginBottom:24},children:[(0,t.jsx)("div",{style:{fontSize:12,color:"#5f6368",marginBottom:8},children:"Tags"}),(0,t.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:e.keywords.map(e=>(0,t.jsx)("span",{style:{fontSize:12,padding:"4px 12px",borderRadius:16,border:"1px solid #dadce0",color:"#3c4043",backgroundColor:"#fff"},children:e},e))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{style:{fontSize:12,color:"#5f6368",marginBottom:4},children:"Skill ID"}),(0,t.jsx)("div",{style:{fontSize:12,fontFamily:"monospace",color:"#3c4043",wordBreak:"break-all"},children:e.id})]})]})]}),"usage"===d&&(0,t.jsxs)("div",{style:{maxWidth:640},children:[(0,t.jsx)("h2",{style:{fontSize:18,fontWeight:400,color:"#202124",margin:"0 0 8px 0"},children:"Using this skill"}),(0,t.jsx)("p",{style:{fontSize:14,color:"#5f6368",margin:"0 0 24px 0",lineHeight:1.6},children:"Once your proxy is set as a marketplace, enable this skill in Claude Code with one command:"}),(0,t.jsxs)("div",{style:{border:"1px solid #dadce0",borderRadius:8,overflow:"hidden",marginBottom:24},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",backgroundColor:"#f8f9fa",borderBottom:"1px solid #dadce0"},children:[(0,t.jsx)("span",{style:{fontSize:13,color:"#3c4043",fontWeight:500},children:"Run in Claude Code"}),(0,t.jsxs)("button",{onClick:()=>u(_,"install"),style:{display:"flex",alignItems:"center",gap:4,fontSize:12,color:"install"===g?"#137333":"#1a73e8",background:"none",border:"none",cursor:"pointer",padding:0},children:["install"===g?(0,t.jsx)(r.CheckOutlined,{}):(0,t.jsx)(o.CopyOutlined,{}),"install"===g?"Copied":"Copy"]})]}),(0,t.jsx)("pre",{style:{margin:0,padding:"14px 16px",fontSize:14,fontFamily:"monospace",color:"#202124",backgroundColor:"#fff"},children:_})]}),(0,t.jsxs)("p",{style:{fontSize:13,color:"#5f6368",lineHeight:1.6,margin:0},children:["Don't have the marketplace configured yet?"," ",(0,t.jsx)("span",{onClick:()=>c("setup"),style:{color:"#1a73e8",cursor:"pointer"},children:"See one-time setup →"})]})]}),"setup"===d&&(0,t.jsxs)("div",{style:{maxWidth:640},children:[(0,t.jsx)("h2",{style:{fontSize:18,fontWeight:400,color:"#202124",margin:"0 0 8px 0"},children:"One-time marketplace setup"}),(0,t.jsxs)("p",{style:{fontSize:14,color:"#5f6368",margin:"0 0 24px 0",lineHeight:1.6},children:["Add this to ",(0,t.jsx)("code",{style:{fontSize:13,backgroundColor:"#f1f3f4",padding:"1px 6px",borderRadius:4},children:"~/.claude/settings.json"})," to point Claude Code at your proxy:"]}),(0,t.jsxs)("div",{style:{border:"1px solid #dadce0",borderRadius:8,overflow:"hidden"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",backgroundColor:"#f8f9fa",borderBottom:"1px solid #dadce0"},children:[(0,t.jsx)("span",{style:{fontSize:13,color:"#3c4043",fontWeight:500},children:"~/.claude/settings.json"}),(0,t.jsxs)("button",{onClick:()=>{u(JSON.stringify({extraKnownMarketplaces:{"my-org":{source:"url",url:`${window.location.origin}/claude-code/marketplace.json`}}},null,2),"settings")},style:{display:"flex",alignItems:"center",gap:4,fontSize:12,color:"settings"===g?"#137333":"#1a73e8",background:"none",border:"none",cursor:"pointer",padding:0},children:["settings"===g?(0,t.jsx)(r.CheckOutlined,{}):(0,t.jsx)(o.CopyOutlined,{}),"settings"===g?"Copied":"Copy"]})]}),(0,t.jsx)("pre",{style:{margin:0,padding:"14px 16px",fontSize:13,fontFamily:"monospace",color:"#202124",backgroundColor:"#fff"},children:JSON.stringify({extraKnownMarketplaces:{"my-org":{source:"url",url:`${window.location.origin}/claude-code/marketplace.json`}}},null,2)})]})]})]})}],652272)},879664,e=>{"use strict";let t=(0,e.i(475254).default)("info",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]]);e.s(["default",()=>t])},916925,e=>{"use strict";var t,i=((t={}).A2A_Agent="A2A Agent",t.AI21="Ai21",t.AI21_CHAT="Ai21 Chat",t.AIML="AI/ML API",t.AIOHTTP_OPENAI="Aiohttp Openai",t.Anthropic="Anthropic",t.ANTHROPIC_TEXT="Anthropic Text",t.AssemblyAI="AssemblyAI",t.AUTO_ROUTER="Auto Router",t.Bedrock="Amazon Bedrock",t.BedrockMantle="Amazon Bedrock Mantle",t.SageMaker="AWS SageMaker",t.Azure="Azure",t.Azure_AI_Studio="Azure AI Foundry (Studio)",t.AZURE_TEXT="Azure Text",t.BASETEN="Baseten",t.BYTEZ="Bytez",t.Cerebras="Cerebras",t.CLARIFAI="Clarifai",t.CLOUDFLARE="Cloudflare",t.CODESTRAL="Codestral",t.Cohere="Cohere",t.COHERE_CHAT="Cohere Chat",t.COMETAPI="Cometapi",t.COMPACTIFAI="Compactifai",t.Cursor="Cursor",t.Dashscope="Dashscope",t.Databricks="Databricks (Qwen API)",t.DATAROBOT="Datarobot",t.DeepInfra="DeepInfra",t.Deepgram="Deepgram",t.Deepseek="Deepseek",t.DOCKER_MODEL_RUNNER="Docker Model Runner",t.DOTPROMPT="Dotprompt",t.ElevenLabs="ElevenLabs",t.EMPOWER="Empower",t.FalAI="Fal AI",t.FEATHERLESS_AI="Featherless Ai",t.FireworksAI="Fireworks AI",t.FRIENDLIAI="Friendliai",t.GALADRIEL="Galadriel",t.GITHUB_COPILOT="Github Copilot",t.Google_AI_Studio="Google AI Studio",t.GradientAI="GradientAI",t.Groq="Groq",t.HEROKU="Heroku",t.Hosted_Vllm="vllm",t.HUGGINGFACE="Huggingface",t.HYPERBOLIC="Hyperbolic",t.Infinity="Infinity",t.JinaAI="Jina AI",t.LAMBDA_AI="Lambda Ai",t.LEMONADE="Lemonade",t.LLAMAFILE="Llamafile",t.LM_STUDIO="Lm Studio",t.LLAMA="Meta Llama",t.MARITALK="Maritalk",t.MiniMax="MiniMax",t.MistralAI="Mistral AI",t.MOONSHOT="Moonshot",t.MORPH="Morph",t.NEBIUS="Nebius",t.NLP_CLOUD="Nlp Cloud",t.NOVITA="Novita",t.NSCALE="Nscale",t.NVIDIA_NIM="Nvidia Nim",t.Ollama="Ollama",t.OLLAMA_CHAT="Ollama Chat",t.OOBABOOGA="Oobabooga",t.OpenAI="OpenAI",t.OPENAI_LIKE="Openai Like",t.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",t.OpenAI_Text="OpenAI Text Completion",t.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",t.Openrouter="Openrouter",t.Oracle="Oracle Cloud Infrastructure (OCI)",t.OVHCLOUD="Ovhcloud",t.Perplexity="Perplexity",t.PETALS="Petals",t.PG_VECTOR="Pg Vector",t.PREDIBASE="Predibase",t.RECRAFT="Recraft",t.REPLICATE="Replicate",t.RunwayML="RunwayML",t.SAGEMAKER_LEGACY="Sagemaker",t.Sambanova="Sambanova",t.SAP="SAP Generative AI Hub",t.Snowflake="Snowflake",t.TEXT_COMPLETION_CODESTRAL="Text-Completion-Codestral",t.TogetherAI="TogetherAI",t.TOPAZ="Topaz",t.Triton="Triton",t.V0="V0",t.VERCEL_AI_GATEWAY="Vercel Ai Gateway",t.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",t.VERTEX_AI_BETA="Vertex Ai Beta",t.VLLM="Vllm",t.VolcEngine="VolcEngine",t.Voyage="Voyage AI",t.WANDB="Wandb",t.WATSONX="Watsonx",t.WATSONX_TEXT="Watsonx Text",t.xAI="xAI",t.XINFERENCE="Xinference",t.ZAI="Z.AI (Zhipu AI)",t);let a={A2A_Agent:"a2a_agent",AI21:"ai21",AI21_CHAT:"ai21_chat",AIML:"aiml",AIOHTTP_OPENAI:"aiohttp_openai",Anthropic:"anthropic",ANTHROPIC_TEXT:"anthropic_text",AssemblyAI:"assemblyai",AUTO_ROUTER:"auto_router",Azure:"azure",Azure_AI_Studio:"azure_ai",AZURE_TEXT:"azure_text",BASETEN:"baseten",Bedrock:"bedrock",BedrockMantle:"bedrock_mantle",BYTEZ:"bytez",Cerebras:"cerebras",CLARIFAI:"clarifai",CLOUDFLARE:"cloudflare",CODESTRAL:"codestral",Cohere:"cohere",COHERE_CHAT:"cohere_chat",COMETAPI:"cometapi",COMPACTIFAI:"compactifai",Cursor:"cursor",Dashscope:"dashscope",Databricks:"databricks",DATAROBOT:"datarobot",DeepInfra:"deepinfra",Deepgram:"deepgram",Deepseek:"deepseek",DOCKER_MODEL_RUNNER:"docker_model_runner",DOTPROMPT:"dotprompt",ElevenLabs:"elevenlabs",EMPOWER:"empower",FalAI:"fal_ai",FEATHERLESS_AI:"featherless_ai",FireworksAI:"fireworks_ai",FRIENDLIAI:"friendliai",GALADRIEL:"galadriel",GITHUB_COPILOT:"github_copilot",Google_AI_Studio:"gemini",GradientAI:"gradient_ai",Groq:"groq",HEROKU:"heroku",Hosted_Vllm:"hosted_vllm",HUGGINGFACE:"huggingface",HYPERBOLIC:"hyperbolic",Infinity:"infinity",JinaAI:"jina_ai",LAMBDA_AI:"lambda_ai",LEMONADE:"lemonade",LLAMAFILE:"llamafile",LLAMA:"meta_llama",LM_STUDIO:"lm_studio",MARITALK:"maritalk",MiniMax:"minimax",MistralAI:"mistral",MOONSHOT:"moonshot",MORPH:"morph",NEBIUS:"nebius",NLP_CLOUD:"nlp_cloud",NOVITA:"novita",NSCALE:"nscale",NVIDIA_NIM:"nvidia_nim",Ollama:"ollama",OLLAMA_CHAT:"ollama_chat",OOBABOOGA:"oobabooga",OpenAI:"openai",OPENAI_LIKE:"openai_like",OpenAI_Compatible:"openai",OpenAI_Text:"text-completion-openai",OpenAI_Text_Compatible:"text-completion-openai",Openrouter:"openrouter",Oracle:"oci",OVHCLOUD:"ovhcloud",Perplexity:"perplexity",PETALS:"petals",PG_VECTOR:"pg_vector",PREDIBASE:"predibase",RECRAFT:"recraft",REPLICATE:"replicate",RunwayML:"runwayml",SAGEMAKER_LEGACY:"sagemaker",SageMaker:"sagemaker_chat",Sambanova:"sambanova",SAP:"sap",Snowflake:"snowflake",TEXT_COMPLETION_CODESTRAL:"text-completion-codestral",TogetherAI:"together_ai",TOPAZ:"topaz",Triton:"triton",V0:"v0",VERCEL_AI_GATEWAY:"vercel_ai_gateway",Vertex_AI:"vertex_ai",VERTEX_AI_BETA:"vertex_ai_beta",VLLM:"vllm",VolcEngine:"volcengine",Voyage:"voyage",WANDB:"wandb",WATSONX:"watsonx",WATSONX_TEXT:"watsonx_text",xAI:"xai",XINFERENCE:"xinference",ZAI:"zai"},o="../ui/assets/logos/",r={"A2A Agent":`${o}a2a_agent.png`,Ai21:`${o}ai21.svg`,"Ai21 Chat":`${o}ai21.svg`,"AI/ML API":`${o}aiml_api.svg`,"Aiohttp Openai":`${o}openai_small.svg`,Anthropic:`${o}anthropic.svg`,"Anthropic Text":`${o}anthropic.svg`,AssemblyAI:`${o}assemblyai_small.png`,Azure:`${o}microsoft_azure.svg`,"Azure AI Foundry (Studio)":`${o}microsoft_azure.svg`,"Azure Text":`${o}microsoft_azure.svg`,Baseten:`${o}baseten.svg`,"Amazon Bedrock":`${o}bedrock.svg`,"Amazon Bedrock Mantle":`${o}bedrock.svg`,"AWS SageMaker":`${o}bedrock.svg`,Cerebras:`${o}cerebras.svg`,Cloudflare:`${o}cloudflare.svg`,Codestral:`${o}mistral.svg`,Cohere:`${o}cohere.svg`,"Cohere Chat":`${o}cohere.svg`,Cometapi:`${o}cometapi.svg`,Cursor:`${o}cursor.svg`,"Databricks (Qwen API)":`${o}databricks.svg`,Dashscope:`${o}dashscope.svg`,Deepseek:`${o}deepseek.svg`,Deepgram:`${o}deepgram.png`,DeepInfra:`${o}deepinfra.png`,ElevenLabs:`${o}elevenlabs.png`,"Fal AI":`${o}fal_ai.jpg`,"Featherless Ai":`${o}featherless.svg`,"Fireworks AI":`${o}fireworks.svg`,Friendliai:`${o}friendli.svg`,"Github Copilot":`${o}github_copilot.svg`,"Google AI Studio":`${o}google.svg`,GradientAI:`${o}gradientai.svg`,Groq:`${o}groq.svg`,vllm:`${o}vllm.png`,Huggingface:`${o}huggingface.svg`,Hyperbolic:`${o}hyperbolic.svg`,Infinity:`${o}infinity.png`,"Jina AI":`${o}jina.png`,"Lambda Ai":`${o}lambda.svg`,"Lm Studio":`${o}lmstudio.svg`,"Meta Llama":`${o}meta_llama.svg`,MiniMax:`${o}minimax.svg`,"Mistral AI":`${o}mistral.svg`,Moonshot:`${o}moonshot.svg`,Morph:`${o}morph.svg`,Nebius:`${o}nebius.svg`,Novita:`${o}novita.svg`,"Nvidia Nim":`${o}nvidia_nim.svg`,Ollama:`${o}ollama.svg`,"Ollama Chat":`${o}ollama.svg`,Oobabooga:`${o}openai_small.svg`,OpenAI:`${o}openai_small.svg`,"Openai Like":`${o}openai_small.svg`,"OpenAI Text Completion":`${o}openai_small.svg`,"OpenAI-Compatible Text Completion Models (Together AI, etc.)":`${o}openai_small.svg`,"OpenAI-Compatible Endpoints (Together AI, etc.)":`${o}openai_small.svg`,Openrouter:`${o}openrouter.svg`,"Oracle Cloud Infrastructure (OCI)":`${o}oracle.svg`,Perplexity:`${o}perplexity-ai.svg`,Recraft:`${o}recraft.svg`,Replicate:`${o}replicate.svg`,RunwayML:`${o}runwayml.png`,Sagemaker:`${o}bedrock.svg`,Sambanova:`${o}sambanova.svg`,"SAP Generative AI Hub":`${o}sap.png`,Snowflake:`${o}snowflake.svg`,"Text-Completion-Codestral":`${o}mistral.svg`,TogetherAI:`${o}togetherai.svg`,Topaz:`${o}topaz.svg`,Triton:`${o}nvidia_triton.png`,V0:`${o}v0.svg`,"Vercel Ai Gateway":`${o}vercel.svg`,"Vertex AI (Anthropic, Gemini, etc.)":`${o}google.svg`,"Vertex Ai Beta":`${o}google.svg`,Vllm:`${o}vllm.png`,VolcEngine:`${o}volcengine.png`,"Voyage AI":`${o}voyage.webp`,Watsonx:`${o}watsonx.svg`,"Watsonx Text":`${o}watsonx.svg`,xAI:`${o}xai.svg`,Xinference:`${o}xinference.svg`};e.s(["Providers",()=>i,"getPlaceholder",0,e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e)return"claude-3-opus";if("Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";else if("Google AI Studio"==e)return"gemini-pro";else if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"my-deployment";else if("Oracle Cloud Infrastructure (OCI)"==e)return"oci/xai.grok-4";else if("Snowflake"==e)return"snowflake/mistral-7b";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else if("Fal AI"==e)return"fal_ai/fal-ai/flux-pro/v1.1-ultra";else if("RunwayML"==e)return"runwayml/gen4_turbo";else if("Watsonx"===e)return"watsonx/ibm/granite-3-3-8b-instruct";else if("Cursor"===e)return"cursor/claude-4-sonnet";else if("Z.AI (Zhipu AI)"===e)return"zai/glm-4.5";else return"gpt-3.5-turbo"},"getProviderLogoAndName",0,e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:r[e],displayName:e}}let t=Object.keys(a).find(t=>a[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let o=i[t];return{logo:r[o],displayName:o}},"getProviderModels",0,(e,t)=>{console.log(`Provider key: ${e}`);let i=a[e];console.log(`Provider mapped to: ${i}`);let o=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(([e,t])=>{if(null!==t&&"object"==typeof t&&"litellm_provider"in t){let a=t.litellm_provider;(a===i||"string"==typeof a&&a.includes(i))&&o.push(e)}}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"cohere_chat"===t.litellm_provider&&o.push(e)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"sagemaker_chat"===t.litellm_provider&&o.push(e)}))),o},"providerLogoMap",0,r,"provider_map",0,a])},798496,e=>{"use strict";var t=e.i(843476),i=e.i(152990),a=e.i(682830),o=e.i(271645),r=e.i(269200),n=e.i(427612),s=e.i(64848),l=e.i(942232),p=e.i(496020),d=e.i(977572),c=e.i(94629),g=e.i(360820),m=e.i(871943);function u({data:e=[],columns:u,isLoading:f=!1,defaultSorting:_=[],pagination:h,onPaginationChange:A,enablePagination:x=!1,onRowClick:b}){let[y,I]=o.default.useState(_),[v]=o.default.useState("onChange"),[C,E]=o.default.useState({}),[O,T]=o.default.useState({}),S=(0,i.useReactTable)({data:e,columns:u,state:{sorting:y,columnSizing:C,columnVisibility:O,...x&&h?{pagination:h}:{}},columnResizeMode:v,onSortingChange:I,onColumnSizingChange:E,onColumnVisibilityChange:T,...x&&A?{onPaginationChange:A}:{},getCoreRowModel:(0,a.getCoreRowModel)(),getSortedRowModel:(0,a.getSortedRowModel)(),...x?{getPaginationRowModel:(0,a.getPaginationRowModel)()}:{},enableSorting:!0,enableColumnResizing:!0,defaultColumn:{minSize:40,maxSize:500}});return(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsx)("div",{className:"relative min-w-full",children:(0,t.jsxs)(r.Table,{className:"[&_td]:py-2 [&_th]:py-2",style:{width:S.getTotalSize(),minWidth:"100%",tableLayout:"fixed"},children:[(0,t.jsx)(n.TableHead,{children:S.getHeaderGroups().map(e=>(0,t.jsx)(p.TableRow,{children:e.headers.map(e=>(0,t.jsxs)(s.TableHeaderCell,{className:`py-1 h-8 relative ${"actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] w-[120px] ml-8":""} ${e.column.columnDef.meta?.className||""}`,style:{width:"actions"===e.id?120:e.getSize(),position:"actions"===e.id?"sticky":"relative",right:"actions"===e.id?0:"auto"},onClick:e.column.getCanSort()?e.column.getToggleSortingHandler():void 0,children:[(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,i.flexRender)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(g.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(m.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(c.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})})]}),e.column.getCanResize()&&(0,t.jsx)("div",{onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`absolute right-0 top-0 h-full w-2 cursor-col-resize select-none touch-none ${e.column.getIsResizing()?"bg-blue-500":"hover:bg-blue-200"}`})]},e.id))},e.id))}),(0,t.jsx)(l.TableBody,{children:f?(0,t.jsx)(p.TableRow,{children:(0,t.jsx)(d.TableCell,{colSpan:u.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading models..."})})})}):S.getRowModel().rows.length>0?S.getRowModel().rows.map(e=>(0,t.jsx)(p.TableRow,{onClick:()=>b?.(e.original),className:b?"cursor-pointer hover:bg-gray-50":"",children:e.getVisibleCells().map(e=>(0,t.jsx)(d.TableCell,{className:`py-0.5 overflow-hidden ${"actions"===e.column.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] w-[120px] ml-8":""} ${e.column.columnDef.meta?.className||""}`,style:{width:"actions"===e.column.id?120:e.column.getSize(),position:"actions"===e.column.id?"sticky":"relative",right:"actions"===e.column.id?0:"auto"},children:(0,i.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(p.TableRow,{children:(0,t.jsx)(d.TableCell,{colSpan:u.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No models found"})})})})})]})})})})}e.s(["ModelDataTable",()=>u])}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/06b2ea8c776c2e9b.js b/litellm/proxy/_experimental/out/_next/static/chunks/06b2ea8c776c2e9b.js deleted file mode 100644 index fe571604a7f..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/06b2ea8c776c2e9b.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,233538,e=>{"use strict";function t(e){let t=e.parentElement,r=null;for(;t&&!(t instanceof HTMLFieldSetElement);)t instanceof HTMLLegendElement&&(r=t),t=t.parentElement;let l=(null==t?void 0:t.getAttribute("disabled"))==="";return!(l&&function(e){if(!e)return!1;let t=e.previousElementSibling;for(;null!==t;){if(t instanceof HTMLLegendElement)return!1;t=t.previousElementSibling}return!0}(r))&&l}e.s(["isDisabledReactIssue7711",()=>t])},220508,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:r},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["CheckCircleIcon",0,r],220508)},503269,214520,601893,694421,140721,942803,35889,722678,e=>{"use strict";var t=e.i(271645),r=e.i(914189);function l(e,l,s){let[a,n]=(0,t.useState)(s),i=void 0!==e,o=(0,t.useRef)(i),c=(0,t.useRef)(!1),d=(0,t.useRef)(!1);return!i||o.current||c.current?i||!o.current||d.current||(d.current=!0,o.current=i,console.error("A component is changing from controlled to uncontrolled. This may be caused by the value changing from a defined value to undefined, which should not happen.")):(c.current=!0,o.current=i,console.error("A component is changing from uncontrolled to controlled. This may be caused by the value changing from undefined to a defined value, which should not happen.")),[i?e:a,(0,r.useEvent)(e=>(i||n(e),null==l?void 0:l(e)))]}function s(e){let[r]=(0,t.useState)(e);return r}e.s(["useControllable",()=>l],503269),e.s(["useDefaultValue",()=>s],214520);let a=(0,t.createContext)(void 0);function n(){return(0,t.useContext)(a)}e.s(["useDisabled",()=>n],601893);var i=e.i(174080),o=e.i(746725);function c(e={},t=null,r=[]){for(let[l,s]of Object.entries(e))!function e(t,r,l){if(Array.isArray(l))for(let[s,a]of l.entries())e(t,d(r,s.toString()),a);else l instanceof Date?t.push([r,l.toISOString()]):"boolean"==typeof l?t.push([r,l?"1":"0"]):"string"==typeof l?t.push([r,l]):"number"==typeof l?t.push([r,`${l}`]):null==l?t.push([r,""]):c(l,r,t)}(r,d(t,l),s);return r}function d(e,t){return e?e+"["+t+"]":t}function u(e){var t,r;let l=null!=(t=null==e?void 0:e.form)?t:e.closest("form");if(l){for(let t of l.elements)if(t!==e&&("INPUT"===t.tagName&&"submit"===t.type||"BUTTON"===t.tagName&&"submit"===t.type||"INPUT"===t.nodeName&&"image"===t.type))return void t.click();null==(r=l.requestSubmit)||r.call(l)}}e.s(["attemptSubmit",()=>u,"objectToFormEntries",()=>c],694421);var m=e.i(700020),f=e.i(2788);let h=(0,t.createContext)(null);function g({children:e}){let r=(0,t.useContext)(h);if(!r)return t.default.createElement(t.default.Fragment,null,e);let{target:l}=r;return l?(0,i.createPortal)(t.default.createElement(t.default.Fragment,null,e),l):null}function p({data:e,form:r,disabled:l,onReset:s,overrides:a}){let[n,i]=(0,t.useState)(null),d=(0,o.useDisposables)();return(0,t.useEffect)(()=>{if(s&&n)return d.addEventListener(n,"reset",s)},[n,r,s]),t.default.createElement(g,null,t.default.createElement(x,{setForm:i,formId:r}),c(e).map(([e,s])=>t.default.createElement(f.Hidden,{features:f.HiddenFeatures.Hidden,...(0,m.compact)({key:e,as:"input",type:"hidden",hidden:!0,readOnly:!0,form:r,disabled:l,name:e,value:s,...a})})))}function x({setForm:e,formId:r}){return(0,t.useEffect)(()=>{if(r){let t=document.getElementById(r);t&&e(t)}},[e,r]),r?null:t.default.createElement(f.Hidden,{features:f.HiddenFeatures.Hidden,as:"input",type:"hidden",hidden:!0,readOnly:!0,ref:t=>{if(!t)return;let r=t.closest("form");r&&e(r)}})}e.s(["FormFields",()=>p],140721);let b=(0,t.createContext)(void 0);function y(){return(0,t.useContext)(b)}e.s(["useProvidedId",()=>y],942803);var v=e.i(835696),j=e.i(294316);let k=(0,t.createContext)(null);function N(){var e,r;return null!=(r=null==(e=(0,t.useContext)(k))?void 0:e.value)?r:void 0}function w(){let[e,l]=(0,t.useState)([]);return[e.length>0?e.join(" "):void 0,(0,t.useMemo)(()=>function(e){let s=(0,r.useEvent)(e=>(l(t=>[...t,e]),()=>l(t=>{let r=t.slice(),l=r.indexOf(e);return -1!==l&&r.splice(l,1),r}))),a=(0,t.useMemo)(()=>({register:s,slot:e.slot,name:e.name,props:e.props,value:e.value}),[s,e.slot,e.name,e.props,e.value]);return t.default.createElement(k.Provider,{value:a},e.children)},[l])]}k.displayName="DescriptionContext";let S=Object.assign((0,m.forwardRefWithAs)(function(e,r){let l=(0,t.useId)(),s=n(),{id:a=`headlessui-description-${l}`,...i}=e,o=function e(){let r=(0,t.useContext)(k);if(null===r){let t=Error("You used a component, but it is not inside a relevant parent.");throw Error.captureStackTrace&&Error.captureStackTrace(t,e),t}return r}(),c=(0,j.useSyncRefs)(r);(0,v.useIsoMorphicEffect)(()=>o.register(a),[a,o.register]);let d=s||!1,u=(0,t.useMemo)(()=>({...o.slot,disabled:d}),[o.slot,d]),f={ref:c,...o.props,id:a};return(0,m.useRender)()({ourProps:f,theirProps:i,slot:u,defaultTag:"p",name:o.name||"Description"})}),{});e.s(["Description",()=>S,"useDescribedBy",()=>N,"useDescriptions",()=>w],35889);let C=(0,t.createContext)(null);function M(e){var r,l,s;let a=null!=(l=null==(r=(0,t.useContext)(C))?void 0:r.value)?l:void 0;return(null!=(s=null==e?void 0:e.length)?s:0)>0?[a,...e].filter(Boolean).join(" "):a}function O({inherit:e=!1}={}){let l=M(),[s,a]=(0,t.useState)([]),n=e?[l,...s].filter(Boolean):s;return[n.length>0?n.join(" "):void 0,(0,t.useMemo)(()=>function(e){let l=(0,r.useEvent)(e=>(a(t=>[...t,e]),()=>a(t=>{let r=t.slice(),l=r.indexOf(e);return -1!==l&&r.splice(l,1),r}))),s=(0,t.useMemo)(()=>({register:l,slot:e.slot,name:e.name,props:e.props,value:e.value}),[l,e.slot,e.name,e.props,e.value]);return t.default.createElement(C.Provider,{value:s},e.children)},[a])]}C.displayName="LabelContext";let E=Object.assign((0,m.forwardRefWithAs)(function(e,l){var s;let a=(0,t.useId)(),i=function e(){let r=(0,t.useContext)(C);if(null===r){let t=Error("You used a