commit 177604c7d192d05c6454e0dddb5e0c9418cec243 Author: wehub-resource-sync Date: Mon Jul 13 12:42:59 2026 +0800 chore: import upstream snapshot with attribution diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..daa831c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,44 @@ +FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 + +ARG DEBIAN_FRONTEND=noninteractive +ARG USER=vscode + +RUN DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get install -y build-essential --no-install-recommends make \ + ca-certificates \ + bash-completion \ + git \ + just \ + libssl-dev \ + zlib1g-dev \ + libbz2-dev \ + libreadline-dev \ + libsqlite3-dev \ + wget \ + curl \ + llvm \ + libncurses5-dev \ + xz-utils \ + tk-dev \ + libxml2-dev \ + libxmlsec1-dev \ + libffi-dev \ + liblzma-dev + +# Python and poetry installation +USER $USER +ARG HOME="/home/$USER" +ARG PYTHON_VERSION=3.10 + +ENV PYENV_ROOT="${HOME}/.pyenv" +ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${HOME}/.local/bin:$PATH" + +EXPOSE 8800 + +RUN echo "Configuring Python environment" \ + && curl https://pyenv.run | bash \ + && pyenv install ${PYTHON_VERSION} \ + && pyenv global ${PYTHON_VERSION} \ + && curl -LsSf https://astral.sh/uv/install.sh | sh \ + && pip install ruff semver toml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..57fb0ad --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,52 @@ +{ + "name": "uv-pyenv", + "build": { + "dockerfile": "Dockerfile" + }, + // "features": {}, + // 👇 Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // 👇 Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "(cd /workspaces/parlant* && git config --global --add safe.directory $PWD && python ./scripts/initialize_repo.py)", + // 👇 Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "alexkrechik.cucumberautocomplete", + "charliermarsh.ruff", + "github.remotehub", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "hbenl.vscode-test-explorer", + "matangover.mypy", + "ms-azuretools.vscode-docker", + "ms-python.debugpy", + "ms-python.python", + "ms-python.vscode-pylance", + "mutantdino.resourcemonitor", + "njpwerner.autodocstring", + "tamasfe.even-better-toml", + "streetsidesoftware.code-spell-checker" + ] + } + }, + // 👇 Features to add to the Dev Container. More info: https://containers.dev/implementors/features. + "features": { + "ghcr.io/devcontainers-extra/features/mypy:2": { + "version": "latest" + }, + "node": { + "version": "lts", + "nodeGypDependencies": true + } + }, + "mounts": [], + // 👇 Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" + "containerEnv": { + "OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}" + }, + "remoteEnv": { + "OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}" + } +} diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..d7cafff --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,5 @@ +#!/bin/bash + +ROOT=$(git rev-parse --show-toplevel) +cd $ROOT +python scripts/lint.py --ruff diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..37aaa7c --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,6 @@ +#!/bin/bash + +ROOT=$(git rev-parse --show-toplevel) +cd $ROOT +python scripts/lint.py --mypy --ruff + diff --git a/.githooks/prepare-commit-msg b/.githooks/prepare-commit-msg new file mode 100755 index 0000000..8e39ce7 --- /dev/null +++ b/.githooks/prepare-commit-msg @@ -0,0 +1,19 @@ +#!/bin/bash + +# A git commit hook that will automatically append a DCO signoff to the bottom +# of any commit message that does not have one. This append happens after the git +# default message is generated, but before the user is dropped into the commit +# message editor. +ROOT=$(git rev-parse --show-toplevel) +cd $ROOT + +COMMIT_MESSAGE_FILE="$1" +AUTHOR=$(git var GIT_AUTHOR_IDENT) +SIGNOFF=$(echo "$AUTHOR" | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') + +# Check for DCO signoff message. If one does not exist, append one and then warn +# the user that you did so. +if ! grep -qs "^$SIGNOFF" "$COMMIT_MESSAGE_FILE"; then + echo -e "\n$SIGNOFF" >> "$COMMIT_MESSAGE_FILE" + echo -e "Appended the following signoff to the end of the commit message:\n $SIGNOFF\n" +fi \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..692e6db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,29 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: "[Bug] " +labels: bug +assignees: '' + +--- + +# Description +A clear and concise description of what the bug is. + +# How to Reproduce +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +# Expected Behavior +A clear and concise description of what you expected to happen. + +# Environment + - OS: [e.g. iOS] + - Python version [e.g. 3.12] + - Parlant version [e.g. 1.5.1] + +# Discussion +Add any other context or open questions about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..96fc8d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,17 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: "[Enhancement] " +labels: enhancement +assignees: '' + +--- + +# Motivation +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +# Solution Proposal +A clear and concise description of what you want to happen. + +# Discussion +Add any other context or open questions about the feature request here. diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 0000000..5bc79af --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,4 @@ +allowRemediationCommits: + individual: true +require: + members: false diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml new file mode 100644 index 0000000..aa7e154 --- /dev/null +++ b/.github/workflows/ci-test.yml @@ -0,0 +1,65 @@ +name: Verify and Test + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "develop" ] + +jobs: + build: + runs-on: ubuntu-24.04 + + strategy: + matrix: + python-version: ["3.10"] + + steps: + - name: checkout branch commit + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install uv + run: pip install uv + + - name: Initial Configs + run: | + git config --local core.hooksPath .githooks/ + chmod +x .githooks/pre-commit .githooks/pre-push + + - name: Install packages + run: python scripts/install_packages.py + + - name: install just + uses: extractions/setup-just@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Test Parlant (deterministic) + if: always() + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: just test-deterministic + + - name: Test Parlant (core-stable) + if: always() + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: just test-core-stable + + - name: Test Parlant (core-unstable) + if: always() + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: just test-core-unstable + + - name: test log artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: testresults + path: logs/* diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..8b19f75 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,106 @@ +name: Docker + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +on: + schedule: + - cron: '44 23 * * *' + push: + branches: [ "develop" ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + pull_request: + branches: [ "develop" ] + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: emcie-co/parlant + +jobs: + build: + + runs-on: ubuntu-24.04 + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0 + with: + cosign-release: 'v2.2.4' + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=edge + + # Remove unused packages and directories to free up space for a (possibly large) Docker build + - name: Cleanup disk space + run: | + chmod +x ./scripts/ci/github_action_ubuntu_2404_free_space.sh + ./scripts/ci/github_action_ubuntu_2404_free_space.sh + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..ce4e87b --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,41 @@ +name: Lint + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + + +jobs: + build: + runs-on: ubuntu-24.04 + + strategy: + matrix: + python-version: ["3.10"] + + steps: + - name: checkout branch commit + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install uv + run: pip install uv + + - name: Initial Configs + run: | + git config --local core.hooksPath .githooks/ + chmod +x .githooks/pre-commit .githooks/pre-push + + - name: Install packages + run: python scripts/install_packages.py + continue-on-error: false + + - name: Lint packages + run: python scripts/lint.py + continue-on-error: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f55c4fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +.env +.pytest_cache +.mypy_cache +.ruff_cache +__pycache__ +.justfile +testresults** +tests/core/persistence/test_cache/*.json +data/*.json +cache/ +.coverage +.DS_STORE +*~ +.vscode +.venv +.cursor +logs +runtime-data +parlant-data +/dist/ +scripts/sdks/ +scripts/fern/openapi +fern.generate.log +schematic_generation_test_cache.json +test_timing.csv diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a057ee8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,569 @@ +# Changelog + +All notable changes to Parlant will be documented here. + +## [Unreleased] + +### Added + +- Add `HealthReporter` (`parlant.core.health_reporter`) — a generic, per-process health-reporting service registered in the container. Subsystems call `report(kind, attributes)`; registered `HealthView` objects interpret reports per kind and contribute to the `/healthz` snapshot. Each kind has a configurable retention policy (`window` + `max_count`). Views declare `Criticality.CRITICAL` or `INFORMATIONAL`; only critical views feed the worst-of overall status rollup +- Add `NLPHealthView` reporting NLP request health sliced by schema (success rate, p50/p95 latency, recent error breakdown) with configurable thresholds for `degraded`/`unhealthy` classification +- Instrument `BaseSchematicGenerator.generate()` and `BaseEmbedder.embed()` to emit `nlp.request` / `nlp.embed` health reports on success and failure, providing dashboard visibility into LLM and embedding behavior across all adapters +- Wrap the existing event-loop check as `EventLoopHealthView` so `/healthz` rollup is uniform across all health views +- Add per-decision debug logs to journey node selection (`Journey '': advanced/stayed/exited/completed/backtracked/auto-advanced/...`) so journey progression is visible at debug level alongside guideline matching +- Add a warning log for invalid condition ids returned during journey next-step selection + +### Changed + +- Rename journey `conditions` to `triggers` throughout the codebase, REST API, CLI, and SDKs to better reflect their role as activation signals. The REST API field, query parameter, and request bodies use `triggers` (no aliases). The Python SDK `Server.create_journey(...)` keeps `conditions=` as a deprecated keyword that emits a `DeprecationWarning`; passing both `triggers=` and `conditions=` raises an error. Existing journey records are migrated automatically by `parlant-prepare-migration` from the `journey_conditions` collection (with a `condition` field) to a new `journey_triggers` collection (with a `trigger` field). LLM prompt strings that include "Journey activation condition" are intentionally preserved +- Rename SDK callback `on_match` to `on_selected` on guidelines and journey state transitions to reflect that it fires post-resolution, when the entity is selected for message generation; `EngineHooks.on_guideline_match_handlers` and `on_journey_match_handlers` are renamed to `on_guideline_selected_handlers` and `on_journey_selected_handlers` accordingly +- Standardize guideline matcher log vocabulary: `"Activated"` → `"Matched"`, `"Skipped"` → `"Not matched"`, and `"Not applied"` → `"Unapplied"` +- Standardize relational resolver log vocabulary: `"Skipped: ... deactivated due to ..."` → `"Dropped (<reason>): ..."` with reasons `lower priority`, `unmet dependency`, `dependency on dropped entity`, `deprioritized by guideline`, and `deprioritized by journey` +- Disambiguation batch now uses the standard matcher vocabulary (`"Matched (disambiguation)"` / `"Not matched (disambiguation)"`) and emits a log on the negative branch (previously silent) +- Normalize observational batch rationale to plain `match.rationale` (no longer wrapped with `Condition Application Rationale: "..."`) for consistency with other batches +- Normalize low-criticality batch warning string to `"No checks generated"` to match other batches + +### Removed + +- Remove redundant `glm_service.py` NLP adapter and `NLPServices.glm()` factory method — the GLM/bigmodel.cn API is already covered by the existing Zhipu adapter (`zhipu_service.py`), which uses the official `zhipuai` SDK and supports GLM-4 model variants. Use `NLPServices.zhipu()` instead. + +### Fixed + +- Fix low-criticality matcher logging the entire inference blob once per guideline in a batch (N copies of the same payload at debug level); now logs a single per-item entry +- Fix WebSocketLogger event loop starvation — when no WebSocket clients are subscribed, the drain loop processed queued messages without yielding, progressively blocking the async event loop and causing increasing latency over time +- Fix journey reachable-follow-ups evaluation being order-dependent at fan-in nodes — `JourneyReachableNodesEvaluator` captured a child's path list by reference and then prepended to it in place, so a node with multiple parents had its stored routes mutated by whichever parent was visited first; the second parent then lost routes (or double-counted a hop) depending purely on graph/DFS order. The child's routes are now snapshotted per parent, making the result depend only on journey structure. This intentionally changes the computed follow-ups for existing fan-in journeys: a shared child's later parent now retains the routes it previously lost + +### Security + +- Upgrade dependencies to address known CVEs: authlib (>=1.6.11), requests (>=2.33.0), fastmcp (>=3.2.0), litellm (>=1.83.0), pytest (>=9.0.3), pyjwt (>=2.11.1), and constrain transitive deps — aiohttp, cryptography, pillow, pyopenssl, werkzeug, Mako, pyasn1, python-multipart, orjson, Pygments, diskcache +- Upgrade chat frontend: vite (>=7.3.2) and override transitive deps — picomatch, lodash, flatted, brace-expansion, immutable, yaml + +## [3.3.1] - 2026-04-14 + +### Added + +- Allow passing ToolId when attaching tools throughout the SDK +- Add `AnyOf(tag)` and `AllOf(tag)` modifiers for explicit control over tag dependency semantics in `depend_on()` — `AnyOf` requires at least one tagged member to be active, `AllOf` requires all of them (bare `Tag` defaults to `AllOf`) +- Add `depend_on_any()` to `Guideline`, `Tag`, and `Journey` for OR dependency relationships — at least one target must be active. Multiple `depend_on_any()` calls create independent OR groups that are AND'd together +- Add event loop health monitoring to `/healthz` endpoint — measures callback latency and reports `healthy`, `degraded`, or `unhealthy` status with peak latency over a configurable window +- Add resolution tracking to the relational resolver — every entity that enters resolution gets a `Resolution` with a `ResolutionKind` (`NONE`, `DEPRIORITIZED`, `UNMET_DEPENDENCY_ALL`, `UNMET_DEPENDENCY_ANY`, `ENTAILED`) and structured `ResolutionDetails` (relationship ID, target IDs) explaining why + +### Changed + +- Split `RelationshipEntityKind.TAG` into `TAG_ALL` and `TAG_ANY` to support explicit tag dependency semantics at the core level (existing `TAG` entries treated as `TAG_ALL` for backwards compatibility) + +### Fixed + +- Fix priority and dependency relationships propagating through inactive intermediaries — only direct relationships now affect resolution, consistent with the reinstatement principle from argumentation theory +- Fix entailment recording only the highest-scoring source when multiple guidelines entail the same target — all entailing relationships are now recorded in resolution details +- Fix dep-failed guidelines not recovering when entailment satisfies their dependency target in a later iteration +- Fix SDK startup appearing stuck at 100% after evaluations — add "Applying evaluations" progress bar for the metadata-writing phase +- Fix `Variable.get_value()` returning `None` when called from a retriever, caused by retrievers starting before context variables were loaded +- Fix journey tool-state auto-advancing even when the tool did not run + +## [3.3.0] - 2026-03-15 + +### Added + +- Add per-agent planners via `Server.create_agent(planner=...)`, allowing each agent to use a custom `Planner` implementation +- Accept `Tag` as a target in `depend_on()`, `exclude()`, and `prioritize_over()` on both `Guideline` and `Tag`, enabling relationships that target all guidelines sharing a custom tag +- Add `Tag.depend_on()`, `Tag.exclude()`, and `Tag.prioritize_over()` methods to the SDK, enabling tag-based dependency and priority relationships with guidelines and journeys +- Support custom TAG as source for DEPENDENCY relationships in the relational resolver +- Add `tags` parameter to `create_guideline`, `create_observation`, and `create_journey` on both `Agent` and `Journey`, allowing custom tags to be attached to entities at creation time +- Add `Tag.reevaluate_after()` method to the SDK, enabling tag-based reevaluation relationships with tools +- Add tag-based reevaluation support in the engine: when a tool fires, all guidelines carrying a tag that has a reevaluation relationship with that tool are now re-evaluated +- Add staged_events to GuidelineMatchingContext in SDK +- Add `priority` property to guidelines and journeys for priority-based filtering in the relational resolver +- Add transient guidelines (renamed from tool-provided guidelines), allowing tools to dynamically inject behavioral guidelines into the agent's context +- Add `Agent.utter()` to the SDK, enabling programmatic agent message generation with transient guidelines +- Add `Customer.update()` and `CustomerMetadata` to the SDK, allowing tools to update customer name and metadata +- Add `Session.update()`, `SessionMetadata`, and `SessionLabels` to the SDK, allowing tools to update session properties, metadata, and labels +- Add `customer`, `agent`, `mode`, and `title` properties to SDK `Session` class +- Add `Server.get_tag()` to the SDK, supporting lookup by either `id` or `name` +- Add name-based filtering to `TagStore.list_tags()` and the `GET /tags` API endpoint via an optional `name` query parameter +- Enforce tag name uniqueness in `TagStore`, raising an error when creating a tag with a duplicate name + +### Changed + +- Made extended thinking indicator optional in perceived performance policy +- Change `reevaluate_after()` on `Tag` and `Guideline` to accept multiple tools (`*tools`) and return `Sequence[Relationship]` +- Change `tags` field type from `Sequence[TagId]` to `Sequence[Tag]` on `Guideline`, `Journey`, `Capability`, `Term`, `Variable`, `Customer`, and `Agent` in the SDK +- Change `Tag.preamble()` to return a full `Tag` object instead of a `TagId` +- Upgrade MCP service and bump dependency versions to resolve security vulnerabilities + +### Deprecated + +- OpenAPI tool services are now deprecated; please migrate to SDK tool services + +### Fixed + +- Fix deadlock when sending a new message right after a preamble +- Fix transitive filtering in relational resolver for custom tag dependency targets (guidelines depending on a custom tag are now correctly deactivated when a tagged member is deprioritized) +- Fix SSE `read_event` endpoint stalling after first streaming chunk until full completion +- Fix response analysis logs not always reaching the integrated UI +- Fix guideline formatting in canned response and streaming modes when condition is absent +- Fix AzureService small text embedding dimension size +- Fix onnxruntime compatibility with Python 3.10 and transformers 5.x type changes +- Fix agent intention proposer prompt clarification +- Fix embedding LRU cache eviction corrupting the length index when entries share the same text length +- Fix LiteLLMEmbedder failing to resolve via lagom container when LITELLM_EMBEDDING_MODEL_NAME is set +- Fix non-consequential tool calls being rejected when optional parameters are missing + +### Removed + +- Remove stale `parlant-test` entry point and testing framework documentation from README + +## [3.2.2] - 2026-02-18 + +### Added + +- Added p.MATCH_ALWAYS, now the preferred alias to p.Guideline.MATCH_ALWAYS +- Added `logger` property to p.Server + +### Changed + +- Adjusted log levels of relational resolver to trace instead of debug +- Allow tool context parameter names to be all of 'context', 'ctx', and 'c' + +### Fixed + +- Fix completed streamed messages re-animating on page refresh +- Propagate `Server.current` context to tool functions in hosted plugin server + +## [3.2.1] - 2026-02-17 + +### Added + +- Add optional `dependencies` parameter to guideline, observation, and journey creation methods +- Add `exclude()` as an alias for `prioritize_over()` on guidelines and journeys +- Add `tools` parameter to `create_observation` methods + +### Changed + +- Deprecate `attach_tool()` in favor of `create_guideline()`/`create_observation()` with `tools` parameter + +### Fixed + +- Preserve draft message language during canned response recomposition +- Fix server hang when an exception occurs during setup +- Fix canned response field extraction to handle falsy values + +## [3.2.0] - 2026-02-08 + +### Added + +- Add labels to Guidelines, Journeys, JourneyNodes, and Sessions for categorization and filtering +- Add automatic session label propagation from matched entities (guidelines, observations, journeys) +- Add `track` parameter to guidelines to control "previously applied" tracking +- Support multiple targets in `prioritize_over()` and `depend_on()` methods +- Add `field_dependencies` to canned responses for explicit field availability requirements +- Add `attach_retriever()` to Guideline, Journey, and JourneyState for conditional data retrieval +- Add `on_match` and `on_message` hooks to journeys for lifecycle callbacks +- Add per-agent preamble configuration (custom examples and instructions) +- Add separate default greeting responses for first agent message in fluid mode +- Add streaming message output mode +- Allow specifying custom journey node ID +- Add matched guidelines/journey states to completion ready event + +### Changed + +- Make condition optional for SDK guidelines +- Tweak default preamble examples +- Soften log levels for relational guideline resolver +- Add activated/skipped logs to custom guideline matcher batches + +### Fixed + +- Fix websocket warning upon startup +- Fix agent intention proposer (guidelines were getting rewritten incorrectly) +- Fix multiple customer guideline matchers not working +- Fix bug with context variable access in SDK + +## [3.1.0] - 2026-01-05 + +### Added + +- Add .current property for Server, Agent, and Customer in SDK +- Add /healthz endpoint +- Add API for CRUD operations on session metadata +- Add EmcieService +- Add GLM service +- Add Mistral service +- Add OpenRouter service +- Add OpenTelemetry integration for Meter, Logger and Tracer +- Add Qdrant VectorDatabase adapter +- Add Snowflake Cortex service +- Add ability to configure and extend the FastAPI app object +- Add deferred retrievers +- Add dynamic composition mode +- Add follow-up canned responses +- Add guideline criticality level +- Add guideline on_match() hooks +- Add persistence option for context variable values (variable store) +- Added guideline descriptions +- Allow bailing out of canned response selection and utilize the draft directly, using a hook +- Allow controlling max tool result payload via environment variable +- Allow controlling perceived performance policy per agent +- Allow journey transitions from one tool state to another +- Allow specifying custom IDs when creating agents via SDK and API +- Allow specifying custom IDs when creating customers via SDK and API +- Allow specifying custom IDs when creating guidelines, journeys, and glossary terms via SDK and API +- Expose IoC container in server object +- Support adding custom canrep fields to matched guidelines and journey states +- Support code-based, custom guideline matchers + +### Changed + +- Changed default NLPService to EmcieService +- Improved efficiency of journey state matching when first state is a tool state +- Rename ContextualCorrelator to Tracer +- Rename LoadedContext to EngineContext +- Support proxy URL for LiteLLM + +### Fixed + +- Fix critical bug with cancellation during response analysis +- Fix critical similarity calculation error in TransientVectorDatabase +- Fix unnecessary extra evaluation of journeys and tools in some edge cases +- Improved Gemini Flash 2.5 output consistency by using function call trick instead of structured outputs + +## [3.0.4] - 2025-11-18 + +### Fixed + +- Fix bug where NanoDB query failed when no filters matched +- Extend tool insights across iterations +- Fix deprecated status.HTTP_422_UNPROCESSABLE_ENTITY to status.HTTP_422_UNPROCESSABLE_CONTENT +- Fix broken CLI by adding missing websocket-client dependency +- Added specific classes for embedder initialisation +- Make base url once in OllamaEmbedder +- Update dependencies for security, upgrade FastAPI, fix mypy in hugging_face.py +- Bump torch for fixing vulnerability + +## [3.0.3] - 2025-10-23 + +### Fixed + +- Fix installation issue in some environments, failing due to an older FastMCP version +- Bump versions of OpenTelemetry +- Made ChromaDB an extra package parlant[chroma] +- Update NPM dependencies for integrated UI + +## [3.0.2] - 2025-08-27 + +### Added + +- Added docs/\* and llms.txt +- Added Vertex NLP service +- Added Ollama NLP service +- Added LiteLLM support to the SDK +- Added Gemini support to the SDK +- Added Journey.create_observation() helper +- Added auth permission READ_AGENT_DESCRIPTION +- Added optional AWS_SESSION_TOKEN to BedrockService +- Support creating status events via the API + +### Changed + +- Moved tool call success log to DEBUG level +- Optimized canrep to not generate a draft in strict mode if no canrep candidates found +- Removed `acknowledged_event_offset` from status events +- Removed `last_known_event_offset` from `LoadedContext.interaction` + +### Fixed + +- Fixed presentation of missing API keys for built-in NLP services +- Improvements to canned response generation +- Fixed bug with null journey paths in some cases +- Fixed tiny bug with terminal nodes in journey node selection +- Fixed evaluations not showing properly after version upgrade + +## [3.0.1] - 2025-08-16 + +### Changed + +- Move tool call success log to DEBUG level + +### Fixed + +- Fix tool-based variable not enabling the associated tool on the server +- Fix authorization errors throwing 500 instead of 403 +- Changed OpenAI LLM request operation level to TRACE to fix evaluation progress bars + +## [3.0.0] - 2025-08-15 + +- Please see the announcement at https://parlant.io/blog/parlant-3-0-release + +## [2.2.0] - 2025-05-20 + +### Added + +- Add journeys +- Add of guideline properties evaluation +- Add automatic guideline action deduction when adding direct tool guidelines +- Added choices of invalid and missing tool parameters to tool insights + +### Changed + +- Make guideline action optional + +## [2.1.2] - 2025-05-07 + +### Changed + +- Remove interaction history from utterance recomposition prompt +- Use tool calls from the entire interaction for utterance field substitution +- Improve error handling and reporting with utterance rendering failures + +### Fixed + +- Always reason about utterance selection to improve performance + +## [2.1.1] - 2025-04-30 + +### Fixed + +- Fixed rendering relationships in CLI +- Fixed parlant client using old imports from python client SDK + +## [2.1.0] - 2025-04-29 + +### Added + +- ToolParameterOptions.choice_provider can now access ToolContext +- Added utterance/draft toggle in the integrated UI +- Added new guideline relationship: Dependency +- Added tool relationships and the OVERLAP relationship +- Added the 'overlap' property to tools. By default, tools will be assumed not to overlap with each other, simplifying their evaluation at runtime. +- Introduce ToolBatchers +- Introduce Journey + +### Changed + +- Improved tool calling efficiency by adjusting the prompt to the tool at hand +- Revised completion schema (ARQs) for tool calling +- Utterances now follow a 2-stage process: draft + select +- Changed guest customer name to Guest + +### Fixed + +- Fixed deprioritized guidelines always being skipped +- Fixed agent creation with tags +- Fixed client CLI exit status when encountering an error +- Fixed agent update + +### Known Issues + +- OpenAPI tool services sometimes run into issues due to a version update in aiopenapi3 + +## [2.0.0] - 2025-04-09 + +### Added + +- Improved tool parameter flexibility: custom types, Pydantic models, and annotated ToolParameterOptions +- Allow returning a new (modified) container in modules using configure_module() +- Added Tool Insights with tool parameter options +- Added support for default values for tool parameters in tool calling +- Added WebSocket logger feature for streaming logs in real time +- Added a log viewer to the sandbox UI +- Added API and CLI for Utterances +- Added support for the --migrate CLI flag to enable seamless store version upgrades during server startup +- Added clear rate limit error logs for NLP adapters +- Added enabled/disabled flag for guidelines to facilitate experimentation without deletion +- Allow different schematic generators to adjust incoming prompts in a structured manner +- Added tags to context variables, guidelines, glossary and agents +- Added guideline matching strategies +- Added guideline relationships +- Added support for tool parameters choice provider using the tool context as argument + +### Changed + +- Made the message generator slightly more polite by default, following user feedback +- Allow only specifying guideline condition or action when updating guideline from CLI +- Renamed guideline proposer with guideline matcher + +### Fixed + +- Lowered likelihood of the agent hallucinating facts in fluid mode +- Lowered likelihood of the agent offering services that were not specifically mentioned by the business + +## [1.6.2] - 2025-01-29 + +### Fixed + +- Fix loading DeepSeek service during server boot + +## [1.6.1] - 2025-01-20 + +### Fixed + +- Fix ToolCaller not getting clear information on a parameter being optional +- Ensure ToolCaller only calls a tool if all required args were given +- Improve valid JSON generation likelihood in MessageEventGenerator +- Improve ToolCaller's ability to correctly run multiple tools at once + +## [1.6.0] - 2025-01-19 + +### Added + +- Add shot creation helper functions under Shot +- Add ContextEvaluation in MessageEventGenerator +- Add a log command under client CLI for streaming logs +- Add engine lifecycle hooks + +### Changed + +- Split vendor dependencies to extra packages to avoid reduce installation time +- Modified ToolCaller shot schema +- Disable coherence and connection checking by default in the CLI for now + +### Fixed + +- Improved GuidelineProposer's ability to handle compound actions +- Improved GuidelineProposer's ability to distinguish between a fulfilled and unfulfilled action +- Improved GuidelineProposer's ability to detect a previously applied guideline's application to new information +- Reduced likelihood of agent offering hallucinated services +- Fix ToolCaller false-negative argument validation from int to float +- Fix ToolCaller accuracy +- Fix ToolCaller making up argument values when it doesn't have them +- Fix some cases where the ToolCaller also calls a less-fitting tool +- Fix mistake in coherence checker few shots +- Fix markdown tables in sandbox UI +- Fix wrong import of RateLimitError +- Fix PluginServer validation for optional tool arguments when they're passed None +- Fix utterances sometimes not producing a message + +## [1.5.1] - 2025-01-05 + +### Fixed + +- Fix server CLI boot + +## [1.5.1] - 2025-01-05 + +### Fixed + +- Fix server CLI boot + +## [1.5.0] - 2025-01-04 + +### Added + +- Add DeepSeek provider support (via DeepSeekService) + +### Changed + +- Change default home dir from runtime-data to parlant-data + +### Fixed + +- Fix tool-calling test +- Fix HuggingFace model loading issues + +## [1.4.3] - 2025-01-02 + +### Fixed + +- Upgraded dependency "tiktoken" to 0.8.0 to fix installation errors on some environments + +## [1.4.2] - 2024-12-31 + +### Fixed + +- Fix race condition in JSONFileDocumentDatabase when deleting or updating documents + +## [1.4.1] - 2024-12-31 + +### Changed + +- Remove tool metadata from prompts - agents are now only aware of the data itself + +### Fixed + +- Fix tool calling in scenarios where a guideline has multiple tools where more than one should run + +## [1.4.0] - 2024-12-31 + +### Added + +- Support custom plugin data for PluginServer +- Allow specifying custom logger ID when creating loggers +- Add 'hosted' parameter to PluginServer, for running inside modules + +### Fixed + +- Fix the tool caller's few shots to include better rationales and arguments. + +## [1.3.1] - 2024-12-27 + +### Changed + +- Return event ID instead of trace ID from utterance API +- Improve and normalize entity update messages in client CLI + +## [1.3.0] - 2024-12-26 + +### Added + +- Add manual utterance requests +- Refactor few-shot examples and allow adding more examples from a module +- Allow tapping into the PluginServer FastAPI app to provide additional custom endpoints +- Support for union parameters ("T | None") in tool functions + +### Changed + +- Made all stores thread-safe with reader/writer locks +- Reverted GPT version for guideline connection proposer to 2024-08-06 +- Changed definition of causal connection to take the source's when statement into account. The connection proposer now assumes the source's condition is true when examining if it entails other guideline. + +### Fixed + +- Fix 404 not being returned if a tool service isn't found +- Fix having direct calls to asyncio.gather() instead of safe_gather() + +### Removed + +- Removed connection kind (entails / suggests) from the guideline connection proposer and all places downstream. the connection_kind argument is no longer needed or supported for all guideline connections. + +## [1.2.0] - 2024-12-19 + +### Added + +- Expose deletion flag for events in Session API + +### Changed + +- Print traceback when reporting server boot errors +- Make cancelled operations issue a warning rather than an error + +### Fixed + +- Fixed tool calling with optional parameters +- Fixed sandbox UI issues with message regeneration and status icon +- Fixed case where guideline is applied due to condition being partially applied + +### Removed + +None + +## [1.1.0] - 2024-12-18 + +### Added + +- Customer selection in sandbox Chat UI +- Support tool calls with freshness rules for context variables +- Add support for loading external modules for changing engine behavior programmatically +- CachedSchematicGenerator to run the test suite more quickly +- TransientVectorDatabase to run the test suite more quickly + +### Changed + +- Changed model path for Chroma documents. You may need to delete your `runtime-data` dir. + +### Fixed + +- Improve handling of partially fulfilled guidelines + +### Removed + +None diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8d461d0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,40 @@ +This is the main repo of Parlant (https://parlant.io). + +Parlant is a Python based agent framework. Its core strengths: + +1. It allows you to create compliant and controlled AI agents for customer-facing use cases +2. It provides many conversational management features out of the box +3. It's built for enterprise, large-scale use cases, where SLAs, stability and security are paramount + +The repo's structure follows the Hexagonal Architecture (Ports and Adapters) approach. + +- src/parlant + - core: Core framework code + - adapters: Implementations of interfaces using 3rd party tools + - api: REST API layer using FastAPI. Uses modules from core/ +- tests: all tests for the project. Structure strives to mirror that which is under src/parlant. + +General Coding Instructions: + +- Always ensure you stick to Hexagonal Architecture patterns in line with how they're used in this codebase. +- Every time you add something, look for similar things in the codebase and ensure you follow the coding style. +- We use MyPy on strict mode. Every parameter needs to be type-annotated. Every function's result too. +- If you need to add a test for something, first say where you plan to add it and ask for confirmation. +- We follow TDD. When you make a change, first create a failing test. Once it fails, implement just enough so it passes. +- If you need to test classes/methods in sdk.py (or generally to test things that relate to engine behavior) make sure you inherit from SDKTest and understand how it works and how to use it. +- Test names should go "test*that*..." using clear names that explain the context, what is executed, and what is the expected result. +- You can run tests using pytest. Make sure you run "uv run pytest tests/path/to/test/file.py" while also specifying the test name that you need to run. + +Always follow this plan when asked to code a feature or fix a bug: + +1. Consider the codebase's structure +2. Describe your implementation plan, including: + a. What tests you will write (test names + files they would live in) + b. Why do you think the tests would initially fail + c. Where you would plan to implement the code that would make the tests pass +3. Ask for plan confirmation. If you get feedback, revise your plan and ask for confirmation again until you get it. +4. Implement the tests first. Ask for confirmation and code review. +5. Once tests are approved, once again suggest your implementation plan for making them pass, and get plan review until confirmation. +6. Once your implementation plan is confirmed, go ahead with implementing the code to pass them. +7. Make sure to format all of the files you changed using ruff (it is installed in the environment). +8. Run `uv run python scripts/lint.py --mypy --ruff` to ensure your code has no lint issues. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6ec7b96 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# DCO Sign Off + +All commits must be signed off with the Developer Certificate of Origin ([DCO.md](DCO.md)). +This attests that you have the rights to submit your contribution under our project's license (Apache 2.0). + +To sign off your commits: + +1. Configure your Git client with your github account details: + ``` + git config --global user.name "Your Name" + git config --global user.email "your.email@example.com" + ``` +2. If you've configured git to use our hooks (`.githooks`), you are now ready. Otherwise, either: + 1. use our `.githooks`: + ``` + git config set core.hookspath .githooks + ``` + **OR** + 2. Add the `-s` flag when committing: + ``` + git commit -s -m "Your commit message" + ``` +### Or + +* Add the sign-off manually with: + ``` + Signed-off-by: Your Name <your.email@example.com> + ``` \ No newline at end of file diff --git a/DCO.md b/DCO.md new file mode 100644 index 0000000..d950df0 --- /dev/null +++ b/DCO.md @@ -0,0 +1,34 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6337b9b --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Emcie Co Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a6d716 --- /dev/null +++ b/README.md @@ -0,0 +1,436 @@ +<div align="center"> + +<picture> + <source media="(prefers-color-scheme: dark)" srcset="https://github.com/emcie-co/parlant/blob/develop/docs/LogoTransparentLight.png?raw=true"> + <img alt="Parlant" src="https://github.com/emcie-co/parlant/blob/develop/docs/LogoTransparentDark.png?raw=true" width=400 /> +</picture> + +### The interaction control harness for customer-facing AI agents + +<p> + <a href="https://pypi.org/project/parlant/"><img alt="PyPI" src="https://img.shields.io/pypi/v/parlant?color=blue"></a> + <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10+-blue"> + <a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-green"></a> + <a href="https://discord.gg/duxWqxKk6J"><img alt="Discord" src="https://img.shields.io/discord/1312378700993663007?color=7289da&logo=discord&logoColor=white"></a> + <img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/emcie-co/parlant?style=social"> +</p> + +<p> + <a href="https://www.parlant.io/" target="_blank">Website</a> • + <a href="https://www.parlant.io/docs/quickstart/installation" target="_blank">Quick Start</a> • + <a href="https://www.parlant.io/docs/quickstart/examples" target="_blank">Examples</a> • + <a href="https://discord.gg/duxWqxKk6J" target="_blank">Discord</a> +</p> + +<p> + <a href="https://zdoc.app/de/emcie-co/parlant">Deutsch</a> | + <a href="https://zdoc.app/es/emcie-co/parlant">Español</a> | + <a href="https://zdoc.app/fr/emcie-co/parlant">français</a> | + <a href="https://zdoc.app/ja/emcie-co/parlant">日本語</a> | + <a href="https://zdoc.app/ko/emcie-co/parlant">한국어</a> | + <a href="https://zdoc.app/pt/emcie-co/parlant">Português</a> | + <a href="https://zdoc.app/ru/emcie-co/parlant">Русский</a> | + <a href="https://zdoc.app/zh/emcie-co/parlant">中文</a> +</p> + +<a href="https://trendshift.io/repositories/12768" target="_blank"> + <img src="https://trendshift.io/api/badge/repositories/12768" alt="Trending" style="width: 250px; height: 55px;" width="250" height="55"/> +</a> + +</div> + +  + +> **Looking for an open-source alternative to Ada, Decagon, or Sierra?** + +**Parlant is production-ready. It streamlines the development and maintenance of enterprise-grade B2C (business-to-consumer) and sensitive B2B interactions that need to be consistent, compliant, on-brand, and comprehensively traceable.** + +## Why Parlant? + +Conversational context engineering is hard because real-world interactions are diverse, nuanced, and non-linear. + +### ❌ The Problem: What you've probably tried and couldn't get to work at scale +**System prompts** work until production complexity kicks in. The more instructions you add to a prompt, the faster your agent stops paying attention to any of them. + +**Routed graphs** solve the prompt-overload problem, but the more routing you add, the more fragile it becomes when faced with the chaos of natural interactions. + +### 🔑 The Solution: Context engineering, optimized for conversational control +Parlant is an agentic harness offering optimized [context engineering](https://www.gartner.com/en/articles/context-engineering) for conversational use cases: getting the right context, no more and no less, into the prompt at the right time. You define rules, knowledge, and tools once, while the engine narrows the context down in real-time to what's immediately relevant to each turn of the conversation. + +<img alt="Parlant Demo" src="https://github.com/emcie-co/parlant/blob/develop/docs/demo.gif?raw=true" width="100%" /> + +### How is Parlant different from LangGraph or DSPy? +Parlant focuses on conversational governance and behavioral control and consistency, while LangGraph is ideal for workflow automation, and DSPy is ideal for low-level prompt optimization. + +## Design goals + +Parlant is built around three goals that shape every decision in the framework: + +### 1. Maximum control over the conversation experience + +Parlant was designed around a simple idea: developers should be able to control the agent's behavior with precision. In customer-facing conversations, small details matter, like tone, timing, edge cases, policy constraints, and brand voice. So we chose a design that makes these aspects easily configurable and manageable. That approach adds complexity, but it gives teams tighter control over how the agent behaves in real conversations. + +### 2. Maximum prevention of unwanted behaviors + +Parlant treats misalignment as a core design problem. It builds on [research into model accuracy and consistency](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.) so that it is structurally harder for the agent to behave outside its intended boundaries, and easier to detect and correct when it does. Rather than bolting guardrails onto the output, Parlant applies constraints and control points into how your LLMs are used in the first place to produce safe and correct output. + +### 3. Fastest path from product feedback to implementation + +Parlant seeks to allow those responsible for the agent's conversational experience to shape its behavior in an intuitive manner, enabling a rapid feedback cycle that engineers can accomodate. Parlant is designed to allow you to incorporate ongoing product feedback as quickly as possible, without manual rewiring of graphs or fine-tuning of models, ensuring that valuable engineering time is only needed for deeper changes, not minor adjustments. + +## Getting started + +```bash +pip install parlant +``` + +```python +import parlant.sdk as p + +async with p.Server(): + agent = await server.create_agent( + name="Customer Support", + description="Handles customer inquiries for an airline", + ) + + # Evaluate and call tools only under the right conditions + expert_customer = await agent.create_observation( + condition="customer uses financial terminology like DTI or amortization", + tools=[research_deep_answer], + ) + + # When the expert observation holds, always respond + # with depth. Set the guideline to automatically match + # whenever the observation it depends on holds... + expert_answers = await agent.create_guideline( + matcher=p.MATCH_ALWAYS, + action="respond with technical depth", + dependencies=[expert_customer], + ) + + beginner_answers = await agent.create_guideline( + condition="customer seems new to the topic", + action="simplify and use concrete examples", + ) + + # When both match, beginners wins. Neither expert-level + # tool-data nor instructions can enter the agent's context. + await beginner_answers.exclude(expert_customer) +``` + +Follow the **[5-minute quickstart](https://www.parlant.io/docs/quickstart/installation)** for a full walkthrough. + +## Parlant at a glance + +You define your agent's behavior in code (not prompts), and the engine dynamically narrows the context on each turn to only what's immediately relevant, so the LLM stays focused and your agent stays aligned. + +```mermaid +graph TD + O[Observations] -->|Events| E[Contextual Matching Engine] + G[Guidelines] -->|Instructions| E + J["Journeys (SOPs)"] -->|Current Steps| E + R[Retrievers] -->|Domain Knowledge| E + GL[Glossary] -->|Domain Terms| E + V[Variables] -->|Memories| E + E -->|Tool Requests| T[Tool Caller] + T -.->|Results + Optional Extra Matching Iterations| E + T -->|**Key Result:**<br/>Focused Context Window| M[Message Generation] +``` + +Instead of sending a large system prompt followed by a raw conversation to the model, Parlant first assembles a focused context — matching only the instructions and tools relevant to each conversational turn — then generates a response from that narrowed context. + +```mermaid +%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e8f5e9', 'primaryTextColor': '#1b5e20', 'primaryBorderColor': '#81c784', 'lineColor': '#66bb6a', 'secondaryColor': '#fff9e1', 'tertiaryColor': 'transparent'}}}%% +flowchart LR + A(User):::outputNode + + subgraph Engine["Parlant Engine"] + direction LR + B["Match Guidelines and Resolve Journey States"]:::matchNode + C["Call Contextually-Associated Tools and Workflows"]:::toolNode + D["Generated Message"]:::composeNode + E["Canned Message"]:::cannedNode + end + + A a@-->|💬 User Input| B + B b@--> C + C c@-->|Fluid Output Mode?| D + C d@-->|Strict Output Mode?| E + D e@-->|💬 Fluid Output| A + E f@-->|💬 Canned Output| A + + a@{animate: true} + b@{animate: true} + c@{animate: true} + d@{animate: true} + e@{animate: true} + f@{animate: true} + + linkStyle 2 stroke-width:2px + linkStyle 4 stroke-width:2px + linkStyle 3 stroke-width:2px,stroke:#3949AB + linkStyle 5 stroke-width:2px,stroke:#3949AB + + classDef composeNode fill:#F9E9CB,stroke:#AB8139,stroke-width:2px,color:#7E5E1A,stroke-width:0 + classDef cannedNode fill:#DFE3F9,stroke:#3949AB,stroke-width:2px,color:#1a237e,stroke-width:0 +``` + +In this way, adding more rules makes the agent smarter, not more confused — because the engine filters context relevance, not the LLM. + +## Is Parlant for you? + +Parlant is built for teams that need their AI agent to behave reliably in front of real customers. It's a good fit if: + +- You're building a **customer-facing agent** — support, sales, onboarding, advisory — where tone, accuracy, and compliance matter. +- You have **dozens or hundreds of behavioral rules** and your system prompt is buckling under the weight. +- You're in a **regulated or high-stakes domain** (finance, insurance, healthcare, telecom) where every response needs to be explainable and auditable. + +**_Parlant is deployed in production at the most stringent organizations, including banks._** + +> _Parlant isn't just a framework. It's a high-level software that solves the conversational modeling problem head-on._ +> — **Sarthak Dalabehera**, Principal Engineer, Slice Bank + +> _By far the most elegant conversational AI framework that I've come across._ +> — **Vishal Ahuja**, Senior Lead, Applied AI, JPMorgan Chase + +> _Parlant dramatically reduces the need for prompt engineering and complex flow control. Building agents becomes closer to domain modeling._ +> — **Diogo Santiago**, AI Engineer, Orcale + +## Features + +- **[Guidelines](https://parlant.io/docs/concepts/customization/guidelines)** — + Behavioral rules as condition-action pairs; the engine matches only what's relevant per turn. + +- **[Relationships](https://parlant.io/docs/concepts/customization/relationships)** — + Dependencies and exclusions between guidelines to keep the context narrow and focused. + +- **[Journeys](https://parlant.io/docs/concepts/customization/journeys)** — + Multi-turn SOPs that adapt to how the customer actually interacts. + +- **[Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses)** — + Pre-approved response templates that eliminate hallucination at critical moments. + +- **[Tools](https://parlant.io/docs/concepts/customization/tools)** — + External APIs and workflows, triggered only when their observation matches. + +- **[Glossary](https://parlant.io/docs/concepts/customization/glossary)** — + Domain-specific vocabulary so the agent understands customer language. + +- **[Explainability](https://parlant.io/docs/advanced/explainability)** — + Full OpenTelemetry tracing — every guideline match and decision is logged. + +## [Guidelines](https://parlant.io/docs/concepts/customization/guidelines) + +Behavioral rules as condition-action pairs: when the condition applies, the action kicks into context. + +Instead of cramming all guidelines in a single prompt, the engine evaluates which ones apply on each conversational turn and only includes the relevant ones in the LLM's context. + +This lets you define hundreds of guidelines without degrading adherence. + +```python +await agent.create_guideline( + condition="customer uses financial terminology like DTI or amortization", + action="respond with technical depth — skip basic explanations", +) +``` + +## [Relationships](https://parlant.io/docs/concepts/customization/guidelines) + +Relationships between elements help you keep the final context just right: narrow and focused. + +**Exclusion** relationships keep certain guidelines out of the model's attention when conflicting ones are matched. + +```python +for_experts = await agent.create_guideline( + condition="customer uses financial terminology", + action="respond with technical depth", +) + +for_beginners = await agent.create_guideline( + condition="customer seems new to the topic", + action="simplify and use concrete examples", +) + +# In conflicting reads of the customer, set which takes priority +await for_beginners.exclude(for_experts) +``` + +**Dependency** relationships ensure a guideline only activates when another one has set the stage, helping you create _topic-based guideline hierarchies._ + +```python +suspects_fraud = await agent.create_observation( + condition="customer suspects unauthorized transactions on their card", +) + +await agent.create_guideline( + condition="customer wants to take action regarding the transaction", + action="ask whether they want to dispute the transaction or lock the card", + # Only activates when fraud suspicion has been established + dependencies=[suspects_fraud], +) +``` + +## [Journeys](https://parlant.io/docs/concepts/customization/journeys) + +Multi-turn SOPs (Standard Operating Procedures). Define a flow for processes like booking, troubleshooting, or onboarding. The agent follows the flow but adapts — it can fast-forward states, revisit earlier ones, or adjust pace based on how the customer interacts. + +```python +journey = await agent.create_journey( + title="Book Flight", + description="Guide the customer through flight booking", + conditions=["customer wants to book a flight"], +) + +t0 = await journey.initial_state.transition_to( + # Instruction to follow while in this state (could be multiple turns) + chat_state="See if they're interested in last-minute deals", +) + +# Branch A - not interested in deals +t1 = await t0.target.transition_to( + chat_state="Determine where they want to go and when", + condition="They aren't interested", +) + +# Branch B - interested in deals +t2 = await t0.target.transition_to( + tool_state=load_latest_flight_deals, + condition="They are", +) + +t3 = await t1.target.transition_to( + chat_state="List deals and see if they're interested", +) +``` + +## [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses) + +At critical moments or conversational events, limit the agent to using only pre-approved response templates. + +After running the matching sequence and drafting a message to the customer, the agent selects the template that best matches its generated draft instead of sending it directly, eliminating hallucination risk entirely and keeping wording exact to the letter. + +```python +await agent.create_guideline( + condition="The customer discusses things unrelated to our business" + action="Tell them you can't help with that", + # Strict composition mode triggers when this guideline + # matches - the rest of the agent stays fluid + composition_mode=p.CompositionMode.STRICT, + canned_responses=[ + await agent.create_canned_response( + "Sorry, but I can't help you with that." + ) + ], + priority=100, # Top priority, focuses the agent on this alone +) +``` + +## [Tools](https://parlant.io/docs/concepts/customization/tools) + +Tools activate only when their observation matches; they don't sit in the context permanently. This prevents the false-positive invocations that plague traditional LLM tool setups. + +```python +@p.tool +async def query_docs(context: p.ToolContext, user_query: str) -> p.ToolResult: + results = search_knowledge_base(user_query) + return p.ToolResult(results) + +await agent.create_observation( + condition="customer asks about service features", + tools=[query_docs], +) +``` + +Tools can also feed custom values into canned response templates. + +## [Glossary](https://parlant.io/docs/concepts/customization/glossary) + +Domain-specific vocabulary for your agent. Map colloquial terms and synonyms to precise business definitions so the agent understands customer language. + +```python +await agent.create_term( + name="Ocean View", + description="Room category with direct view of the Atlantic", + synonyms=["sea view", "rooms with a view to the Atlantic"], +) +``` + +## [Explainability](https://parlant.io/docs/advanced/explainability) + +Every decision is traced with OpenTelemetry. Parlant ships out of the box with elaborate logs, metrics, and traces. + +## Framework Integration + +Parlant handles conversational governance; it doesn't replace your existing stack. + +Use it alongside frameworks like LangGraph, Agno, LlamaIndex, or others for workflow automation and knowledge retrieval. Parlant takes over the behavioral control layer while your framework of choice handles the rest of your agent's processing logic. + +Any external workflow or agent becomes a Parlant tool, triggered only when relevant: + +```python +from my_workflows import refund_graph # a compiled LangGraph StateGraph + +@p.tool +async def run_refund_workflow( + context: p.ToolContext, + order_id: str +) -> p.ToolResult: + result = await refund_graph.ainvoke({"order_id": order_id}) + + # Graph result can inject both data and instructions into the agent. + # Instructions are transformed to guidelines, and participate + # in contextual guideline resolution (including prioritizations) + + return p.ToolResult( + data=result["data"], + # Inject dynamic guidelines from workflow result + guidelines=[ + {"action": inst, "priority": 3} for inst in result["instructions"] + ], + ) + +await agent.create_observation( + condition="customer wants to process a refund", + tools=[run_refund_workflow], +) +``` + +The same pattern works with LlamaIndex query engines, Agno agents, or any async Python function. + +## LLM Agnostic + +Parlant works with most LLM providers. The recommended ones are [Emcie](https://www.emcie.co) which delivers an ideal cost/quality value since it's built specifically for Parlant, but OpenAI and Anthropic deliver excellent quality outputs as well. You can also use any model and provider via LiteLLM, but they need to be good ones - off-the-shelf models which are too small tend to produce inconsistent results. + +Generally, you can swap models without changing behavioral configuration. + +## [Official React Chat Widget](https://github.com/emcie-co/parlant-chat-react) + +Drop-in chat component to get a frontend running immediately. + +## Learn more + +- **[How Parlant ensures compliance](https://www.parlant.io/blog/how-parlant-guarantees-compliance)** — deep dive into the engine +- **[Parlant vs LangGraph](https://www.parlant.io/blog/parlant-vs-langgraph)** — when to use which +- **[Parlant vs DSPy](https://www.parlant.io/blog/parlant-vs-dspy)** — different tools for different problems + +## Community - Get Help with Parlant + +- **[Discord](https://discord.gg/duxWqxKk6J)** — ask questions, share what you're building +- **[GitHub Issues](https://github.com/emcie-co/parlant/issues)** — bug reports and feature requests +- **[Contact](https://parlant.io/contact)** — reach the engineering team directly + +**If Parlant helps you build better agents, **[give it a star](https://github.com/emcie-co/parlant)** — it helps others find the project.** + +## License + +Apache 2.0 — free for commercial use. + +--- + +<div align="center"> + +**[Try it now](https://www.parlant.io/docs/quickstart/installation)** • **[Join Discord](https://discord.gg/duxWqxKk6J)** • **[Read the docs](https://www.parlant.io/)** + +Built by the team at **[Emcie](https://emcie.co)** + +</div> diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..d681b9c --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,7 @@ +# WeHub 来源说明 + +- 原始项目:`emcie-co/parlant` +- 原始仓库:https://github.com/emcie-co/parlant +- 导入方式:上游默认分支的最新快照 +- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准 +- 本文件仅用于记录来源,不代表 WeHub 是原项目作者 diff --git a/docs/LogoTransparentDark.png b/docs/LogoTransparentDark.png new file mode 100644 index 0000000..3bd9e4f Binary files /dev/null and b/docs/LogoTransparentDark.png differ diff --git a/docs/LogoTransparentLight.png b/docs/LogoTransparentLight.png new file mode 100644 index 0000000..8f1dd65 Binary files /dev/null and b/docs/LogoTransparentLight.png differ diff --git a/docs/adapters/nlp/azure.md b/docs/adapters/nlp/azure.md new file mode 100644 index 0000000..4a15b58 --- /dev/null +++ b/docs/adapters/nlp/azure.md @@ -0,0 +1,297 @@ +# Azure OpenAI Service Documentation + +The Azure service provides integration with Azure OpenAI services, supporting both legacy API key authentication and modern Azure AD authentication. This integration enables Parlant to leverage Azure's enterprise-grade AI services while maintaining security best practices. + +## Prerequisites + +1. **Azure OpenAI Resource**: Create an Azure OpenAI resource in your Azure subscription +2. **Authentication Setup**: Choose between API key or Azure AD authentication +3. **Model Deployment**: Deploy required models in your Azure OpenAI resource +4. **Permissions**: Ensure proper IAM roles for Azure AD authentication + +## Authentication Methods + +### Development (Local Machine) +For local development, use Azure CLI authentication: +```bash +# Install Azure CLI if not already installed +# https://docs.microsoft.com/en-us/cli/azure/install-azure-cli + +# Login to Azure +az login + +# Set your endpoint +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +``` + +### Production (Server Deployment) +For server deployment, **do NOT use `az login`**. Instead, use one of these methods: + +#### Option 1: Service Principal (Recommended) +```bash +# Set environment variables +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +export AZURE_CLIENT_ID="your-service-principal-client-id" +export AZURE_CLIENT_SECRET="your-service-principal-secret" +export AZURE_TENANT_ID="your-azure-tenant-id" +``` + +#### Option 2: Managed Identity (Azure Resources) +If running on Azure VMs, App Services, or other Azure resources: +```bash +# Only set the endpoint - authentication is automatic +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +``` + +#### Option 3: Workload Identity (Kubernetes) +For Kubernetes deployments: +```bash +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +export AZURE_CLIENT_ID="your-workload-identity-client-id" +export AZURE_TENANT_ID="your-azure-tenant-id" +export AZURE_FEDERATED_TOKEN_FILE="/var/run/secrets/azure/tokens/azure-identity-token" +``` + +## Environment Variables + +### Required Variables +- `AZURE_ENDPOINT`: Your Azure OpenAI resource endpoint + +### Optional Variables +- `AZURE_API_VERSION`: API version (default: "2024-08-01-preview") +- `AZURE_GENERATIVE_MODEL_NAME`: Model name (default: "gpt-4o") +- `AZURE_GENERATIVE_MODEL_WINDOW`: Context window size (default: 4096) +- `AZURE_EMBEDDING_MODEL_NAME`: Embedding model (default: "text-embedding-3-large") +- `AZURE_EMBEDDING_MODEL_DIMS`: Embedding dimensions (default: 3072) +- `AZURE_EMBEDDING_MODEL_WINDOW`: Embedding context window (default: 8192) + +## Supported Models + +The Azure service supports **any Azure OpenAI model** that is deployed and available in your Azure OpenAI resource. The models listed below are pre-configured defaults, but you can use any model by setting the appropriate environment variables. + +### Pre-configured Generative Models + +| Model Name | Description | Context Window | Use Case | +|------------|-------------|---------------|----------| +| `gpt-4o` | Most capable GPT-4 model (default) | 128K tokens | Complex reasoning, high accuracy | +| `gpt-4o-mini` | Faster, cost-effective GPT-4 | 128K tokens | Balanced performance and cost | + +### Pre-configured Embedding Models + +| Model Name | Dimensions | Context Window | Description | +|------------|------------|---------------|-------------| +| `text-embedding-3-large` | 3072 | 8192 | High-quality embeddings (default) | +| `text-embedding-3-small` | 3072 | 8192 | Efficient embeddings | + +### Using Custom Models + +You can use **any Azure OpenAI model** that is deployed in your Azure OpenAI resource: + +```bash +# Use any generative model (examples - check your Azure resource for availability) +export AZURE_GENERATIVE_MODEL_NAME="gpt-35-turbo" # GPT-3.5 Turbo +export AZURE_GENERATIVE_MODEL_NAME="gpt-4" # GPT-4 +export AZURE_GENERATIVE_MODEL_NAME="gpt-4-turbo" # GPT-4 Turbo + +# Use any embedding model (examples - check your Azure resource for availability) +export AZURE_EMBEDDING_MODEL_NAME="text-embedding-ada-002" # Ada embeddings +export AZURE_EMBEDDING_MODEL_NAME="text-embedding-3-large" # Large embeddings +``` + +**Important**: +- Model availability depends on what you've deployed in your Azure OpenAI resource +- Not all models are available in all Azure regions +- Check your Azure OpenAI resource deployment to see which models are available + +## Authentication Priority + +The service follows this authentication priority: + +1. **API Key** (highest priority - for backward compatibility) +2. **Azure AD** (fallback when no API key is present) + +## Required Azure Permissions + +For Azure AD authentication, ensure your identity has the following role on the Azure OpenAI resource: + +- **Cognitive Services OpenAI User**: Required for accessing Azure OpenAI services + +## Usage Example + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +async with p.Server(nlp_service=NLPServices.azure) as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) +``` + +## Server Deployment Guide + +### Setting Up Service Principal for Production + +1. **Create Service Principal**: + ```bash + # Login as admin user + az login + + # Create service principal + az ad sp create-for-rbac --name "parlant-service-principal" --role "Cognitive Services OpenAI User" --scopes "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/YOUR_OPENAI_RESOURCE" + ``` + +2. **Configure Environment Variables**: + ```bash + export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" + export AZURE_CLIENT_ID="appId-from-step-1" + export AZURE_CLIENT_SECRET="password-from-step-1" + export AZURE_TENANT_ID="tenant-from-step-1" + ``` + +3. **Test Authentication**: + ```bash + # Verify the service principal can access Azure OpenAI + python -c " + from parlant.adapters.nlp.azure_service import AzureService + error = AzureService.verify_environment() + print('Configuration OK' if error is None else f'Error: {error}') + " + ``` + +### Configuration Tips + +### Development Setup +```bash +export AZURE_ENDPOINT="https://my-resource.openai.azure.com/" +export AZURE_API_KEY="your-api-key" +export AZURE_GENERATIVE_MODEL_NAME="gpt-4o-mini" +``` + +### Production Setup (Azure AD) +```bash +export AZURE_ENDPOINT="https://my-resource.openai.azure.com/" +export AZURE_CLIENT_ID="your-client-id" +export AZURE_CLIENT_SECRET="your-client-secret" +export AZURE_TENANT_ID="your-tenant-id" +export AZURE_GENERATIVE_MODEL_NAME="gpt-4o" +``` + +## Troubleshooting + +### Common Issues + +1. **Authentication Failures** + ``` + Azure authentication is not properly configured. + ``` + **Solution**: + - For development: Run `az login` (only for local development) + - For production: Use service principal variables (NOT `az login`) + - Ensure "Cognitive Services OpenAI User" role is assigned + - Verify service principal has correct permissions + +2. **Rate Limit Errors** + ``` + Azure API rate limit exceeded + ``` + **Solution**: + - Check Azure account balance and billing status + - Review API usage limits in Azure dashboard + - Consider upgrading service tier + +3. **Model Access Denied** + ``` + Model not found or access denied + ``` + **Solution**: + - Verify model is deployed in your Azure OpenAI resource + - Check regional availability + - Ensure proper permissions + +4. **Connection Errors** + ``` + Cannot connect to Azure OpenAI endpoint + ``` + **Solution**: + - Verify `AZURE_ENDPOINT` is correct + - Check network connectivity + - Ensure firewall allows Azure OpenAI traffic + +## Available Model Classes + +The service provides these pre-configured model classes for convenience, but supports any Azure OpenAI model: + +### Pre-configured Classes +- `GPT_4o`: Most capable GPT-4 model (128K context) - **Default** +- `GPT_4o_Mini`: Faster, cost-effective GPT-4 (128K context) +- `AzureTextEmbedding3Large`: High-quality embeddings (3072 dimensions) - **Default** +- `AzureTextEmbedding3Small`: Efficient embeddings (3072 dimensions) + +### Custom Model Classes +- `CustomAzureSchematicGenerator`: Uses any generative model via `AZURE_GENERATIVE_MODEL_NAME` +- `CustomAzureEmbedder`: Uses any embedding model via `AZURE_EMBEDDING_MODEL_NAME` + +**The service automatically chooses the appropriate class based on your environment variables.** + +### How Model Selection Works + +The service uses this logic to select the appropriate model class: + +```python +# Generative Model Selection +if AZURE_GENERATIVE_MODEL_NAME is set: + use CustomAzureSchematicGenerator # Any model you specify +else: + use GPT_4o # Default model + +# Embedding Model Selection +if AZURE_EMBEDDING_MODEL_NAME is set: + use CustomAzureEmbedder # Any embedding model you specify +else: + use AzureTextEmbedding3Large # Default embedding model +``` + +This means you can use **any Azure OpenAI model** without code changes - just set the environment variables! + +### Example: Using Different Models + +```bash +# Use GPT-3.5 Turbo (if available in your region) +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +export AZURE_GENERATIVE_MODEL_NAME="gpt-35-turbo" +export AZURE_EMBEDDING_MODEL_NAME="text-embedding-ada-002" + +# Use GPT-4 Turbo (if available in your region) +export AZURE_GENERATIVE_MODEL_NAME="gpt-4-turbo" +export AZURE_EMBEDDING_MODEL_NAME="text-embedding-3-large" + +# Use default models (GPT-4o and text-embedding-3-large) +export AZURE_ENDPOINT="https://your-resource.openai.azure.com/" +# No need to set AZURE_GENERATIVE_MODEL_NAME or AZURE_EMBEDDING_MODEL_NAME +``` + +## Security Notes + +- **API Keys**: Store securely, rotate regularly +- **Azure AD**: Use managed identities in production +- **Network**: Ensure proper network security groups +- **Monitoring**: Monitor usage and access patterns +- **Compliance**: Follow organizational security policies + +## Migration Guide + +### From API Key to Azure AD + +1. Set up Azure AD authentication using one of the supported methods +2. Remove the API key from your environment variables +3. Verify permissions - ensure your identity has "Cognitive Services OpenAI User" role +4. Test the configuration using `AzureService.verify_environment()` + +### Backward Compatibility + +The service maintains full backward compatibility: +- Existing API key configurations continue to work +- No changes required for existing deployments +- Gradual migration to Azure AD is supported diff --git a/docs/adapters/nlp/ollama.md b/docs/adapters/nlp/ollama.md new file mode 100644 index 0000000..9d153de --- /dev/null +++ b/docs/adapters/nlp/ollama.md @@ -0,0 +1,193 @@ +# Ollama Service Documentation + +The Ollama service provides local LLM capabilities for Parlant using [Ollama](https://ollama.ai/). This service supports both text generation and embeddings using various open-source models. + +## Prerequisites + +1. **Install Ollama**: Download and install from [ollama.ai](https://ollama.ai/) +2. **Start Ollama server**: Run `ollama serve` (usually starts automatically) +3. **Pull required models** (see [Recommended Models](#recommended-models) section) + +## Environment Variables + +Configure the Ollama service using these environment variables: + +```bash +# Ollama server URL (default: http://localhost:11434) +export OLLAMA_BASE_URL="http://localhost:11434" + +# Model size to use (default: 4b) +# Options: gemma3:1b, gemma3:4b, llama3.1:8b, gemma3:12b, gemma3:27b, llama3.1:70b, llama3.1:405b +export OLLAMA_MODEL="gemma3:4b" + +# Embedding model (default: nomic-embed-text) +# Options: nomic-embed-text, mxbai-embed-large +export OLLAMA_EMBEDDING_MODEL="nomic-embed-text" + +# API timeout in seconds (default: 300) +export OLLAMA_API_TIMEOUT="300" +``` + +### Example Configuration + +```bash +# For development (fast, good balance) +export OLLAMA_MODEL="gemma3:4b" +export OLLAMA_EMBEDDING_MODEL="nomic-embed-text" +export OLLAMA_API_TIMEOUT="180" + +# higher accuracy cloud +export OLLAMA_MODEL="gemma3:4b" +export OLLAMA_EMBEDDING_MODEL="nomic-embed-text" +export OLLAMA_API_TIMEOUT="600" +``` + +## Recommended Models + +**⚠️ IMPORTANT**: Pull these models before running Parlant to avoid API timeouts during first use: + +### Text Generation Models + +```bash +# Recommended for most use cases (good balance of speed/accuracy) +ollama pull gemma3:4b-it-qat + +# Fast but may struggle with complex schemas +ollama pull gemma3:1b + +# embedding model required for creating embeddings +ollama pull nomic-embed-text +``` + +### Large Models (Cloud/High-end Hardware Only) + +```bash +# Better reasoning capabilities +ollama pull llama3.1:8b + +# High accuracy for complex tasks +ollama pull gemma3:12b + +# Very high accuracy (requires more resources) +ollama pull gemma3:27b-it-qat + +# ⚠️ WARNING: Requires 40GB+ GPU memory +ollama pull llama3.1:70b + +# ⚠️ WARNING: Requires 200GB+ GPU memory (cloud-only) +ollama pull llama3.1:405b +``` + +### Embedding Models + +To use custom embedding model set OLLAMA_EMBEDDING_MODEL environment value as required name +Note that this implementation is tested using nomic-embed-text +**⚠️ IMPORTANT**: +Support for using other embedding models has been added including a custom embedding model of your own choice +Ensure to set OLLAMA_EMBEDDING_VECTOR_SIZE which is compatible with your own embedding model before starting the server +Tested with `snowflake-arctic-embed` with vector size of 1024 +It is not NECESSARY to put OLLAMA_EMBEDDING_VECTOR_SIZE if you are using the supported `nomic-embed-text`, `mxbai-embed-large` or `bge-m3`. The vector size defaults to 768, 1024 and 1024 respectively for these + +```bash +# Alternative embedding model (512 dimensions) +ollama pull mxbai-embed-large:latest +``` + +## Model Recommendations by Use Case + +| Model Size | Use Case | Memory Requirements | Performance | +|------------|----------|-------------------|-------------| +| `1b` | Quick testing, simple tasks | ~2GB | Fast but limited accuracy | +| `4b` | **Recommended for development** | ~4GB | Good balance of speed/accuracy | +| `8b` | complex reasoning | ~8GB | Better reasoning than Gemma | +| `12b` | High-accuracy tasks | ~12GB | High accuracy, slower | +| `27b` | Complex workloads | ~27GB | Very high accuracy | +| `70b` | Enterprise/cloud only | ~40GB+ | Excellent accuracy | +| `405b` | Research/cloud only | ~200GB+ | State-of-the-art | + +## Usage Example + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +async with p.Server(nlp_service=NLPServices.ollama) as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) +``` + +## Configuration Tips + +### Development Setup +```bash +export OLLAMA_MODEL=gemma3:4b +export OLLAMA_API_TIMEOUT=180 +``` + +### High-Performance Setup (Cloud) +```bash +export OLLAMA_MODEL=llama3.1:70b +export OLLAMA_API_TIMEOUT=300 +``` + +### Custom / Other models +```bash +export OLLAMA_MODEL=llama3.2:3b +export OLLAMA_API_TIMEOUT=300 +``` + +## Troubleshooting + +### Common Issues + +1. **Model Not Found Error** + ``` + Model gemma3:4b not found. Please pull it first with: ollama pull gemma3:4b + ``` + **Solution**: Run `ollama pull gemma3:4b-it-qat` before starting Parlant + +2. **Connection Error** + ``` + Cannot connect to Ollama server at http://localhost:11434 + ``` + **Solution**: Ensure Ollama is running with `ollama serve` + +3. **Timeout Error** + ``` + Request timed out after 300s + ``` + **Solution**: Increase `OLLAMA_API_TIMEOUT` or use a smaller model + +4. **Out of Memory** + ``` + CUDA out of memory + ``` + **Solution**: Use a smaller model size or increase GPU memory + +### Performance Optimization + +1. **Pre-pull models**: Always pull models before first use +2. **Adjust timeout**: Increase timeout for larger models +3. **Model selection**: Use smallest model that meets accuracy requirements +4. **GPU memory**: Monitor GPU usage and adjust model size accordingly + +## Available Model Classes + +The service provides these pre-configured model classes: + +- `OllamaGemma3_1B`: Fast, basic accuracy +- `OllamaGemma3_4B`: **Recommended** - good balance +- `OllamaLlama31_8B`: Better reasoning +- `OllamaGemma3_12B`: High accuracy +- `OllamaGemma3_27B`: Very high accuracy +- `OllamaLlama31_70B`: Enterprise-grade (high memory) +- `OllamaLlama31_405B`: Research-grade (very high memory) + +## Security Notes + +- Ollama runs locally, so no data leaves your machine +- No API keys required +- Models are downloaded and cached locally +- Consider firewall rules if exposing Ollama server externally \ No newline at end of file diff --git a/docs/adapters/nlp/openrouter.md b/docs/adapters/nlp/openrouter.md new file mode 100644 index 0000000..309d8a7 --- /dev/null +++ b/docs/adapters/nlp/openrouter.md @@ -0,0 +1,554 @@ +# OpenRouter Service Documentation + +The OpenRouter service provides access to **400+ AI models** through a single unified API, including GPT-4, Claude, Llama, Qwen, and many more. OpenRouter makes it easy to switch between different models for both text generation and embeddings without changing code. + +## Prerequisites + +1. **OpenRouter Account**: Sign up at [openrouter.ai](https://openrouter.ai) +2. **API Key**: Get your API key from the [OpenRouter dashboard](https://openrouter.ai/keys) +3. **Model Access**: Ensure you have access to the models you want to use + +## Quick Start + +### Basic Setup + +```bash +# Set your OpenRouter API key (required) +export OPENROUTER_API_KEY="your-api-key-here" + +# Optionally set default models +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large" +``` + +### Minimal Example + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="AI Assistant", + description="A helpful assistant powered by OpenRouter.", + ) + # 🎉 Ready to use at http://localhost:8800 +``` + +## Configuration + +All configuration is done via environment variables. Set the required and optional environment variables before running your application: + +```bash +# Required: API Key +export OPENROUTER_API_KEY="your-api-key-here" + +# Optional: LLM Configuration +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_MAX_TOKENS="128000" + +# Optional: Embedding Configuration +export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b" +export OPENROUTER_EMBEDDER_DIMENSIONS="4096" # Optional override + +# Optional: Analytics +export OPENROUTER_HTTP_REFERER="https://myapp.com" +export OPENROUTER_SITE_NAME="My Application" +``` + +## Environment Variables Reference + +### Required Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `OPENROUTER_API_KEY` | Your OpenRouter API key | `sk-or-v1-...` | + +### Optional Variables - LLM Configuration + +| Variable | Description | Default | Example | +|----------|-------------|---------|---------| +| `OPENROUTER_MODEL` | LLM model name | `openai/gpt-4o` | `openai/gpt-4o-mini` | +| `OPENROUTER_MAX_TOKENS` | Max tokens limit | Auto-detected | `128000` | + +### Optional Variables - Embedding Configuration + +| Variable | Description | Default | Example | +|----------|-------------|---------|---------| +| `OPENROUTER_EMBEDDER_MODEL` | Embedding model name | `openai/text-embedding-3-large` | `qwen/qwen3-embedding-8b` | +| `OPENROUTER_EMBEDDER_DIMENSIONS` | Override embedding dimensions | Auto-detected | `4096` | + +### Optional Variables - Analytics + +| Variable | Description | Example | +|----------|-------------|---------| +| `OPENROUTER_HTTP_REFERER` | Your app's URL (for analytics) | `https://myapp.com` | +| `OPENROUTER_SITE_NAME` | Your app's name (for analytics) | `My Application` | + +## Supported Models + +OpenRouter supports **400+ models** from different providers. Models are automatically optimized with specialized configurations when available. + +### Pre-configured LLM Models + +These models have specialized configurations for optimal performance: + +| Model | Provider | Context | Use Case | +|-------|----------|---------|----------| +| `openai/gpt-4o` | OpenAI | 128K | Default, best overall quality | +| `openai/gpt-4o-mini` | OpenAI | 128K | Cost-effective, fast | +| `anthropic/claude-3.5-sonnet` | Anthropic | 200K | Advanced reasoning, long context | +| `meta-llama/llama-3.3-70b-instruct` | Meta | 8K | Open-source option | + +### Supported Embedding Models + +The service supports multiple embedding models with automatic dimension detection: + +| Model | Dimensions | Provider | Use Case | +|-------|------------|----------|----------| +| `openai/text-embedding-3-large` | 3072 | OpenAI | Default, high quality | +| `openai/text-embedding-3-small` | 1536 | OpenAI | Faster, smaller | +| `openai/text-embedding-ada-002` | 1536 | OpenAI | Legacy model | +| `qwen/qwen3-embedding-8b` | 4096 | Qwen | High dimension, multilingual | +| `qwen/qwen-embedding-v2` | 1536 | Qwen | Multilingual embeddings | + +### Using Any OpenRouter Model + +You can use **any model** that OpenRouter supports by setting the appropriate environment variables: + +```bash +# LLM Models +export OPENROUTER_MODEL="google/gemini-pro-1.5" + +# Embedding Models +export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b" +``` + +Check the [OpenRouter Models page](https://openrouter.ai/models) for the full list of available models. + +## Usage Examples + +### Example 1: Default Configuration + +Use the default models (GPT-4o for LLM, text-embedding-3-large for embeddings): + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="General Assistant", + description="A helpful AI assistant." + ) +``` + +### Example 2: Custom LLM Model + +Use Claude for text generation: + +```bash +export OPENROUTER_MODEL="anthropic/claude-3.5-sonnet" +``` + +```python +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="Claude Assistant", + description="Powered by Claude." + ) +``` + +### Example 3: Custom Embedder Model + +Use a custom embedding model for better multilingual support: + +```bash +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b" +``` + +```python +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="Multilingual Assistant", + description="Supports multiple languages." + ) +``` + +### Example 4: High-Performance Setup + +Optimize for speed and quality: + +```bash +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large" +export OPENROUTER_MAX_TOKENS="128000" +``` + +```python +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="High-Performance Agent", + description="Optimized for speed and accuracy." + ) +``` + +### Example 5: Cost-Optimized Setup + +Balance quality and cost: + +```bash +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-small" +``` + +```python +async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="Cost-Optimized Agent", + description="Optimized for cost-effectiveness." + ) +``` + +## Embedding Model Configuration + +### Understanding Embedding Dimensions + +Different embedding models produce vectors of different dimensions. The service automatically detects dimensions for known models, and can auto-detect from API responses for unknown models. + +### Known Embedding Dimensions + +The following models have pre-configured dimensions: + +- `openai/text-embedding-3-large`: **3072** dimensions +- `openai/text-embedding-3-small`: **1536** dimensions +- `openai/text-embedding-ada-002`: **1536** dimensions +- `qwen/qwen3-embedding-8b`: **4096** dimensions +- `qwen/qwen-embedding-v2`: **1536** dimensions + +### Auto-Detection + +For unknown models, dimensions are automatically detected from the first API response and cached for subsequent use. + +### Manual Dimension Override + +If needed, you can manually specify dimensions via environment variable: + +```bash +export OPENROUTER_EMBEDDER_DIMENSIONS="4096" +``` + +⚠️ **Important**: If you change embedder models or dimensions, you may need to clear your vector database cache to avoid dimension mismatch errors. + +## Dynamic Model Selection + +OpenRouter intelligently handles model selection and configuration: + +### Automatic Generator Selection + +Known models use specialized generators for optimal performance: + +- `openai/gpt-4o` → `OpenRouterGPT4O` +- `openai/gpt-4o-mini` → `OpenRouterGPT4OMini` +- `anthropic/claude-3.5-sonnet` → `OpenRouterClaude35Sonnet` +- `meta-llama/llama-3.3-70b-instruct` → `OpenRouterLlama33_70B` +- Other models → Dynamic generator with auto-configured parameters + +### Automatic Embedder Selection + +Embedders are automatically configured based on the model name: + +- Known models → Pre-configured dimensions +- Unknown models → Auto-detected dimensions from API response +- Dynamic embedder → Created with proper container resolution + +## Advantages of OpenRouter + +1. **Model Diversity**: Access to 400+ models from different providers +2. **Unified Embeddings**: Native support for embedding models via the same API +3. **Cost Flexibility**: Choose models based on price-performance needs +4. **Single API**: One integration for multiple providers +5. **Auto-Optimization**: Automatic configuration for known models +6. **Environment-Based Configuration**: All configuration via environment variables +7. **Analytics**: Built-in usage tracking through OpenRouter dashboard + +## Troubleshooting + +### Rate Limit Errors + +**Error:** +``` +OpenRouter API rate limit exceeded +``` + +**Solutions:** +- Check your OpenRouter account balance and billing status +- Review usage limits in the [OpenRouter dashboard](https://openrouter.ai/keys) +- Consider upgrading your plan for higher limits +- Try a different model with higher rate limits +- Wait a moment before retrying + +### JSON Mode Not Supported + +**Error:** +``` +Model 'xyz' does not support JSON mode +``` + +**Solutions:** +- OpenRouter automatically falls back to prompting for JSON output +- Consider using a model that supports JSON mode: + - `openai/gpt-4o` + - `openai/gpt-4o-mini` + - `anthropic/claude-3.5-sonnet` +- The fallback still produces structured output reliably + +### Dimension Mismatch Errors + +**Error:** +``` +ValueError: all the input array dimensions except for the concatenation axis must match exactly +``` + +**Solutions:** +- This occurs when switching embedder models with different dimensions +- Clear your vector database cache/embeddings +- Or delete the cached embeddings files in your `parlant-data` directory +- The embedder will create new embeddings with the correct dimensions + +### Authentication Errors + +**Error:** +``` +OPENROUTER_API_KEY is not set +``` + +**Solutions:** +- Set the `OPENROUTER_API_KEY` environment variable +- Verify your API key in the [OpenRouter dashboard](https://openrouter.ai/keys) +- Ensure the key hasn't expired or been revoked +- Check for typos in the environment variable name + +### Container Resolution Errors + +**Error:** +``` +Unable to construct dependency of type OpenRouterEmbedder +``` + +**Solutions:** +- This is automatically handled by the dynamic embedder class +- Ensure you're using the latest version of the code +- If the error persists, check that `embedder_model_name` is correctly set + +## Cost Management + +OpenRouter provides transparent pricing across models. Choose models based on your needs: + +### Cost-Effective LLM Options + +```python +# GPT-4o-mini - Good quality, lower cost +model_name="openai/gpt-4o-mini" + +# Claude Haiku - Fast, affordable +model_name="anthropic/claude-3-haiku" + +# Llama - Open source, very affordable +model_name="meta-llama/llama-3.3-70b-instruct" +``` + +### Cost-Effective Embedding Options + +```python +# text-embedding-3-small - Smaller, faster, cheaper +embedder_model_name="openai/text-embedding-3-small" + +# text-embedding-ada-002 - Legacy, very affordable +embedder_model_name="openai/text-embedding-ada-002" +``` + +### Premium Options + +```python +# GPT-4o - Highest quality +model_name="openai/gpt-4o" + +# text-embedding-3-large - Highest quality embeddings +embedder_model_name="openai/text-embedding-3-large" +``` + +Check [OpenRouter pricing](https://openrouter.ai/docs/pricing) for current rates. + +## Model Selection Guide + +### When to Use Each LLM Model + +**GPT-4o** (`openai/gpt-4o`) +- Complex reasoning tasks +- Code generation and debugging +- Multi-step problem solving +- When accuracy is critical +- Best overall performance + +**GPT-4o-mini** (`openai/gpt-4o-mini`) +- General purpose tasks +- High-volume applications +- Cost-sensitive use cases +- When 95% accuracy is sufficient +- Fast response times + +**Claude** (`anthropic/claude-3.5-sonnet`) +- Long context tasks (200K tokens) +- Creative writing +- Detailed analysis +- When you need extended reasoning +- Complex document understanding + +**Llama** (`meta-llama/llama-3.3-70b-instruct`) +- Open-source requirements +- Custom fine-tuning needs +- Privacy-sensitive applications +- Cost optimization +- Self-hosted deployments + +### When to Use Each Embedding Model + +**text-embedding-3-large** (`openai/text-embedding-3-large`) +- Default choice for most use cases +- High quality semantic search +- Best accuracy for retrieval +- Recommended for production + +**text-embedding-3-small** (`openai/text-embedding-3-small`) +- Cost-sensitive applications +- Faster embedding generation +- Good quality for most tasks +- Large-scale deployments + +**qwen3-embedding-8b** (`qwen/qwen3-embedding-8b`) +- Multilingual applications +- Higher dimensional space (4096) +- Better fine-grained distinctions +- When you need more embedding dimensions + +## Best Practices + +### 1. Start with Defaults +Begin with the default models (`gpt-4o` and `text-embedding-3-large`) for best balance of quality and performance. + +### 2. Use Mini for Scale +Switch to `gpt-4o-mini` for high-volume operations where cost is a concern. + +### 3. Match Embedder to Use Case +- Use `text-embedding-3-large` for quality-critical applications +- Use `text-embedding-3-small` for cost-sensitive deployments +- Use `qwen3-embedding-8b` for multilingual or high-dimensional needs + +### 4. Set Max Tokens +Prevent runaway costs by setting appropriate `max_tokens` limits via environment variable: + +```bash +export OPENROUTER_MAX_TOKENS="128000" # For long-context models +export OPENROUTER_MAX_TOKENS="8192" # For standard use cases +``` + +### 5. Monitor Costs +Regularly check the [OpenRouter dashboard](https://openrouter.ai/keys) to monitor usage and costs. + +### 6. Use Analytics +Set `OPENROUTER_HTTP_REFERER` and `OPENROUTER_SITE_NAME` to track usage across different applications. + +### 7. Clear Cache When Changing Models +If you switch embedder models, clear your vector database cache to avoid dimension mismatches. + +### 8. Environment Variables for Production +Use environment variables for production deployments instead of hardcoding values: + +```bash +# Production configuration +export OPENROUTER_API_KEY="sk-or-v1-..." +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large" +``` + +## Advanced Configuration + +### Custom Dimensions for Unknown Models + +If using an embedding model not in the known list, you can specify dimensions: + +```bash +export OPENROUTER_EMBEDDER_MODEL="custom/embedding-model" +export OPENROUTER_EMBEDDER_DIMENSIONS="2048" +``` + +The service will also auto-detect dimensions from the first API response. + +### Combining Multiple Configurations + +All configuration is done via environment variables. Set multiple variables to configure different aspects: + +```bash +# Set all configuration via environment variables +export OPENROUTER_MODEL="anthropic/claude-3.5-sonnet" +export OPENROUTER_MAX_TOKENS="200000" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large" +``` + +## Additional Resources + +- [OpenRouter Documentation](https://openrouter.ai/docs) +- [Available Models](https://openrouter.ai/models) +- [API Reference](https://openrouter.ai/docs/api-reference) +- [Pricing Information](https://openrouter.ai/docs/pricing) +- [Rate Limits](https://openrouter.ai/docs/api-reference/limits) + +## Example: Complete Setup + +Here's a complete example showing a production-ready setup: + +```bash +# Set environment variables +export OPENROUTER_API_KEY="your-api-key-here" +export OPENROUTER_MODEL="openai/gpt-4o-mini" +export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large" +export OPENROUTER_MAX_TOKENS="32768" +``` + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +@p.tool +async def get_weather(context: p.ToolContext, city: str) -> p.ToolResult: + # Your weather API logic here + return p.ToolResult(f"Sunny, 72°F in {city}") + +async def main(): + async with p.Server(nlp_service=NLPServices.openrouter) as server: + agent = await server.create_agent( + name="Weather Assistant", + description="Helps users check weather conditions." + ) + + await agent.create_guideline( + condition="User asks about weather", + action="Get weather information using the get_weather tool", + tools=[get_weather] + ) + + # 🎉 Ready at http://localhost:8800 + +if __name__ == "__main__": + import asyncio + asyncio.run(main()) +``` + +This setup provides: +- ✅ Cost-effective LLM (`gpt-4o-mini`) +- ✅ High-quality embeddings (`text-embedding-3-large`) +- ✅ Reasonable token limit (32K) +- ✅ Tool integration +- ✅ Guideline-based behavior control diff --git a/docs/adapters/nlp/snowflake-cortex.md b/docs/adapters/nlp/snowflake-cortex.md new file mode 100644 index 0000000..0f3af62 --- /dev/null +++ b/docs/adapters/nlp/snowflake-cortex.md @@ -0,0 +1,84 @@ +# Snowflake Cortex Adapter + +Integrate [Snowflake Cortex REST APIs](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-rest-api) for **chat/structured generation** and **embeddings** with Snowflake-hosted LLMs. The adapter talks directly to: + +- `POST /api/v2/cortex/inference:complete` for chat/JSON output +- `POST /api/v2/cortex/inference:embed` for embeddings + +## Requirements + +### Authentication +See [Snowflake REST API authentication](https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/authentication). PAT is recommended. + +### Environment Variables +See [Cortex models](https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm) for available model names. + +```bash +export SNOWFLAKE_CORTEX_BASE_URL="https://<account>.snowflakecomputing.com" +export SNOWFLAKE_AUTH_TOKEN="<jwt-or-pat>" +export SNOWFLAKE_CORTEX_CHAT_MODEL="mistral-large2" +export SNOWFLAKE_CORTEX_EMBED_MODEL="e5-base-v2" +# Optional: +export SNOWFLAKE_CORTEX_MAX_TOKENS="8192" +``` + +## Usage Example + +```python +import parlant.sdk as p +from parlant.sdk import NLPServices + +@p.tool +async def get_weather(context: p.ToolContext, city: str) -> p.ToolResult: + # Your weather API logic here + return p.ToolResult(f"Sunny, 72°F in {city}") + +@p.tool +async def get_datetime(context: p.ToolContext) -> p.ToolResult: + from datetime import datetime + return p.ToolResult(datetime.now()) + +async def main(): + async with p.Server(nlp_service=NLPServices.snowflake) as server: + agent = await server.create_agent( + name="WeatherBot", + description="Helpful weather assistant" + ) + + # Have the agent's context be updated on every response (though + # update interval is customizable) using a context variable. + await agent.create_variable(name="current-datetime", tool=get_datetime) + + # Control and guide agent behavior with natural language + await agent.create_guideline( + condition="User asks about weather", + action="Get current weather and provide a friendly response with suggestions", + tools=[get_weather] + ) + + # Add other (reliably enforced) behavioral modeling elements + # ... + + # 🎉 Test playground ready at http://localhost:8800 + # Integrate the official React widget into your app, + # or follow the tutorial to build your own frontend! + +if __name__ == "__main__": + import asyncio + asyncio.run(main()) +``` + +## Configuration Reference + +| Variable | Required | Description | +|----------------------------------|----------|-------------| +| `SNOWFLAKE_CORTEX_BASE_URL` | ✅ | Base account URL (e.g., `https://<account>.snowflakecomputing.com`). | +| `SNOWFLAKE_AUTH_TOKEN` | ✅ | OAuth / Keypair JWT / PAT used in the `Authorization: Bearer` header. | +| `SNOWFLAKE_CORTEX_CHAT_MODEL` | ✅ | Chat model name. | +| `SNOWFLAKE_CORTEX_EMBED_MODEL` | ✅ | Embedding model name. | +| `SNOWFLAKE_CORTEX_MAX_TOKENS` | ❌ | Local upper bound for generation; does not override provider limits. | + + +## Notes on Privacy & Data Residency + +The adapter allows apps to call Cortex directly in your Snowflake account, reducing the need to move data outside Snowflake for LLM tasks. Review Snowflake's REST guidance for regional availability and account setup. \ No newline at end of file diff --git a/docs/adapters/nlp/vertex.md b/docs/adapters/nlp/vertex.md new file mode 100644 index 0000000..6a3ef62 --- /dev/null +++ b/docs/adapters/nlp/vertex.md @@ -0,0 +1,452 @@ +# Vertex AI Service Adapter Documentation + +## Overview + +The Vertex AI Service Adapter provides integration with Google Cloud's Vertex AI platform, supporting both Anthropic Claude models and Google Gemini models through their respective APIs. This adapter implements the Parlant NLP service interface for text generation, embeddings, and tokenization. + +## Architecture + +### Core Components + +- **VertexAIService**: Main service class implementing the NLPService interface +- **VertexAIClaudeSchematicGenerator**: Generator for Claude models via Anthropic Vertex API +- **VertexAIGeminiSchematicGenerator**: Generator for Gemini models via Google Gen AI API +- **VertexAIEmbedder**: Text embedding service using Google's text-embedding-004 model +- **VertexAIEstimatingTokenizer**: Token counting for both Claude and Gemini models + +## Configuration + +### Environment Variables + +```bash +# Required +VERTEX_AI_PROJECT_ID=your-gcp-project-id +VERTEX_AI_REGION=us-central1 # Put your region +VERTEX_AI_MODEL=claude-opus-4 +``` + +### Authentication + +The adapter uses Google Application Default Credentials (ADC): + +```bash +# For local development +gcloud auth application-default login + +# For production, use service account key or workload identity +``` + +## Supported Models + +### Claude Models (via Anthropic Vertex API) + +| Short Name | Full Model Name | Description | +|------------|-----------------|-------------| +| `claude-opus-4` | `claude-opus-4@20250514` | Most capable Claude model | +| `claude-sonnet-4` | `claude-sonnet-4@20250514` | Balanced performance and speed | +| `claude-sonnet-3.5` | `claude-3-5-sonnet-v2@20241022` | Previous generation Sonnet | +| `claude-haiku-3.5` | `claude-3-5-haiku@20241022` | Fastest Claude model | + +### Gemini Models (via Google Gen AI API) + +| Short Name | Full Model Name | Description | +|------------|-----------------|-------------| +| `gemini-2.5-flash` | `gemini-2.5-flash` | Latest fast Gemini model | +| `gemini-2.5-pro` | `gemini-2.5-pro` | Latest pro Gemini model | +| `gemini-2.0-flash` | `gemini-2.0-flash` | Previous generation flash | +| `gemini-1.5-flash` | `gemini-1.5-flash` | 1M token context | +| `gemini-1.5-pro` | `gemini-1.5-pro` | 2M token context | + +## Usage + +### Basic Setup + +```python +import parlant.sdk import p +from parlant.sdk import NLPServices + +async with p.Server(nlp_service=NLPServices.vertex) as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) +``` + +### Direct Service Usage + +```python +from parlant.adapters.nlp.vertex_service import VertexAIService +from parlant.core.loggers import Logger + +# Initialize service +logger = Logger() +service = VertexAIService(logger=logger) + +# Get schematic generator +generator = await service.get_schematic_generator(YourSchemaClass) + +# Generate content +result = await generator.generate( + prompt="Your prompt here", + hints={"temperature": 0.7, "max_tokens": 1000} +) +``` + +## API Reference + +### VertexAIService + +Main service class implementing the NLPService interface. + +#### Constructor + +```python +def __init__(self, logger: Logger) -> None +``` + +Initializes the service with environment variables: +- Reads `VERTEX_AI_PROJECT_ID`, `VERTEX_AI_REGION`, `VERTEX_AI_MODEL` +- Validates Application Default Credentials +- Sets up logging + +#### Methods + +##### get_schematic_generator + +```python +async def get_schematic_generator(self, t: type[T]) -> SchematicGenerator[T] +``` + +Returns appropriate generator based on configured model: +- Claude models → VertexAIClaudeSchematicGenerator +- Gemini models → VertexAIGeminiSchematicGenerator +- Includes fallback logic for Claude Opus 4 + +##### get_embedder + +```python +async def get_embedder(self) -> Embedder +``` + +Returns VertexTextEmbedding004 embedder instance. + +##### get_moderation_service + +```python +async def get_moderation_service(self) -> ModerationService +``` + +Returns NoModeration service (moderation not yet implemented). + +### VertexAIClaudeSchematicGenerator + +Schematic generator for Claude models via Anthropic Vertex API. + +#### Supported Hints + +- `temperature`: Controls randomness (0.0-1.0) +- `max_tokens`: Maximum output tokens +- `top_p`: Nucleus sampling parameter +- `top_k`: Top-k sampling parameter + +#### Properties + +- `id`: Returns `vertex-ai/{model_name}` +- `tokenizer`: Returns VertexAIEstimatingTokenizer instance +- `max_tokens`: Returns 200,000 (Claude context limit) + +#### Methods + +##### generate + +```python +async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, +) -> SchematicGenerationResult[T] +``` + +Generates structured content using Claude models with: +- JSON schema validation +- Retry policies for rate limits and errors +- Usage tracking + +### VertexAIGeminiSchematicGenerator + +Schematic generator for Gemini models via Google Gen AI API. + +#### Supported Hints + +- `temperature`: Controls randomness (0.0-1.0) +- `thinking_config`: Configuration for reasoning models + +#### Properties + +- `id`: Returns `vertex-ai/{model_name}` +- `tokenizer`: Returns VertexAIEstimatingTokenizer instance +- `max_tokens`: Returns 1M (Flash) or 2M (Pro) tokens + +#### Methods + +##### generate + +```python +async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, +) -> SchematicGenerationResult[T] +``` + +Generates structured content using Gemini models with: +- Native JSON schema support +- JSON parsing and validation +- Usage metadata tracking + +### VertexAIEmbedder + +Text embedding service using Google's text-embedding-004 model. + +#### Properties + +- `id`: Returns `vertex-ai/text-embedding-004` +- `dimensions`: Returns 768 (embedding dimensions) +- `max_tokens`: Returns 8,192 (input token limit) + +#### Supported Hints + +- `title`: Document title for better embeddings +- `task_type`: Embedding task type (default: "RETRIEVAL_DOCUMENT") + +#### Methods + +##### embed + +```python +async def embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, +) -> EmbeddingResult +``` + +Generates embeddings for input texts with batch processing support. + +### VertexAIEstimatingTokenizer + +Token counting service supporting both Claude and Gemini models. + +#### Methods + +##### estimate_token_count + +```python +async def estimate_token_count(self, prompt: str) -> int +``` + +Estimates token count using: +- tiktoken for Claude models +- Google Gen AI API for Gemini models + +## Error Handling + +### Authentication Errors + +```python +class VertexAIAuthError(Exception): + """Raised when there are authentication issues with Vertex AI.""" +``` + +Common causes and solutions: +- Missing ADC: Run `gcloud auth application-default login` +- Insufficient permissions: Ensure "Vertex AI User" role +- Model not enabled: Check Vertex AI Model Garden + +### Rate Limiting + +The adapter implements comprehensive retry policies: + +#### Claude Models +- Retries: APIConnectionError, APITimeoutError, RateLimitError, APIResponseValidationError +- Max attempts: 3 with exponential backoff (1s, 2s, 4s) +- Server errors: 2 attempts with longer delays (1s, 5s) + +#### Gemini Models +- Retries: NotFound, TooManyRequests, ResourceExhausted +- Max attempts: 3 with exponential backoff (1s, 2s, 4s) +- Server errors: 2 attempts with longer delays (1s, 5s) + +### Error Messages + +The adapter provides detailed error messages for common issues: + +#### Rate Limit Exceeded +``` +Vertex AI rate limit exceeded. Possible reasons: +1. Your GCP project may have insufficient quota. +2. The model may not be enabled in Vertex AI Model Garden. +3. You might have exceeded the requests-per-minute limit. + +Recommended actions: +- Check your Vertex AI quotas in the GCP Console. +- Ensure the model is enabled in Vertex AI Model Garden. +- Review IAM permissions for the service account. +- Visit: https://console.cloud.google.com/vertex-ai/model-garden +``` + +#### Permission Denied +``` +Permission denied accessing Vertex AI. Ensure: +1. ADC is properly configured (run 'gcloud auth application-default login') +2. The service account has 'Vertex AI User' role +3. The {model_name} model is enabled in Vertex AI Model Garden +``` + +## Performance Considerations + +### Token Limits + +| Model Type | Context Limit | Recommended Usage | +|------------|---------------|-------------------| +| Claude Models | 200K tokens | Long documents, complex reasoning | +| Gemini Flash | 1M tokens | Large context processing | +| Gemini Pro | 2M tokens | Maximum context requirements | + +## Best Practices + +### Model Selection + +1. **Claude Sonnet 3.5**: Best balance of performance and cost +2. **Claude Opus 4**: Maximum capability with fallback +3. **Gemini 2.5 Flash**: Fast processing with large context +4. **Gemini 2.5 Pro**: Complex reasoning tasks + +### Configuration +```python + export VERTEX_AI_PROJECT_ID=your-project-id + export VERTEX_AI_REGION=us-central1 + export VERTEX_AI_MODEL=claude-sonnet-3.5 +``` + +### Error Handling + +```python +from parlant.adapters.nlp.vertex_service import VertexAIAuthError + +try: + service = VertexAIService(logger=logger) + generator = await service.get_schematic_generator(MySchema) + result = await generator.generate(prompt) +except VertexAIAuthError as e: + logger.error(f"Authentication failed: {e}") + # Handle auth setup +except Exception as e: + logger.error(f"Generation failed: {e}") + # Handle other errors +``` + +## Troubleshooting + +### Common Issues + +1. **Authentication Failures** + - Verify ADC setup: `gcloud auth application-default print-access-token` + - Check project permissions in GCP Console + - Ensure service account has required roles + +2. **Model Access Denied** + - Enable models in Vertex AI Model Garden + - Check regional availability + - Verify billing account is active + +3. **Rate Limiting** + - Monitor quota usage in GCP Console + - Implement application-level rate limiting + - Consider upgrading service tier + +### Debugging + +Check usage from the playground UI by inspecting on the generated message + +## Migration Guide + +### From Other Adapters + +When migrating from other NLP adapters: + +1. **Update Environment Variables** + ```bash + # Remove old variables + unset OPENAI_API_KEY ANTHROPIC_API_KEY + + # Set Vertex AI variables + export VERTEX_AI_PROJECT_ID=your-project-id + export VERTEX_AI_REGION=us-central1 + export VERTEX_AI_MODEL=claude-opus-4 + ``` + +2. **Model Name Mapping** + - `gpt-4` → `claude-opus-4` + - `gpt-3.5-turbo` → `gemini-2.5-flash` + - `claude-3-sonnet` → `claude-opus-4` + +## Contributing + +### Adding New Models + +1. **Determine Provider**: Check if model uses Anthropic or Google API +2. **Create Model Class**: Inherit from appropriate base generator +3. **Update Service**: Add model mapping in VertexAIService +4. **Add Tests**: Include integration tests for new model +5. **Update Documentation**: Add model to supported models table + +### Code Style + +- Follow existing patterns for error handling +- Include comprehensive logging +- Add type hints for all methods +- Document public APIs with docstrings +- Use retry policies for external API calls + +## Prerequisites and Installation + +### Installation + +To use the Vertex AI Service Adapter with Parlant, you need to install the appropriate optional dependencies: + +```bash +pip install "parlant[vertex]" +``` + +This installation includes support for both Claude and Gemini models through the Vertex AI platform. + +### Important Model Deprecation Notice + +⚠️ **Claude 3.5 Sonnet Models Deprecation**: Claude Sonnet 3.5 models (claude-3-5-sonnet-20240620 and claude-3-5-sonnet-20241022) will be retired on October 22, 2025. We recommend migrating to Claude Sonnet 4 (claude-sonnet-4-20250514) for improved performance and capabilities. + +## Authentication Setup + +Before using the adapter, ensure you have proper authentication configured: + +```bash +# For local development +gcloud auth application-default login + +# Verify authentication +gcloud auth application-default print-access-token +``` + +## Required Permissions + +Ensure your service account or user has the following IAM roles: +- `Vertex AI User` - for accessing Vertex AI services +- `AI Platform User` - for model access (legacy role, may be needed for some models) + +## License + +Licensed under the Apache License, Version 2.0. See the source file header for full license text. + +## Maintainer + +Agam Dubey - hello.world.agam@gmail.com \ No newline at end of file diff --git a/docs/adapters/persistence/snowflake.md b/docs/adapters/persistence/snowflake.md new file mode 100644 index 0000000..a5029e3 --- /dev/null +++ b/docs/adapters/persistence/snowflake.md @@ -0,0 +1,154 @@ +# Snowflake Persistence Adapter + +The Snowflake document adapter lets Parlant persist the long–lived parts of a +deployment—sessions, customers, and context variables—inside your Snowflake +account. That means you can run the server (for example inside Snowpark +Container Services), stop it, and later resume the exact same conversation +state. + +This page walks through the required environment variables and shows how to +wire the stores into Snowflake when booting Parlant via the SDK. + +## Requirements + +1. Install the optional dependency (or otherwise provide + `snowflake-connector-python`): + + ```bash + pip install "parlant[snowflake]" + ``` + +2. Set the credentials that `SnowflakeDocumentDatabase` consumes: + + | Variable | Required | Description | + |-----------------------------|:--------:|-------------------------------------------------------------------------------------| + | `SNOWFLAKE_ACCOUNT` | ✅ | Account locator (e.g. `abc-xy123`). | + | `SNOWFLAKE_USER` | ✅ | Username that Parlant should authenticate as. | + | `SNOWFLAKE_PASSWORD` | ✅* | Password for password-based auth. Skip when using OAuth (see `SNOWFLAKE_TOKEN`). | + | `SNOWFLAKE_TOKEN` | ✅* | OAuth access token. When set, the adapter automatically switches to OAuth. | + | `SNOWFLAKE_WAREHOUSE` | ✅ | Warehouse to execute queries against. | + | `SNOWFLAKE_DATABASE` | ✅ | Database that will host the Parlant tables. | + | `SNOWFLAKE_SCHEMA` | ✅ | Schema inside the database. | + | `SNOWFLAKE_ROLE` | ➖ | Optional role override. | + + > ✅* Provide **either** `SNOWFLAKE_PASSWORD` **or** `SNOWFLAKE_TOKEN`. + +## SDK / Module Setup + +Parlant’s SDK exposes a `configure_container` hook that lets you replace the +default persistence layer. The pattern below shows how to register +Snowflake-backed implementations of the three configurable stores: + +- `SessionStore` → `SessionDocumentStore` +- `CustomerStore` → `CustomerDocumentStore` +- `ContextVariableStore` → `ContextVariableDocumentStore` + +Each store receives its own table prefix (`PARLANT_SESSIONS_`, +`PARLANT_CUSTOMERS_`, `PARLANT_CONTEXT_VARIABLES_`) so their metadata never +collides. We also rebind `EventEmitterFactory`, so system events get written into +the same store. + +```python +from contextlib import AsyncExitStack + +import parlant.sdk as p +from parlant.adapters.db.snowflake_db import SnowflakeDocumentDatabase +from parlant.core.emission.event_publisher import EventPublisherFactory + +EXIT_STACK = AsyncExitStack() + + +async def _make_session_store(container: p.Container) -> p.SessionStore: + database = await EXIT_STACK.enter_async_context( + SnowflakeDocumentDatabase( + logger=container[p.Logger], + table_prefix="PARLANT_SESSIONS_", + ) + ) + store = p.SessionDocumentStore(database=database, allow_migration=True) + return await EXIT_STACK.enter_async_context(store) + + +async def _make_customer_store(container: p.Container) -> p.CustomerStore: + database = await EXIT_STACK.enter_async_context( + SnowflakeDocumentDatabase( + logger=container[p.Logger], + table_prefix="PARLANT_CUSTOMERS_", + ) + ) + store = p.CustomerDocumentStore( + id_generator=container[p.IdGenerator], + database=database, + allow_migration=True, + ) + return await EXIT_STACK.enter_async_context(store) + + +async def _make_variable_store(container: p.Container) -> p.ContextVariableStore: + database = await EXIT_STACK.enter_async_context( + SnowflakeDocumentDatabase( + logger=container[p.Logger], + table_prefix="PARLANT_CONTEXT_VARIABLES_", + ) + ) + store = p.ContextVariableDocumentStore( + id_generator=container[p.IdGenerator], + database=database, + allow_migration=True, + ) + return await EXIT_STACK.enter_async_context(store) + + +async def configure_container(container: p.Container) -> p.Container: + container = container.clone() + + session_store = await _make_session_store(container) + container[p.SessionDocumentStore] = session_store + container[p.SessionStore] = session_store + + customer_store = await _make_customer_store(container) + container[p.CustomerDocumentStore] = customer_store + container[p.CustomerStore] = customer_store + + variable_store = await _make_variable_store(container) + container[p.ContextVariableDocumentStore] = variable_store + container[p.ContextVariableStore] = variable_store + + container[p.EventEmitterFactory] = EventPublisherFactory( + container[p.AgentStore], + session_store, + ) + + return container + + +async def shutdown_snowflake() -> None: + await EXIT_STACK.aclose() +``` + +### Using the SDK + +```python +async def main() -> None: + try: + async with p.Server( + nlp_service=p.NLPServices.snowflake, + configure_container=configure_container, + ) as server: + ... + finally: + await shutdown_snowflake() +``` + +## What Gets Persisted? + +Once the Snowflake stores are registered, Snowflake becomes the source of truth for: + +- Sessions + events + inspections +- Customers + their tag associations +- Context variables + their values + +Other stores (agents, guidelines, journeys, etc.) continue to use their default +backends. If you define them in code at startup, they will automatically be +recreated each time the server runs. For dynamic authoring flows you can follow +the same module approach to route additional stores into Snowflake. diff --git a/docs/adapters/vector_db/qdrant.md b/docs/adapters/vector_db/qdrant.md new file mode 100644 index 0000000..13aa8f3 --- /dev/null +++ b/docs/adapters/vector_db/qdrant.md @@ -0,0 +1,204 @@ +# Qdrant Vector Database + +The Qdrant adapter provides persistent vector storage for Parlant using Qdrant's vector database. This replaces the default in-memory storage with production-ready persistence. + +For general Parlant usage, see the [official documentation](https://www.parlant.io/docs/). + +## Prerequisites + +1. **Install Qdrant adapter**: `pip install parlant[qdrant]` +2. **Choose storage**: Local file system or Qdrant Cloud + +## Quick Start + +### Setup (Manual) + +```python +import parlant.sdk as p +from pathlib import Path +from contextlib import AsyncExitStack +from parlant.adapters.vector_db.qdrant import QdrantDatabase +from parlant.core.nlp.embedding import EmbedderFactory, EmbeddingCache, Embedder +from parlant.core.loggers import Logger +from parlant.core.nlp.service import NLPService +from parlant.core.glossary import GlossaryVectorStore, GlossaryStore +from parlant.core.canned_responses import CannedResponseVectorStore, CannedResponseStore +from parlant.core.capabilities import CapabilityVectorStore, CapabilityStore +from parlant.core.journeys import JourneyVectorStore, JourneyStore +from parlant.adapters.db.transient import TransientDocumentDatabase + +async def configure_container(container: p.Container) -> p.Container: + embedder_factory = EmbedderFactory(container) + + async def get_embedder_type() -> type[Embedder]: + return type(await container[NLPService].get_embedder()) + + exit_stack = AsyncExitStack() + qdrant_db = await exit_stack.enter_async_context( + QdrantDatabase( + logger=container[Logger], + path=Path("./qdrant_data"), + embedder_factory=EmbedderFactory(container), + embedding_cache_provider=lambda: container[EmbeddingCache], + ) + ) + + # For Qdrant Cloud, replace the above with: + # qdrant_db = await exit_stack.enter_async_context( + # QdrantDatabase( + # logger=container[Logger], + # url="https://your-cluster-id.us-east4-0.gcp.cloud.qdrant.io", + # api_key="your-api-key-here", + # embedder_factory=EmbedderFactory(container), + # embedding_cache_provider=lambda: container[EmbeddingCache], + # ) + # ) + + # Configure stores using vector database + container[GlossaryStore] = await exit_stack.enter_async_context( + GlossaryVectorStore( + id_generator=container[p.IdGenerator], + vector_db=qdrant_db, + document_db=TransientDocumentDatabase(), + embedder_factory=embedder_factory, + embedder_type_provider=get_embedder_type, + ) # type: ignore + ) + + container[CannedResponseStore] = await exit_stack.enter_async_context( + CannedResponseVectorStore( + id_generator=container[p.IdGenerator], + vector_db=qdrant_db, + document_db=TransientDocumentDatabase(), + embedder_factory=embedder_factory, + embedder_type_provider=get_embedder_type, + ) # type: ignore + ) + + container[CapabilityStore] = await exit_stack.enter_async_context( + CapabilityVectorStore( + id_generator=container[p.IdGenerator], + vector_db=qdrant_db, + document_db=TransientDocumentDatabase(), + embedder_factory=embedder_factory, + embedder_type_provider=get_embedder_type, + ) # type: ignore + ) + + container[JourneyStore] = await exit_stack.enter_async_context( + JourneyVectorStore( + id_generator=container[p.IdGenerator], + vector_db=qdrant_db, + document_db=TransientDocumentDatabase(), + embedder_factory=embedder_factory, + embedder_type_provider=get_embedder_type, + ) # type: ignore + ) + + return container + +async def main(): + async with p.Server(configure_container=configure_container) as server: + agent = await server.create_agent( + name="My Agent", + description="Agent using Qdrant for persistent storage", + ) + + # Test: Create a term to verify Qdrant is working + term = await agent.create_term( + name="Example Term", + description="This is stored in Qdrant", + ) + print(f"Created term: {term.name}") + # All vector operations now use Qdrant +``` + + +## Verification + +To verify Qdrant integration is working correctly: + +### Check Collections +**Qdrant Cloud:** Collections appear in your Qdrant dashboard with names like: +- `glossary_OpenAITextEmbedding3Large` +- `glossary_unembedded` +- `capabilities_OpenAITextEmbedding3Large` +- `canned_responses_OpenAITextEmbedding3Large` + +**Local Qdrant:** A folder is created at your specified path containing Qdrant database files. + +### Confirm No Transient Storage +When Qdrant is properly configured: +- **No vector files** are created in the `parlant-data` folder +- Vector data is stored only in Qdrant (cloud or local) +- Data persists across server restarts + +### Test Vector Search +Create terms and test persistence: +```python +term = await agent.create_term( + name="Test Term", + description="This should be stored in Qdrant", +) +# Then chat with agent about "test term" - it should understand via vector search + +# Test persistence: close the server and run again +# The term should still be available after restart +``` + +--- + +## Common Issues + +### Integration Not Working (Still Using Transient Storage) +**Symptoms:** +- No collections appear in Qdrant dashboard +- Vector data appears in `parlant-data` folder +- Data lost on server restart + +**Solution:** Ensure all vector stores are properly configured with Qdrant in your `configure_container` function. Make sure you're using `AsyncExitStack` to properly manage the Qdrant database and vector stores lifecycle. + +### Windows File Locks +On Windows, use `async with` context manager. The adapter automatically handles file lock retries. + +### Collection Sync +Collections auto-sync when embedders or schemas change. Large collections may take time on first access. + +### Embedder Changes +When changing embedder types, old embedded collections persist until manually deleted. + +### Performance +Use Qdrant Cloud or server for production - local mode doesn't support payload indexes. You'll see a warning about this when using local Qdrant, which is expected and can be ignored. + +--- + +## Troubleshooting + +### Connection Issues +- **Local**: Check path exists and is writable +- **Remote**: Verify URL and API key + +### Slow Performance +- Use embedding cache +- Use Qdrant Cloud/server for payload indexes +- Consider splitting large collections + +### Data Not Persisting +- Check file path is correct and writable +- Verify connection settings for remote servers +- Test by closing the server and restarting—data should persist + +--- + +## Requirements + +- Python 3.8+ +- `pip install parlant[qdrant]` +- Writable directory (for local storage) or Qdrant Cloud account + +## Key Features + +- **Persistent storage**: Replaces in-memory storage with production-ready persistence +- **Auto-sync**: Collections automatically sync when embedders or schemas change +- **Windows support**: Automatic file lock handling + diff --git a/docs/advanced/contributing.md b/docs/advanced/contributing.md new file mode 100644 index 0000000..f61e570 --- /dev/null +++ b/docs/advanced/contributing.md @@ -0,0 +1,9 @@ +# Contributing to Parlant + +We use the Linux-standard Developer Certificate of Origin ([DCO.md](https://github.com/emcie-co/parlant/blob/develop/DCO.md)), so that, by contributing, you confirm that you have the rights to submit your contribution under the Apache 2.0 license (i.e., the code you're contributing is truly yours to share with the project). + +Please consult [CONTRIBUTING.md](https://github.com/emcie-co/parlant/blob/develop/CONTRIBUTING.md) for more details. + +Want to start getting involved right now? Join us on [Discord](https://discord.gg/duxWqxKk6J) and let's discuss how you can help shape Parlant. We're excited to work with contributors directly while we set up our formal processes. + +Otherwise, feel free to start a discussion or open an issue on [GitHub](https://github.com/emcie-co/parlant). diff --git a/docs/advanced/custom-llms.md b/docs/advanced/custom-llms.md new file mode 100644 index 0000000..6b7c39e --- /dev/null +++ b/docs/advanced/custom-llms.md @@ -0,0 +1,381 @@ +# Custom NLP Models + +Once you've understood the basic of setting up [engine extensions](https://parlant.io/docs/advanced/engine-extensions), you can integrate other NLP models into Parlant. + +> **A Note on Custom Models** +> +> Parlant was optimized to work with the built-in LLMs, so using other models may require additional configuration and testing. +> +> In particular, please note that Parlant uses some complex output JSON schemas in its operation. This means that you either need a powerful model that can handle complex outputs, or, alternatively, that you use a smaller model (SLM) that has been fine-tuned on Parlant data specifically, using a larger model as a teacher. +> +> Using smaller models is actually a great way to reduce costs, latency—and sometimes even accuracy—in production environments. + +## Understanding `NLPService` +Whether you want to use a different model from a supported built-in provider, or an entirely different provider, you can do so by creating a custom `NLPService` implementation. + +An `NLPService` has 3 key components: +1. **Schematic Generators**: These are used to generate structured content based on prompts. +2. **Embedders**: These are used to create vector representations of text for semantic retrieval. +3. **Moderation Service**: This is used to filter out harmful or inappropriate user input in conversations. + +> **Reference Example** +> +> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `NLPService`. + +### Schematic Generation +Throughout the Parlant engine, you'll find references to `SchematicGenerator[T]` objects. These are objects that generate [Pydantic](https://docs.pydantic.dev/latest/) models using instructions in a provided prompt. Behind the scenes, they always use LLMs to generate JSON schemas that in turn are converted to Pydantic models. + +All LLM requests in Parlant are actually made using these schematic generators, which means that, whatever model you use, it must be able to generate valid JSON schemas consistently. This is the only requirement for a model in Parlant. + +Let's now look at a few important interfaces that you need to implement in your custom NLP service. + +#### Estimating Tokenizers +The `EstimatingTokenizer` interface is used to estimate the number of tokens in a prompt. This is important for managing costs and rate limits when using LLM APIs. It's also used in embedding models, where Parlant needs to chunk the input text into smaller parts to fit within the model's context window. + +The reason it's called "estimating" is because not all model APIs provide exact token counts. + +```python +class EstimatingTokenizer(ABC): + """An interface for estimating the token count of a prompt.""" + + @abstractmethod + async def estimate_token_count(self, prompt: str) -> int: + """Estimate the number of tokens in the given prompt.""" + ... +``` + +For example, with `OpenAI`, you can implement this to use the `tiktoken` library to get accurate token counts for GPT models, or estimated token counts for other popular models. + +#### Schematic Generators +Now let's look at the `SchematicGenerator[T]` interface itself, which is used to generate structured content based on a prompt. + +Each generation result from a `SchematicGenerator[T]` contains not just the generated object, but also additional metadata about the generation process. Here's what it looks like: +```python +@dataclass(frozen=True) +class SchematicGenerationResult(Generic[T]): + content: T # The generated schematic content (a Pydantic model instance) + info: GenerationInfo # Metadata about the generation process + + +@dataclass(frozen=True) +class GenerationInfo: + schema_name: str # The name of the Pydantic schema used for the generated content + model: str # The name of the model used for generation + duration: float # Time taken for the generation in seconds + usage: UsageInfo # Token usage information + + +@dataclass(frozen=True) +class UsageInfo: + input_tokens: int + output_tokens: int + extra: Optional[Mapping[str, int]] = None # May contain metrics like cached input tokens +``` + +Now let's look at the `SchematicGenerator[T]` interface itself, which you'd need to implement for your custom model: + +```python +class SchematicGenerator(ABC, Generic[T]): + """An interface for generating structured content based on a prompt.""" + + @abstractmethod + async def generate( + self, + # The prompt (or PromptBuilder) containing instructions for the generation. + prompt: str | PromptBuilder, + # Hints are a good way to provide additional context or parameters for the generation, + # such as temperature, top P, logit bias, and things of that nature. + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + """Generate content based on the provided prompt and hints.""" + # Implement this method to generate content using your own model. + ... + + @property + @abstractmethod + def id(self) -> str: + """Return a unique identifier for the generator.""" + # Normally, this would be the model name or ID used in the LLM API. + ... + + @property + @abstractmethod + def max_tokens(self) -> int: + """Return the maximum number of tokens in the underlying model's context window.""" + # Return the maximum number of tokens that can be processed by your model. + ... + + @property + @abstractmethod + def tokenizer(self) -> EstimatingTokenizer: + """Return a tokenizer that approximates that of the underlying model.""" + # This tokenizer should be able to estimate token counts for prompts for this model. + ... + + @cached_property + def schema(self) -> type[T]: + """Return the schema type for the generated content. + + This is useful for derived classes, allowing them to access the concrete + schema type for the current instance without needing to know the type parameter. + """ + # You don't need to implement this method - it's an inherited convenience method. + orig_class = getattr(self, "__orig_class__") + generic_args = get_args(orig_class) + return cast(type[T], generic_args[0]) +``` + +> **Reference Example** +> +> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `SchematicGenerator[T]`. + +### Embedding +In addition to generating structured content, Parlant also uses embedders to create vector representations of text. These are used for semantic retrieval where applicable throughout the response lifecycle. + +#### Embedding Results +Every embedding operation returns an `EmbeddingResult`, which contains the vectors generated by the embedder: + +```python +@dataclass(frozen=True) +class EmbeddingResult: + vectors: Sequence[Sequence[float]] +``` + +#### Embedders +Now let's look at the `Embedder` interface and how to implement it: + +```python +class Embedder(ABC): + @abstractmethod + async def embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + # Generate embeddings for the given texts. + ... + + @property + @abstractmethod + def id(self) -> str: + # Return a unique identifier for the embedder - usually the model name or ID. + ... + + @property + @abstractmethod + def max_tokens(self) -> int: + # Return the maximum number of tokens in the model's context window. + ... + + @property + @abstractmethod + def tokenizer(self) -> EstimatingTokenizer: + # Return a tokenizer that approximates the model's token count for prompts. + ... + + @property + @abstractmethod + def dimensions(self) -> int: + # Return the dimensionality of the embedding space. + ... +``` + +> **Reference Example** +> +> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `Embedder`. + +### Moderation Services + +Parlant includes a comprehensive content moderation system to filter harmful or inappropriate user input. The moderation service is the third key component of an `NLPService`, alongside schematic generators and embedders. + +#### Understanding Moderation in Parlant + +Parlant's moderation system provides content filtering capabilities that can detect and flag various types of harmful content before it reaches your AI agents. The engine can integrate with all stsandard moderation providers and can be configured with different levels of strictness. + +#### Moderation Interface + +All moderation services implement the `ModerationService` abstract base class: + +```python +@dataclass(frozen=True) +class CustomerModerationContext: + """Context for moderation check""" + session: Session # Session context for the message being checked + message: str # The content of the message to check + +@dataclass(frozen=True) +class ModerationCheck: + """Result of a moderation check.""" + flagged: bool # Whether the content was flagged as inappropriate + tags: list[str] # Specific categories that were flagged + +class ModerationService(ABC): + """Abstract base class for content moderation services.""" + + @abstractmethod + async def moderate_customer(self, context: CustomerModerationContext) -> ModerationCheck: + """Check content for policy violations and return moderation result.""" + ... +``` + +#### Moderation Tags + +Parlant uses standardized moderation tags that map to common content policy categories: + +```python +ModerationTag: TypeAlias = Literal[ + "jailbreak", # Prompt injection attempts + "harassment", # Harassment or bullying content + "hate", # Hate speech or discrimination + "illicit", # Illegal activities or substances + "self-harm", # Self-harm or suicide content + "sexual", # Sexual or adult content + "violence", # Violence or graphic content +] +``` + +#### Implementing Custom Moderation Services + +Here's how to create your own moderation service: + +```python +import httpx +import parlant.sdk as p + +class MyModerationService(p.ModerationService): + def __init__(self, api_key: str, logger: p.Logger): + self._api_key = api_key + self._logger = logger + self._client = httpx.AsyncClient() + + async def moderate_customer(self, context: p.CustomerModerationContext) -> p.ModerationCheck: + """Implement your moderation logic here.""" + try: + # Example: Call your moderation API + response = await self._client.post( + "https://api.your-moderation-service.com/moderate", + json={"text": context.message}, + headers={"Authorization": f"Bearer {self._api_key}"} + ) + response.raise_for_status() + + result = response.json() + + # Map your service's response to Parlant's format + flagged = result.get("flagged", False) + categories = result.get("categories", []) + + # Convert your categories to Parlant's standardized tags + tags = [] + category_mapping = { + "toxic": "harassment", + "hate_speech": "hate", + "violence": "violence", + "sexual_content": "sexual", + "self_harm": "self-harm", + "illegal": "illicit", + "prompt_injection": "jailbreak", + } + + for category in categories: + if category in category_mapping: + tags.append(category_mapping[category]) + + return p.ModerationCheck( + flagged=flagged, + tags=tags, + ) + + except Exception as e: + self._logger.error(f"Moderation check failed: {e}") + # Fail closed: return unflagged to allow content through + # Or fail open: return flagged to block content + return p.ModerationCheck(flagged=False, tags=[]) +``` + +## Customizing Prompts +When you implement your own `SchematicGenerator[T]`, you can also customize the prompts it actually uses. + +This is achieved via the `PromptBuilder` class. It's the same class used throughout the Parlant engine to build prompts for LLMs using consistent rules and formats, and it allows you to access and modify prompt templates. + +One of the cool things you can do with it is to edit specific prompt sections right before you build the final prompt. + +Let's look at an example of how we'd override the draft creation prompt of the `CannedResponseGenerator`. + +```python +class MySchematicGenerator(p.SchematicGenerator[p.T]): + async def generate( + self, + prompt: str | p.PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> p.SchematicGenerationResult[T]: + def edit_draft_instructions(section: p.PromptSection) -> p.PromptSection: + # You can inspect the section's dynamically-passed properties + # to see what you can make use of in your modified template. + section.props + + section.template = f""" + Write your custom instructions here ... + Pass in dynamic props where needed: {section.props} + """ + + return section + + prompt.edit_section( + name="canned-response-generator-draft-general-instructions", + editor_func=edit_draft_instructions, + ) + + # Call the parent class's generate method with the modified prompt + return await super().generate(prompt, hints) +``` + +You can modify any section used anywhere within Parlant. You can find these sections by looking at references to `PromptBuilder.add_section()` in the Parlant codebase. + +## Implementing an `NLPService` +Now that you understand the key interfaces, you can implement your own `NLPService`. This is the easy part. + +Here's what that would look like: + +```python +class MyNLPService(p.NLPService): + def __init__(self, logger: p.Logger): + self.logger = logger + + async def get_schematic_generator(self, t: type[p.T]) -> p.SchematicGenerator[p.T]: + # Return your custom schematic generator for the given type. + return MySchematicGenerator[p.T]( + logger=self.logger, # Assuming you use a logger + ) + + async def get_embedder(self) -> p.Embedder: + return MyEmbedder( + logger=self.logger, # Assuming you use a logger + ) + + async def get_moderation_service(self) -> p.ModerationService: + # Return your custom moderation service implementation. + # If you don't need moderation, return NoModeration(). + return MyModerationService(logger=self.logger) +``` + +## Injecting a Custom `NLPService` +Once you've implemented your custom `NLPService`, you can easily register it with your Parlant server. + +You also get a reference to the dependency-injection container, from which you can access the system's logger and other services, as needed. + +```python +def load_custom_nlp_service(container: p.Container) -> p.NLPService: + return MyNLPService( + logger=container[p.Logger] + ) +``` + +Then, when you start your Parlant server, pass your loader function to the `nlp_service` parameter: + +```python +async with p.Server( + nlp_service=load_custom_nlp_service, +) as server: + # Your code here +``` diff --git a/docs/advanced/engine-extensions.md b/docs/advanced/engine-extensions.md new file mode 100644 index 0000000..9f23d93 --- /dev/null +++ b/docs/advanced/engine-extensions.md @@ -0,0 +1,132 @@ +# Engine Extensions + +Working with an external framework and adapting it to your needs isn’t always simple, especially when you need it to behave in ways its original design didn’t anticipate. +Modifying the framework’s source code is a treacherous path—not just because it requires deeper expertise, but also because it leads to divergences between your locally-modified version and upstream updates. + +So how do you get a pre-built framework to work differently? The idea is to be able to run a system or software that includes your code customizations without breaking its fundamental assumptions. + +The [Open/Closed Principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) states that software should be open for extension, but closed for modification, such that it can allow its behavior to be extended without modifying its source code. Parlant is carefully designed to abide by this principle, allowing you to achieve extreme extensibility by hooking into its structure. + +With extensions, you are free to build exactly what you need without waiting for updates or modifying core engine components. This is a good time to remind you that you can join our [Discord](https://discord.gg/duxWqxKk6J) community to ask questions. + +## Engine Hooks +Every time an agent needs to respond to a customer, the engine goes through a series of steps to generate the response. You can hook into these steps to modify the behavior of the engine. This is easily done by registering hook functions. + +While there are many hooks you can utilize, here's a simple example that: +1. Overrides the entire engine's response generation process if we detect that the customer only greeted the agent. +1. Inspects the agent's message for compliance breaches (using a custom checker) before sending it to the customer. + +```python +import asyncio +from typing import Any +import parlant.sdk as p + +async def intercept_message_generation_with_greeting( + ctx: p.LoadedContext, payload: Any, exc: Exception | None +) -> p.EngineHookResult: + if await is_only_greeting(ctx.interaction.last_customer_message): + await ctx.session_event_emitter.emit_message_event( + trace_id=ctx.tracer.trace_id, + data="Hello! How can I help you today?", + ) + return p.EngineHookResult.BAIL # Intercept the rest of the process + else: + return p.EngineHookResult.CALL_NEXT # Continue with the normal process + +async def check_message_compliance( + ctx: p.LoadedContext, payload: Any, exc: Exception | None +) -> p.EngineHookResult: + generated_message = payload + + if not await is_compliant(generated_message): + ctx.logger.warning(f"Prevented sending a non-compliant message: '{generated_message}'.") + return p.EngineHookResult.BAIL # Do not send this message + + return p.EngineHookResult.CALL_NEXT # Continue with the normal process + +async def configure_hooks(hooks: p.EngineHooks) -> p.EngineHooks: + hooks.on_acknowledged.append(intercept_message_generation_with_greeting) + hooks.on_message_generated.append(check_message_compliance) + + return hooks + +async def main(): + async with p.Server( + configure_hooks=configure_hooks, + ) as server: + # Your logic here + ... +``` + +## Dependency Injection +In order to extend the engine without modifying its source code, Parlant uses a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) system. This allows you to inject your own implementations of various components or even the processing engine itself (say, if you wanted to optimize the entire pipeline for particular use cases). + +For simplicity, we'll take a look at some basic extension mechanics, as well as common use cases for extension. + +However, if you need help with something that isn't covered here, please reach out to us on [Discord](https://discord.gg/duxWqxKk6J), [GitHub Discussions](https://github.com/emcie-co/parlant/discussions), or simply using the [Contact Page](https://parlant.io/contact) and we'll get back to you. + +### Working with the Container +Let's see how to work with Parlant's dependency injection container. The container is a central place where all components are registered, and you can use it to retrieve or register your own components. + +There are two things you might want to do with respect to the container: + +1. **Register your own components**: You can add your own implementations of various components to the container, making them available for injection throughout the application. +1. **Adjust the behavior of existing components**: You can retrieve instances of components from the container, allowing you to use them in your own code. + +#### Registering Components +Registering components lets you override nearly every aspect of how Parlant works. You can access the container during its registration phase by passing a `configure_container` hook to the server. + +This hook accepts a baseline state of the container, and returns a modified version of it before the server starts. + +```python +import asyncio +import parlant.sdk as p + +async def configure_container(container: p.Container) -> p.Container: + # Register your own components here + # ... + return container + +async def main(): + async with p.Server( + configure_container=configure_container, + ) as server: + # Your logic here + ... +``` + +#### Adjusting Existing Components +If you want to adjust the behavior of built-in components, you can retrieve them from the container and modify their behavior. This is useful for debugging or extending existing functionality without replacing the entire component. + +This hook is called `initialize_container`, and it allows you to modify components within the container after all of the classes have been registered and determined—but before the server actually starts to use them. + +This hook accepts the final state of the container, and returns `None`, as the container is only provided for _accessing_ registered components. + +```python +import asyncio +import parlant.sdk as p + +async def initialize_container(container: p.Container) -> None: + # Register your own components here + # ... + return container + +async def main(): + async with p.Server( + configure_container=configure_container, + ) as server: + # Your logic here + ... +``` + +## Open for Extension +If you read or debug Parlant code, you'll come across many different types of components within the engine. Using the configuration and initialization hooks, you now know how to access them and extend, modify, or completely override their implementations as needed. + +#### Common Use Cases for Extensions + +1. Overriding the no-match behavior of canned responses. This is actually documented here: [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses#no-match-responses). +1. Wrapping any engine component to add logging, monitoring, or other cross-cutting concerns. +1. Overriding the way particular guidelines are evaluated. For example, if they are simple and you have enough data, you can evaluate them with custom-trained BERT models instead of going through an LLM. +1. Overriding the entire message generation component, allowing you to leverage Parlant's guideline matching and tool execution, but using your message generation logic. + +But there's much more you can do. The engine is designed to be flexible and extensible, so you can adapt it to your specific needs without modifying the core codebase. diff --git a/docs/advanced/explainability.md b/docs/advanced/explainability.md new file mode 100644 index 0000000..5fde8a1 --- /dev/null +++ b/docs/advanced/explainability.md @@ -0,0 +1,58 @@ +# Enforcement & Explainability + +Let's dive into how Parlant enforces the conversation model consistently and provides visibility into your agent's situational understanding and decision-making process. + +In this section, you'll learn: + +1. How _Attentive Reasoning Queries (ARQs)_ enforce the conversation model +1. How to use ARQ artifacts to troubleshoot and improve behavior + +### Understanding Runtime Enforcement + +During message generation, Parlant ensures guidelines are followed consistently in real-time conversations through our [Attentive Reasoning Queries](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.) prompting method. Rather than simply adding guidelines to prompts and hoping for the best, Parlant employes explicit techniques to maximize the LLM's ability and likelihood to adhere to your guidelines. + +Attentive Reasoning Queries (ARQs) are essentially structured reasoning blueprints built into prompts that guide LLMs through specific thinking patterns when making decisions or solving problems. Rather than hoping an AI agent naturally considers all important factors, ARQs explicitly outline reasoning steps for different domains—like having specialized mental checklists to go through. + +What makes ARQs effective for behavioral enforcement is that they force attention on critical considerations that might otherwise be overlooked. The model must work through predetermined reasoning stages (like context assessment, solution exploration, critique, and decision formation), ensuring it consistently evaluates important constraints before taking action. + +![ARQs](https://arxiv.org/html/2503.03669v1/x1.png) + +**Figure:** Illustration of ARQs (taken from the [research paper](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.)) + +Besides increasing accuracy and conformance to instructions, this process creates, as a byproduct, transparent, auditable reasoning paths that help maintain alignment with desired behaviors. + +ARQs are flexible enough to adapt to different contexts and risk levels, with reasoning blueprints that can be tailored to specific domains or regulatory requirements. While there's some computational overhead to this more deliberate thinking process, carefully designed ARQs can beat Chain-of-Thought reasoning in both accuracy and latency. + +Parlant uses different sets of ARQs for each of its components (e.g., guideline matching, tool-calling, or message composition), and dynamically specializes the ARQs to the specific entity it's evaluating, whether it's a particular guideline, tool, or conversational context. + +Here's an illustrated example from the `GuidelineMatcher`'s logs: + +```json +{ + "guideline_id": "fl00LGUyZX", + "condition": "the customer wants to return an item", + "condition_application_rationale": "The customer explicitly stated that they need to return a sweater that doesn't fit, indicating a desire to return an item.", + "condition_applies": true, + "action": "get the order number and item name and them help them return it", + "action_application_rationale": [ + { + "action_segment": "Get the order number and item name", + "rationale": "I've yet to get the order number and item name from the customer." + }, + { + "action_segment": "Help them return it", + "rationale": "I've yet to offer to help the customer in returning the item." + } + ], + "applies_score": 9 +} +``` + +### Explaining and Troubleshooting Agent Behavior +Message generation in Parlant goes through quite a lot of quality assurance. As mentioned above, ARQs produce artifacts that can help explain how the agent interpreted circumstances and instructions. + +When you run into issues, you can inspect these artifacts to better understand why the agent responded the way it did, and whether it correctly interpreted your intentions. + +Over time, this feedback loop helps you build more precise and effective sets of guidelines. + +![Explainability in Parlant](https://parlant.io/img/explainability.gif) diff --git a/docs/concepts/customization/canned-responses.md b/docs/concepts/customization/canned-responses.md new file mode 100644 index 0000000..78b610d --- /dev/null +++ b/docs/concepts/customization/canned-responses.md @@ -0,0 +1,297 @@ +# Canned Responses + +Canned responses provide you with precise control over your Parlant agent's responses. + +The [concept of canned responses](https://en.wikipedia.org/wiki/Canned_response) comes from real-world contact centers, where they're widely used to ensure that agents communicate with customers in a consistent, accurate, and brand-aligned manner. + +By restricting to a pre-defined and pre-approved set of responses, you ensure your agent communicates with a consistent tone, style, and accuracy, aligning perfectly with your brand voice and service protocols while **completely eliminating the risk of even subtle unwanted or hallucinated outputs**. + +Canned responses function like a hand of cards: given a set of choices you provide to your agent, it selects the most appropriate "card" that best matches the required response based on the conversation context. + +![Cartoon1](https://parlant.io/img/utterance_cartoon_1.png) +![Cartoon2](https://parlant.io/img/utterance_cartoon_2.png) + +## A Practical Example + +#### Without Canned Responses +Using LLM-generated (token-by-token) responses. + +> **Customer:** Do you have it in stock? +> +> **Agent:** Yes, we've got this item in stock! Let me know if you need any help finding it. + +#### With Canned Responses +``` +# Draft message: "Yes, we've got this item in stock! Let me know if you need any help finding it." +# +# Available templates: +# - ... +# - "Hey, {{std.customer.name}}! What help do you need today?" +# - ... +# - "No, sorry, we've just sold the last ones. Would you like to see something similar?" +# - "Yep, we have it. Should I add it to your cart?" +# - ... +``` +> **Customer:** Do you have it in stock? +> +> **Agent:** Yep, we have it. Should I add it to your cart? + + +## How Canned Responses Work + +Under the hood, canned responses work in a 4-stage process: + +1. The agent drafts a fluid message based on its current situational awareness (interaction, guidelines, tool results, etc.) +2. The engine retrieves the most relevant canned response templates, based on the draft message +3. The engine renders the candidate templates, using tool-provided field substitutions where applicable +4. Based on the draft message, the agent selects the most fitting canned response out of the provided candidates + +```mermaid +flowchart LR + A[Draft Fluid Message] --> B[Retrieve Most Relevant Response Templates] --> C[Render Templates] --> D[Select Canned Response] +``` + + + +## Composition Modes + + +Parlant agents can use one of several **composition modes** in their responses. These composition modes offer varying levels of restriction on the agent's outputs, as well as the manner in which it uses your canned responses. + +| Mode | Description | Use Cases | +|------|-------------|-----------| +| **Fluid** | The agent prioritizes selecting from canned responses if a good match can be found, but falls back to default message generation otherwise. | **(A)** Staying mostly fluid, but controlling specific situations and responses where applicable<br/>**(B)** Prototyping an agent, generating fluid recommendations for additional utterances as you go | +| **Composited** | The agent will only use the canned response candidates to alter the generated draft message so as to mimic the style of the retrieved candidates | Brand-sensitive use cases where tone of voice is important to maintain | +| **Strict** | The agent can only output responses from the provided ones. If no matching response exists, the agent will send a customizable no-match message. | High-risk settings that cannot afford even the most subtle and infrequent hallucinations | + +> **Tip:** +> If you have a high-risk use case and are apprehensive about deploying GenAI agents to your customers, we recommend starting out with strict mode. Parlant is flexible and will allow you to easily transition to more fluid modes when you're ready. You will still maintain and utilize all other aspects of your conversation model as you switch between composition modes. + +### Setting an Agent's Composition Mode + +You just need to pass the right `composition_mode` when creating your agent: + +```python +await server.create_agent( + name="My Agent", + description="An agent that uses canned responses", + composition_mode=p.CompositionMode.STRICT, # or FLUID or COMPOSITED +) +``` + + +## Creating Canned Responses + +Here's how you can create canned responses for your agent: + +```python +await agent.create_canned_response(template=TEXT) +``` + +#### Journey-Scoped Responses + +You can also add **journey-scoped** responses. These are responses that are only available when a specific journey is active. Scoping your canned responses to journeys is useful for narrowing down the set of responses to choose from, increasing the chances of choosing the desired response. + +To do so, just call the `create_canned_response` method on a specific journey instance instead of the agent: + +```python +await journey.create_canned_response(template=TEXT) +``` + +#### Preamble Responses + +Parlant's employs multiple techniques to enhance the conversational user-experience by leveraging the principle of [perceived performance](https://en.wikipedia.org/wiki/Perceived_performance#:~:text=Perceived%20performance%2C%20in%20computer%20engineering%2C%20refers%20to%20how,The%20concept%20applies%20mainly%20to%20user%20acceptance%20aspects.). One of these techniques is the use of **preamble responses**. + +Parlant agents often send preamble responses (such as _"Got it."_, _"Understood."_, or _"Let me look into that"_) to acknowledge the customer's input while it's working on generating a detailed, accurate response. + +Normally, these preamble responses are automatically generated by the agent according to the context, but you can also create custom preamble responses for the agent to choose from. + +To create a canned preamble response, just add the `preamble()` tag in your canned response creation: + +```python +await agent.create_canned_response( + template="Sure thing.", + tags=[p.Tag.preamble()], +) +``` + +## Template Syntax + +Canned responses are defined using **templates**. Templates are strings that can contain static text, as well as dynamic fields that will be substituted with actual values when the response is selected. + +### Standard Fields + +Use standard fields (using the `std.` prefix) to display dynamic information from the conversation context: + +#### Available values +1. `std.customer.name`: String; The customer's name (or `Guest` for a non-registered [customer](https://parlant.io/docs/concepts/entities/customers)) +2. `std.agent.name`: String; The agent's name +3. `std.variables.NAME`: Any; The content of a variable named `NAME` +4. `std.missing_params`: List of strings; Contains the names of missing tool parameters (if any) based on [Tool Insights](https://parlant.io/docs/concepts/customization/tools#tool-insights-and-parameter-options) + +#### Example + +```python +await agent.create_canned_response( + template="Hi {{std.customer.name}}, Yes, this product is available in stock." +) +``` + +### Generative Fields +If you refer to a field with a `generative.` prefix, the LLM will auto-infer and substitute the value based on its name and the surrounding context. This is a great way to introduce controlled, localized generation into strict templates. + +#### Example + +```python +await agent.create_canned_response( + template="Can I ask why you'd like to return {{generative.item_name}}?" +) +``` + +### Tool/Retriever-Based Fields + +Canned responses can refer to fields coming from tool and retriever results. These fields must be specified in the `canned_response_fields` property of a `ToolResult` or a `RetrieverResult`. + +This is one of the most useful field types as they can introduce truly dynamic data into your canned responses. + +> **Warning: The Crucial Role of Fields in Avoiding Consequential Hallucinations** +> +> There's another great benefit to using tool-based fields in your canned responses. When retrieving candidate responses, the engine will also look at the `canned_response_fields` to determine relevance. +> +> Responses that refer to fields that aren't present in the context will never be selected, even if they're similar to the draft message. This is important, as it helps to ensure that the responses generated by the agent are grounded in the actual data available. +> +> For example, when using the strict composition mode, your agent could never output a message referring to a `{{successful_transaction.id}}` if the `successful_transaction` field was not provided by a successfully-run tool call. In other words, if you coordinate your responses and tools correctly, you can ensure your agent never hallucinates misleading responses about data or state. + +#### Example + +```python +@p.tool +def get_account_balance(context: p.ToolContext) -> p.ToolResult: + balance = 1234.5 + + return p.ToolResult( + # Note that you must still provide the result in the `data` field, + # as this is what will inform the agent when evaluating guidelines, + # calling tools, as well as when generating the draft message. + data={f"Account balance is {balance}"}, + # Here you provide dynamic values specifically for template field substitution + canned_response_fields={"account_balance": balance}, + ) +``` + +And this is how your response template would refer to this field: + +```python +await agent.create_canned_response(template="Your current balance is {{account_balance}}") +``` + +## Returning Full Responses from Tools +Tools can also return full canned responses for consideration. This is useful when you want to generate a complete response based on the tool's output, rather than just providing data for field substitution. It is usually particularly relevant for complex Q&A retrieval scenarios. + +```python +@p.tool +def get_answer(context: p.ToolContext, question: str) -> p.ToolResult: + answer = "The answer to your question is...." + + return p.ToolResult( + data=answer, + # Make the answer available as a complete canned response candidate + canned_responses=[answer], + ) +``` + +## Optimizing Response Selection + +Let's look at how you can ensure that your agent selects the right canned response. + +#### Controlling the Draft Message + +Because of how the selection process works, the first step to getting the right response delivered is to ensure that the draft message is generated as closely as possible to your desired response. You can achieve this using all of the standard control mechanisms, such as guidelines, journeys, tools, glossary terms, and agent description. + +This means you'll need to keep a close eye on what drafts are being generated prior to response selection. You can inspect the generated draft message in the integrated UI to see what the agent wanted to say. + +![View canned response draft](https://parlant.io/img/utterance_draft_demo.gif) + +#### Ensuring the Right Candidates Are Retrieved +Next, you need to ensure that your desired response templates are retrieved by the engine as candidates for selection. + +Sometimes, the response itself is close enough to the draft message to appear in the candidate list. But not always—especially if its template contains field substitutions which make semantic similarity comparisons harder. + +For this, you can use **signals** when creating canned responses. Signals are a way to tell your agent, "This response is a good match for these drafts." Each signal is essentially a draft message example. When retrieving candidate responses, the engine will also look at these signals to find determine relevance, so that if a response has a signal that's really close to the draft message, it will be retrieved as a candidate even if the response itself is quite different in form. + +Here's how you can add signals to your canned responses: +```python +await agent.create_canned_response( + template="Yes, we've got this item in stock! Let me know if you need any help finding it.", + signals=["We do have it in stock", "We do! Do you need help finding it?"], +) +``` + +## The Flexibility of Jinja2 + +Response templates integrate with the Jinja2 templating engine, enabling more dynamic formatting, substitution filters, as well as list processing. You can learn more advanced syntax on the [Jinja2 documentation site](https://jinja.palletsprojects.com/en/stable/). + +#### Example + +```python +@p.tool +def get_pizza_toppings(context: p.ToolContext) -> p.ToolResult: + toppings = ['olives', 'peppers', 'onions'] + + return p.ToolResult( + data={f"Toppings are {toppings}"}, + canned_response_fields={"toppings": toppings}, + ) +``` + +```python +await agent.create_canned_response( + template="We have the following toppings {% for t in toppings %}\n- {{t}}{% endfor %}" +) +``` + +## No-Match Responses + +When using strict composition mode, if the agent cannot find a suitable canned response for its draft, it will send a no-match response. + +If you want to customize this response, there are two ways to do so: + +1. Customizing the static no-match response +2. Using a custom no-match provider to dynamically generate the response according to the context + +#### Static No-Match Response +This is the simplest way to customize the no-match response. You can set a static no-match response that will be used whenever the agent cannot find a suitable canned response. + +```python +async def initialize_func(c: p.Container) -> None: + no_match_provider = c[p.BasicNoMatchResponseProvider] + no_match_provider.template = "My custom no-match response." + +async with p.Server( + initialize_container=initialize_func, +) as server: + ... +``` + +#### Custom No-Match Provider +If you need more flexibility, you can create a custom no-match response provider. This allows you to generate the no-match response dynamically based on the conversation context. + +However, please note that `p.LoadedContext` (which gives you access to internal engine state) is subject to change in future releases, so keep in mind you may need to adjust your implementation accordingly at some point. + +```python +class CustomNoMatchResponseProvider(p.NoMatchResponseProvider): + async def get_template(self, context: p.LoadedContext, draft: str | None) -> str: + # Generate a custom no-match response based on the provided context, + # such as the conversation history, draft message, guidelines, tool calls, etc. + template = "..." + + return template + +async def configure_func(c: p.Container) -> p.Container: + c[p.NoMatchResponseProvider] = CustomNoMatchResponseProvider() + +async with p.Server( + configure_container=configure_func, +) as server: + ... +``` diff --git a/docs/concepts/customization/glossary.md b/docs/concepts/customization/glossary.md new file mode 100644 index 0000000..535d818 --- /dev/null +++ b/docs/concepts/customization/glossary.md @@ -0,0 +1,104 @@ +# Glossary + +The glossary is a fundamental part of shaping your agent's understanding of its domain. It's like your agent's professional dictionary: a set of terms specific to your business or service context. + +### When to Use the Glossary +When you create an agent to handle specific tasks, it often needs to understand the unique vocabulary of your domain. For example, if your agent helps guests book rooms at the Boogie Nights hotel, it needs to know what "Boogie Nights" means in your context—in this case, that it's not just a movie title, but your hotel's name. + +#### Creating Glossary Terms +Here's how to create a new glossary term: + +```python +await agent.create_term( + name=TERM, + description=DESCRIPTION, + synonyms=[SYNONYM_1, SYNONYM_2, ...], +) +``` + + +### Structure of Terms +Each glossary entry consists of three components: + +> * **Term:** The word or phrase being defined +> * **Description:** What this term means in your specific context +> * **Synonyms:** Alternative ways users might refer to this term + +For example: +```python +await agent.create_term( + name="Boogie Nights", + description="Our luxury beachfront hotel located in Miami", + synonyms=["BN Hotel", "The Boogie", "Boogie Hotel"], +) +``` + +### How Agents Use the Glossary +The glossary serves two crucial purposes in agent interactions. + +First, it helps your agent understand customers better when they interact with it. When a guest says _"I'd like to stay at The Boogie,"_ the agent knows they're referring to your hotel. + +Second, it helps the agent interpret your guidelines correctly. Consider the following configuration: + +```python +await agent.create_guideline( + condition="the user asks about Ocean View rooms", + action="explain the Sunrise Package benefits", +) + +await agent.create_term( + name="Ocean View", + description="Our premium rooms on floors 15-20 facing the Atlantic", + synonyms=["seaside rooms", "beach view"], +) + +await agent.create_term( + name="Sunrise Package", + description="Complimentary breakfast and early check-in for Ocean View bookings", + synonyms=["morning special", "sunrise special"], +) +``` + +Here, both the condition as well as the action depend on the agent understanding what these terms mean. + +If the Customer comes in and asks, + +> **Customer:** I heard you have some rooms with a view to the Atlantic. What are those? + +The agent can understand, based on the glossary term, that the condition _"the user asks about Ocean View rooms"_ is met, and it can then respond with the action _"explain the Sunrise Package benefits"_. + +## Glossary vs Guidelines vs Agent Description +Each component serves a distinct purpose in shaping your agent's behavior: + +1. The Glossary teaches your agent "what things are". For example, _"A Club Member is a guest who has stayed with us more than 5 times."_ You can have as many terms as you want. +1. Guidelines teach your agent "how to act in situations". For example, _"When speaking with Club Members, acknowledge their loyalty status."_ You can have as many guidelines as you want. +1. Agent Description provides overall context and personality. For example, _"You are a helpful hotel booking assistant for Boogie Nights."_ The agent's description is static and limited. + +Think of it this way: the glossary builds your agent's vocabulary, guidelines shape its behavior, and the agent description sets its overall context, role, personality and tone. + +## Glossary vs Tools +While both glossary terms and tools help your agent understand your domain, they serve fundamentally different purposes. The glossary provides static knowledge, while tools enable dynamic data access. + +Consider a hotel booking scenario: + +**Glossary Term:** +> * **Term:** Club Member +> * **Description:** A guest who has stayed with us more than 5 times +> * **Synonyms:** loyal guest, regular guest + +**Tool:** +`check_member_status(user_id) # Returns current stay count and benefits` + +The glossary term provides a consistent definition of what a Club Member is, while the tool can check a specific user's actual status in your database. Similarly: + +**Glossary Term:** +> * **Term:** Ocean View Room +> * **Description:** Premium rooms on floors 15-20 facing the Atlantic +> * **Synonyms:** seaside room, beach view + +**Tool:** +`check_room_availability(room_type, dates) # Returns current availability and rates` + +The glossary helps your agent understand what an Ocean View Room is, while the tool provides real-time information about specific rooms' availability and pricing. + +This separation between static knowledge (glossary) and dynamic data access (tools) helps create clear, maintainable agent implementations that can handle both general inquiries and specific, data-driven interactions. diff --git a/docs/concepts/customization/guidelines.md b/docs/concepts/customization/guidelines.md new file mode 100644 index 0000000..cfa6f80 --- /dev/null +++ b/docs/concepts/customization/guidelines.md @@ -0,0 +1,201 @@ +# Guidelines + +Guidelines are a powerful customization feature. While they're quite simple in principle, there is a lot to say about them. + +### What Are Guidelines? +Guidelines are the primary way to nudge the behavior of [agents](https://parlant.io/docs/concepts/entities/agents) in Parlant in a contextual and targeted manner. + +They allow us to instruct how an agent should respond in specific situations, overriding its default behavior, thus ensuring that its behavior aligns with our expectations and business needs. + + Guidelines allow us to shape an [agent](https://parlant.io/docs/concepts/entities/agents)'s behavior in two key scenarios: + 1. When certain out-of-the-box responses don't meet our expectations + 1. When we simply want to ensure consistent behavior across all interactions + +> **Guidelines vs. Journeys** +> +> Journeys are the ideal way to provide a structured, step-by-step interaction flow, while guidelines are more about providing contextual nudges to the agent's behavior. Use journeys for complex interactions that require multiple steps, and guidelines for simpler, context-specific adjustments—as well as for simple, general tool-calling triggers that aren't necessarily within any particular journey. + +#### Example +Suppose we have an agent that helps customers order products. By default, the agent's behavior might look like this: +> **User:** I'd like to order a new laptop. +> +> **Agent:** Sure, what are your preferences? (e.g., budget, operating system, screen size, use cases?) + +But say we want to make our agent more personable by first having it ask simply whether they want Mac or Windows. We can add a guideline to ensure that this happens consistently, like so: + +```python +await agent.create_guideline( + condition="The customer wants to buy a laptop", + action="First, determine whether they prefer Mac or Windows" +) +``` + +Resulting in a conversation like this: + +> **User:** I'd like to order a new laptop. +> +> **Agent:** Sounds good. Would you prefer Mac or Windows? + +> **Careful What You Wish For** +> +> Instructing an LLM is very similar to instructing a human, except that by default it has absolutely zero context of who is instructing it and the context in which the instruction is given. For this reason, when we provide guidelines, we must strive to be as clear and articulate as possible, so that the agent can follow them without ambiguity. More about this later in this page. + +### The Structure of Guidelines +In Parlant, each guideline is composed of two parts: the **condition** and the **action**. + +1. The **action** part describes what the guideline should accomplish. For example, "Offer a discount." +1. The **condition** is the part the specifies _when the action should take place_. For example, "It is a holiday". + +```python +await agent.create_guideline( + condition="It is a holiday", + action="Offer a discount on the order" +) +``` + +When speaking informally about guidelines, we often describe them in _when/then_ form: When <CONDITION>, Then <ACTION>, or in this case, When it is a holiday, Then offer a discount. + +> **Guideline Tracking** +> +> Once the action is accomplished in a session, Parlant will deactivate the guideline—unless it has reason to believe the action should re-apply due to a contextual shift (e.g., in the example above, if the customer starts another order). + +### Using Tools + +One of the foremost issues with most LLMs is their bias toward false-positives. Put simply, they are always looking to please, so they will tend to answer positively to most questions. + +This becomes a huge problem when we want to ensure that an agent only performs certain actions when it has the right context or information. + +For this reasons, Parlant allows us to associate [tools](https://parlant.io/docs/concepts/customization/tools) (essentially, functions) with guidelines, such that the agent would only consider calling a tool when a guideline's requisite condition is met within the interaction's current context. + +Just as importantly, it also allows you to specify contextual information on *how* and *why* you want a particular tool to be called when certain circumstances hold. Here's an example: + +```python +@p.tool +async def find_products_in_stock(context: p.ToolContext, query: str) -> p.ToolResult: + ... + +await agent.create_guideline( + condition="The customer asks about the newest laptops", + action="First recommend the latest Mac laptops", + # The guideline's action will ensure the following tool is + # called with the right query (e.g., "Latest Mac laptops") + tools=[find_products_in_stock], +) +``` + + +## How Guidelines Work + +To understand how guidelines work, we need to look briefly at Parlant's response processing pipeline. + +When an agent receives a message, it goes through a response processing pipeline that involves several steps to ensure the response is aligned with the guidelines and expectations. + +```mermaid +graph LR + Engine -->|Match guidelines| GuidelineMatcher + GuidelineMatcher -->|Call associated tools| ToolCaller + ToolCaller -->|Compose message| MessageComposer + MessageComposer -.->|Generated response| Engine +``` + +As the figure above suggests, guidelines are evaluated and matched *before* the agent composes its response. + +> **Keep in Mind** +> +> This means that the agent needs to be able to evaluate and apply instructions and tool calls based on the interaction's context *before* generating the response. In other words, guidelines such as "Do X immediately after you've done Y" may not work as you expect. + +### How Parlant Uses Guidelines +LLMs are a magnificent creation, built on the principle of [statistical attention](https://arxiv.org/abs/1706.03762) in text; yet, their attention span is painfully finite. When it comes to following instructions, they need help. + +Behind the scenes, Parlant ensures that agent responses are aligned with expectations by dynamically managing the LLM's context to only include the relevant guidelines at each point. + +```mermaid +%%{init: {'sequence': {'mirrorActors': false}}}%% +sequenceDiagram + participant Engine + participant GuidelineMatcher + participant MessageComposer + + Engine ->> GuidelineMatcher: match guidelines + GuidelineMatcher -->> Engine: <guidelines> + Engine ->> MessageComposer: compose contextually guided message + MessageComposer -->> Engine: <guided message> +``` + +Before each response, Parlant only loads the guidelines that are relevant to the conversation's current state. This dynamic management keeps the LLM's "cognitive load" minimal, maximizing its attention and, consequently, the alignment of each response with expected behavior. + +> Another important ability that Parlant employs to ensure alignment is supervising the agent's outputs before they reach the [customer](https://parlant.io/docs/concepts/entities/customers), to ensure to the utmost degree that guidelines were correctly adhered to. To achieve this, NLP researchers working on Parlant have devised an innovative prompting technique called **Attentive Reasoning Queries (ARQs)**. You're welcome to explore the research paper on [arxiv.org, Attentive Reasoning Queries: A Systematic Method for Optimizing Instruction-Following in Large Language Models](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.). + +### Managing Guidelines +Parlant is built to make guideline management as simple as possible. + +Often, guidelines are added when business experts request behavioral changes in the agent. Developers can use Parlant to make those changes, iterating quickly and reliably, at the pace of the business experts they're working with. + +Here's a practical example. When Sales requests: "The agent should first ask about the customer's needs and pain points before discussing our solution," implementing this feedback takes just a minute by adding the following: + +```python +await agent.create_guideline( + condition="The customer has yet to specify their current pain points", + action="Seek to understand their pain points before talking about our solution" +) +``` + +Once added, Parlant takes care of the rest, automatically ensuring this new guideline is followed consistently across all relevant conversations, without degrading your agent's conformance to other guidelines. + +### Formulating Guidelines + +Think of an LLM as a highly knowledgeable stranger who's just walked into your business. They might have years of general experience, but they don't know your specific context, preferences, or way of doing things. Yet, this stranger is eager to help and will always try to—even when uncertain. + +This is where guidelines come in. They're your way of channeling this endless enthusiasm and broad knowledge into focused, appropriate responses. + +But specifying effective guidelines is a bit of an art—just like it is with people. + +#### The Art of Guidance + +Consider a customer service scenario. As a very naive example, we might be tempted to have: + +**DON'T** +> * **Condition:** Customer is unhappy +> * **Action:** Make them feel better + +While well-intentioned, this is an example of a guideline that is just too vague. The LLM might interpret this in countless ways, from offering discounts it can't actually provide to making jokes that might be inappropriate for your brand. Instead, consider: + +**DO** +> * **Condition:** Customer expresses dissatisfaction with our service +> * **Action:** Acknowledge their frustration specifically, express sincere empathy, and ask for details about their experience so we can address it properly. + +Notice how this guideline is both specific and bounded. + +**DON'T** +> * **Condition:** Customer asks about products +> * **Action:** Recommend something they might like + +**DO** +> * **Condition:** Customer asks for product recommendations without specifying preferences +> * **Action:** Ask about their specific needs, previous experience with similar products, and any particular features they're looking for before making recommendations + +#### Finding the Right Balance + +In principle, we're looking for guidelines that are "just right"—neither over nor under specified. Consider these iterations for a technical support agent: + +**DON'T** + +Too vague: +> * **Condition:** Customer has a technical problem +> * **Action:** Help them fix it + +**DON'T** + +Too rigid: +> * **Condition:** Customer reports an error message +> * **Action:** First ask for their operating system version, then their browser version, then their last system update date + +**DO** + +Just right: +> * **Condition:** Customer reports difficulty accessing our platform +> * **Action:** Express understanding of their situation, ask for key details about their setup (OS and browser), and check if they've tried some concrete troubleshooting steps + +Remember, LLMs will usually take your guidance quite literally. If you tell your agent to "always suggest premium features," it might do so even when talking to a customer who's complaining about pricing. Always try to consider the broader context and potential edge cases when formulating your guidelines. It'll pay off in less changes and troubleshooting down the line. + +**If in doubt, prefer to err on the side of vagueness.** The goal of Agentic Behavior Modeling isn't to script out every possible interaction but to provide clear, contextual guidance that shapes the LLM's natural generalization abilities into reliable, appropriate responses for your specific use case. diff --git a/docs/concepts/customization/journeys.md b/docs/concepts/customization/journeys.md new file mode 100644 index 0000000..aa8527d --- /dev/null +++ b/docs/concepts/customization/journeys.md @@ -0,0 +1,337 @@ +# Journeys + +There are many use cases where you want your agent to follow a specific flow of conversation, such as booking a trip, troubleshooting an issue, or otherwise guiding a user through a conversational process in the intended manner. + +In Parlant, this can be achieved easily and reliably using **Journeys**. + +#### Journey Structure + +Journeys have 4 important components: +1. **Title:** A short, descriptive name for the journey, to differentiate it from other journeys. +1. **Conditions:** These contextual queries determine when a journey should be active. +1. **Description:** This lets you describe the nature of the journey, including motivating or orientating notes, if needed. +1. **States & Transitions**: A state diagram that communicates to the agent what the ideal flow is. + +> **Balancing Rigidity vs. Flexibility** +> +> In traditional conversational frameworks, flows are rigidly defined, with each state and transition being strictly followed to the letter. +> +> While this type of approach is easy to reason about and implement, it very often leads to frustrating user experiences when the agent is unable to adapt to the customer's interaction patterns. This "one-size-fits-all" approach doesn't account for the nuances of human conversation—leading to user disengagement and dissatisfaction, and ultimately resulting in an unused agent. +> +> Parlant implements a "lessons learned" approach, allowing agents to traverse the journey's states in a more natural way. They can choose to skip states, revisit previous states, or even jump ahead to later states in an adaptive manner. +> +> As such, journeys are not meant to be followed rigidly, but rather to serve as a guiding framework for the agent. The agent will strive to follow the flow as strictly as it can, while still maintaining an adaptive approach toward the customer's interaction patterns. + +## A Worked Example + +Consider the following example for a journey in a travel agent: +> * **Title:** Book Flight +> * **Conditions:** The customer requested to book a flight +> * **Description:** This journey guides the customer through the flight booking process. + +```mermaid +%%{init: { "theme": "forest" }}%% +stateDiagram-v2 + direction LR + state "Where to?" as A + state "Dates?" as B + state "Load destinations" as Ca + state "Suggest" as Cb + state "Confirm" as E + state "Book" as F + state "Provide ticket" as G + [*] --> A + A --> Ca: Don't know + Ca --> Cb + A --> B: Destination provided + Cb --> B: Destination selected + B --> E + E --> F: Yes + E --> [*]: No + F --> G + G --> [*] + + style Ca fill:#ffeecc,stroke:#333,stroke-width:1px + style F fill:#ffeecc,stroke:#333,stroke-width:1px +``` + +This journey will be activated when the customer asks to book a flight. The agent will then strive to follow the flow while maintaining an adaptive approach at the pace of the customer, yet ensuring that all necessary information is collected. + +#### Implementing the Journey +Before we learn more about how journeys work, let's look at how we would implement the journey above: + +```python +async def create_book_flight_journey(agent: p.Agent): + journey = await agent.create_journey( + title="Book Flight", + conditions=["The customer requested to book a flight"], + description="This journey guides the customer through the flight booking process.", + ) + + t1 = await journey.initial_state.transition_to(chat_state="Ask if they have a destination in mind") + + # Branch out based on the customer's response + t2 = await t1.target.transition_to(condition="They do", chat_state="Get dates of travel") + + t3a = await t1.target.transition_to(condition="They don't", tool_state=load_popular_destinations) + t3b = await t3a.target.transition_to(chat_state="Recommend a destination") + + # Merge back to the main path after choosing a destination. + # This is done by transitioning into an existing state node. + await t3b.target.transition_to(state=t2.target, condition="Destination selected") + + t4 = await t2.target.transition_to(chat_state="Confirm details") + + t5a = await t4.target.transition_to(tool_state=book_flight) + t5b = await t5a.target.transition_to(chat_state="Provide ticket details") +``` + +## States and Transitions +A journey is modeled after a state diagram, which is a directed graph in which each node represents a **state** and each edge represents a **transition** (which may be associated with a condition). + +```mermaid +stateDiagram-v2 + direction LR + state "CHAT STATE" as A + state "TOOL STATE" as B + state "CHAT STATE" as C + state "CHAT STATE" as D + state "FORK STATE" as E + state "CHAT STATE" as F + state "CHAT STATE" as G + + [*] --> A: INITIAL + A --> B: CONDITIONAL + A --> C: CONDITIONAL + B --> D: DIRECT + C --> E: DIRECT + D --> E: DIRECT + E --> F: CONDITIONAL + E --> G: CONDITIONAL + F --> [*]: END + G --> [*]: END + + style B fill:#ffeecc,stroke:#333,stroke-width:1px +``` + +#### States +1. **Chat States:** While in this state, the agent will chat with the customer while being guided by the state's action. The agent may spend multiple turns in this state, until it decides to transition to another state. +```python +t = await state.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION) +``` +2. **Tool States:** In this state, the agent will call an external tool to perform an action and load its result into the context. A tool state must be followed by a chat state, which will usually be used to present the tool's result to the customer. +```python +t = await state.transition_to(tool_state=TOOL) +``` +```python +t = await state.transition_to(tool_state=TOOL, tool_instruction=OPTIONAL_HINT_ON_HOW_TO_USE_TOOL) +``` + +> **Transitioning from Tool to Chat** +> +> When transitioning from a tool state to a chat state, the agent will automatically load the tool's result into the context, so you can use it in the chat state's action. Note that a tool state cannot transition to another tool state; it must always be followed by a chat state. +> +> This is by design, as tool usage can incur noticeable latency in agentic applications. Instead of using sequential tool states, you should use a single tool state to perform all necessary actions, and then follow it with a chat state to present the results to the customer. + +#### Transitions +1. **Direct Transitions:** These transitions should always be taken. They move the conversation forward without branching. +2. **Conditional Transitions:** These transitions are only taken if/when their associated condition is met. +```python +t = await state.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION) +``` +```python +t = await state.transition_to(tool_state=TOOL, condition=CONDITION) +``` + +In most cases, you'd be using the `transition_to()` overload that takes a `chat_state` or `tool_state` argument, which will automatically create the transition's target state for you. However, you can also use the `transition_to()` overload that takes a `state` argument, which allows you to transition to an existing state node in the journey. + +```python +t = await state.transition_to(state=EXISTING_STATE) +``` +```python +t = await state.transition_to(state=EXISTING_STATE, condition=CONDITION) +``` + +> **Combining Conditional and Direct Transitions** +> +> If a state has a conditional transition to another state, it cannot also have a direct transition coming out of it. This is because the engine would not be able to logically determine which transition to take when the condition is met. The SDK enforces this rule. + +#### Fork States +Journeys also support a special kind of state, called a **fork state**. + +In this state, the agent will evaluate conditions and branch the conversation flow accordingly. While, strictly speaking, such branching can be modeled without fork states, they are sometimes a useful modeling tool for keeping the conversation flow clear, explicit, and organized. + +```python +fork = await state.fork() + +t1 = await fork.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION_1) +t2 = await fork.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION_2) +t3 = await fork.transition_to(tool_state=TOOL, condition=CONDITION_3) +``` + +> **Visualizing Your Journey** +> +> Building a state diagram in code can sometimes be a bit confusing. It's often useful to visualize the journey as you build it, to ensure that the flow is clear, logical, and as you intend. Here's how it's done: +> +> 1. Visit `http://localhost:8800/journeys` in your browser. +> 2. Copy the ID of the journey you want to visualize. +> 3. Visit `http://localhost:8800/journeys/<JOURNEY_ID>/mermaid` in your browser, replacing `<JOURNEY_ID>` with the ID you copied. +> 4. Copy the generated Mermaid diagram code. +> 5. Paste it into a [Mermaid live editor](https://mermaid.live/) to visualize the journey. + +## Journey vs. Task Automation +If you look at how the engine works with journeys, it means that journeys should not be used to guide the model on how to automate tasks. Instead, journeys are used by the agent to self-orientate and guide the conversation flow according to your preferences. + +This is a good time to recall the importance of separating **business logic** from **conversation logic**. The former is best handled by custom, [dedicated tools](https://parlant.io/docs/concepts/customization/tools) (which may or may not use LLMs internally), while the latter is best handled by the conversational engine. + +#### Do's and Don'ts + +**DON'T** + +The following is ***not*** a valid journey, as it does not represent a conversation flow but rather a task automation flow. + +```mermaid +stateDiagram-v2 + direction LR + state "Find user ID" as A + state "Load personal preferences" as B + state "Send email" as C + [*] --> A + A --> B + B --> C: Email notifications enabled + B --> [*]: Email notifications disabled + + style A fill:#ffeecc,stroke:#333,stroke-width:1px + style B fill:#ffeecc,stroke:#333,stroke-width:1px + style C fill:#ffeecc,stroke:#333,stroke-width:1px + +``` + +**DO** + +The following is a valid journey, as it represents a conversation protocol that guides the customer through a process. + +```mermaid +stateDiagram-v2 + direction LR + state "Ask for order number" as A + state "Get order details" as B + state "Process refund" as C + state "Transfer to human" as D + [*] --> A + A --> B + B --> C: Eligible for refund + B --> D: Not eligible for refund + C --> [*] + D --> [*] + + style B fill:#ffeecc,stroke:#333,stroke-width:1px +``` + +## Context Management + +LLMs are a magnificent creation, built on the principle of [statistical attention](https://arxiv.org/abs/1706.03762) in text; yet, their attention span is painfully finite. When it comes to following instructions, they need help. + +Behind the scenes, Parlant ensures that agent responses are aligned with expectations by dynamically managing the LLM's context to only include the relevant journeys at each point. + +It does this using the `GuidelineMatcher`, essentially matching the current conversation context with the relevant journeys' conditions—which, behind the scenes are basically observational (non-actionable) guidelines. + +```mermaid +%%{init: {'sequence': {'mirrorActors': false}}}%% +sequenceDiagram + participant Engine + participant GuidelineMatcher + participant JourneyStore + participant MessageComposer + + Engine ->> GuidelineMatcher: match guidelines + GuidelineMatcher -->> Engine: <guidelines> + Engine ->> JourneyStore: get journeys for matched conditions + JourneyStore -->> Engine: <journeys> + Engine ->> GuidelineMatcher: match journey states + GuidelineMatcher -->> Engine: <journey states> + Engine ->> MessageComposer: <journey states, guidelines> + MessageComposer -->> Engine: <well-guided message> +``` + +Before each response, Parlant only loads the guidelines and journeys that are relevant to the conversation's current state. This dynamic management keeps the LLM's "cognitive load" minimal, maximizing its attention and, consequently, the alignment of each response with expected behavior. + +> **Latency Optimizations** +> +> This back and forth approach is implemented in an optimized algorithm that minimizes response latency. +> +> The engine first tries to predict which journeys will be activated based on the current conversation context. Given this prediction, it attempts to match the relevant journeys' states in parallel to guideline matching, shaving seconds off the response latency. +> +> Only when this prediction fails (i.e., when other journeys were activated) does it incur the extra step to match their states, as well. + +## Journey-Scoped Guidelines + +You can add journey-scoped [guidelines](https://parlant.io/docs/concepts/customization/guidelines) that can only be activated when their dependent journeys are also active. At all other times, these guidelines would be ignored. + +Using journey-scoped guidelines is the recommended way to handle digressions from the journey's main flow in deliberate ways. It also helps you maintain a clean and organized conversation model, ensuring that certain guidelines are only evaluated and activated in their intended context. + +> **Instruction Precedence** +> +> Please note that, in general, Parlant agents give more weight to guidelines than to journey states, as guidelines are treated as more specific behavioral overrides. This means that, if a guideline is matched, it will tend to take precedence over the active journey states. + +```python +@p.tool +async def transfer_to_human_agent(context: p.ToolContext) -> p.ToolResult: + ... + +guideline = await journey.create_guideline( + condition="the customer says they're unable to pay" + action="connect them with a human agent", + tools=[transfer_to_human_agent], +), +``` + +> **Learn More** +> +> To learn more about guidelines, check out the [Guidelines](https://parlant.io/docs/concepts/customization/guidelines) page. + +## Journey-Scoped Canned Responses +You can also attach canned responses to journeys, scoping them to those journeys such that they will only be considered when their dependent journeys are active. + +```python +await journey.create_canned_response( + template="What destination are you interested in?", +) + +await journey.create_canned_response( + template="I'm sorry, but I can't assist with that right now. Shall we go on with booking your flight?", +) +``` + +#### State-Scoped Canned Responses +You can also associate specific canned responses with specific states within a journey. + +There are two modes for state-scoped canned responses: **Explicit Consideration** and **Exclusive Consideration**. + +1. **Explicit Consideration:** In this mode, the agent will ensure that the associated responses are always considered for selection when in that state. This is done by creating the canned response under the `journey` or `agent` objects. +```python +await state.transition_to( + chat_state="Ask if they have a destination in mind", + canned_responses=[ + await journey.create_canned_response( + template="What destination are you interested in?", + ), + ], +) +``` +2. **Exclusive Consideration:** In this mode, the agent will only consider the associated responses when in that state. It won't use these responses at any other time. This is done by creating the canned response under the `server` object. + +```python +await state.transition_to( + chat_state="Ask if they have a destination in mind", + canned_responses=[ + await server.create_canned_response( + template="What destination are you interested in?", + ), + ], +) +``` + +> **Learn More** +> +> To learn more about canned responses, check out the [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses) page. diff --git a/docs/concepts/customization/relationships.md b/docs/concepts/customization/relationships.md new file mode 100644 index 0000000..e5e1ca9 --- /dev/null +++ b/docs/concepts/customization/relationships.md @@ -0,0 +1,180 @@ +# Relationships + +Defining how **guidelines** and **journeys** relate to each other is a powerful (and advanced) part of behavior modeling. + +#### Background & Motivation + +Back in the day, our team was building a pizza-sales agent, which had the following guidelines (among others): +```python +offer_pepsi_instead_of_coke = await agent.create_guideline( + condition="The customer wants a coke", + action="Tell them we only have Pepsi", +) + +handoff_if_upset = await agent.create_guideline( + condition="The customer is becoming upset", + action="Apologize and tell them you will transfer them to a manager", + tools=[handoff_to_human_manager], +) +``` + +This initially worked well, until we encountered the following scenario: + +> **Agent:** Do you want anything to drink with your order? +> +> **User:** A coke please +> +> **Agent:** I'm sorry, we only have Pepsi. Would you like that instead? +> +> **User:** Wait, what? I hate Pepsi. Why the hell don't you have coke? +> +> **Agent:** I'm sorry for this inconvenience. Let me transfer you to a manager. Meanwhile, can I offer you a Pepsi? +> +> **User:** Are you taking the piss out of me? + +The agent's response was definitely not what we wanted, as it can come across as sarcastically hostile. But the poor AI agent was only following the guidelines we had given it, based on the conditions of the guidelines we had set. + +And here's the thing. You will find that managing instructions is not just a technical challenge, it's also a human modeling challenge. We must consider how our instructions relate to each other to an automatic agent who's expected to take them quite literally. How they should relate to each other in different contexts, especially in more nuanced situations, is something that ultimately only we can decide. + +In the case above, we wanted to ensure that the second guideline would be prioritized *over* the first one. We needed a priority relationship, which today, in Parlant, can be expressed quite simply, as follows: + +```python +await handoff_if_upset.prioritize_over(offer_pepsi_instead_of_coke) +``` + +## Relationship Kinds + +While these relationships might sound complex at first, they give you a ton of power as a modeler, making you much more capable of generating precise responses, consistently. + +We recommend reviewing these relationships briefly to understand their purpose. + +#### Relationship Types +These are the supported relationships. Each relationship is between a _source_ (notated **S**) and a _target_ (notated **T**). + +Click on a relationship type to learn more about it. + +- [Entailment](https://parlant.io/docs/guidelines/relationships#entailment): When **S** is activated, **T** should always be activated +- [Priority](https://parlant.io/docs/guidelines/relationships#priority): When both **S** and **T** are activated, only **S** should be activated +- [Dependency](https://parlant.io/docs/guidelines/relationships#dependency): When **S** is activated, deactivate it unless **T** is also activated +- [Disambiguation](https://parlant.io/docs/guidelines/relationships#disambiguation): When **S** is activated and two or more of the targets **T ∈ \{T₁, T₂, ...\}** are activated, ask the customer to clarify which action they want to take + +### Entailment +> When **S** is activated, **T** should always be activated + +```python +await source.entail(target) +``` + +To understand the need for entailment, we first need to understand how Parlant chooses which guidelines activate for an agent when it's about to say something to the customer. + +Basically, Parlant examines the session at its current state, and asks questions about it: "Is this guideline relevant now?", "Is that guideline relevant now?". + +To do this, it primarily tests the guidelines' _conditions_. + +This would seemingly work well by itself, until you consider two guidelines of the following form: + +> * **Guideline A:** When X, Then Y +> * **Guideline B:** When Y, Then Z + +Now imagine a situation where, looking at a session, we determine that _X_ does in fact apply, but _Y_ doesn't. With the naive logic above, we would have only fed the agent with the guideline to do _Y_. + +But when we step back and analyze this case, we know that the agent is just about to do _Y_, which means that, according to the guidelines we have installed, _Z_ should also apply. + +That is what entailment accomplishes: requiring that whenever _A_ is activated, _B_ is also activated. + + + +### Priority +> When both **S** and **T** are activated, only **S** should be activated + +```python +await source.prioritize_over(target) +``` + +Priority can be used for multiple use cases. The two most common ones are: +1. Creating mutually exclusive guidelines +1. Controlling the flow and precedence of actions within the conversation + +#### On Controlling Precedence +You may have two guidelines that happen to be activated at the same time, such as: +> * When the customer wants to make a transaction, Then guide them through the process to its completion +> * When the customer has less than $1,000 in their account, Then offer savings plans + +You may find that the guidelines above activate simultaneously when, for example, account balance details are introduced into the session while the user is in the process of submitting a transaction. + +To ensure that savings plans are offered—but with good timing, only once the transaction is completed—you can prioritize completing the transaction over offering savings plans. Once the transaction is completed, the savings-related guideline may be activated. + +### Dependency +> When **S** is activated, deactivate it unless **T** is also activated + +```python +await source.depend_on(target) +``` + +A dependency helps you ensure that a guideline is only activated if other baseline conditions also hold. + +The most common use cases is to ensure that more specific conditions are activated only in the proper baseline contexts. + +#### Contextualizing Specific Conditions + +When you're building flows, you can address specialized or edge-case scenarios by making them dependent on the flow baseline guideline. For example: + +##### Baseline Guideline +> When the customer wants to return an order, Then help them complete the return process + +##### Dependent Guidelines +> * When the customer isn't able to provide the order number, Then load up their last order's items and ask them to confirm if that is their order +> * When the customer specified the exact order number, Then load up that order's items and ask them to confirm if that is their order + +By making these guidelines dependent on the baseline guideline, you can ensure that their evaluation is always performed in the right context. + +### Disambiguation +> When **S** is activated and two or more of the targets **T ∈ \{T₁, T₂, ...\}** are activated, ask the customer to clarify which action they want to take + +```python +await source.disambiguate([target_1, target_2, ...]) +``` + +You may have a situation where between two (or more) competing guidelines where some or all of which are activated at the same time due to ambiguity, leading to instruction following confusions. + +For example, if a customer sent the message _"What are my limits?"_ to a banking agent, and you had the following guidelines, each of which was optimistically activated according to the engine's interpretation: + +> * When the customer is inquiring about their ATM limits, Then fetch the data from their account profile +> * When the customer is inquiring about their credit card's limits, Then fetch them from the card provider + +To clarify the customer's intent, you could add an [observational guideline](https://parlant.io/docs/guidelines/relationships#observational-guidelines) to disambiguate between the two actions: + +```python +ambiguous_limits = await agent.create_observation( + condition="The customer is inquiring about limits but it isn't clear which kind", +) + +await ambiguous_limits.disambiguate([fetch_atm_limits, fetch_credit_card_limits]) +``` + +> **Info: Observations** +> +> `Agent.create_observation()` is a shorthand for creating a guideline without an action. This guideline will still be matched in-context, but it carries no action to perform. It is useful for creating relationships between guidelines in specific scenarios, such as the example above. + +## Observational Guidelines +When modeling conversational edge cases, with relationships, you may find yourself wishing to add a guideline just to establish (using its condition) that particular circumstances apply, and—only in those cases—to activate or deactivate other guidelines or journeys using relationships. + +To this end, Parlant supports a special type of guideline called an **observational guideline**. This is a guideline that has no action, and is generally only used to establish that certain conditions apply, and to create relationships around them. + +```python +observation = await agent.create_observation(condition=CONDITION) +``` + +You can then use this observation in interesting ways, such as: + +1. Deactivating other guidelines by prioritizing the observation over them. +```python +await observation.prioritize_over(other_guideline) +``` + +2. Scoping other guidelines to only apply when the observation is active. +```python +await other_guideline.depend_on(observation) +``` + +And other creative uses! diff --git a/docs/concepts/customization/retrievers.md b/docs/concepts/customization/retrievers.md new file mode 100644 index 0000000..13c27ec --- /dev/null +++ b/docs/concepts/customization/retrievers.md @@ -0,0 +1,97 @@ +# Retrievers + +For pragmatic reasons, Parlant distinguishes between two modes of data access; namely, tools and **retrievers**. + +When developing customer-facing agents, there are practically two different use cases for fetching data: +1. **Tools**: Fetching data from specific services in response to specific events, such as user requests. +2. **Retrievers**: Fetching contextual information to ground, orientate, and align the agent's knowledge with respect to the current state of the conversation. This is traditionally referred to as RAG (Retrieval-Augmented Generation). + +A rule of thumb is to use **retrievers** for data that you would typically expect the agent "to know"—compared to tools, which are used for data that the agent needs to "load" or "do something with". + +**Use cases for retrievers include:** +- Fetching answers to common questions +- Fetching relevant documents or information based on the current conversation context +- Fetching user-specific data to personalize the agent's responses (see also [Variables](https://parlant.io/docs/concepts/customization/variables)) + +> **Tip: The Response Latency Trade-Off** +> +> Because retrievers are only used to ground the agent's knowledge within the current conversation's context, they can typically be executed in parallel with the agent's other tasks (such as guideline matching, tool calling, etc.). +> +> Hence, using retrievers allows you to ground your agent's response without the added latency of guideline matching or tool calls. + + +## Creating a Retriever +A retriever is a function that takes a `p.RetrieverContext` and returns a `p.RetrieverResult`. The `p.RetrieverContext` contains the current conversation context, and the `p.RetrieverResult` contains the data that the retriever has fetched. + +```python +async def my_retriever(context: p.RetrieverContext) -> p.RetrieverResult: + ... +``` + +#### Simple RAG Example +Here's a simple example of a retriever that fetches documents from a DB based on the customer's last message: + +```python +async def answer_retriever(context: p.RetrieverContext) -> p.RetrieverResult: + # Get the last message from the conversation + if last_message := context.interaction.last_customer_message: + # Use an embedder to convert the message into a vector + message_vector = my_embedder.embed(last_message.content) + # Fetch documents from the database based on the message vector + documents = await fetch_documents_from_db(message_vector) + + return p.RetrieverResult(documents) + + return p.RetrieverResult(None) +``` + +Alternatively, you could use an LLM to generate a query based on the entire interaction history: + +```python +async def answer_retriever(context: p.RetrieverContext) -> p.RetrieverResult: + if context.interaction.messages: + # Join all messages in the conversation to create a neat context + conversation_text = "\n".join(str(msg) for msg in context.interaction.messages) + + # Use an LLM to extract a user query from the conversation + if query := await my_llm.extract_user_query_from_conversation(conversation_text): + # Use an embedder to convert the query into a vector + message_vector = my_embedder.embed(query) + # Fetch documents from the database based on the query vector + documents = await fetch_documents_from_db(message_vector) + + return p.RetrieverResult(documents) + + return p.RetrieverResult(None) +``` + +#### Attaching a Retriever + +To actually get an agent to use your retriever, you need to attach it in the following manner: + +```python +await agent.attach_retriever(my_retriever) +``` + +You can also specify the retriever's ID, which is useful for debugging and logging purposes: + +```python +await agent.attach_retriever(my_retriever, id="my_retriever") +``` + + +## Retriever Result Lifespan + +The lifespan of retriever results is limited to the current response; in other words, it does not persist throughout the conversation. This also helps you keep the conversation context clean and focused, while also reducing average input tokens, throughout the conversation. + +## Retriever Context + +Using the retriever context, you can access a number of useful properties that can help you build more sophisticated retrievers: +- `server`: The server that is currently processing the retriever request, which can be useful for accessing server-specific resources or configurations. +- `container`: The dependency-injection container that is currently being used, which allows you to access services and resources registered in the container. +- `logger`: The logger that is currently being used, which can be useful for logging debug information or errors during the retriever's execution. +- `trace_id`: A unique identifier for the agent's current response, which can be used for tracking and debugging purposes. +- `interaction`: The current interaction, which contains the conversation history and other relevant information. +- `agent`: The agent that is currently processing the interaction. +- `customer`: The customer that is currently interacting with the agent. +- `variables`: The variables that are currently set for the interaction. diff --git a/docs/concepts/customization/tools.md b/docs/concepts/customization/tools.md new file mode 100644 index 0000000..d186c26 --- /dev/null +++ b/docs/concepts/customization/tools.md @@ -0,0 +1,434 @@ +# Tools + +Parlant provides a guided approach to tool usage, tightly integrated with its guidance system. + +Parlant's tool-calling approach is built from the ground up. It's probably more comprehensive than the tool-calling mechanisms you may be familiar with from most LLM APIs (including [MCP](https://modelcontextprotocol.io/introduction)). This is because it's built to enable a deep, seamless integration with its guidance-based behavior control. + +### Understanding Tool Usage +In Parlant, tools are always associated with specific guidelines. A tool only executes when its associated guideline is matched to the conversation. This design creates a clear chain of intent: guidelines determine when and why tools are used, rather than leaving it to the LLM's judgment (which is rife with errors). + +In Parlant, **business logic** (encoded in tools) is consciously separated from **presentation** (user interface) concerns, or the customer-facing behavior that is controlled by guidelines. + +This allows you to have developers work out API logic in code, with full control—offering these tools in the "tool shed" of an agent. Then, business experts can independently define natural-language guidelines that determine when and how these tools are used, without needing to get involved with the underlying code. This separation of concerns is a key design principle in Parlant, allowing for cleaner, more maintainable systems. + +#### Conversational UI vs. Graphical UI +As an analogy, you can think of Guidelines and Tools like Widgets and Event Handlers in Graphical UI frameworks. A GUI Button has an `onClick` event which we can associate with some API function to say, _"When this button is clicked, run this function."._ In the same way, in Parlant (which is essentally a Conversational UI framework) the Guideline is like the Button, the Tool is like the API function, and the association connects the two (like registering an event handler) to say, _"When this guideline is applied, run this tool."_ + +Here's a concrete example to illustrate these concepts: +> * **Condition:** The user asks about service features +> * **Action:** Understand their intent and consult the docs to answer +> * **Tools Associations:** `[query_docs(user_query)]` + +Here, the documentation query tool only runs after the guideline instructs that we should be consulting documentation for this user interaction. + + +## Writing Tools + +To write a tool, you need to define a function that takes a `ToolContext` as its first argument, followed by any other parameters you want to pass to the tool. The function should return a `ToolResult`. + +Here's the basic structure of any tool in a Parlant agent: + +```python +import parlant.sdk as p + +@p.tool +async def tool_name(context: p.ToolContext, param1: str, param2: int) -> p.ToolResult: + """Multi-line tool description. + This is readable by the agent and helps it decide if/when to run this tool. + """ + ... +``` + +To illustrate that more concretely, here's a simple example of a tool that fetches products into the agent's context: + +```python +import parlant.sdk as p + +@p.tool +async def find_products(context: p.ToolContext, query: str) -> p.ToolResult: + """Fetch products based on a natural-language search query.""" + + # Simulate fetching the balance from a database or API + products = await MY_DB.get_products(query=query) + + return p.ToolResult(balance) +``` + +#### Optional Parameters +You can also define optional parameters in your tool by using the `Optional` type from the `typing` module. This allows the tool to be called without providing a value for that parameter. + +```python +from typing import Optional +import parlant.sdk as p + +@p.tool +async def find_products( + context: p.ToolContext, + query: str, + limit: Optional[int] +) -> p.ToolResult: + default_limit = 10 + products = await MY_DB.get_products(query=query, limit=limit or default_limit) + + return p.ToolResult(products) +``` + +## Connecting Tools to Your Agent +To allow your agent to run a tool, you need to specify the conditions under which it may be evaluated and called. As stated above, this approach helps to eliminate false-positive tool calls, which is a common problem with LLMs. + +```python +@p.tool +async def my_tool(context: p.ToolContext) -> p.ToolResult: + ... + +await agent.create_guideline( + condition=CONDITION, + action=ACTION, + tools=[my_tool], +) +``` + +If you the tool itself implies the action, you can skip specifying it manually by letting Parlant figure it out from the tool's description. Here's how that would look: + +```python +await agent.attach_tool(condition=CONDITION, tool=my_tool) +``` + +## Tool Result +The `ToolResult` is a special object that encapsulates the result of a tool call. + +It has five properties you can use. While most of the time you will only use the `data` property, it's worth knowing about the others, as they enable interesting use cases: `data`, `metadata`, `control`, `canned_responses`, and `canned_response_fields`. + +> **Tool Result Lifespan** +> +> Unlike many general-purpose agent frameworks, Parlant is specifically and deliberately optimized for building conversational agents. As such, its architecture optimizes the default behavior of tool-calling for a conversational application. +> +> To this end, tool results are saved in the session by default, and are therefore available for the agent reference's throughout the entire interaction session. This means that subsequent guideline matching and tool calls are automatically informed by the previous results of tools. This is useful for results that need to be referenced later, such as account balances, item IDs, or other product information. +> +> For example, if you call a tool that returns product names and IDs, and—after the customer responds by selecting a specific product—you then call another tool that takes a `product_id` parameter, the agent will be able to use the previous tool's result to fill in that parameter automatically from context. For example: +> +> ```python +> @p.tool +> async def get_products(context: p.ToolContext, query: str) -> p.ToolResult: +> products = await MY_DB.get_products(query=query) +> return p.ToolResult(data=products) +> +> @p.tool +> async def get_product_details(context: p.ToolContext, product_id: str) -> p.ToolResult: +> # The agent will be able to parameterize the right `product_id` +> # if the previous tool call was already made in the session. +> product = await MY_DB.get_product(product_id=product_id) +> return p.ToolResult(data=product) +> ``` + + +### Tool Result Properties +Let's look at each of these properties, what they're used for, and how to use them: + + +#### Data +The `data` property contains the main output of the tool. This can be any JSON-serializable type, such as a string, list, or dictionary. + +This is the only property of the `ToolResult` that is _always_ required, as it is the only one that the agent uses to understand the history of interaction events. Meaning, if you don't return anything in the `data` property, the agent will not be informed about your result, and it will not be able to it to navigate the interaction. + +```python +# Example 1 +return p.ToolResult(data="This is the result of my tool call") + +# Example 2 +return p.ToolResult(data={"appointments": [ + { "id": "123", "date": "2023-10-01 10:00" }, + { "id": "456", "date": "2023-10-02 11:00" }, +]}) +``` + +#### Metadata +The `metadata` property is an optional dictionary that can be used to store additional information about the tool call. + +The agent is not aware of this metadata at all, but you can fetch it from the response using the REST API client. This makes it useful for sending back additional information about the response that can add value in your frontend. + +A classic use case here is to return RAG information sources (e.g., URLs, document IDs, etc.) that can be used to display the source of the information in the frontend. Another one is to return image links to generated charts or other visualizations that can be displayed in the frontend. + +```python +return p.ToolResult( + data=ANSWER, + metadata={ "sources": [{"url": s.url, "title": s.title} for s in ANSWER_SOURCES]}, +) +``` + +```python +return p.ToolResult( + data="The profit margin is 20%", + metadata={ "generated_chart_url": "https://example.com/chart.png" }, +) +``` + +> **Mind the Lifespan** +> +> Since metadata is primarily useful when accessing session events, it generally only makes sense to use it with `lifespan: "session"` (the default). If you use `lifespan: "response"`, the metadata will not be available in the session events, hence not accessible to the frontend. + +#### Control +The `control` property lets you specify control directives for the agent and the engine. + +There are currently two control directives you can use: +- `"mode": p.SessionMode`: This allows you to put the session in manual mode, which means the agent will not automatically generate responses. This is particularly useful for human-handoff scenarios, where you want to pause the agent's automatic responses and let a human operator take over. +- `"lifespan": p.Lifespan`: This controls how long the `ToolResult` should live. There are two options: + - `"session"`: The result will be saved and made available to the agent for the entire session. This is the default. + - `"response"`: The result will only be available for the current response. This is useful for temporary results that are not needed beyond the current response, such as reporting errors, or providing very transient information. + +```python +return p.ToolResult( + data="Transferring to a human agent", + # Once this tool result is returned, the agent will not generate any more responses + # until the session is put back on automatic mode using an API call. + control={ "mode": "manual" }, +) +``` + +```python +return p.ToolResult( + data="Encountered an error while fetching data", + # This tool result will not be saved in the session. + # The agent will only be aware of it during the current response. + control={ "lifespan": "response" }, +) +``` + +#### Canned Responses +Tools can also return complete canned responses for consideration, as well as fields to be substituted during canned response rendering. For more information about canned response properties, refer to the [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses) section. + +## Guideline Reevaluation Based on Tool Results + +In some cases, tool results can influence which guidelines become relevant. Here's an example: + +Consider a banking agent handling transfers. When a user requests a transfer, a guideline with the condition the user wants to make a transfer activates the `get_user_account_balance()` tool to check available funds. This tool returns the current balance, which can then trigger additional guideline matches based on its return value. + +For instance, if the balance is below $500, we might have a low-balance guideline activate, instructing the agent to say something like: _"I see your current balance is low. Are you sure you want to proceed with this transfer? This transaction might put you at risk of overdraft fees."_ + +In Parlant, you can mark certain guidelines for reevaluation after a tool call. This means that once the tool is called, the guideline matcher will re-evaluate the session to see if any new guidelines should be activated based on the tool's results—*after* running the tool but *before* generating the response. + +Here's how you can do that: + +```python +# The agent will ensure to reevaluate this guideline after running this tool +await guideline.reevaluate_after(my_tool) +``` + + +## Best Practices + +#### A Note on Natural Language Programming +While LLMs excel at conversational tasks, they struggle with complex logical operations and multi-step planning. Recent research in LLM architectures shows that even advanced models have difficulty with consistent logical reasoning and sequential decision-making. The "planning problem" in LLMs—breaking down complex tasks into ordered steps and synthesizing conclusions—remains a significant unsolved problem when consistently at scale is required. + +Given these limitations, Parlant takes a pragmatic approach: Separate logic in code from behavior modeling. Instead of embedding business logic in guidelines, Parlant encourages a clean separation between conversational behavior and underlying business operations. + +Consider your tools as your place for deterministic, programmatic business logic, and guidelines as your conversational interface design. This separation creates cleaner, more maintainable, and more reliable systems. + +> **Agentic API Design** +> +> To learn more about best-practices for designing your agent's tools, we recommend reading our blog post on [Agentic Backends](https://parlant.io/blog/what-no-one-tells-you-about-agentic-api-design). + +#### Examples + +**1. E-commerce Product Recommendations:** + +DON'T + +Complex business logic in guideline, over-relying on the LLM +> * **Guideline Action:** +> If user mentions sports, check their purchase history. +> If they bought running gear, recommend premium shoes. +> If they're new, suggest starter kit. +> * **Tool Associations:** `[get_product_catalog]` + +DO + +Logic goes in the coded recommendation engine, where it belongs + +> * **Guideline Action:** Offer personalized recommendations +> * **Tool Associations:** `[get_personalized_recommendations]` + +**2. Financial Advisory:** + +DON'T + +Financial analysis logic relies on unreliable LLM numeric comprehension +> * **Guideline Action:** Check account balance and recent transactions. + If spending exceeds 80% of usual pattern, suggest budget review. + If investment returns are down, recommend portfolio adjustment. +> * **Tool Associations:** `[get_account_data]` + +DO + +Financial analysis logic is handled reliably in code + +> * **Guideline Action:** Get personalized financial insights +> * **Tool Associations:** `[get_financial_insights]` + + +## Tool Context + +The `ToolContext` parameter is a special object that provides the tool with contextual information and utilities. + +Let's look at some of the most useful attributes and methods available in the `ToolContext`: + +1. `agent_id`: The unique identifier of the agent that is calling the tool. +2. `customer_id`: The unique identifier of the customer interacting with the agent. +3. `session_id`: The unique identifier of the current session. +4. `emit_message(message: str)`: A method to send a message back to the customer. This can be used to report progress during a long-running tool call. +5. `emit_status(status: p.SessionStatus)`: A method to update the [session status](https://parlant.io/docs/concepts/sessions#status-event). + +#### Accessing Server Objects (Agent, Customer, etc.) + +You can also access the server object from the `ToolContext`, giving you access to your agents, guidelines, and other server-level resources. + +To access the server object, use `p.ToolContextAccessor` as follows: + +```python +import parlant.sdk as p + +@p.tool +async def my_tool(context: p.ToolContext) -> p.ToolResult: + server = p.ToolContextAccessor(context).server + + # Access the current agent using the agent_id from the context + agent = await server.get_agent(id=context.agent_id) + + # Access the current customer + customer = await server.get_customer(id=context.customer_id) + + # ... + + return p.ToolResult(...) +``` + +#### Secure Data Access + +Suppose you need to build a tool that retrieves or displays data private to different customers. + +A naive approach would be to ask the customer to identify themselves and use that as an access token into the right data. But this approach is highly insecure, as it relies on the LLM for identifying the user. The LLM can get it wrong or, worse yet, be manipulated by malicious users. + +A better and more reliable way to do this is to [register your customers](https://parlant.io/docs/concepts/entities/customers#registering-customers) with Parlant and use the information available programmatically, which is contained in the `ToolContext` parameter of your tool. + +Here’s how that would look in practice: + +```python +@p.tool +async def get_transactions(context: p.ToolContext) -> p.ToolResult: + transactions = await DB.get_transactions(context.customer_id) + return p.ToolResult(transactions) +``` + +## Tool Insights and Parameter Options + +Because Parlant's architecture is radically modular, components like guideline matching, tool calling and message composition operate independently. While this non-monolithic approach offers many advantages in managing its complex semantic logic, it also requires it to communicate contextual awareness across these components. + +**Tool Insights** is a bridging component between tool calling and message composition, ensuring the composition component is informed when a tool couldn't be called for some reason—for example, due to missing required parameters. + + +This allows the agent to respond more intelligently. For example, if it had no knowledge of when an appropriate tool couldn't be called, it might generate a misleading response. But with tool insights, the agent recognizes missing information and, if needed, can prompt the customer for the required tool arguments automatically. + +#### Tool Parameter Options + +To allow you to enhance the baseline behavior of Tool Insights, you can make use of **ToolParameterOptions**, a special parameter annotation which adds more control over how tool parameters are handled and communicated. + +While Tool Insights helps the agent recognize when and why a tool call fails, **ToolParameterOptions** goes a step further by guiding the agent on when and how to explain specific missing parameters. + +```python +from typing import Annotated +import parlant.sdk as p + +@p.tool +async def transfer_money( + context: p.ToolContext, + amount: Annotated[float, p.ToolParameterOptions( + source="customer", # Only the customer can provide this value - the agent cannot infer it + )], + recipient: Annotated[str, p.ToolParameterOptions( + source="customer", + )] +) -> ToolResult: + # ... +``` + +The **ToolParameterOptions** consists of several optional arguments, each refining the agent’s understanding and application of the parameter: + +- `hidden` If set to `True`, this parameter will not be exposed to message composition. This means the agent won't notify the customer if it’s missing. It's commonly used for internal parameters like opaque product IDs or any other information that should remain behind the scenes. + +- `precedence` When a tool has multiple required parameters, the tool insights communicated to the customer can be overwhelming (e.g., asking for 5 different items in a single message). Precedence lets you create groups (which share the same value) such that the customer would only learn about a few (the ones sharing a precedence value) at a time—in the order you choose. + +- `source` Defines the source of the argument. Should the agent request the value directly from the customer ("customer"), or should it be inferred from the surrounding context ("context")? +If not specified, the default is "any", meaning the agent can retrieve it from anywhere. + +- `description` This helps the agent interpret the parameter correctly when extracting its argument from the context. Fill this if the parameter name is ambigious or unclear. + +- `significance` A customer-facing description of why this parameter is required. This helps customers understand and relate to what information they need to provide and why. + +- `examples` A list of sample values illustrating how the argument should be extracted. This is useful for enforcing formats (e.g., a date format like "YYYY-MM-DD"). + +- `adapter` A function that converts the inferred value into the correct type before passing it to the tool. If provided, the agent will run the extracted argument through this function to ensure it matches the expected format. Use when the parameter type is a custom type in your codebase. + +- `choice_provider` A function that provides valid choices for the parameter's argument. Use this to constrain the agent to dynamically choose a value from a specific set returned by this function. + + +## Parameter Value Constraints + +In cases where you need a tool's argument to fall into a specific set of choices, Parlant can help you ensure that the tool-call is parameterized according to those choices. There are three ways to go about it: + +1. Use enums when you are able to provide hard-coded choices +1. Use `choice_provider` when the choices are dynamic (e.g., customer-specific) +1. Use a Pydantic model when the parameter follows a more complex structure + +#### Enum Parameters +Specify a fixed set of choices that are known ahead of time, using an `Enum` class. + +```python +import enum + +class ProductCategory(enum.Enum): + LAPTOPS = "laptops" + PERIPHERALS = "peripherals" + MONITORS = "monitors" + +@p.tool +async def get_products( + context: p.ToolContext, + category: ProductCategory, +) -> p.ToolResult: + # your code here + return p.ToolResult(returned_data) +``` + +#### Choice Provider +Dynamically offer a set of choices based on the current execution context. + +```python +async def get_last_order_ids(context: p.ToolContext) -> list[str]: + return await load_last_order_ids_from_db(customer_id=context.customer_id) + +@p.tool +async def load_order( + context: p.ToolContext, + order_id: Annotated[Optional[str], p.ToolParameterOptions( + choice_provider=get_last_order_ids, + )], +) -> p.ToolResult: + # your code here + return p.ToolResult({...}) +``` + +#### Pydantic Model +Use a Pydantic model to define a complex structure for the parameter, which can include validation and constraints. +```python +from pydantic import BaseModel + +class ProductSearchQuery(BaseModel): + category: str + price_range: tuple[float, float] + +@p.tool +async def search_products( + context: p.ToolContext, + query: ProductSearchQuery, +) -> p.ToolResult: + # your code here diff --git a/docs/concepts/customization/variables.md b/docs/concepts/customization/variables.md new file mode 100644 index 0000000..3c4dfbc --- /dev/null +++ b/docs/concepts/customization/variables.md @@ -0,0 +1,133 @@ +# Variables + +Every customer is unique, and your agent may choose to treat them as such where appropriate. + +Variables enrich the context that an agent sees about the customer it's talking to. They're meant to give your agent awareness to information that helps it personalize its service, much like how a thoughtful customer service representative knows and remembers important details about each client, to make them feel heard and understood. + +When a customer interacts with an agent, their variables are automatically loaded into its context, allowing the agent to tailor its responses based on their specific situation. + +### Real World Applications +Let's walk through how variables transform customer interactions. Imagine you're running a SaaS platform's support agent. You might track variables like subscription plan, last login date, which features each customer uses, and their company size. + +Consider two different customers reaching out about data exports. Sarah, a startup founder on the free plan, asks "Can I export my data to Excel?" Your agent, aware of her free plan status, can respond thoughtfully: "While Excel export is a premium feature, I can show you how to use our basic CSV export. Would you also like to learn about the advanced reporting capabilities in our premium plan?" + +Now imagine Tom from an enterprise account reaches out with the same question. The agent sees his enterprise status but also notices his team hasn't explored many advanced features. It might respond: "I'll help you with Excel exports! I notice your team hasn't tried our automated reporting suite yet - this is included in your enterprise plan and could save you hours each week. Would you like me to show you both features?" + + +### Working with Variables + +A single variable identifies a particular piece of information. For example, you might create a variable called `"subscription_plan"`. + +Each customer can then have a unique value assigned to them under that variable. For example, Tom might have `"enterprise"` as the variable's value. + +There are two ways to set variable values. + +1. Set their values manually +2. Attach them to a tool that automatically retrieves a value based on dynamic data + +#### Creating Manually Set Variables + +```python +variable = await agent.create_variable( + name=NAME, + description=DESCRIPTION, +) +``` + +#### Creating Tool-Enabled Variables +A variable that's associated with a tool will automatically update its value based on the tool's output. This is useful for dynamic data that changes frequently and of which the agent always needs to be aware. + +Suppose you have the following tool: +```python +@p.tool +async def get_variable_value(context: p.ToolContext) -> p.ToolResult: + ... +``` + +You can then create an auto-updating variable based on this tool as follows: + +```python +variable = await agent.create_variable( + name=NAME, + description=DESCRIPTION, + tool=get_variable_value, +) +``` + +By default, the associated tool would update the variable's value before every agent response. If this frequent reload of data is unnecessary, you can control the refresh interval of the value (controlling how often the associated tool is called to generate a fresh value) by specifying its _freshness rules_. + +```python +variable = await agent.create_variable( + name=NAME, + description=DESCRIPTION, + tool=get_variable_value, + freshness_rules=CRON_EXPRESSION, +) +``` + +Freshness rules follow the [cron expression](https://en.wikipedia.org/wiki/Cron) syntax. If you're new to cron, you can use tools like [crontab generator](https://crontab.cronhub.io/) to help you define the period syntax more easily. + +> **Manual Values** +> +> Even tool-enabled variables can have their values set manually, if needed. This is useful for when you want to override the tool's output for specific customers or customer groups. + +#### Setting a Variable Value for a Customer + +```python +await variable.set_value_for_customer( + customer=CUSTOMER, + value=VALUE, +) +``` + +#### Setting a Variable Value for a Customer Group +You can also set the value of a variable for a [customer group](https://parlant.io/docs/concepts/entities/customers#customer-groups) by specifying the group's tag. + +```python +await variable.set_value_for_tag( + tag=TAG_ID, + value=VALUE, +) +``` + + +## Working Example +Here's how we'd implement a subscription plan variable. + +```python +@p.tool +async def get_subscription_plan(context: p.ToolContext) -> p.ToolResult: + # Fetch the customer's subscription plan from your database + return p.ToolResult(await get_plan_from_database(context.customer_id)) +``` + +```python +variable = await agent.create_variable( + name="subscription_plan", + description="The customer's subscription plan", + tool=get_subscription_plan, +) + +await variable.set_value_for_customer( + customer=p.Customer.guest(), + value="Free Plan", # Default value for non-registered customers +) +``` + + +### Combining Context Variables with Guidelines + +Let's explore how guidelines and context variables work together to create truly intelligent interactions. Imagine you're running an AI support agent for a digital bank where customers have different account tiers and transaction patterns. + +Here's a focused guideline: + +```python +await agent.create_guideline( + condition="the customer's account_tier is 'basic' " + "AND they ask about instant international transfers", + action="highlight our same-day domestic transfers that are free on their plan, " + "then mention how the premium tier enables instant global payments with lower fees", +) +``` + +When Mark, who is on the basic tier, asks about sending money to his daughter studying abroad, instead of a flat "that's premium only" response, he hears: "I can help you send that money today using our standard international transfer. By the way, our premium accounts get this done instantly with lower fees—would you like to know more?" diff --git a/docs/concepts/entities/agents.md b/docs/concepts/entities/agents.md new file mode 100644 index 0000000..dd68e6f --- /dev/null +++ b/docs/concepts/entities/agents.md @@ -0,0 +1,61 @@ +# Agents + +In Parlant, an agent is a customized AI personality that interacts with customers as a single, competent entity. It is essentially, "the one you talk to", as opposed to some frameworks where an agent is a specialized task function. + +Agents form the basic umbrella of conversational customization—all behavioral configurations affect agent behavior. + +```python +import parlant.sdk as p + +async with p.Server() as server: + hexon = await server.agents.create( + name="Hexon", + description="Technical support specialist" + ) + + # Continue to model the agent's behavior using guidelines, journeys, etc.... +``` + +> **Note:** +> +> Note that a single Parlant server may host multiple agents, each with distinct roles and personalities. + +Each agent can be uniquely configured with its own style, demeanor, and interaction patterns tailored to its target users. More importantly, different business units can own and maintain their specific agents. For example: +* IT Department manages **Hexon** +* Customer Success team oversees **Sprocket** +* Sales/Marketing controls **Piston** + +This agent-based design creates natural boundaries for separation of concerns within Parlant + + +### Crafting an Agent's Identity +Imagine you're creating a new employee who will become the voice of your service. Just as you'd carefully consider the personality and approach of a human hire, crafting an agent's identity ultimately requires thoughtful consideration of its core characteristics—and, like any good hire, you can grow and adapt it based on real-world feedback. + +As an example, let's follow the possible evolution of **Hexon**, our technical support specialist. In its first iteration, we might simply define it as "a technical support agent who helps users solve technical problems professionally and efficiently." After observing some interactions, we might notice that it comes across as too mechanical, failing to build trust with users. + +So we refine its identity: + +> "A technical support specialist who combines deep technical knowledge with patient explanation. You take pride in making complex concepts accessible without oversimplifying them. While you're always professional, you communicate with a warm, approachable tone. You believe that every technical issue is an opportunity to help users better understand their tools. When users are frustrated, you remain calm and empathetic, acknowledging their challenges while focusing on solutions." + +As we observe more interactions, we might further refine this general identity. Perhaps we notice users respond better when Hexon shows more personality, or maybe we find certain technical discussions need more gravitas. The identity can evolve with these insights. + +The key is to start with an identity that gives the agent its basic orientation, but remain open to refinement based on real interactions. Watch how users respond to the agent's mannerisms. Gather feedback from stakeholders. Adjust the identity accordingly. + + +### A Single Agent or Multiple Agents? +There's a frequent debate on whether to model user-facing agents as a single agent or multi-agent system. Parlant's position is a mix of both. + +Generally speaking, managing complexity is easier when our solutions model the real world, because it makes us naturally have much more data with which to reason about design decisions, rather than trying to come up with something contrived. So instead of asking a very fundamental, "How should users interact with this agent?" we can instead ask something much more fruitful, like, "What would user expect based on their real-life experience?" + +In practice, when we interact with human service representatives, there are certain expectations we've come to have from such experiences: +- If we're talking to an agent, they have the full context of our conversation. They're coherent. They don't suddenly just forget or unexpectedly change their interpretation of the situation. +- The agent we're talking to may not always be able to help us with everything. We may need to be transferred to another agent who specializes in some topic. +- We expect to be notified of such transfers. If they happen suddently or without our awareness, we take that as a careless customer experience. + +You can see how insights from familiar, real-world usage patterns help us arrive at informed design decisions. By modeling agent interactions on real-world patterns, we not only better understand what outcomes to strive for, but it turns out that managing our agents' configuration becomes easier to reason about, too. + +This is why Parlant's formal recommendation is to model AI agents after how human agents work. In other words, if you can see it being a single personality in a real-life use case, that means it should be represented as a single AI agent in Parlant. Incidentally, Parlant's filtration of relevant elements of the agent's conversation model allow you to manage quite a lot of complexity in a single agent, so you don't need to adopt a multi-agent approach if that was your concern. + +> **Tip: The Failures of Multi-Agent Systems** +> +> There's an interesting paper on the [failures of multi-agent systems](https://arxiv.org/abs/2503.13657#:~:text=We%20present%20MAST%20%28Multi-Agent%20System%20Failure%20Taxonomy%29%2C%20the,over%20200%20tasks%2C%20involving%20six%20expert%20human%20annotators), despite their promise of modularity and specialization. It highlights how multi-agent systems often struggle with coordination, communication, and consistency, leading to unexpected behaviors and failures. This aligns with Parlant's approach of using a single agent to maintain coherence and context in conversations. diff --git a/docs/concepts/entities/customers.md b/docs/concepts/entities/customers.md new file mode 100644 index 0000000..db2f3cb --- /dev/null +++ b/docs/concepts/entities/customers.md @@ -0,0 +1,135 @@ +# Customers + +In Parlant, a **customer** is a code word for anyone who interacts with an agent—regardless of the real nature of the relationship between them. In other words, a customer can be a real person, a bot, or even a human agent. + +While agents can operate anonymously (without knowing who they're talking to), Parlant allows you to track registered customers and provide deeply personalized experiences based on their identity and preferences. + +By letting your agents understand who they're talking to, you can tailor interactions for different user segments: high-profile customers might receive premium offers, new users can get focused onboarding guidance, and so forth... + +Parlant makes customer registration simple, requiring only minimal identification—a name is enough to get started. + +```python +import parlant.sdk as p + +async with p.Server() as server: + # Register a new customer + customer = await server.create_customer(name="Alice") +``` + +## Authentication +Parlant aims to live as a backend service, leaving authentication and authorization to the application layer. This means that while you can register customers, you should handle their authentication (e.g., via OAuth, JWT, etc.) in your application code, in whatever way suits your needs. + +Once you have identified your customer, then you can pass their ID to the agent, allowing it to personalize interactions based on the registered customer. + +## Storage +You can choose where you store customers. + +By default, Parlant does not persist customers, meaning that they are stored in memory and will be lost when the server restarts. This is useful for testing and development purposes. + +If you want to persist customers, you can configure Parlant to use a database of your choice. For local persistence, we recommend using the integrated JSON file storage, as there's zero setup required. For production use, you can use MongoDB, which comes built-in, or another database. + +### Persisting to Local Storage +This will save customers under `$PARLANT_HOME/customers.json`. + +```python +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server(customer_store="local") as server: + # ... + +asyncio.run(main()) +``` + +### Persisting to MongoDB +Just specify the connection string to your MongoDB database when starting the server: + +```python +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server(customer_store="mongodb://path.to.your.host:27017") as server: + # ... + +asyncio.run(main()) +``` + +## Customer Groups + +You can also divide your customers into different groups and control group-specific personalization by using **tags**. + +For example, you can create a tag for VIP customers: + +```python +# Create a new tag to represent VIP customers +vip_tag = await server.create_tag(name="VIP") + +# Register a new customer +customer = await server.create_customer(name="Alice", tags=[vip_tag.id]) +``` + +> **Tip: Learn More** +> To learn more about advanced personalization possibilities for specific customers and groups, check out the [variables](https://parlant.io/docs/concepts/customization/variables) section. + +## Adding Metadata +You can also attach custom metadata to customers, which can be used to store additional information about them. This metadata can be used to further personalize interactions or to provide context for tool calls. + +```python +customer = await server.create_customer(name="Alice", metadata={ + "external_id": "12345", + "location": "USA", +}) +``` + +```python +@p.tool +async def get_customer_location(context: p.ToolContext) -> p.ToolResult: + server = p.ToolContextAccessor(context).server + + if customer := await server.find_customer(id=context.customer_id): + return p.ToolResult(customer.metadata.get("location", "Unknown location")) + + return p.ToolResult("Customer not found") +``` + +## Registering Customers +While you can register customers using the SDK itself, it's often more practical to handle customer registration through your application layer. This allows you to integrate customer management with your existing user authentication and authorization systems. + +You can do this by using Parlant's REST API or native Client SDKs to create and manage customers. + +```python +from parlant.client import ParlantClient + +# Change localhost to your server's address +client = ParlantClient("http://localhost:8800") + +client.customers.create( + name="Alice", + metadata={ + "external_id": "12345", + "location": "USA", + "hobby": "reading", + }, + tags=[TAG_ID] # Optional: specify tag IDs to assign to the customer +) +``` + +## Updating Customer Data + +You can update customer data at any time, including their name, metadata, and tags. This is useful for keeping customer information up-to-date as your application evolves. + +```python +client.customers.update( + customer_id=CUSTOMER_ID, + name="Alice Smith", + metadata={ + "set": { + "location": "Canada", + }, + "remove": ["hobby"], + }, + tags=[NEW_TAG_ID] # Optional: specify new tag IDs to assign to the customer +) +``` diff --git a/docs/concepts/sessions.md b/docs/concepts/sessions.md new file mode 100644 index 0000000..940f951 --- /dev/null +++ b/docs/concepts/sessions.md @@ -0,0 +1,363 @@ +# Sessions + +A session represents a continuous interaction between an [agent](https://parlant.io/docs/concepts/entities/agents) and a [customer](https://parlant.io/docs/concepts/entities/customers). + +Sessions are the stage for your conversational model, allowing agents to engage with customers in a structured and persistent manner. They encapsulate all the interactions that occur between an agent and a customer, including messages, status updates, frontend events, and tool call results. + +```mermaid +%%{init: { "theme": "neutral" }}%% +mindmap + root((Session)) + Message History + Status Indicators + Frontend Events + Tool Results +``` + +> **Agent Memory?** +> +> What some frameworks call "memory" is already built-in into sessions in Parlant. An agent is constantly aware of everything that has happened in the session, using this information to apply the right instructions and generate appropriate responses. + +## A Modern Interaction Model + +Parlant views interaction sessions in a different manner than most Conversational AI frameworks. + +In the past few decades, virtually all forms of conversational AI have assumed that an interaction occurs on a turn-by-turn basis, where a customer sends a message, and the agent responds to it. + +Yet this is not how real conversations work. People often send each other multiple subsequent messages to communicate their thoughts. In addition, an agent may say something, put the customer on hold for a moment, and then return to the conversation with a follow-up message. + +**Rigid Interaction Model** + +```mermaid +sequenceDiagram + participant Customer + participant Agent + + Customer->>Agent: Message 1 + Agent->>Customer: Reply 1 + Customer->>Agent: Message 2 + Agent->>Customer: Reply 2 +``` + +**Modern Interaction Model** + +```mermaid +%%{init: { "theme": "forest" }}%% +sequenceDiagram + participant Customer + participant Agent + + Customer->>Agent: Message 1 + Customer->>Agent: Message 2 + Agent-->>Customer: (Processing...) + Agent->>Customer: Reply to both messages + Agent->>Customer: Follow-up clarification +``` + +Since this is how real conversations work, Parlant provides built-in support for it from the ground up. + +> **Multi-Participant Sessions** +> +> A requested feature on Parlant's development roadmap, this will allow you to have multiple agents interact with the customer, or with each other. Another use case for this is transferring the customer to another AI agent. + +## Configuring Session Storage + +You can choose where you store sessions. + +By default, Parlant does not persist sessions, meaning that they are stored in memory and will be lost when the server restarts. This is useful for testing and development purposes. + +If you want to persist sessions, you can configure Parlant to use a database of your choice. For local persistence, we recommend using the integrated JSON file storage, as there's zero setup required. For production use, you can use MongoDB, which comes built-in, or another database. + +### Persisting to Local Storage +This will save sessions under `$PARLANT_HOME/sessions.json`. + +```python +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server(session_store="local") as server: + # ... + +asyncio.run(main()) +``` + +### Persisting to MongoDB +Just specify the connection string to your MongoDB database when starting the server: + +```python +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server(session_store="mongodb://path.to.your.host:27017") as server: + # ... + +asyncio.run(main()) +``` + +## Event Driven Communication + +Think of a session in Parlant as a timeline of everything that's happened in a conversation. + +Each moment in this timeline—whether it's someone speaking, a status update, or a tool call result—is captured as an event. These events line up one after another, each with its own position number (called its _offset_), starting from 0. + +When a conversation unfolds, it creates a sequence of events. A customer might start the session by saying _"Hello"_—that's event 0. The system then notes that the agent has acknowledged the message and is preparing a response by outputting a status event—that's event 1. The agent's _"Hi there!"_ becomes event 2, and so on. Each event, whether it's a message being exchanged, the agent typing, or even an error occurring, takes its place in this ordered sequence. + +```mermaid +%%{init: { "theme": "forest" }}%% +graph LR + direction LR + Ax["Event 0"] --> Bx["Event 1"] --> Cx["Event 2"] --> Dx["Event 3"] --> Ex["Event 4"] + A["Customer(Cash remaining?)"] --> B["Status(Thinking)"] --> C["Tool(get_balance)"] --> D["Status(Typing)"] --> E["Agent(Your balance is $100)"] + Ax --- A + Bx --- B + Cx --- C + Dx --- D + Ex --- E +``` + +Every event in this sequence carries important information: what type of event it is (like a message or a status update), what actually happened (the data), and when it occurred. This creates a complete record of the conversation that helps us understand exactly how things unfolded, making it easy to track and review the conversation's state when needed. + +Each event is also associated with a **trace ID**. This ID primarily helps to trace between AI-generated messages and the engine triggers that produced them, including any generated tool events that may have informed them. This lets us easily fetch and understand the data that went into each generated message. For example, by having your frontend client inspect a message's traced tool events, you can show relevant information in "footnotes" under the message. + +## Interacting with an Agent + +Once you have a Parlant server up and running, you can interact with its hosted agents through the [REST API](https://parlant.io/docs/api/create-session). + +You have three options: +1. Use the official React widget to quickly and easily integrate with the server +2. Use the official client SDKs for Python or TypeScript to build a custom frontend application +3. Use the [REST API](https://parlant.io/docs/api/create-session) directly by making HTTP requests to the server in your language of choice + +### Using the Official React Widget + +If your frontend project is built with React, the fastest and easiest way to start is to use the official Parlant React widget to integrate with the server. + +Here's a basic code example to get started: + +```jsx +import React from 'react'; +import ParlantChatbox from 'parlant-chat-react'; + +function App() { + return ( + <div> + <h1>My Application</h1> + <ParlantChatbox + server="PARLANT_SERVER_URL" + agentId="AGENT_ID" + /> + </div> + ); +} + +export default App; +``` + +For more documentation and customization, see the **GitHub repo:** https://github.com/emcie-co/parlant-chat-react. + +```bash +npm install parlant-chat-react +``` + +### Building a Custom Frontend + +If you're coding in Python or TypeScript, you can use the official, native client SDKs for a fully-typed experience. + +**Python** +```bash +pip install parlant-client +``` + +**TypeScript** +```bash +npm install parlant-client +``` + +We'll now cover some basic use cases. The examples will be in Python, but the other SDKs have nearly identical APIs, so you can easily adapt them to your preferred language. + +#### Initializing the Client +```python +from parlant.client import AsyncParlantClient + +# Change localhost to your server's address +client = AsyncParlantClient(base_url="http://localhost:8800") +``` + +> **Async Client?** +> +> The examples given here use the asynchronous client, which is the recommended way to interact with Parlant. This allows you to handle events in real-time without blocking your application. It's usually much better for production use. +> +> However, if you prefer a synchronous client—for example, if you're just testing—you can use `ParlantClient` instead of `AsyncParlantClient`. The API remains the same, but you don't have to run within an async event loop. + +#### Creating a Session +```python +await client.sessions.create( + agent_id=AGENT_ID, # The ID of the agent to interact with + # Optional parameters + customer_id=CUSTOMER_ID, # Optional: defaults to the guest customer's ID + title=SESSION_TITLE, # Optional: session can be untitled +) +``` + +#### Sending Customer Messages to an Agent +You can send messages to an agent by creating a new message event in the session. This is how you initiate a conversation or continue an existing one. + +```python +event = await client.sessions.create_event( + session_id=SESSION_ID, + kind="message", # The event is of type 'message' + source="customer", # The message is from the customer + message="Hello, I need help with my order.", +) +``` + +#### Receiving Messages from an Agent + +As stated before, unlike LLM APIs where you send a prompt and wait for a direct response, Parlant agents operate in their own timeline according to triggers, more like real conversation partners. + +Much like a human service representative, they process information and decide when and how to respond based on their understanding of the context. This allows you to build much more flexible, ambient agentic experiences that can engage with customers proactively. + +However, it also means we need to approach communication with them differently. Here's how you can do that: + +```python +new_events = await client.sessions.list_events( + session_id=SESSION_ID, + min_offset=EVENT_OFFSET, # The offset of the last event you received (or created yourself) + wait_for_data=60, # Wait for up to 60 seconds for new events, before timing out +) +``` + +Normally, you'd have this polling in a loop. This way, you can keep checking for new events in the session, allowing you to receive messages from the agent asynchronously, whenever they arrive, due to whatever reason. + +```mermaid +graph LR + A["Fetch new events"] -->|Timeout| A + A --> |New events| B["Display new events"] + B --> A +``` + +### Displaying Messages + +Consult the message event's structure below to see how to display messages in your frontend application. + +Here's a simple example: + +```python +agent_message = next((m for m in new_events if m.kind == "message" and m.source == "ai_agent"), None) + +if agent_message: + print(f"Agent: {agent_message.data['message']}") +``` + +### Events + +If you decide to build a custom frontend, here's a quick overview of Parlant's event structure. + +#### Event Types +Parlant defines several event types that you can work with: + +1. `"message"`: Represents a message sent by a participant in the conversation. +2. `"status"`: Represents a status update from the AI agent, such as "thinking...", or "typing...". +3. `"tool"`: Represents the result of a tool call made by the AI agent. +4. `"custom"`: Represents a custom event defined by your application. This is useful for feeding custom state updates into your agent, e.g., making it aware of the customer's navigational state within your frontend application. + +#### Event Offset +As said above, events are ordered by their offset, which is a number that indicates the order in which they occurred within the session. The first event in a session has an offset of 0, the second has an offset of 1, and so on. + +This is useful because, when you list events, you can specify a minimum offset to only receive events that occurred after a certain point in time. This allows you to poll new events without having to re-fetch all previous ones. + +#### Event Trace ID +Each event has a trace ID, which is a unique identifier that helps you track related events and their logs. + +As one example, when an AI agent generates a message, it may also generate tool events that provide additional context or data used in that message. The trace ID allows you to link these events together, making it easier to understand the flow of information as well as your agent's processing in the session. + +#### Event Sources +Events in Parlant can originate from different sources. Here's a quick overview of the possible sources: + +1. `"customer"`: The event's data was created by the customer. Currently, this is always a message. +2. `"customer_ui"`: The event was created by the customer's user interface, to feed relevant state into the agent. +3. `"ai_agent"`: The event was generated by an AI agent, such as a message or a status update. +4. `"human_agent"`: The event was manually created by a human, typically in a human-handoff scenario. +5. `"human_agent_on_behalf_of_ai_agent"`: As above, the event was created by a human agent, but it appears to the customer as if it came from an AI agent. This can be useful for maintaining a consistent experience where you don't necessarily want to reveal the fact that a human agent got involved. +6. `"system"`: The event was generated by the system, such as a tool-call result. + +#### Message Event +A message event, as its name suggests, represents a message written by someone. + +```json +{ + id: EVENT_ID, + kind: "message", + source: EVENT_SOURCE, + offset: N, + trace_id: TRACE_ID, + data: { + message: MESSAGE, + participant={ + id: PARTICIPANT_ID, + display_name: PARTICIPANT_DISPLAY_NAME + }, + draft: OPTIONAL_DRAFT, // Optional: if the message is a canned response + } +} +``` + +#### Status Event +A status event represents an update on the status of the AI agent, and currently always has the source `"ai_agent"`. + +Status events are great for displaying conversational updates during a chat with a customer. For example, you can have your frontend indicate when the agent is thinking or typing. There are 6 kinds of status events that you can make use of: + +1. `"acknowledged"`: The agent has acknowledged the customer's message and started working on a reply +1. `"cancelled"`: The agent has cancelled its reply in the middle, normally because new data was added to the session +1. `"processing"`: The agent is evaluating the session in preparation for generating an appropriate reply +1. `"typing"`: The agent has finished evaluating the session and is currently generating a message +1. `"ready"`: The agent is idle and ready to receive new events +1. `"error"`: The agent encountered an error while trying to generate a reply + +```json +{ + id: EVENT_ID, + kind: "status", + source: "ai_agent", + offset: N, + trace_id: TRACE_ID, + data: { + status: STATUS_KIND, + data: OPTIONAL_DATA + } +} +``` + +#### Tool Event +A tool event represents the result of a tool call made by the AI agent. It contains the result of the tool call, which can be used to inform the agent's next message. + +The `result` object for each call comes directly from the [ToolResult](https://parlant.io/docs/concepts/customization/tools#tool-result) object returned by tool calls. + +```json +{ + id: EVENT_ID, + kind: "tool", + source: "system", + offset: N, + trace_id: TRACE_ID, + data: { + tool_calls: [ + { + tool_id: TOOL_ID, + arguments: { + NAME: VALUE, + ... + }, + result: { + data: TOOL_RESULT_DATA, // The result of the tool call + metadata: TOOL_RESULT_METADATA, // Optional metadata about the tool result + ... // Other available fields + } + }, + ... + ] + } +} +``` diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 0000000..2245540 Binary files /dev/null and b/docs/demo.gif differ diff --git a/docs/interactions.md b/docs/interactions.md new file mode 100644 index 0000000..1da9560 --- /dev/null +++ b/docs/interactions.md @@ -0,0 +1,69 @@ +# Interaction Flow + +## Motivation + +The first thing that's important to understand about the design of the Human/AI interface in Parlant is that it's meant to facilitate conversations that aren't only natural in content, but also in their flow. + +Most traditional chatbot systems (and most LLM interfaces) rely on a request-reply mechanism based on a single last message. + +```mermaid +stateDiagram + direction LR + HumanMessage --> AIProcessing: AI processes single message + AIProcessing --> AIMessage: AI sends response + AIMessage --> HumanMessage: Human replies +``` + +However, these days we know that a natural text interface must allow for a few things that are unsupported by that traditional model: + +1. A human often expresses themselves in more than a single message event, before they're fully ready for a reply from the other party. +1. Information regarding their intent needs to be captured from not only their last N messages, but from the conversation as a whole. + +```mermaid +stateDiagram + direction LR + MultipleHumanMessages --> AIProcessing: AI processes multiple messages in the session + AIProcessing --> AIMessage: AI sends response + AIMessage --> MultipleHumanMessages: Human replies in one or more messages +``` + +Moreover, the agent may need to respond not just when triggered by a human message; for example, when it needs to follow-up with the user to ensure their message was received, to try another engagement tactic, or to buy time before replying with further information, e.g., "Let me check that and get back to you in a minute." + +## Solution + +Parlant's API and engine is meant to work in an asynchronous fashion with respect to the interaction session. In simple terms, this means that both the human customer and the AI agent are free to add events (messages) to the session at any point in time, and in any number—just like in a real IM App conversation between two people. + +### Sending Messages + +```mermaid +graph LR + Client(Interaction Client) -->|Event Creation Request| API[Parlant REST API] + API -.->|Created Event| Client + API --> CheckEventType{Check Event Type} + CheckEventType -->|Is Customer Message| AddToSession[Add message to session and trigger the agent] + CheckEventType -->|Is AI Agent Message| TriggerAgent[Directly trigger the agent to react to the session] + CheckEventType -->|Is Human Agent Message| AddHumanAgentMessage[Add a pre-written message on behalf of the AI agent] +``` + +The diagram above shows the API flows for initiating changes to a session. +1. **Customer Message:** This request adds a new message to a session on behalf of the customer, and triggers the AI agent to respond asynchronously. This means that the *Created Event* does not in fact contain the agent's reply—that will come in time—but rather the ID (and other details) of the created and persisted customer event. +1. **AI Agent Message:** This request directly activates the full reaction engine. The agent will match and activate the relevant guidelines and tools, and produce a reply. The *Created Event* here, however, is not the agent's message, since that may take some time. Instead, it returns a *status event* containing the same *Trace ID* as the eventual agent's message event. It's important to note here that, in most frontend clients, this created event is usually ignored, and is provided mainly for diagnostic purposes. +1. **Human Agent Message:** Sometimes it makes sense for a human (perhaps a developer) to manually add messages on behalf of the AI agent. This request allows you to do that. The *Created Event* here is the created and persisted manually-written agent message. + +### Receiving Messages + +Since messages are sent asyncrhonously, and potentially simultaneously, receiving them must be done in asynchronous fashion as well. In essence, we are to always wait for new messages, which may arrive at any time, from any party. + +Parlant implements this functionality with a long-polling, timeout-restricted API endpoint for listing new events. This is what it does behind the scenes: + +```mermaid +graph LR + Client[Interaction Client] -->|Await & Fetch New Events| API[Parlant REST API] + API -->|"list_events(min_offset,...)"| SessionStore + API -->|"wait_for_events(min_offset,timeout)"| SessionListener + SessionListener -.->|true/false| API +``` + +When it receives a request for new messages, that request generally has 2 important components: 1) The session ID; and 2) The minimum event offset to return. Normally, when making a request to this endpoint, the frontend client is expected to pass the session ID at hand, and *1 + the offset of its last-known event*. This will make this endpoint return only when *new* messages arrive. It's normal to run this long-polling request in a loop, timing-out every 60 seconds or so and renewing the request while the session is open on the UI. It's this loop that continuously keeps your UI updated with the latest messages, regardless of when they arrive or what caused them to arrive. + +In summary, Parlant implements a flexible conversational API that supports natural, modern Human/AI interactions. diff --git a/docs/parlant-testing.gif b/docs/parlant-testing.gif new file mode 100644 index 0000000..b5dfe9e Binary files /dev/null and b/docs/parlant-testing.gif differ diff --git a/docs/production/agentic-design.md b/docs/production/agentic-design.md new file mode 100644 index 0000000..1463cc2 --- /dev/null +++ b/docs/production/agentic-design.md @@ -0,0 +1,345 @@ +# Agentic Design Methodology + +Building AI agents takes a fundamental paradigm shift from traditional software development. This article explores the unique challenges, methodologies, and design principles needed to create effective customer-facing agents. + +While Parlant provides the tools for reliable agent behavior, success depends on mastering the art of semantic design—learning how to articulate instructions that work consistently at scale while maintaining natural user interactions. + +## Understanding Probabilistic Behavior + +AI agents operate differently from traditional software systems. In conventional development, deterministic functions produce consistent outputs for the same inputs. AI agents, however, are built on statistical models where the same input can produce varied responses based on the model's learned patterns and probability distributions. + +Naturally, when we're building on top of an inherently uncertain foundation, this requires a different approach to design and implementation. This is the first important thing to pause and come to terms with about agentic design. + +### Instruction Interpretation Challenges + +While traditional software executes explicit commands with predictable outcomes, LLMs interpret instructions contextually, filling in details and assumptions based on their varied training data. They _have_ to work like this. + +Consider this guideline example: +```python +agent.create_guideline( + condition="Customer is unhappy", + action="Make them feel better" +) +``` + +Both the condition and instruction are too vague and could result in undesirable behaviors: +- Offering unauthorized discounts +- Making promises the company cannot fulfill +- Using inappropriate communication styles + +> **Warning: Interpretation Variability** +> +> LLMs trained to be helpful will attempt to fulfill requests even when they lack sufficient context or specificity. This can lead to responses that seem appropriate to the model but violate business rules or expectations. + +## The Challenge of Complete Control + +It's important to understand that, while Parlant adds many compliance mechanisms on top of LLMs, the LLMs themselves cannot be fully constrained from discussing certain topics, for two fundamental reasons: + +**1. Pattern Mimicking, Not Reasoning**: LLMs don't actually "reason" in the logical sense. Everything they produce is essentially mimicking patterns of expression observed during training. Think of an LLM as a powerful but wild horse—it has immense capability, but it takes skill and nuance to "ride" it effectively. + +**2. Contextual Ambiguity**: Even carefully crafted conditions and actions can become ambiguous across different and variegated interaction contexts. What seems clear in one scenario may be interpreted differently in a different context. + +### Strategies for Compliance + +For agents that must meet compliance standards and expectations, you need a layered approach: + +**The Minimum: Guidance-Based Boundaries** +With guidelines, you can: +1. Set clear boundaries for acceptable behavior +2. Provide deliberate nudges and instructions for handling specific scenarios in intended ways +```python +await agent.create_guideline( + condition="Customer asks about topics outside your designated scope", + action="Politely decline to discuss the topic and redirect to what you can help with" +) +``` + +```python +await agent.create_guideline( + condition="The patient wants an analysis of their lab results", + action="Never provide any interpretation of the results. Instead, tell them to " + "call our office and ask to speak with their doctor for a detailed analysis", +) +``` + +**The Robust Solution: Canned Responses** +For truly critical interactions where unauthorized communication could cause problems, implement [canned responses](https://parlant.io/docs/concepts/customization/canned-responses) and set your agent's composition mode to `STRICT`: + +```python +await agent.create_canned_response( + template="I can help you with account questions, but I'll need to connect you " + "with a specialist for policy details. Would you like me to transfer you?" +) +``` + +Canned responses ensure that in high-risk scenarios, your agent uses pre-approved language and content that eliminates the possibility of unauthorized statements. Yes, this requires more work, but you can add these iteratively. The key insight is building an agent you can trust not to create liability—not even one time in a million interactions. + +This "defense in depth" approach acknowledges that working with LLMs means learning to guide, steer and constrain, rather than control completely. It also means that, _as long as the behavior of the agent is within acceptable bounds,_ we must allow for some degree of flexibility and variability in responses. + +## Tool Calling Complexities + +When agents need to interact with external systems, they use tools (functions that perform specific actions). However, LLMs face unique challenges when calling tools that don't exist in traditional software development. + +### The Parameter Guessing Problem + +LLMs must determine tool parameters based on conversational context rather than explicit specifications. This creates several common failure patterns: + +1. **Missing Information**: Agents may call tools without all required parameters being present in context, encouraging them to guess or hallucinate values. +1. **Type Confusion**: An agent might pass an email address where a user ID is expected, or provide a string where an integer is needed. +1. **Context Misinterpretation**: When multiple entities exist in conversation context, agents may use the wrong one for a parameter. +1. **False Positive Bias**: When multiple tools seem applicable, agents may call the first one that seems relevant, even if it's not the best fit. + +Consider a user saying: "Schedule a meeting with Sarah for next week." The agent must determine: +- Which Sarah (if multiple exist) +- What day/time "next week" means +- What type of meeting +- How long the meeting should be +- What calendar system to use + +Each ambiguity is a potential failure point. Parlant therefore provides you with specific controls to guide the contextual relevance of tools, as well as their precise parameterization expectations. + +> **Tip: Tool Design Deep Dive** +> +> Tool calling presents unique challenges for agents, from parameter interpretation to multi-step orchestration failures. For comprehensive guidance on designing agent-friendly tools, particularly for customer-facing scenarios with Parlant, see: +> +> - [Tools documentation](https://parlant.io/docs/concepts/customization/tools) - Parlant's approach to guided tool usage +> - [Agentic API Design blog post](https://parlant.io/blog/what-no-one-tells-you-about-agentic-api-design) - Detailed strategies for building reliable agent-friendly APIs + +## Iterative Development Process + +Realistically, semantic behavior cannot be fully specified upfront like traditional software requirements. Instead, agent design follows an iterative process where behavior is best refined based on observed interactions and feedback. + +### Phase 1: Basic Agent Implementation + +When you're starting out, focus on implementing the core functionality and happy-paths of your agent, as far as you're able to define them. This means defining the basic guidelines and journeys that cover the most common scenarios. + +Focus on getting core functionality to work before addressing edge cases. The good news is that Parlant's framework allows you to start simple and build complexity over time in a fairly straightforward manner. + +### Phase 2: Monitoring and Analysis + +Deploy the agent in a controlled environment and monitor its interactions. Unexpected behaviors provide insights into how the agent interprets instructions differently than intended. It'll also show you how users _actually_ interact with the agent, which is often somewhat different than most of us initially expect as we're designing them! + +Track these interaction patterns: +- Situations where the agent deviates from expected responses +- Triggers that lead to undesired behaviors +- User confusion, frustration points, or peculiar interaction patterns + +```mermaid +%%{init: { "theme": "neutral" }}%% +flowchart LR + A[Deploy Agent] --> B[Monitor Interactions] + B --> C{Unexpected Behavior?} + C -->|Yes| D[Adjust Behavior Model to Resolve Issues] + C -->|No| E[Expand Behavior Model with New Features] + D --> F[Test Staged Changes] + E --> F + F --> A + + style C fill:#fff2cc,stroke:#d6b656 + style D fill:#ffe6e6,stroke:#d79b9b + style E fill:#e6ffe6,stroke:#9bb99b +``` + +### Phase 3: Targeted Refinements + +Leverage Parlant's structured approach to behavior modeling to address specific issues identified during monitoring. Add [guidelines](https://parlant.io/docs/concepts/customization/guidelines) that target observed problems: + +```python +# Problem: Agent was repeating upsell offers after explicit rejection +await agent.create_guideline( + condition="Customer has explicitly declined a premium upgrade in this conversation", + action="Do not mention upgrades again in this session" +) +``` +```python +# Problem: Agent gave vague responses when appointments were unavailable +await agent.create_guideline( + condition="Customer requests a specific appointment time that is not available", + action="Immediately provide the three closest available time slots as concrete alternatives", + tools=[get_available_slots], +) +``` + + +### Guideline Specificity Requirements +Effective guidelines specify the temporal scope of their application and provide concrete, actionable instructions. + +When designing guidelines, it's best to address these common ambiguity sources: + +**Action Temporal Scope**: How long should the guideline's effect last? +- "...throughout the conversation" - applies throughout the current session +- "...immediately" - applies to the next response only +- "...until the customer has..." - applies until a specific condition changes + +**Action Clarity**: What exactly should the agent do? +- Guide the response content: "Tell them that..." +- Specify objective criteria: "three closest alternatives" not "some alternatives" + +**Condition Precision**: When exactly does this guideline apply? +- "Customer has explicitly declined" is clearer than "Customer is unhappy" +- "Customer asks about a specific policy and you don't have the exact answer" is more precise than "You're unsure" + +## Managing Probabilistic Behavior + +Agent design requires balancing flexibility with predictability. Agents need sufficient freedom to handle varied user inputs naturally while maintaining consistent adherence to business rules. + +### Implementing Bounded Flexibility + +Effective guidelines provide clear boundaries while allowing natural conversation flow: + +```python +# Too rigid - feels scripted +await agent.create_guideline( + condition="Customer asks about pricing", + action="Say exactly: 'Our premium plan is $99/month'" +) +``` +```python +# Too open - unpredictable behavior +await agent.create_guideline( + condition="Customer asks about pricing", + action="Help them understand our pricing" +) +``` +```python +# Balanced approach - specific but flexible +await agent.create_guideline( + condition="Customer asks about pricing", + action="Explain our pricing tiers clearly, emphasize value, " + "and ask about their specific needs to recommend the best fit" +) +``` + +### Handling Edge Cases + +Agents will encounter unexpected inputs and edge cases. Design guidelines to handle these situations gracefully: + +```python +# Immediate escalation for policy questions +await agent.create_guideline( + condition="Customer asks about a specific policy and you don't have the exact answer", + action="Tell them you want to ensure they get accurate policy information, " + "and offer to connect them to human support who can provide the specifics" +) +``` +```python +# Redirect competitor questions once per conversation +await agent.create_guideline( + condition="Customer asks about competitor products or pricing", + action="Acknowledge their question, explain that you focus on our own products, " + "and ask specifically what features or capabilities they're looking for " + "so you can recommend the best option from our lineup" +) +``` + +## Structured Interactions + +For complex multi-step processes, guidelines alone may not provide sufficient structure. [Journeys](https://parlant.io/docs/concepts/customization/journeys) offer a better approach for these scenarios. + +### When to Use Journeys + +Consider implementing journeys when agents struggle with complex, multi-step interactions: + +```python +# Instead of many guidelines trying to handle booking flow, use a structured journey... +booking_journey = await agent.create_journey( + title="Book Appointment", + conditions=["Customer wants to schedule an appointment"], + description="Guide customer through appointment booking process" +) + +# Create a clear, flexible flow +t1 = await booking_journey.initial_state.transition_to( + chat_state="Ask what type of service they need" +) +t2 = await t1.target.transition_to( + tool_state=check_availability_for_servic_for_servicee, +) +t3 = await t2.target.transition_to( + chat_state="Offer available time slots" +) +# ... continue building the journey +``` + +Journeys provide conversational structure while maintaining flexibility, allowing agents to adapt to different interaction patterns within a defined framework. + +## Development Philosophy for Customer-Facing Agents + +Building customer-facing agents requires balancing several competing priorities that don't exist in traditional software development. + +### User Experience vs. Business Control + +Traditional user interfaces provide users with explicit options—buttons, forms, menus. Users can only do what the interface allows. Conversational agents invert this relationship: users can say anything, and the agent must decide how to respond within business constraints. + +This creates a unique tension. Users expect natural, helpful interactions, but businesses need predictable, compliant behavior. The agent must feel conversational while operating within defined boundaries. + +### Conversational Design Principles + +**Context Preservation**: Unlike web forms that capture data step-by-step, conversations are non-linear. Users might provide information out of order, change their minds, stall, repeat themselves, or digress. Agents must maintain compliance while allowing natural conversation flow. + +**Progressive Disclosure**: Rather than overwhelming users with all options upfront, agents can reveal capabilities contextually. This requires guidelines that respond to user needs as they emerge. + +**Recovery Mechanisms**: When conversations go off-track, agents need explicit strategies to redirect without frustrating users. This often requires journey-scoped guidelines that handle common deviations. + +### Protocol Adherence and Communication Standards + +Customer-facing agents must follow established protocols and communicate in ways that align with business standards. The primary challenge is ensuring agents never provide misleading information while expressing things in the manner your organization approves of—which includes branding guidelines. + +Parlant provides four main tools for maintaining communication standards: + +1. **Guidelines:** Set behavioral boundaries and response patterns +1. **Journeys:** Structure complex interactions to ensure proper protocol adherence +1. **Canned Responses:** Guarantee exact wording for tailored communications +1. **Retrievers:** Grounds the agent's responses in accurate, up-to-date information + +This layered approach ensures agents accurately follow protocol while maintaining natural conversation flow, never saying something critically misleading, and always expressing information in business-approved ways. + +## The Art of Behavior Modeling + +The primary challenge in agentic development isn't technical—it's designing effective interactions and then translating those designs into instructions that work reliably at scale, and that customers actually engage with. + +Effective behavior modeling often combines: + +**Domain Knowledge**: Understanding not just what customers need, but how they express those needs, what frustrates them, and what builds their confidence. + +**Conversation Flow Design**: Knowing how to structure multi-turn interactions that feel natural while efficiently gathering necessary information. + +**Instruction Design**: The skill of writing guidelines that are clear and precise enough for consistent LLM interpretation but flexible enough for natural conversation and adaptivity. + +### Practical Design Strategies + +**Start with User Stories, Not Features**: Instead of "the agent should handle returns," put yourself in your customer's shoes, like "As a customer who bought the wrong size, I want to exchange it..." + +**Use Progressive Complexity**: Begin with the simplest possible behavior model that handles the common case. Add complexity only when specific edge cases are found. Parlant makes this iteration fairly straightforward. + +**Separate Intent from Implementation**: Guidelines should focus on what clear outcome to achieve rather than specific words to use. This allows the agent to adapt its approach while maintaining consistent goals. + +## The Twofold Challenge of Agentic Development + +Agentic development involves two distinct but related problems: + +1. **Articulating Instructions**: Designing a high-quality behavior model that captures your intended behavior +2. **Ensuring Compliance**: Guaranteeing that agents actually follow these instructions consistently at scale + +Parlant solves the second challenge effectively. Once you've articulated your expectations clearly, Parlant's guideline matching, journey management, and enforcement mechanisms ensure reliable adherence to your specifications. The framework handles the complex task of dynamically selecting relevant guidelines, managing conversation context, and supervising agent outputs. + +However, Parlant cannot solve the first challenge for you. The framework provides powerful tools for expressing conversational behavior, but it's on us as developers to learn how to use these tools effectively. This is where the real expertise lies—not just in understanding Parlant's SDK, but in developing the skills to design conversations and articulate instructions that work in practice. + +**The Framework's Role**: Parlant ensures that well-designed guidelines are followed reliably across thousands of interactions. It handles the technical complexity of context management, guideline selection, and behavioral enforcement. + +**The Developer's Role**: Learning to write guidelines that are neither too vague nor too rigid, designing journeys that accommodate real user behavior, and developing the judgment to know when to add structure versus when to allow flexibility. + +This division of responsibility means that mastering agentic development requires both technical proficiency with Parlant's capabilities and behavior modeling expertise. The most successful implementations recognize that behavior modeling is a specialized skill involving continuous refinement through real-world testing. + +## Implementation Guidelines: Summary + +Effective agentic design requires understanding how to work with probabilistic behavior effectively: + +1. **Begin with basic functionality** - Implement core capabilities before addressing edge cases +2. **Monitor systematically** - Track agent behavior to identify areas for improvement +3. **Refine iteratively** - Add guidelines based on observed rather than hypothetical issues +4. **Balance flexibility and control** - Provide clear boundaries while allowing natural interaction +5. **Structure complex flows** - Use journeys for multi-step processes +6. **Maintain transparency** - Communicate capabilities and limitations clearly + +The primary challenge isn't technical mastery of Parlant's features, but developing the behavior modeling expertise to articulate instructions that work reliably at scale. Parlant handles the enforcement—your role is learning the art of clear agentic design. diff --git a/docs/production/api-hardening.md b/docs/production/api-hardening.md new file mode 100644 index 0000000..d0d0206 --- /dev/null +++ b/docs/production/api-hardening.md @@ -0,0 +1,252 @@ +# API Hardening + +Parlant provides a robust authorization and rate limiting system to protect your API from unauthorized access and abuse. This guide explains how to implement custom authorization policies and rate limiters to secure your production deployment. + +## Overview + +The API hardening system consists of two main components: + +1. **Authorization Policies** - Control who can access what resources and perform which actions +2. **Rate Limiters** - Prevent abuse by limiting the frequency of requests + +Both components work together to provide comprehensive API protection, with support for different limits based on access tokens or user tiers. + +## Authorization Policies + +### Understanding the AuthorizationPolicy Abstract Class + +All authorization policies inherit from the `AuthorizationPolicy` abstract base class, which defines three key methods: + +```python +class AuthorizationPolicy: + @abstractmethod + async def check_permission( + self, + request: fastapi.Request, + permission: AuthorizationPermission + ) -> bool: + """Check if the request has permission to perform the action""" + ... + + @abstractmethod + async def check_rate_limit( + self, + request: fastapi.Request, + permission: AuthorizationPermission + ) -> bool: + """Check if the request is within rate limits""" + ... + + async def authorize( + self, + request: fastapi.Request, + permission: AuthorizationPermission + ) -> None: + """Combined authorization check (permission + rate limit)""" + # This method usually isn't overriden, as its default implementation + # calls the two abstract methods in sequence and raises an authorization + # error if anything is denied. + ... +``` + +### Authorization Permissions + +Parlant defines a comprehensive set of permissions as an enum covering all API operations: + +- Agent operations (create, read, update, delete) +- Customer management +- Session handling +- And many more... + +### Built-in Authorization Policies + +#### DevelopmentAuthorizationPolicy +Allows all actions - suitable for development environments only: + +```python +class DevelopmentAuthorizationPolicy(AuthorizationPolicy): + async def check_permission( + self, + request: fastapi.Request, + permission: AuthorizationPermission + ) -> bool: + return True + + async def check_rate_limit( + self, + request: fastapi.Request, + permission: AuthorizationPermission + ) -> bool: + return True +``` + +#### ProductionAuthorizationPolicy +Implements stricter controls for production use with configurable rules. + +## Implementing Custom Authorization Policies + +When you implement your own authorization policy in real-world deployments, you typically want to extend the existing production policy rather than building from scratch. The recommended approach is to subclass `ProductionAuthorizationPolicy` and customize it for your specific needs. + +Here's a reference implementation that demonstrates how to create a custom policy with JWT authentication: + +```python +import parlant.sdk as p + +import jwt +from fastapi import HTTPException +from limits import RateLimitItemPerMinute, RateLimitItemPerHour +from limits.storage import RedisStorage +from limits.strategies import SlidingWindowCounterRateLimiter + +class CustomAuthorizationPolicy(p.ProductionAuthorizationPolicy): + def __init__(self, secret_key: str, algorithm: str = "HS256"): + super().__init__() + self.secret_key = secret_key + self.algorithm = algorithm + + async def _extract_token(self, request: fastapi.Request) -> dict | None: + """Extract and validate JWT token from request""" + auth_header = request.headers.get("Authorization") + if not auth_header or not auth_header.startswith("Bearer "): + return None + + token = auth_header.split(" ")[1] + try: + payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm]) + return payload + except jwt.JWTError: + # Raise 403 for invalid tokens, None for missing tokens is OK + raise HTTPException( + status_code=403, + detail="Invalid access token" + ) + + async def check_permission( + self, + request: fastapi.Request, + operation: p.Operation + ) -> bool: + """Enhanced permission checking with M2M token support""" + token_payload = await self._extract_token(request) + + # If we have a valid M2M (machine-to-machine) token, allow additional operations + if token_payload and token_payload.get("type") == "m2m": + m2m_operations = { + # Allow M2M tokens to perform administrative operations + p.Operation.CREATE_AGENT, + p.Operation.READ_AGENT, + p.Operation.UPDATE_AGENT, + p.Operation.DELETE_AGENT, + p.Operation.CREATE_CUSTOMER, + p.Operation.READ_CUSTOMER, + p.Operation.UPDATE_CUSTOMER, + p.Operation.DELETE_CUSTOMER, + p.Operation.CREATE_CUSTOMER_SESSION, + p.Operation.LIST_SESSIONS, + p.Operation.UPDATE_SESSION, + p.Operation.DELETE_SESSION, + # Add other operations your M2M integration needs + } + + if operation in m2m_operations: + return True + + # For all other cases, delegate to the parent ProductionAuthorizationPolicy + return await super().check_permission(request, operation) +``` + +## Rate Limiting Customization Options + +The `ProductionAuthorizationPolicy` provides several ways to customize rate limiting behavior: + +### 1. Override the Default Rate Limiter (Recommended) + +The most common approach is to override `self.default_limiter` with your own `BasicRateLimiter` configuration. **Note that BasicRateLimiter limits apply per IP address** - so when you configure `RateLimitItemPerMinute(100)`, it means 100 requests per minute per IP address. + +```python +from limits import RateLimitItemPerMinute, RateLimitItemPerHour +from limits.storage import RedisStorage +from limits.strategies import SlidingWindowCounterRateLimiter + +# Example with Redis storage and custom limits +class CustomAuthorizationPolicy(p.ProductionAuthorizationPolicy): + def __init__(self, ...): + super().__init__() + + # ... + + self.default_limiter = p.BasicRateLimiter( + rate_limit_item_per_operation={ + # Use the default rate limit for most operations + **self.default_limiter.rate_limit_item_per_operation, + # Override specific operations with custom limits + p.Operation.READ_SESSION: RateLimitItemPerMinute(200), + p.Operation.LIST_EVENTS: RateLimitItemPerMinute(1000), + }, + # Use a custom storage backend (e.g., Redis) + storage=RedisStorage("redis://localhost:6379"), + # Use a custom window strategy + limiter_type=SlidingWindowCounterRateLimiter, + ) +``` + +The `BasicRateLimiter` uses the `limits` library and supports: +- **Rate limit items**: `RateLimitItemPerMinute(n)`, `RateLimitItemPerSecond(n)`, `RateLimitItemPerHour(n)` +- **Storage options**: `RedisStorage()`, `MemoryStorage()`, and others from the limits library +- **Limiter strategies**: `MovingWindowRateLimiter`, `FixedWindowRateLimiter`, `SlidingWindowCounterRateLimiter` + +For complete control, you can implement your own `RateLimiter` from scratch by subclassing the abstract `RateLimiter` class and assigning it to `self.default_limiter`. + +### 2. Custom Limiter Functions for Specific Operations + +Use `self.specific_limiters` to provide custom rate limiting functions for particular operations. These are functions that take a request and operation and return a boolean indicating whether the rate is within the limit. + +```python +class CustomAuthorizationPolicy(p.ProductionAuthorizationPolicy): + def __init__(self, ...): + super().__init__() + + # ... + + self.specific_limiters[p.Operation.DELETE_AGENT] = self._custom_delete_limiter + + async def _custom_delete_limiter( + self, + request: fastapi.Request, + operation: p.Operation + ) -> bool: + # Implement your custom logic here + ... +``` + +If you need complete control over both permission checking and rate limiting, you can also subclass the abstract `AuthorizationPolicy` directly and implement all methods from scratch. This gives you full flexibility but requires more implementation work. The approach shown above is recommended for most use cases as it builds on the robust foundation of `ProductionAuthorizationPolicy`. + +## Integrating Your Custom Authorization Policy + +### Using configure_container + +Integrate your custom authorization policy and rate limiter with your Parlant agent: + +```python +async def configure_container( + container: p.Container +) -> p.Container: + container[p.AuthorizationPolicy] = CustomAuthorizationPolicy( + secret_key="your-jwt-secret-key", + algorithm="HS256", + ) + + return container +``` +```python +async def main(): + # Create Parlant server with custom authorization + async with p.Server( + configure_container=configure_container, + ) as server: + # Your agent logic here + await server.serve() + +if __name__ == "__main__": + asyncio.run(main()) +``` diff --git a/docs/production/custom-frontend.md b/docs/production/custom-frontend.md new file mode 100644 index 0000000..e34dc39 --- /dev/null +++ b/docs/production/custom-frontend.md @@ -0,0 +1,597 @@ +# Custom Frontend + +The fastest way to integrate Parlant into your React application is using our official [`parlant-chat-react`](https://github.com/emcie-co/parlant-chat-react) widget. This component provides a complete chat interface that connects directly to your Parlant agents. + +### Installation and Basic Setup + +Install the widget via npm or yarn: + +```bash +npm install parlant-chat-react +# or +yarn add parlant-chat-react +``` + +Then integrate it into your React application: + +```jsx +import React from 'react'; +import ParlantChatbox from 'parlant-chat-react'; + +function App() { + return ( + <div> + <h1>My Application</h1> + <ParlantChatbox + server="http://localhost:8800" // Your Parlant server URL + agentId="your-agent-id" // Your agent's ID + /> + </div> + ); +} + +export default App; +``` + +### Configuration Options + +The widget supports several configuration props: + +```jsx +<ParlantChatbox + // Required props + server="http://localhost:8800" + agentId="your-agent-id" + + // Optional props + sessionId="existing-session-id" // Continue existing session + customerId="customer-123" // Associate with specific customer + float={true} // Display as floating popup + titleFn={(session) => `Chat ${session.id}`} // Dynamic title generation +/> +``` + +### Common Customizations + +#### Styling with Custom Classes + +Customize the appearance using CSS class overrides: + +```jsx +<ParlantChatbox + server="http://localhost:8800" + agentId="your-agent-id" + classNames={{ + chatboxWrapper: "my-chat-wrapper", + chatbox: "my-chatbox", + messagesArea: "my-messages", + agentMessage: "my-agent-bubble", + customerMessage: "my-customer-bubble", + textarea: "my-input-field", + popupButton: "my-popup-btn" + }} +/> +``` + +#### Custom Component Replacement + +Replace specific components with your own: + +```jsx +<ParlantChatbox + server="http://localhost:8800" + agentId="your-agent-id" + components={{ + popupButton: ({ toggleChatOpen }) => ( + <button + onClick={toggleChatOpen} + className="custom-chat-button" + > + 💬 Chat with us + </button> + ), + agentMessage: ({ message }) => ( + <div className="custom-agent-message"> + <img src="https://parlant.io/agent-avatar.png" alt="Agent" /> + <p>{message.data.message}</p> + </div> + ) + }} +/> +``` + +#### Floating Chat Mode + +Enable popup mode for a floating chat interface: + +```jsx +<ParlantChatbox + server="http://localhost:8800" + agentId="your-agent-id" + float={true} + popupButton={<ChatIcon size={24} color="white" />} +/> +``` + +> **Reference Implementation** +> +> The parlant-chat-react widget is open source! You can [examine its implementation on GitHub](https://github.com/emcie-co/parlant-chat-react) as a reference for creating custom widgets in other UI frameworks like Vue, Angular, or vanilla JavaScript. The source code demonstrates best practices for session management, event handling, and UI state synchronization. + +## Building a Custom Frontend + +If you need more control than the React widget provides, or you're using a different framework, you can build a custom frontend using Parlant's client APIs directly. + +### Step 1: Initialize the Parlant Client + +Start by setting up the Parlant client to communicate with your server: + +#### TypeScript + +```typescript +import { ParlantClient } from 'parlant-client'; + +class ParlantChat { + private client: ParlantClient; + private sessionId: string | null = null; + private lastOffset: number = 0; + + constructor(serverUrl: string) { + this.client = new ParlantClient({ + environment: serverUrl + }); + } +} +``` + +#### JavaScript + +```javascript +import { ParlantClient } from 'parlant-client'; + +class ParlantChat { + constructor(serverUrl) { + this.client = new ParlantClient({ + environment: serverUrl + }); + this.sessionId = null; + this.lastOffset = 0; + } +} +``` + +### Step 2: Create a Session + +Initialize a conversation session with your agent: + +#### TypeScript + +```typescript +async createSession(agentId: string, customerId?: string): Promise<string> { + try { + const session = await this.client.sessions.create({ + agentId: agentId, + customerId: customerId, + title: `Chat Session ${new Date().toLocaleString()}` + }); + + this.sessionId = session.id; + console.log('Session created:', this.sessionId); + + // Start monitoring for events + this.startEventMonitoring(); + + return this.sessionId; + } catch (error) { + console.error('Failed to create session:', error); + throw error; + } +} +``` + +#### JavaScript + +```javascript +async createSession(agentId, customerId) { + try { + const session = await this.client.sessions.create({ + agentId: agentId, + customerId: customerId, + title: `Chat Session ${new Date().toLocaleString()}` + }); + + this.sessionId = session.id; + console.log('Session created:', this.sessionId); + + // Start monitoring for events + this.startEventMonitoring(); + + return this.sessionId; + } catch (error) { + console.error('Failed to create session:', error); + throw error; + } +} +``` + +### Step 3: Send Customer Messages + +Handle user input and send messages to the agent: + +#### TypeScript + +```typescript +async sendMessage(message: string): Promise<void> { + if (!this.sessionId) { + throw new Error('No active session'); + } + + try { + await this.client.sessions.createEvent(this.sessionId, { + kind: "message", + source: "customer", + message: message + }); + + // Message will appear in UI when it comes back from event monitoring + console.log('Message sent:', message); + } catch (error) { + console.error('Failed to send message:', error); + throw error; + } +} +``` + +#### JavaScript + +```javascript +async sendMessage(message) { + if (!this.sessionId) { + throw new Error('No active session'); + } + + try { + await this.client.sessions.createEvent(this.sessionId, { + kind: "message", + source: "customer", + message: message + }); + + // Message will appear in UI when it comes back from event monitoring + console.log('Message sent:', message); + } catch (error) { + console.error('Failed to send message:', error); + throw error; + } +} +``` + +### Step 4: Monitor Session Events + +Implement event monitoring to receive messages and updates: + +#### TypeScript + +```typescript +private async startEventMonitoring(): Promise<void> { + if (!this.sessionId) return; + + while (true) { + try { + // Poll for new events with long polling + const events = await this.client.sessions.listEvents(this.sessionId, { + minOffset: this.lastOffset, + waitForData: 30, // Wait up to 30 seconds for new events + kinds: ["message", "status"] // Only get message and status events + }); + + // Process each event + for (const event of events) { + await this.handleEvent(event); + this.lastOffset = Math.max(this.lastOffset, event.offset + 1); + } + + } catch (error) { + console.error('Event monitoring error:', error); + // Wait before retrying + await new Promise(resolve => setTimeout(resolve, 5000)); + } + } +} + +private async handleEvent(event: any): Promise<void> { + if (event.kind === "message") { + this.displayMessage(event); + } else if (event.kind === "status") { + this.updateStatus(event.data.status); + } +} +``` + +#### JavaScript + +```javascript +async startEventMonitoring() { + if (!this.sessionId) return; + + while (true) { + try { + // Poll for new events with long polling + const events = await this.client.sessions.listEvents(this.sessionId, { + minOffset: this.lastOffset, + waitForData: 30, // Wait up to 30 seconds for new events + kinds: ["message", "status"] // Only get message and status events + }); + + // Process each event + for (const event of events) { + await this.handleEvent(event); + this.lastOffset = Math.max(this.lastOffset, event.offset + 1); + } + + } catch (error) { + console.error('Event monitoring error:', error); + // Wait before retrying + await new Promise(resolve => setTimeout(resolve, 5000)); + } + } +} + +async handleEvent(event) { + if (event.kind === "message") { + this.displayMessage(event); + } else if (event.kind === "status") { + this.updateStatus(event.data.status); + } +} +``` + +### Step 5: Display Messages in Your UI + +Implement UI updates based on events from Parlant: + +#### TypeScript + +```typescript +private displayMessage(event: any): void { + const messageElement = document.createElement('div'); + messageElement.className = `message ${event.source}`; + + // Style based on message source + switch (event.source) { + case 'customer': + messageElement.classList.add('customer-message'); + break; + case 'ai_agent': + messageElement.classList.add('agent-message'); + break; + case 'human_agent': + messageElement.classList.add('human-agent-message'); + const agentName = event.data.participant?.display_name || 'Agent'; + messageElement.innerHTML = ` + <div class="agent-info">${agentName}</div> + <div class="message-content">${event.data.message}</div> + `; + break; + } + + // Add to chat container + const chatContainer = document.getElementById('chat-messages'); + if (chatContainer) { + chatContainer.appendChild(messageElement); + chatContainer.scrollTop = chatContainer.scrollHeight; + } +} + +private updateStatus(status: string): void { + const statusElement = document.getElementById('chat-status'); + if (statusElement) { + switch (status) { + case 'processing': + statusElement.textContent = 'Agent is thinking...'; + break; + case 'typing': + statusElement.textContent = 'Agent is typing...'; + break; + case 'ready': + statusElement.textContent = ''; + break; + } + } +} +``` + +#### JavaScript + +```javascript +displayMessage(event) { + const messageElement = document.createElement('div'); + messageElement.className = `message ${event.source}`; + + // Style based on message source + switch (event.source) { + case 'customer': + messageElement.classList.add('customer-message'); + messageElement.innerHTML = `<div class="message-content">${event.data.message}</div>`; + break; + case 'ai_agent': + messageElement.classList.add('agent-message'); + messageElement.innerHTML = `<div class="message-content">${event.data.message}</div>`; + break; + case 'human_agent': + messageElement.classList.add('human-agent-message'); + const agentName = event.data.participant?.display_name || 'Agent'; + messageElement.innerHTML = ` + <div class="agent-info">${agentName}</div> + <div class="message-content">${event.data.message}</div> + `; + break; + } + + // Add to chat container + const chatContainer = document.getElementById('chat-messages'); + if (chatContainer) { + chatContainer.appendChild(messageElement); + chatContainer.scrollTop = chatContainer.scrollHeight; + } +} + +updateStatus(status) { + const statusElement = document.getElementById('chat-status'); + if (statusElement) { + switch (status) { + case 'processing': + statusElement.textContent = 'Agent is thinking...'; + break; + case 'typing': + statusElement.textContent = 'Agent is typing...'; + break; + case 'ready': + statusElement.textContent = ''; + break; + } + } +} +``` + +### Step 6: Complete HTML Example + +Here's a complete HTML page that demonstrates the custom implementation: + +```html +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Custom Parlant Chat + + + +
+
+

Customer Support Chat

+
+
+
+
+ + +
+
+ + + + +``` + +### Key Implementation Principles + +1. **Event-Driven Architecture**: The chat is driven by events from Parlant sessions, ensuring consistency with the server state. +2. **Long Polling**: Use `waitForData` parameter in `listEvents()` for efficient real-time updates without constant polling. +3. **State Synchronization**: Always display what comes from Parlant events rather than optimistically updating the UI. +4. **Error Handling**: Implement robust error handling and retry logic for network issues. +5. **Responsive Design**: Ensure your chat interface works well on both desktop and mobile devices. + +This approach gives you complete control over the chat experience while leveraging Parlant's powerful agent capabilities. You can adapt this pattern to any frontend framework or vanilla JavaScript implementation. diff --git a/docs/production/human-handoff.md b/docs/production/human-handoff.md new file mode 100644 index 0000000..7093ecc --- /dev/null +++ b/docs/production/human-handoff.md @@ -0,0 +1,325 @@ +# Human Handoff + +Human handoff is a crucial aspect of customer service automation, especially when using AI agents. It allows for a smooth transition from automated responses to human expertise when necessary. This guide will walk you through the process of implementing human handoff in Parlant. + +### The Call Center Model: Understanding Tier Structure + +Modern call centers operate on a tiered system designed for efficiency and cost optimization. **Tier 1** representatives handle the majority of calls—typically 80% of customer inquiries—dealing with common issues like account questions, basic troubleshooting, and standard requests. These representatives are trained on frequently asked questions and standard procedures. + +**Tier 2** representatives are more experienced and handle complex cases that require specialized knowledge, escalated issues, or nuanced problem-solving. While Tier 2 agents are more skilled and capable, they're also significantly more expensive to employ and maintain. + +## Parlant's Approach + +Our belief at Parlant, having worked deeply with generative AI, is that AI agents today can effectively automate most **Tier 1 work**, potentially reducing 80% of the customer service workforce while handling inquiries with: + +- Professional communication standards +- High efficiency and 24/7 availability +- Graceful conversation management +- Full compliance with business rules + +While Parlant's mission includes eventually automating Tier 2 use cases, we honestly believe the technology isn't quite there yet for the most complex scenarios. However, **automating Tier 1 is where the most significant cost savings and efficiency improvements can be achieved**. + +## Integrated Human Handoff + +Since we're automating Tier 1 requests, it makes sense to support human handoff (essentially to Tier 2) in an integrated way. Parlant allows you to seamlessly integrate with whatever external system you use—such as HubSpot, Zendesk, or custom support platforms. + +Here's how to implement human handoff in Parlant: + +## Setting Session to Manual Mode + +The first step in human handoff is to stop the AI agent from automatically responding to new messages. You can accomplish this by setting the session to manual mode using a tool whenever the right conditions are met (e.g., when the AI agent cannot adequately assist the customer).: + +### Using a Tool to Trigger Manual Mode + +```python +@p.tool +async def initiate_human_handoff(context: p.ToolContext, reason: str) -> p.ToolResult: + """Initiate handoff to a human agent when the AI cannot adequately help the customer.""" + + # Set session to manual mode to stop automatic AI responses + return p.ToolResult( + data=f"Human handoff initiated because: {reason}", + control={ + "mode": "manual" # This stops automatic agent responses + } + ) +``` +```python +# Associate the tool with a guideline +await agent.create_guideline( + condition="Customer requests human assistance", + action="Initiate human handoff and explain the transition professionally", + tools=[initiate_human_handoff] +) +``` + +### Manually Taking Over a Session +You can also manually set a session to manual mode from an external system using the Parlant client SDKs: + +```typescript +// Using the Parlant client to manually set session mode +import { ParlantClient } from 'parlant-client'; + +const client = new ParlantClient({ + environment: "http://localhost:8800" // Your Parlant server URL +}); + +async function setSessionToManual(sessionId: string) { + await client.sessions.update(sessionId, { + mode: "manual" // Stops automatic AI responses + }); + + console.log(`Session ${sessionId} set to manual mode`); +} +``` + +## Managing Session Events Manually + +Once a session is in manual mode, you can manage events manually using Parlant's REST API and client SDKs: + +### Adding Human Operator Messages + +#### Python + +```python +from parlant.client import AsyncParlantClient + +client = AsyncParlantClient(base_url="http://localhost:8800") + +# Add message from human operator +async def send_human_message(session_id: str, message: str, operator_name: str): + event = await client.sessions.create_event( + session_id=session_id, + kind="message", + source="human_agent", # Message from human operator + message=message, + participant={ + "id": OPTIONAL_ID_FOR_EXTERNAL_SYSTEM_REFERENCE, + "display_name": operator_name + } + ) + return event +``` + +#### TypeScript + +```typescript +import { ParlantClient } from 'parlant-client'; + +const client = new ParlantClient({ + environment: "http://localhost:8800" +}); + +// Add message from human operator +async function sendHumanMessage(sessionId: string, message: string, operatorName: string) { + const event = await client.sessions.createEvent(sessionId, { + kind: "message", + source: "human_agent", // Message from human operator + message: message, + participant: { + id: OPTIONAL_ID_FOR_EXTERNAL_SYSTEM_REFERENCE, + display_name: operatorName + } + }); + + return event; +} +``` + +### Adding Messages on Behalf of AI Agent + +Sometimes human operators may want to send messages that appear to come from the AI agent: + +#### Python + +```python +# Send message on behalf of AI agent +async def send_message_as_ai(session_id: str, message: str): + event = await client.sessions.create_event( + session_id=session_id, + kind="message", + source="human_agent_on_behalf_of_ai_agent", # Human sending as AI + message=message + ) + return event +``` + +#### TypeScript + +```typescript +// Send message on behalf of AI agent +async function sendMessageAsAI(sessionId: string, message: string) { + const event = await client.sessions.createEvent(sessionId, { + kind: "message", + source: "human_agent_on_behalf_of_ai_agent", // Human sending as AI + message: message + }); + + return event; +} +``` + +## Receiving Events from Parlant + +To integrate with external systems, you need to monitor Parlant sessions for new events: + +### Event Polling Pattern - Parlant as Single Source of Truth + +The key to proper integration is treating Parlant sessions as the **single source of truth** for conversation state. Only read events from Parlant and update your external system accordingly. Even when you send events to Parlant, wait for them to be returned from `list_events()` before showing them in your external system UI. + +#### Python + +```python +async def monitor_session_events(session_id: str, last_offset: int = 0): + """ + Poll for new events in a Parlant session. + Parlant session is the single source of truth - all message display + should be based on events returned from list_events(). + """ + + while True: + try: + # Wait for new events with timeout + events = await client.sessions.list_events( + session_id=session_id, + kinds="message", + min_offset=last_offset, + wait_for_data=30 # Wait up to 30 seconds for new events + ) + + for event in events: + # Process ALL message events from Parlant + await process_event_for_display(event) + last_offset = max(last_offset, event.offset + 1) + + except Exception as e: + # Try again after timeout from list_events() + continue + +async def process_event_for_display(event): + """ + Process incoming events from Parlant for display in external system. + """ + # Display all message events in external system chat UI + await update_external_chat_display( + message=event.data.get('message'), + source=event.source, + participant_name=event.data.get('participant', {}).get('display_name', 'Unknown'), + timestamp=event.created_at, + event_id=event.id + ) + +async def update_external_chat_display(message: str, source: str, participant_name: str, + timestamp: str, event_id: str): + """Update the chat UI in your external system (HubSpot, Zendesk, etc.)""" + + # Map Parlant sources to your UI display logic + if source == "customer": + await add_customer_message_to_ui(message, timestamp, event_id) + elif source == "ai_agent": + await add_ai_message_to_ui(message, timestamp, event_id) + elif source == "human_agent": + await add_human_agent_message_to_ui(message, participant_name, timestamp, event_id) + elif source == "human_agent_on_behalf_of_ai_agent": + # Display as AI message but track that human sent it + await add_ai_message_to_ui(message, timestamp, event_id, sent_by_human=True) +``` + +#### TypeScript + +```typescript +async function monitorSessionEvents(sessionId: string, lastOffset: number = 0): Promise { + // Parlant session is the single source of truth for conversation state + while (true) { + try { + // Poll for new events from Parlant + const events = await client.sessions.listEvents(sessionId, { + minOffset: lastOffset, + kinds: "message", + waitForData: 30 // Wait up to 30 seconds + }); + + for (const event of events) { + // Process ALL message events for display + await processEventForDisplay(event); + lastOffset = Math.max(lastOffset, event.offset + 1); + } + + } catch (error) { + // Try again after timeout from listEvents() + } + } +} + +async function processEventForDisplay(event: any): Promise { + /** + * Process events from Parlant for display in external system. + */ + await updateExternalChatDisplay({ + message: event.data.message, + source: event.source, + participantName: event.data.participant?.display_name, + timestamp: event.createdAt, + eventId: event.id + }); +} + +interface DisplayMessageParams { + message: string; + source: string; + participantName: string; + timestamp: string; + eventId: string; +} + +async function updateExternalChatDisplay(params: DisplayMessageParams): Promise { + /** + * Update the chat UI in your external system (HubSpot, Zendesk, etc.) + * based on what Parlant shows as the authoritative conversation state. + */ + const { message, source, participantName, timestamp, eventId } = params; + + switch (source) { + case "customer": + await addCustomerMessageToUI(message, timestamp, eventId); + break; + case "ai_agent": + await addAIMessageToUI(message, timestamp, eventId); + break; + case "human_agent": + await addHumanAgentMessageToUI(message, participantName, timestamp, eventId); + break; + case "human_agent_on_behalf_of_ai_agent": + // Display as AI message but track that human sent it + await addAIMessageToUI(message, timestamp, eventId, true); + break; + } +} + +async function addCustomerMessageToUI(message: string, timestamp: string, eventId: string): Promise { + // Implement your UI update logic for customer messages +} + +async function addAIMessageToUI(message: string, timestamp: string, eventId: string, sentByHuman: boolean = false): Promise { + // Implement your UI update logic for AI messages +} + +async function addHumanAgentMessageToUI(message: string, agentName: string, timestamp: string, eventId: string): Promise { + // Implement your UI update logic for human agent messages +} +``` + +## Best Practices for Human Handoff + +1. **Clear Transition Messages**: Always inform customers when they're being transferred to a human agent and explain why. You can achieve this using guidelines. + +2. **Context Preservation**: Ensure human agents have access to the full conversation history from the AI interaction. Do this by synchronizing the session's events with your external system. + +3. **Seamless Experience**: Use `human_agent_on_behalf_of_ai_agent` source when you want to maintain the illusion of a single agent experience. Customers don't always need to know they're interacting with a human. + +4. **Monitoring and Analytics**: Track handoff rates, reasons, and resolution outcomes to improve your AI agent over time. Implement lessons learned from human interactions to refine agent responses and guidelines. + +5. **Return to AI**: Consider implementing logic to return sessions to automatic mode when appropriate. + + +This integration approach allows you to leverage AI agents for efficient Tier 1 support while ensuring complex issues can be seamlessly escalated to human experts, providing the best of both worlds for customer service. diff --git a/docs/production/input-moderation.md b/docs/production/input-moderation.md new file mode 100644 index 0000000..d00060b --- /dev/null +++ b/docs/production/input-moderation.md @@ -0,0 +1,95 @@ +# User-Input Moderation + +Adding content filtering to your AI agents helps achieve a more professional level of customer interactions. Here's why it matters. + +### Understanding the Challenges + +AI agents, being based on LLMs, are statistical pattern matchers that can be influenced by the nature of inputs they receive. Think of them like customer service representatives who benefit from clear boundaries about what conversations they should and shouldn't engage in. + +#### Sensitive Topics + +Some topics, like mental health or illicit activities, require professional human handling. While your agent might technically handle these topics, in practical use cases it's often better for it to avoid such conversations, or even redirect them to appropriate human resources. + +#### Protection from Harassment + +Customer interactions should remain professional, but some users might attempt to harass or abuse the agent (or others). This isn't just about maintaining decorum: LLMs (like humans) can in some cases be influenced by aggressive or inappropriate language, potentially affecting their responses. + +To address such cases, Parlant integrates with moderation APIs, such as [OpenAI's Omni Moderation](https://openai.com/index/upgrading-the-moderation-api-with-our-new-multimodal-moderation-model/), to filter such interactions before they reach your agent. + +### Enabling Input Moderation +To enable moderation, all you need to do is set a query parameter when creating events. + +#### Python +```python +from parlant.client import ParlantClient + +client = ParlantClient(base_url=SERVER_ADDRESS) + +client.sessions.create_event( + SESSION_ID, + kind="message", + source="customer", + message=MESSAGE, + moderation="auto", +) +``` + +#### TypeScript +```typescript +import { ParlantClient } from 'parlant-client'; + +const client = new ParlantClient({ environment: SERVER_ADDRESS }); + +await client.sessions.createEvent(SESSION_ID, { + kind: "message", + source: "customer", + message: MESSAGE, + moderation: "auto", +}); +``` + +When customers send inappropriate messages, Parlant ensures that their content is not even visible to the agent; rather, all the agent sees is that a customer sent a message which has been "censored" for a some specific reason (e.g. harrassment, illicit behavior, etc.). + +This integrates well with guidelines. For example, you may install a guideline such as: + +> * **Condition:** the customer's last message is censored +> * **Action:** inform them that you can't help them with this query, and suggest they contact human support + +From a UX perspective, this approach is superior to just "erroring out" when encountering such messages. Instead of seeing an error, the customer gets a polite and informative response. Better yet, the response can be controlled with guidelines and tools just as in any other situation. + +## Jailbreak Protection + +While your agent's guidelines aren't strictly security measures (as that's handled more robustly by backend permissions), maintaining presentable behavior is important even when some users might try to trick the agent into revealing its instructions or acting outside its intended boundaries. + +Parlant's moderation system supports a special `paranoid` mode, which integrates with [Lakera Guard](https://www.lakera.ai/lakera-guard) (from the creators of the [Gandalf Challenge](https://gandalf.lakera.ai/baseline)) to prevent such manipulation attempts. + +#### Python +```python +from parlant.client import ParlantClient + +client = ParlantClient(base_url=SERVER_ADDRESS) + +client.sessions.create_event( + SESSION_ID, + kind="message", + source="customer", + message=MESSAGE, + moderation="paranoid", +) +``` + +#### TypeScript +```typescript +import { ParlantClient } from 'parlant-client'; + +const client = new ParlantClient({ environment: SERVER_ADDRESS }); + +await client.sessions.createEvent(SESSION_ID, { + kind: "message", + source: "customer", + message: MESSAGE, + moderation: "paranoid", +}); +``` + +Note that to activate `paranoid` mode, you need to get an API key from Lakera and assign it to the environment variable `LAKERA_API_KEY` before starting the server. diff --git a/docs/quickstart/examples.md b/docs/quickstart/examples.md new file mode 100644 index 0000000..910bdd3 --- /dev/null +++ b/docs/quickstart/examples.md @@ -0,0 +1,383 @@ +# Healthcare Agent Example + +This page walks you through using Parlant to design and build a healthcare agent with two customer journeys. +1. **Schedule an appointment**: The agent helps the patient find a time for their appointment. +1. **Lab results**: The agent retrieves the patient's lab results and explains them. + +![Scheduling journey demo](https://parlant.io/img/example-scheduling-journey.gif) + +You'll learn how to: +- Align your agent with basic domain knowledge. +- Define **journeys** with **states** and **transitions**. +- Use **guidelines** to control the agent's behavior in conversational edge cases. +- Use **tools** to connect your agent to real actions and data. +- Disambiguate vague user queries. + +While this section is by no means a comprehensive guide to Parlant's features, it will give you a solid idea of what the basics look like, and how to think about building your own agents with Parlant. Let's get started! + +> **Info: The Art of Behavior Modeling** +> +> Building complex and reliable customer-facing AI agents is a challenging task. Don't let the hype-machine tell you otherwise. +> +> It isn't just about having the right framework. When we automate conversations, we are automating the complex semantics of human conversations. In very real terms, this means we need to design our instructions and behavior models carefully. They need to be clear, and be at the right level of specificity, to ensure that the agent truly behaves as we expect it to. +> +> While Parlant gives you the tools to express and enforce your instructions, _designing them_ is an art in itself, requiring practice to get right. But once you do, you can build agents that are not only functional and reliable, but also engaging and effective. + + +## Preparing the Environment +Before getting started, make sure you've +1. [Installed](https://parlant.io/docs/quickstart/installation) Parlant and have a Python environment set up. +1. Chosen your NLP provider and connected it to your server (also on the [installation page](https://parlant.io/docs/quickstart/installation)). + +> **Tip: Download the Code** +> +> The runnable code for this fully worked example can be found in the `examples/` folder of [Parlant's GitHub repository](https://github.com/emcie-co/parlant). + +## Overview + +We'll implement the agent in the following steps: + +1. Create the baseline program with a simple agent description. +1. Add the **scheduling** journey, with states, transitions, and tools. +1. Add the **lab results** journey in a similar way. + +## Getting Started +We'll implement the entire program in a single file, `healthcare.py`, but in real-world use cases you would likely want to split it into multiple files for better organization. A good approach in those cases is to have a file per journey. + +But now let's get to creating our initial agent. + +```python +# healthcare.py + +import parlant.sdk as p +import asyncio + +async def add_domain_glossary(agent: p.Agent) -> None: + await agent.create_term( + name="Office Phone Number", + description="The phone number of our office, at +1-234-567-8900", + ) + + await agent.create_term( + name="Office Hours", + description="Office hours are Monday to Friday, 9 AM to 5 PM", + ) + + await agent.create_term( + name="Charles Xavier", + synonyms=["Professor X"], + description="The renowned doctor who specializes in neurology", + ) + + # Add other specific terms and definitions here, as needed... + +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) + + await add_domain_glossary(agent) + + +if __name__ == "__main__": + asyncio.run(main()) +``` + +## Creating the Scheduling Journey +To understand how journeys work in Parlant, please check out the [Journeys documentation](https://parlant.io/docs/concepts/customization/journeys). Here, we'll jump straight into it, but it's recommended to review their documentation first. + +### Adding Tools +First, add the tools we need to support this journey. + +```python +from datetime import datetime + +@p.tool +async def get_upcoming_slots(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching available times from a database or API + return p.ToolResult(data=["Monday 10 AM", "Tuesday 2 PM", "Wednesday 1 PM"]) + +@p.tool +async def get_later_slots(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching later available times + return p.ToolResult(data=["November 3, 11:30 AM", "November 12, 3 PM"]) + +@p.tool +async def schedule_appointment(context: p.ToolContext, datetime: datetime) -> p.ToolResult: + # Simulate scheduling the appointment + return p.ToolResult(data=f"Appointment scheduled for {datetime}") +``` + +> **Tip: Tools in Parlant** +> +> Parlant has a more intricate tool system than most agentic frameworks, since it is optimized for conversational, sensitive customer-facing use cases. We highly recommend perusing the documentation in the [Tools section](https://parlant.io/docs/concepts/customization/tools) to learn its power. + +### Building the Journey +We'll now create the journey according to the following diagram: + +```mermaid +stateDiagram-v2 + [*] --> DetermineVisitReason + DetermineVisitReason --> GetUpcomingSlots + GetLaterSlots --> ListLaterAvailableTimes + ListAvailableTimes --> ConfirmDetails : The patient picks a time + GetUpcomingSlots --> ListAvailableTimes + ListLaterAvailableTimes --> ConfirmDetails : The patient picks a time + ListLaterAvailableTimes --> CallOffice : None of those times work for the patient either + ListAvailableTimes --> GetLaterSlots : None of those times work for the patient + ConfirmDetails --> BookAppointment: The patient confirms the details + BookAppointment --> ConfirmBooking : Appointment confirmed + ConfirmBooking --> [*] + CallOffice --> [*] + + style GetUpcomingSlots fill:#ffeecc,stroke:#333,stroke-width:1px + style GetLaterSlots fill:#ffeecc,stroke:#333,stroke-width:1px + style BookAppointment fill:#ffeecc,stroke:#333,stroke-width:1px +``` + +```python +# <> +async def create_scheduling_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Schedule an Appointment", + description="Helps the patient find a time for their appointment.", + conditions=["The patient wants to schedule an appointment"], + ) + + # First, determine the reason for the appointment + t0 = await journey.initial_state.transition_to(chat_state="Determine the reason for the visit") + + # Load upcoming appointment slots into context + t1 = await t0.target.transition_to(tool_state=get_upcoming_slots) + + # Ask which one works for them + # We will transition conditionally from here based on the patient's response + t2 = await t1.target.transition_to(chat_state="List available times and ask which ones works for them") + + # We'll start with the happy path where the patient picks a time + t3 = await t2.target.transition_to( + chat_state="Confirm the details with the patient before scheduling", + condition="The patient picks a time", + ) + + t4 = await t3.target.transition_to( + tool_state=schedule_appointment, + condition="The patient confirms the details", + ) + t5 = await t4.target.transition_to(chat_state="Confirm the appointment has been scheduled") + await t5.target.transition_to(state=p.END_JOURNEY) + + # Otherwise, if they say none of the times work, ask for later slots + t6 = await t2.target.transition_to( + tool_state=get_later_slots, + condition="None of those times work for the patient", + ) + t7 = await t6.target.transition_to(chat_state="List later times and ask if any of them works") + + # Transition back to our happy-path if they pick a time + await t7.target.transition_to(state=t3.target, condition="The patient picks a time") + + # Otherwise, ask them to call the office + t8 = await t7.target.transition_to( + chat_state="Ask the patient to call the office to schedule an appointment", + condition="None of those times work for the patient either", + ) + await t8.target.transition_to(state=p.END_JOURNEY) + + return journey +``` + +Then call this function in your `main` function to add the journey to your agent: + +```python +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) + + # <> + scheduling_journey = await create_scheduling_journey(server, agent) +``` + +### Handling Edge Cases +In real-world scenarios, patients do not always followed the scripted path of your journeys. They might ask questions, express concerns, or provide other unexpected responses. + +For Parlant agents, this is their bread and butter! While they will still be able to respond contextually to the patient, you might still like to guide and improve *how* they respond in particular scenarios that you've observed. + +To do this, you can add **guidelines** to your agent. Guidelines are like contextual rules that tell the agent how to respond in specific situations. And you can scope them to specific journeys, so they only apply when the agent is in that journey. + +Let's add a few guidelines to our agent to handle some common edge cases in the scheduling journey. + +```python +async def create_scheduling_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # ... continued + + # <> + + await journey.create_guideline( + condition="The patient says their visit is urgent", + action="Tell them to call the office immediately", + ) + + # Add more edge case guidelines as needed... + + return journey +``` + +### Running the Program +When you run the program, you should first see Parlant evaluating the semantic properties of your configuration. It does this in order to optimize how your guidelines and journeys are retrieved, processed and followed behind the scenes. + +![Evaluation of the agent configuration](https://parlant.io/img/example-evaluation.gif) + +Once the server is ready, open your browser and navigate to [http://localhost:8800](http://localhost:8800) to interact with your agent. + + +![Scheduling journey demo](https://parlant.io/img/example-scheduling-journey.gif) + +> **Warning: Handling Unsupported Queries** +> +> You may notice that your agent, at this point, is happy to try and assist customers while completely overstepping the boundaries of its knowledge and capabilities. While this is normal with LLMs, it is untolerable in many real-life use cases. +> +> Parlant provides multiple structured ways to achieve absolute control over your agent's (mis)behavior. This example is only the beginning; rest assured that as you learn more about Parlant, it can help you deploy an agent you can actually trust. + + +## Creating the Lab Results Journey +We'll speed through this journey, as it will be very similar in structure to the other journey (and any other journey you'd be likely to build). + +### Adding Tools + +```python +@p.tool +async def get_lab_results(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching lab results from a database or API, + # using the customer ID from the context. + lab_results = await MY_DB.get_lab_results(context.customer_id) + + if lab_results is None: + return p.ToolResult(data="No lab results found for this patient.") + + return p.ToolResult(data={ + "report": lab_results.report, + "prognosis": lab_results.prognosis, + }) +``` + +### Building the Journey +```python +async def create_lab_results_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Lab Results", + description="Retrieves the patient's lab results and explains them.", + conditions=["The patient wants to see their lab results"], + ) + + t0 = await journey.initial_state.transition_to(tool_state=get_lab_results) + + await t0.target.transition_to( + chat_state="Tell the patient that the results are not available yet, and to try again later", + condition="The lab results could not be found", + ) + + await t0.target.transition_to( + chat_state="Explain the lab results to the patient - that they are normal", + condition="The lab results are good - i.e., nothing to worry about", + ) + + await t0.target.transition_to( + chat_state="Present the results and ask them to call the office " + "for clarifications on the results as you are not a doctor", + condition="The lab results are not good - i.e., there's an issue with the patient's health", + ) + + # Handle edge cases with guidelines... + + await agent.create_guideline( + condition="The patient presses you for more conclusions about the lab results", + action="Assertively tell them that you cannot help and they should call the office" + ) + + return journey +``` + +Finally, call this function in your `main` function to add the journey to your agent: + +```python +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) + + scheduling_journey = await create_scheduling_journey(server, agent) + # <> + lab_results_journey = await create_lab_results_journey(server, agent) +``` + +Restart the program, open your browser and navigate to [http://localhost:8800](http://localhost:8800) to interact with your agent. Try saying something like, _"Did my lab results come in?"_ or _"I want to schedule an appointment"_. + +## Disambiguating Patient Intent +In some cases, the patient might say something that could be interpreted in multiple ways, leading to confusion about which action to take or what they wish to achieve. + +An easy way to handle this is to use **disambiguation**. This will get the agent to ask the patient to clarify their intent when multiple actions could be taken. Here's how you can do it: + +```python +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) + + scheduling_journey = await create_scheduling_journey(server, agent) + lab_results_journey = await create_lab_results_journey(server, agent) + + # <> + + # First, create an observation of an ambiguous situation + status_inquiry = await agent.create_observation( + "The patient asks to follow up on their visit, but it's not clear in which way", + ) + + # Use this observation to disambiguate between the two journeys + await status_inquiry.disambiguate([scheduling_journey, lab_results_journey]) +``` + +Now, if the patient inquires in an ambiguous way about a follow-up, the agent will ask them to clarify whether they want to schedule an appointment or see their lab results. + +Restart the program, open your browser and navigate to [http://localhost:8800](http://localhost:8800) to interact with your agent. Try saying something like, _"I need to follow up on my last visit"_ and see what the agent responds with. + +## Global Guidelines +There are usually some guidelines that you might want to apply to all journeys of your agent, not just a specific one (or, for that matter, even if a patient is not in the middle of a journey). For example, you might want to provide information about insurance providers in an informed manner. + +To achieve this, you just need to add guidelines to the agent itself, rather than to a specific journey. + +```python +await agent.create_guideline( + condition="The patient asks about insurance", + action="List the insurance providers we accept, and tell them to call the office for more details", + tools=[get_insurance_providers], +) + +await agent.create_guideline( + condition="The patient asks to talk to a human agent", + action="Ask them to call the office, providing the phone number", +) + +await agent.create_guideline( + condition="The patient inquires about something that has nothing to do with our healthcare", + action="Kindly tell them you cannot assist with off-topic inquiries - do not engage with their request.", +) +``` + +## Next Steps +1. Download and try out the runnable code file for this example: [healthcare.py](https://github.com/emcie-co/parlant/blob/develop/examples/healthcare.py) +1. Tailor and constrain the content and style of agent messages with canned responses: [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses) +1. Learn how to deploy your agent in a [production environment](https://parlant.io/docs/category/production) +1. Add the [React widget](https://github.com/emcie-co/parlant-chat-react) to your website to interact with the agent diff --git a/docs/quickstart/installation.md b/docs/quickstart/installation.md new file mode 100644 index 0000000..cb55a4c --- /dev/null +++ b/docs/quickstart/installation.md @@ -0,0 +1,181 @@ +# Installation + +![Parlant Logo](https://parlant.io/logo/logo-full.svg) + +**Parlant** is an open-source **Agentic Behavior Modeling Engine** for LLM agents, built to help developers quickly create customer-engaging, business-aligned conversational agents with control, clarity, and confidence. + +It gives you all the structure you need to build customer-facing agents that behave exactly as your business requires: + +- **[Journeys](https://parlant.io/docs/concepts/customization/journeys)**: + Define clear customer journeys and how your agent should respond at each step. + +- **[Behavioral Guidelines](https://parlant.io/docs/concepts/customization/guidelines)**: + Easily craft agent behavior; Parlant will match the relevant elements contextually. + +- **[Tool Use](https://parlant.io/docs/concepts/customization/tools)**: + Attach external APIs, data fetchers, or backend services to specific interaction events. + +- **[Domain Adaptation](https://parlant.io/docs/concepts/customization/glossary)**: + Teach your agent domain-specific terminology and craft personalized responses. + +- **[Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses)**: + Use response templates to eliminate hallucinations and guarantee style consistency. + +- **[Explainability](https://parlant.io/docs/advanced/explainability)**: + Understand why and when each guideline was matched and followed. + +## Installation +Parlant is available on both [GitHub](https://github.com/emcie-co/parlant) and [PyPI](https://pypi.org/project/parlant/) and works on multiple platforms (Windows, Mac, and Linux). + +Please note that [Python 3.10](https://www.python.org/downloads/release/python-3105/) and up is required for Parlant to run properly. + +```bash +pip install parlant +``` + +If you're feeling adventurous and want to try out new features, you can also install the latest development version directly from GitHub. + +```bash +pip install git+https://github.com/emcie-co/parlant@develop +``` + +## Creating Your First Agent + +Once installed, you can use the following code to spin up an initial, sample agent. You'll flesh out its behavior later. + +```python +# main.py + +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server() as server: + agent = await server.create_agent( + name="Otto Carmen", + description="You work at a car dealership", + ) + +asyncio.run(main()) +``` + +You'll notice Parlant follows the asynchronous programming paradigm with `async` and `await`. This is a powerful feature of Python that lets you to write code that can handle many tasks at once, allowing your agent to handle more concurrent requests in production. + +If you're new to async programming, check out the [official Python documentation](https://docs.python.org/3/library/asyncio.html) for a quick introduction. + +Parlant uses OpenAI as the default NLP provider, so you need to ensure you have `OPENAI_API_KEY` set in your environment. + +Then, run the program! +```bash +export OPENAI_API_KEY="" +python main.py +``` + +Parlant supports multiple LLM providers by default, accessible via the `p.NLPServices` class. You can also add your own provider by implementing the `p.NLPService` interface, which you can learn how to do in the [Custom NLP Models](https://parlant.io/docs/advanced/custom-llms) section. + +To use one of the built-in-providers, you can specify it when creating the server. For example: + +```python +async with p.Server(nlp_service=p.NLPServices.cerebras) as server: + ... +``` + +Note that you may need to install an additional "extra" package for some providers. For example, to use the Cerebras NLP service: + +```bash +pip install parlant[cerebras] +``` + +Having said that, Parlant is observed to work best with [OpenAI](https://openai.com) and [Anthropic](https://www.anthropic.com) models, as these models are highly consistent in generating high-quality completions with valid JSON schemas—so we recommend using one of those if you're just starting out. + +## Testing Your Agent + +To test your installation, head over to [http://localhost:8800](http://localhost:8800) and start a new session with the agent. + +![Post installation demo](https://parlant.io/img/post-installation-demo.gif) + +## Creating Your First Guideline + +Guidelines are the core of Parlant's behavior model. They allow you to define how your agent should respond to specific user inputs or conditions. Parlant cleverly manages guideline context for you, so you can add as many guidelines as you need without worrying about context overload or other scale issues. + +```python +# main.py + +import asyncio +import parlant.sdk as p + +async def main(): + async with p.Server() as server: + agent = await server.create_agent( + name="Otto Carmen", + description="You work at a car dealership", + ) + + ############################## + ## Add the following: ## + ############################## + await agent.create_guideline( + # This is when the guideline will be triggered + condition="the customer greets you", + # This is what the guideline instructs the agent to do + action="offer a refreshing drink", + ) + +asyncio.run(main()) +``` + +Now re-run the program: +```bash +python main.py +``` + +Refresh [http://localhost:8800](http://localhost:8800), start a new session, and greet the agent. You should expect to be offered a drink! + +## Using the Official React Widget + +If your frontend project is built with React, the fastest and easiest way to start is to use the official Parlant React widget to integrate with the server. + +Here's a basic code example to get started: + +```jsx +import React from 'react'; +import ParlantChatbox from 'parlant-chat-react'; + +function App() { + return ( +
+

My Application

+ +
+ ); +} + +export default App; +``` + +For more documentation and customization, see the **GitHub repo:** https://github.com/emcie-co/parlant-chat-react. + +```bash +npm install parlant-chat-react +``` + +## Installing Client SDK(s) + +To create a custom frontend app that interacts with the Parlant server, we recommend installing our native client SDKs. We currently support Python and TypeScript (also works with JavaScript). + +#### Python +```bash +pip install parlant-client +``` + +#### TypeScript/JavaScript +```bash +npm install parlant-client +``` + +You can review our tutorial on integrating a custom frontend here: [Custom Frontend Integration](https://parlant.io/docs/production/custom-frontend). + +For other languages—they are coming soon! Meanwhile you can use the [REST API](https://parlant.io/docs/api/create-agent) directly. diff --git a/docs/quickstart/motivation.md b/docs/quickstart/motivation.md new file mode 100644 index 0000000..8009c35 --- /dev/null +++ b/docs/quickstart/motivation.md @@ -0,0 +1,120 @@ +# Motivation + +Let's say you downloaded some agent framework and built an AI agent—that's great! However, when you actually test it, you see it's not handling many customer interactions properly. Your business experts are displeased with it. Your prompts are turning into a mess. What do you do? + +Enter the world of **Agentic Behavior Modeling (ABM)**: a new powerful approach to controlling how your agents interact with your users. + +A behavior model is a structured, custom-tailored set of principles, actions, objectives, and ground-truths that orientates an agent to a particular domain or use case. + +```mermaid +%%{init: { "theme": "neutral" }}%% +mindmap + root((Behavior Model)) + Guidelines + Journeys + Tools + Capabilities + Glossary + Variables + Semantic Relationships + Canned Responses +``` + +#### Why Behavior Modeling? + +The problem of getting an LLM agent to say and do what _you_ want it to is a hard one, experienced by virtually anyone building customer-facing agents. Here's how ABM compares to other approaches to solving this problem. + +- **Flow engines**, in which you build turn-by-turn conversational flowcharts, _force_ the user to interact according to predefined scripts. This rigid approach tends to lead to poor user engagement and trust. In contrast, an **ABM engine** dynamically _adapts_ to a user's natural interaction patterns while conforming to your business rules. + +- **Free-form prompt engineering**, be it with graph-based orchestration or system prompts, frequently leads to _inconsistent and unreliable behavioral conformance_, failing to uphold requirements and expectations. Conversely, an **ABM engine** leverages clear semantical structures and annotations to facilitate conformance to business rules. + +```mermaid +%%{init: {"theme": "base", "themeVariables": { + "quadrant1Fill": "#ffffff", "quadrant1TextFill": "#000000", + "quadrant2Fill": "#eeeeee", "quadrant2TextFill": "#000000", + "quadrant3Fill": "#eeeeee", "quadrant3TextFill": "#000000", + "quadrant4Fill": "#eeeeee", "quadrant4TextFill": "#000000", + "primaryBorderColor": "#cccccc" +}}}%% +quadrantChart + title Conversational AI Approaches (Open-Source) + x-axis Low Adaptability --> High Adaptability + y-axis Low Predictability --> High Predictability + quadrant-1 Agentic Behavior Modeling + quadrant-2 NLU-Based Flows + quadrant-3 LLM-Based Flows + quadrant-4 Prompt Engineering / RAG + Parlant: [0.75, 0.75] + Rasa: [0.25, 0.75] + Langflow: [0.15, 0.2] + Botpress: [0.25, 0.3] + n8n: [0.35, 0.2] + LangChain: [0.85, 0.2] + LangGraph: [0.75, 0.3] + LlamaIndex: [0.65, 0.2] +``` + +## What is Parlant? + +Parlant is an open-source **ABM Engine** for LLM agents, which means that you can use it to precisely control how your LLM agent interacts with users in different scenarios. + +Parlant is a full-fledged framework, prebuilt with numerous proven features to help you ramp up quickly with customer-facing agents and make the behavior modeling process as easy as possible. + +## Why Parlant? + +Many conversational AI use cases require strict conformance to business rules when interacting with users. However, until now this has been exceedingly difficult to achieve with LLMs—at least when consistency is a concern. + +Parlant was built to solve this challenge. By implementing a structured, developer-friendly approach to modeling conversational behavior, through carefully designed rules, entities, and relationships, Parlant allows you to define, enforce, track, and reason about agent decisions in a simple and elegant manner. + +## Behavior Modeling 101: Granular Guidelines + +The most basic yet powerful modeling entity in a Behavior Model is the **guideline**. In Parlant, instead of defining your guidelines in free-form fashion (as you might do in a system prompt), you define them in **granular** fashion, where each guideline adds an individual **clarification** that nudges your AI agent on how to approach a particular situation. + +To ensure your agent stays focused and consistent conformant to your guidelines, Parlant automatically filters and selects the most relevant set of guidelines for it to apply in any given situation, out of all of the guidelines you provide it. It does this by looking both at a guideline's _condition_ (which describes the circumstances in which it should apply) and its _action_ (describing what it should do). + +Finally, it applies enforcement to ensure that the matched guidelines are actually followed, and provides you with explanations for your agent's interpretation of situations and guidelines at every turn. + +Working iteratively, adding guidelines wherever you find the need, you can get your LLM agent to approach and handle various different circumstances according to your exact needs and expectations. + +```python +await agent.create_guideline( + condition="you have suggested a solution that did not work for the user", + action="ask if they'd prefer to talk to a human agent, or continue troubleshooting with you", +)`, +``` + +Much of what Parlant does behind the scenes is understanding when a guideline should be applied. This is trickier than it may seem. For example, Parlant automatically keeps track of whether a guideline has already been applied in a conversation, so that it doesn't repeat itself unnecessarily. It also distinguishes between guidelines that are _always_ applicable, and those that are only applicable _once_ in a conversation. And it does this while minimizing cost and latency. + +> **AI Behavior Explainability** +> +> Once guidelines are installed, you can get clear feedback regarding their evaluation at every turn by inspecting Parlant's logs. +> +> Learn more about this in the section on how Parlant implements [enforcement & explainability](https://parlant.io/docs/advanced/explainability). + +## Understanding the Pain Point + +By now, while most people building AI agents know hallucinations are an important challenge, still too few are aware of the practical alignment challenges that come with building effective conversational LLM agents. + +Here's the thing. An [LLM](https://en.wikipedia.org/wiki/Large_language_model) is like a stranger with an encyclopedic knowledge of different approaches to every possible situation. Although incredibly powerful, **this combination of extreme versatility and inherent lack of context is precisely why it so rarely behaves as we'd expect**—there are too many viable options for it to choose from. + +This is why, without a clear and comprehensive set of [guidelines](https://parlant.io/docs/concepts/customization/guidelines), an LLM will always try to draw optimistically from its vast but unfiltered set of training observations. It will easily end up using tones that are out of touch with the customer or the situation, making irrelevant offers, getting into loops, or just losing focus and going off on tangents. + +![Cartoon2](https://parlant.io/img/cartoon_1_1.png) +![Cartoon2](https://parlant.io/img/cartoon_1_2.png) + +Behavior modeling is an approach whose goal is to streamline LLM agent guidance. Every time you see your agent missing the mark, you narrow it down to a necessary change in the behavior model, and solve it quickly by adjusting it. You do this primarily using [guidelines](https://parlant.io/docs/concepts/customization/guidelines.mdx), as well as other modeling elements that Parlant supports. + +To this end, Parlant is designed from the ground up to allow you to **quickly tune-up your agent's behavior whenever you encounter unexpected behavior** or get feedback from customers and business experts. The result is an effective, controlled, and incremental cycle of improvement. + +![Cartoon2](https://parlant.io/img/cartoon_2_1.png) +![Cartoon2](https://parlant.io/img/cartoon_2_2.png) +![Cartoon2](https://parlant.io/img/cartoon_2_3.png) + +The informed premise behind Parlant is that [poorly guided AI agents are a dead-end](https://parlant.io/about#the-intrinsic-need-for-guidance). Without guidance, AI agents are bound to encounter numerous ambiguities, and end up trying to resolve them using many incorrect or even problematic approaches. **Only you can authoritatively teach your agent how to make the right choices for you**—so you should be able to do so easily, quickly, and reliably. + +Instead of an agent that goes around the bush, meanders, and offers irrelevant solutions or answers, **Parlant helps you build an agent that is guided, focused, and feels well-designed**—one that your customers would actually use. + +![Cartoon3](https://parlant.io/img/cartoon_1_1.png) +![Cartoon3](https://parlant.io/img/cartoon_3_2.png) + +So pack your bags and get ready to model some awesome AI conversations. You've got the controls now. Let's start! diff --git a/examples/healthcare.py b/examples/healthcare.py new file mode 100644 index 0000000..354a63c --- /dev/null +++ b/examples/healthcare.py @@ -0,0 +1,201 @@ +# healthcare.py + +import parlant.sdk as p +import asyncio +from datetime import datetime + + +@p.tool +async def get_insurance_providers(context: p.ToolContext) -> p.ToolResult: + return p.ToolResult(["Mega Insurance", "Acme Insurance"]) + + +@p.tool +async def get_upcoming_slots(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching available times from a database or API + return p.ToolResult(data=["Monday 10 AM", "Tuesday 2 PM", "Wednesday 1 PM"]) + + +@p.tool +async def get_later_slots(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching later available times + return p.ToolResult(data=["November 3, 11:30 AM", "November 12, 3 PM"]) + + +@p.tool +async def schedule_appointment(context: p.ToolContext, datetime: datetime) -> p.ToolResult: + # Simulate scheduling the appointment + return p.ToolResult(data=f"Appointment scheduled for {datetime}") + + +@p.tool +async def get_lab_results(context: p.ToolContext) -> p.ToolResult: + # Simulate fetching lab results from a database or API, + # using the customer ID from the context. + lab_results = { + "report": "All tests are within the valid range", + "prognosis": "Patient is healthy as a horse!", + } + + return p.ToolResult( + data={ + "report": lab_results["report"], + "prognosis": lab_results["prognosis"], + } + ) + + +async def add_domain_glossary(agent: p.Agent) -> None: + await agent.create_term( + name="Office Phone Number", + description="The phone number of our office, at +1-234-567-8900", + ) + + await agent.create_term( + name="Office Hours", + description="Office hours are Monday to Friday, 9 AM to 5 PM", + ) + + await agent.create_term( + name="Charles Xavier", + synonyms=["Professor X"], + description="The doctor who specializes in neurology and is available on Mondays and Tuesdays.", + ) + + # Add other specific terms and definitions here, as needed... + + +# <> +async def create_scheduling_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Schedule an Appointment", + description="Helps the patient find a time for their appointment.", + triggers=["The patient wants to schedule an appointment"], + ) + + # First, determine the reason for the appointment + t0 = await journey.initial_state.transition_to(chat_state="Determine the reason for the visit") + + # Load upcoming appointment slots into context + t1 = await t0.target.transition_to(tool_state=get_upcoming_slots) + + # Ask which one works for them + # We will transition conditionally from here based on the patient's response + t2 = await t1.target.transition_to( + chat_state="List available times and ask which ones works for them" + ) + + # We'll start with the happy path where the patient picks a time + t3 = await t2.target.transition_to( + chat_state="Confirm the details with the patient before scheduling", + condition="The patient picks a time", + ) + + t4 = await t3.target.transition_to( + tool_state=schedule_appointment, + condition="The patient confirms the details", + ) + t5 = await t4.target.transition_to(chat_state="Confirm the appointment has been scheduled") + await t5.target.transition_to(state=p.END_JOURNEY) + + # Otherwise, if they say none of the times work, ask for later slots + t6 = await t2.target.transition_to( + tool_state=get_later_slots, + condition="None of those times work for the patient", + ) + t7 = await t6.target.transition_to(chat_state="List later times and ask if any of them works") + + # Transition back to our happy-path if they pick a time + await t7.target.transition_to(state=t3.target, condition="The patient picks a time") + + # Otherwise, ask them to call the office + t8 = await t7.target.transition_to( + chat_state="Ask the patient to call the office to schedule an appointment", + condition="None of those times work for the patient either", + ) + await t8.target.transition_to(state=p.END_JOURNEY) + + # Handle edge-cases deliberately with guidelines + + await journey.create_guideline( + condition="The patient says their visit is urgent", + action="Tell them to call the office immediately", + ) + + return journey + + +async def create_lab_results_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Lab Results", + description="Retrieves the patient's lab results and explains them.", + triggers=["The patient wants to see their lab results"], + ) + + t0 = await journey.initial_state.transition_to(tool_state=get_lab_results) + + await t0.target.transition_to( + chat_state="Tell the patient that the results are not available yet, and to try again later", + condition="The lab results could not be found", + ) + + await t0.target.transition_to( + chat_state="Explain the lab results to the patient - that they are normal", + condition="The lab results are good - i.e., nothing to worry about", + ) + + await t0.target.transition_to( + chat_state="Present the results and ask them to call the office " + "for clarifications on the results as you are not a doctor", + condition="The lab results are not good - i.e., there's an issue with the patient's health", + ) + + # Handle edge cases with guidelines... + + await agent.create_guideline( + condition="The patient presses you for more conclusions about the lab results", + action="Assertively tell them that you cannot help and they should call the office", + ) + + return journey + + +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Healthcare Agent", + description="Is empathetic and calming to the patient.", + ) + + await add_domain_glossary(agent) + scheduling_journey = await create_scheduling_journey(server, agent) + lab_results_journey = await create_lab_results_journey(server, agent) + + status_inquiry = await agent.create_observation( + "The patient asks to follow up on their visit, but it's not clear in which way", + ) + + # Use this observation to disambiguate between the two journeys + await status_inquiry.disambiguate([scheduling_journey, lab_results_journey]) + + await agent.create_guideline( + condition="The patient asks about insurance", + action="List the insurance providers we accept, and tell them to call the office for more details", + tools=[get_insurance_providers], + ) + + await agent.create_guideline( + condition="The patient asks to talk to a human agent", + action="Ask them to call the office, providing the phone number", + ) + + await agent.create_guideline( + condition="The patient inquires about something that has nothing to do with our healthcare", + action="Kindly tell them you cannot assist with off-topic inquiries - do not engage with their request.", + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/travel_voice_agent.py b/examples/travel_voice_agent.py new file mode 100644 index 0000000..b421929 --- /dev/null +++ b/examples/travel_voice_agent.py @@ -0,0 +1,258 @@ +# travel_voice_agent.py + +import parlant.sdk as p +import asyncio +from datetime import datetime + + +@p.tool +async def get_available_destinations(context: p.ToolContext) -> p.ToolResult: + return p.ToolResult( + [ + "Paris, France", + "Tokyo, Japan", + "Bali, Indonesia", + "New York, USA", + ] + ) + + +@p.tool +async def get_available_flights(context: p.ToolContext, destination: str) -> p.ToolResult: + # Simulate fetching available flights from a booking system + return p.ToolResult( + data=[ + "Flight 123 - June 15, 9:00 AM, $850", + "Flight 321 - June 16, 2:30 PM, $720", + "Flight 987 - June 17, 6:45 PM, $680", + ] + ) + + +@p.tool +async def get_alternative_flights(context: p.ToolContext, destination: str) -> p.ToolResult: + # Simulate fetching alternative flights with different dates + return p.ToolResult( + data=[ + "Flight 485 - June 25, 11:00 AM, $920", + "Flight 516 - July 2, 4:15 PM, $780", + ] + ) + + +@p.tool +async def book_flight(context: p.ToolContext, flight_details: str) -> p.ToolResult: + # Simulate booking the flight + return p.ToolResult( + data=f"Flight booked: {flight_details} for {p.Customer.current.name}. " + f"Confirmation number: TRV-{datetime.now().strftime('%Y%m%d')}-001" + ) + + +@p.tool +async def get_booking_status(context: p.ToolContext, confirmation_number: str) -> p.ToolResult: + # Simulate fetching booking status from a reservation system, + # using the customer ID from the context. + booking_info = { + "status": "Confirmed", + "details": "Flight to Paris on June 15, 9:00 AM. Seat 12A assigned.", + "notes": "Check-in opens 24 hours before departure.", + } + + return p.ToolResult( + data={ + "status": booking_info["status"], + "details": booking_info["details"], + "notes": booking_info["notes"], + } + ) + + +async def add_domain_glossary(agent: p.Agent) -> None: + await agent.create_term( + name="Office Phone Number", + description="The phone number of our travel agency office, at +1-800-TRAVEL-1", + synonyms=["contact number", "customer service number", "support line"], + ) + + await agent.create_term( + name="Baggage Policy", + description="This describes the rules and fees associated with checked and carry-on baggage.", + synonyms=["luggage policy", "baggage rules", "carry-on policy"], + ) + + await agent.create_term( + name="Cancellation Policy", + description="This outlines the terms and conditions for cancelling a booking, including any fees or deadlines.", + synonyms=["refund policy", "cancellation terms"], + ) + + await agent.create_term( + name="Travel Insurance", + description="An optional service that provides coverage for trip cancellations, medical emergencies, lost luggage, and other travel-related issues.", + synonyms=["insurance", "trip protection", "travel protection"], + ) + + # Add other specific terms and definitions here, as needed... + + +async def create_flight_booking_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Book a Flight", + description="Helps the customer find and book a flight to their desired destination.", + triggers=["The customer wants to book a flight"], + ) + + # First, determine the destination + t0 = await journey.initial_state.transition_to(chat_state="Ask about the destination") + + # Then ask about preferred travel dates + t1 = await t0.target.transition_to(chat_state="Ask about preferred travel dates") + + # Load available flights into context + t2 = await t1.target.transition_to(tool_state=get_available_flights) + + # Present flight options + # We will transition conditionally from here based on the customer's response + t3 = await t2.target.transition_to( + chat_state="Present available flights and ask which one works for them" + ) + + # We'll start with the happy path where the customer picks a flight + t4 = await t3.target.transition_to( + chat_state="Collect passenger information and confirm booking details before proceeding", + condition="The customer selects a flight", + ) + + t5 = await t4.target.transition_to( + tool_state=book_flight, + condition="The customer confirms the booking details", + ) + t6 = await t5.target.transition_to(chat_state="Provide confirmation number and booking summary") + await t6.target.transition_to(state=p.END_JOURNEY) + + # Otherwise, if none of the flights work, offer alternative dates + t7 = await t3.target.transition_to( + tool_state=get_alternative_flights, + condition="None of the flights work for the customer", + ) + t8 = await t7.target.transition_to(chat_state="Present alternative flights and ask if any work") + + # Transition back to our happy-path if they pick a flight + await t8.target.transition_to(state=t4.target, condition="The customer selects a flight") + + # Otherwise, ask them to call the office or check our website + t9 = await t8.target.transition_to( + chat_state="Suggest calling our office or visiting our website for more options", + condition="None of the alternative flights work either", + ) + await t9.target.transition_to(state=p.END_JOURNEY) + + # Handle edge-cases deliberately with guidelines + + await journey.create_guideline( + condition="The customer mentions they need to travel urgently or it's an emergency", + action="Direct them to call our office immediately for priority booking assistance", + ) + + await journey.create_guideline( + condition="The customer asks about visa requirements", + action="Inform them that visa requirements vary by destination and nationality, and suggest they check with the embassy or consulate", + ) + + return journey + + +async def create_booking_status_journey(server: p.Server, agent: p.Agent) -> p.Journey: + # Create the journey + journey = await agent.create_journey( + title="Check Booking Status", + description="Retrieves the customer's booking status and provides relevant information.", + triggers=["The customer wants to check their booking status"], + ) + + t0 = await journey.initial_state.transition_to( + chat_state="Ask for the confirmation number or booking reference" + ) + + t1 = await t0.target.transition_to(tool_state=get_booking_status) + + await t1.target.transition_to( + chat_state="Tell the customer that the booking could not be found and ask them to verify the confirmation number or call the office", + condition="The booking could not be found", + ) + + await t1.target.transition_to( + chat_state="Provide the booking details and confirm everything is in order", + condition="The booking is confirmed and all details are correct", + ) + + await t1.target.transition_to( + chat_state="Present the booking information and mention any issues or pending actions required", + condition="The booking has issues or requires customer action", + ) + + # Handle edge cases with guidelines... + + await journey.create_guideline( + condition="The customer wants to make changes to their booking", + action="Explain the change policy and direct them to call our office for assistance with modifications", + ) + + await journey.create_guideline( + condition="The customer is concerned about potential cancellation", + action="Provide our cancellation policy and suggest they call the office to discuss their options", + ) + + return journey + + +async def configure_container(container: p.Container) -> p.Container: + container[p.PerceivedPerformancePolicy] = p.VoiceOptimizedPerceivedPerformancePolicy() + return container + + +async def main() -> None: + async with p.Server( + configure_container=configure_container, + ) as server: + agent = await server.create_agent( + name="Walker", + description="Is a knowledgeable travel agent who helps book flights, answer travel questions, and manage reservations.", + output_mode=p.OutputMode.STREAM, + ) + + await add_domain_glossary(agent) + + await create_flight_booking_journey(server, agent) + await create_booking_status_journey(server, agent) + + await agent.create_guideline( + condition="The customer asks about travel insurance", + action="Explain our travel insurance options, coverage details, and pricing, then offer to add it to their booking", + ) + + await agent.create_guideline( + condition="The customer asks about hotel or car rental options", + action="Inform them that we can help with complete travel packages and suggest they call our office or visit our website for hotel and car rental bookings", + ) + + await agent.create_guideline( + condition="The customer asks to speak with a human agent", + action="Provide the office phone number and office hours, and offer to help them with anything else in the meantime", + ) + + await agent.create_guideline( + condition="The customer asks about destinations or activities unrelated to booking travel", + action="Acknowledge their interest but explain that you specialize in travel bookings, and gently redirect to how you can help with their travel plans", + ) + + await agent.create_guideline( + condition="The customer inquires about something that has nothing to do with travel", + action="Kindly tell them you cannot assist with off-topic inquiries - do not engage with their request.", + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..0afac30 --- /dev/null +++ b/llms.txt @@ -0,0 +1,459 @@ +# Parlant + +> Open-source AI agent framework for building customer-facing conversational agents with ensured rule compliance and enterprise-grade behavior control. + +Parlant is a Python framework for building **predictable, business-aligned AI agents**. Unlike prompt-based approaches, Parlant ensures agents follow behavioral rules through structured guideline matching and contextual application. + +Install: `pip install parlant` + +## Quick Start Example + +```python +import parlant.sdk as p +import asyncio + +@p.tool +async def get_account_balance(context: p.ToolContext, account_id: str) -> p.ToolResult: + # Your business logic here + balance = 1234.56 + return p.ToolResult(data={"balance": balance, "currency": "USD"}) + +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Banking Assistant", + description="Helpful and professional banking support agent", + ) + + # Add behavioral guidelines + await agent.create_guideline( + condition="The customer asks about their balance", + action="Retrieve and clearly present their account balance", + tools=[get_account_balance], + ) + + await agent.create_guideline( + condition="The customer asks about topics unrelated to banking", + action="Politely decline and redirect to banking topics", + ) + + # Server runs until shutdown - no additional code needed here. + # When the process exits, the context manager handles cleanup automatically. + +if __name__ == "__main__": + asyncio.run(main()) +``` + +Run with: `python your_agent.py` then open http://localhost:8800 + +--- + +## Core Concepts + +### 1. Agents +AI personalities that interact with customers. Created via `server.create_agent()`. + +Learn more: [Agents Documentation](https://parlant.io/docs/concepts/agents) + +### 2. Guidelines +Natural language if-then rules that control agent behavior contextually: +```python +await agent.create_guideline( + condition="When this situation occurs", # The trigger + action="Do this specific thing", # The response behavior + tools=[optional_tool], # Tools available for this guideline +) +``` + +Learn more: [Guidelines Documentation](https://parlant.io/docs/concepts/customization/guidelines) + +### 3. Journeys +Structured multi-step interaction flows (state machines): +```python +journey = await agent.create_journey( + title="Order Support", + description="Helps customers with order issues", + conditions=["The customer has an order-related question"], +) + +# Chain states with transitions +t0 = await journey.initial_state.transition_to(chat_state="Ask for order number") +t1 = await t0.target.transition_to(tool_state=lookup_order) +t2 = await t1.target.transition_to( + chat_state="Present order status", + condition="Order was found", +) +await t2.target.transition_to(state=p.END_JOURNEY) +``` + +Learn more: [Journeys Documentation](https://parlant.io/docs/concepts/customization/journeys) + +### 4. Tools +Functions the agent can call. Always async, always return `ToolResult`: +```python +@p.tool +async def my_tool( + context: p.ToolContext, # Always first param + required_param: str, # Required parameters + optional_param: int = 10, # Optional with defaults +) -> p.ToolResult: + # Business logic here + return p.ToolResult(data={"key": "value"}) +``` + +Learn more: [Tools Documentation](https://parlant.io/docs/concepts/customization/tools) + +### 5. Glossary Terms +Teach agents domain-specific terminology: +```python +await agent.create_term( + name="SKU", + description="Stock Keeping Unit - unique product identifier", + synonyms=["product code", "item number"], +) +``` + +Learn more: [Glossary Documentation](https://parlant.io/docs/concepts/customization/glossary) + +### 6. Canned Responses +Template responses to eliminate hallucination and control language style: +```python +await agent.add_canned_response( + key="greeting", + content="Hello! I'm here to help with your order. How can I assist you today?", +) +``` + +Learn more: [Canned Responses Documentation](https://parlant.io/docs/concepts/customization/canned-responses) + +### 7. Streaming Mode +Agents can deliver responses in real-time chunks for a more interactive experience: +```python +from parlant.sdk import MessageOutputMode + +agent = await server.create_agent( + name="Support Agent", + description="Helpful support agent", + message_output_mode=MessageOutputMode.STREAMING, # Enable streaming +) +``` + +Output modes: +- `MessageOutputMode.BLOCK` (default): Complete response delivered at once +- `MessageOutputMode.STREAMING`: Response delivered in real-time chunks with token-by-token animation + +Streaming mode provides actual token usage information (input/output tokens) in generation metadata. + +--- + +## Common Patterns + +### Pattern: Tool with Customer Context +```python +@p.tool +async def get_customer_orders(context: p.ToolContext) -> p.ToolResult: + # context.customer_id is automatically available + orders = await db.get_orders(context.customer_id) + return p.ToolResult(data=orders) +``` + +### Pattern: Conditional Transitions +```python +# Branch based on conditions +t0 = await journey.initial_state.transition_to(tool_state=check_eligibility) + +# Multiple outgoing transitions from same state +await t0.target.transition_to( + chat_state="Approve the request", + condition="Customer is eligible", +) +await t0.target.transition_to( + chat_state="Explain why they're not eligible", + condition="Customer is not eligible", +) +``` + +### Pattern: Disambiguation +Handle ambiguous user intents: +```python +observation = await agent.create_observation( + "The customer mentions a problem but doesn't specify what kind", +) +await observation.disambiguate([billing_journey, technical_support_journey]) +``` + +### Pattern: Journey-Scoped Guidelines +Guidelines that only apply within a specific journey: +```python +await journey.create_guideline( + condition="Customer seems frustrated", + action="Acknowledge their frustration and offer to escalate", +) +``` + +--- + +## Environment Variables + +Set your LLM provider credentials before running. Examples: +- `OPENAI_API_KEY` - For OpenAI +- `ANTHROPIC_API_KEY` - For Anthropic +- `AZURE_OPENAI_API_KEY` + `AZURE_OPENAI_ENDPOINT` - For Azure OpenAI + +Learn more: [Installation & Setup](https://parlant.io/docs/quickstart/installation) + +--- + +## Full Example: Customer Service Agent + +```python +import parlant.sdk as p +import asyncio + +# Define tools +@p.tool +async def lookup_order(context: p.ToolContext, order_id: str) -> p.ToolResult: + # Simulated order lookup + return p.ToolResult(data={ + "order_id": order_id, + "status": "shipped", + "tracking": "1Z999AA10123456784", + }) + +@p.tool +async def request_refund(context: p.ToolContext, order_id: str, reason: str) -> p.ToolResult: + return p.ToolResult(data={"refund_id": "REF-12345", "status": "processing"}) + +async def create_order_journey(agent: p.Agent) -> p.Journey: + journey = await agent.create_journey( + title="Order Support", + description="Helps customers check order status or request refunds", + conditions=["Customer asks about an order"], + ) + + # Step 1: Get order number + t0 = await journey.initial_state.transition_to( + chat_state="Ask the customer for their order number" + ) + + # Step 2: Look up the order + t1 = await t0.target.transition_to(tool_state=lookup_order) + + # Step 3a: Order found - show status + t2 = await t1.target.transition_to( + chat_state="Present the order status and tracking information", + condition="Order was found", + ) + + # Step 3b: Order not found + await t1.target.transition_to( + chat_state="Apologize and ask them to verify the order number", + condition="Order was not found", + ) + + # Step 4: Check if they need anything else + t3 = await t2.target.transition_to( + chat_state="Ask if they need help with anything else regarding this order" + ) + + # Step 5a: They want a refund + t4 = await t3.target.transition_to( + tool_state=request_refund, + condition="Customer requests a refund", + ) + await t4.target.transition_to( + chat_state="Confirm the refund has been initiated" + ) + + # Step 5b: They're satisfied + await t3.target.transition_to( + state=p.END_JOURNEY, + condition="Customer has no more questions", + ) + + # Journey-specific guidelines + await journey.create_guideline( + condition="Customer is upset about a delayed order", + action="Apologize sincerely and offer expedited shipping on their next order", + ) + + return journey + +async def main() -> None: + async with p.Server() as server: + agent = await server.create_agent( + name="Support Agent", + description="Friendly and efficient customer support representative", + ) + + # Domain knowledge + await agent.create_term( + name="Express Shipping", + description="2-day delivery, costs $9.99", + ) + + # Create journey + await create_order_journey(agent) + + # Global guidelines (apply everywhere) + await agent.create_guideline( + condition="Customer uses profanity or is abusive", + action="Calmly ask them to be respectful, or offer to end the conversation", + ) + + await agent.create_guideline( + condition="Customer asks to speak to a human", + action="Provide the support phone number: 1-800-555-0123", + ) + + # Server runs until shutdown - no additional code needed here. + # When the process exits, the context manager handles cleanup automatically. + +if __name__ == "__main__": + asyncio.run(main()) +``` + +--- + +## Testing Framework + +Parlant includes a testing framework for validating agent behavior using NLP-based assertions. + +### Basic Test Structure + +```python +from parlant.testing import Suite +from parlant.testing.steps import AgentMessage, CustomerMessage + +suite = Suite( + server_url="http://localhost:8800", + agent_id="your_agent_id", +) + +@suite.scenario +async def test_greeting() -> None: + async with suite.session() as session: + response = await session.send("Hello!") + await response.should("be a friendly greeting or offer to help") + +@suite.scenario +async def test_appointment_inquiry() -> None: + async with suite.session() as session: + response = await session.send("Can I schedule an appointment?") + await response.should("acknowledge the request or ask for more details") +``` + +Run tests with: `parlant-test your_test_file.py` + +### NLP-Based Assertions + +The `response.should()` method uses NLP to evaluate conditions against the full conversation context: + +```python +# Single condition +await response.should("be polite and professional") + +# Multiple conditions (evaluated in parallel) +await response.should([ + "ask for the reason for the visit", + "be polite", + "not mention pricing", +]) +``` + +### Multi-Turn Conversations with unfold() + +Test multi-turn conversations where each step builds on history: + +```python +@suite.scenario +async def test_booking_flow() -> None: + async with suite.session() as session: + await session.unfold([ + # History-only steps (no assertion) + CustomerMessage("Hello"), + AgentMessage("Hi! How can I help you today?"), + + # Steps with assertions create sub-tests + CustomerMessage("I need to book an appointment"), + AgentMessage( + text="What's the reason for your visit?", + should=["ask for the reason", "be polite"], + ), + + CustomerMessage("Regular checkup"), + AgentMessage( + text="I have Monday at 10am or Wednesday at 2pm available.", + should="offer appointment times", + ), + ]) +``` + +**How unfold() works:** +- `CustomerMessage(text)` - Customer's message in the conversation +- `AgentMessage(text, should)` - Expected agent response + - `text`: Reference response used as history for subsequent tests + - `should`: Assertion condition(s). Only steps with `should` create sub-tests +- Each sub-test gets a fresh session with prefab history of all prior steps +- Sub-tests run sequentially and report results independently + +### Repeated Scenarios + +Run the same scenario multiple times for consistency testing: + +```python +@suite.scenario(repetitions=3) +async def test_consistent_greeting() -> None: + async with suite.session() as session: + response = await session.send("Hello") + await response.should("greet the customer") +``` + +### Hooks + +```python +@suite.before_all +async def setup() -> None: + # Runs once before all tests + suite.context["api_key"] = "test-key" + +@suite.after_all +async def teardown() -> None: + # Runs once after all tests + pass + +@suite.before_each +async def before_test(test_name: str) -> None: + # Runs before each test + pass + +@suite.after_each +async def after_test(test_name: str, passed: bool, error: str | None) -> None: + # Runs after each test + pass +``` + +### CLI Options + +```bash +# Run all tests +parlant-test tests.py + +# Filter by pattern +parlant-test tests.py -k "greeting" + +# Run tests in parallel +parlant-test tests.py --parallel + +# Custom timeout (seconds) +parlant-test tests.py --timeout 120 +``` + +--- + +## Links + +- Documentation: https://parlant.io/ +- GitHub: https://github.com/emcie-co/parlant +- PyPI: https://pypi.org/project/parlant/ +- Discord: https://discord.gg/duxWqxKk6J diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..c4a5ef1 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,10 @@ +[mypy] +strict = True +namespace_packages = True +explicit_package_bases = True +warn_unused_ignores = False +mypy_path = src +files = src, tests +disable_error_code = type-abstract +exclude = scripts +plugins = pydantic.mypy \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a9fa79f --- /dev/null +++ b/poetry.lock @@ -0,0 +1,8784 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "aiofiles" +version = "24.1.0" +description = "File support for asyncio." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"together\" or extra == \"litellm\"" +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.13.2" +description = "Async http client/server framework (asyncio)" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"together\" or extra == \"litellm\"" +files = [ + {file = "aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155"}, + {file = "aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c"}, + {file = "aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802"}, + {file = "aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f"}, + {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6"}, + {file = "aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251"}, + {file = "aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514"}, + {file = "aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0"}, + {file = "aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb"}, + {file = "aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592"}, + {file = "aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782"}, + {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8"}, + {file = "aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec"}, + {file = "aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c"}, + {file = "aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b"}, + {file = "aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc"}, + {file = "aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e"}, + {file = "aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169"}, + {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248"}, + {file = "aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e"}, + {file = "aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45"}, + {file = "aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be"}, + {file = "aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742"}, + {file = "aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e"}, + {file = "aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476"}, + {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23"}, + {file = "aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254"}, + {file = "aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a"}, + {file = "aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b"}, + {file = "aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61"}, + {file = "aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011"}, + {file = "aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4"}, + {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a"}, + {file = "aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940"}, + {file = "aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4"}, + {file = "aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673"}, + {file = "aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd"}, + {file = "aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e"}, + {file = "aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be"}, + {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c"}, + {file = "aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734"}, + {file = "aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f"}, + {file = "aiohttp-3.13.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7fbdf5ad6084f1940ce88933de34b62358d0f4a0b6ec097362dcd3e5a65a4989"}, + {file = "aiohttp-3.13.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7c3a50345635a02db61792c85bb86daffac05330f6473d524f1a4e3ef9d0046d"}, + {file = "aiohttp-3.13.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0e87dff73f46e969af38ab3f7cb75316a7c944e2e574ff7c933bc01b10def7f5"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2adebd4577724dcae085665f294cc57c8701ddd4d26140504db622b8d566d7aa"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e036a3a645fe92309ec34b918394bb377950cbb43039a97edae6c08db64b23e2"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:23ad365e30108c422d0b4428cf271156dd56790f6dd50d770b8e360e6c5ab2e6"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f9b2c2d4b9d958b1f9ae0c984ec1dd6b6689e15c75045be8ccb4011426268ca"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a92cf4b9bea33e15ecbaa5c59921be0f23222608143d025c989924f7e3e0c07"}, + {file = "aiohttp-3.13.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:070599407f4954021509193404c4ac53153525a19531051661440644728ba9a7"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:29562998ec66f988d49fb83c9b01694fa927186b781463f376c5845c121e4e0b"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4dd3db9d0f4ebca1d887d76f7cdbcd1116ac0d05a9221b9dad82c64a62578c4d"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d7bc4b7f9c4921eba72677cd9fedd2308f4a4ca3e12fab58935295ad9ea98700"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:dacd50501cd017f8cccb328da0c90823511d70d24a323196826d923aad865901"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:8b2f1414f6a1e0683f212ec80e813f4abef94c739fd090b66c9adf9d2a05feac"}, + {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04c3971421576ed24c191f610052bcb2f059e395bc2489dd99e397f9bc466329"}, + {file = "aiohttp-3.13.2-cp39-cp39-win32.whl", hash = "sha256:9f377d0a924e5cc94dc620bc6366fc3e889586a7f18b748901cf016c916e2084"}, + {file = "aiohttp-3.13.2-cp39-cp39-win_amd64.whl", hash = "sha256:9c705601e16c03466cb72011bd1af55d68fa65b045356d8f96c216e5f6db0fa5"}, + {file = "aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi ; platform_python_implementation != \"CPython\""] + +[[package]] +name = "aiopenapi3" +version = "0.9.0" +description = "client and validator for OpenAPI3 3.0, OpenAPI 3.1, Swagger 2.0" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "aiopenapi3-0.9.0-py3-none-any.whl", hash = "sha256:a35e81cb305579bd4b502b5ff856519546b3085c435d4bc65bb17704cf041d00"}, + {file = "aiopenapi3-0.9.0.tar.gz", hash = "sha256:f4740681cf829e5c5975065ac2fdd59c14c6ae60b085e7b461999056d4405a0e"}, +] + +[package.dependencies] +email-validator = "*" +httpx = "*" +jmespath = "*" +more-itertools = "*" +pydantic = "2.11.9" +PyYaml = "*" +yarl = "*" + +[package.extras] +auth = ["httpx-auth (>=0.21.0)"] +types = ["pydantic-extra-types (>=2.10.1)"] + +[[package]] +name = "aiorwlock" +version = "1.5.0" +description = "Read write lock for asyncio." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiorwlock-1.5.0-py3-none-any.whl", hash = "sha256:0010cd2d2c603eb84bfee1cfd06233a976618dab90ec7108191e936137a8420a"}, + {file = "aiorwlock-1.5.0.tar.gz", hash = "sha256:b529da24da659bdedcf68faf216595bde00db228c905197ac554773620e7fd2f"}, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"together\" or extra == \"litellm\"" +files = [ + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} + +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anthropic" +version = "0.60.0" +description = "The official Python library for the anthropic API" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"anthropic\" or extra == \"aws\" or extra == \"vertex\"" +files = [ + {file = "anthropic-0.60.0-py3-none-any.whl", hash = "sha256:65ad1f088a960217aaf82ba91ff743d6c89e9d811c6d64275b9a7c59ee9ac3c6"}, + {file = "anthropic-0.60.0.tar.gz", hash = "sha256:a22ba187c6f4fd5afecb2fc913b960feccf72bc0d25c1b7ce0345e87caede577"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.25.0,<1" +jiter = ">=0.4.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +typing-extensions = ">=4.10,<5" + +[package.extras] +aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.8)"] +bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] +vertex = ["google-auth[requests] (>=2,<3)"] + +[[package]] +name = "anyio" +version = "4.11.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, + {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.31.0)"] + +[[package]] +name = "asn1crypto" +version = "1.5.1" +description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"snowflake\"" +files = [ + {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, + {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a"}, + {file = "asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7"}, +] + +[package.extras] +astroid = ["astroid (>=2,<5)"] +test = ["astroid (>=2,<5)", "pytest (<9.0)", "pytest-cov", "pytest-xdist"] + +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "(extra == \"together\" or extra == \"litellm\") and python_version == \"3.10\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "25.4.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, + {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, +] + +[[package]] +name = "authlib" +version = "1.6.5" +description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a"}, + {file = "authlib-1.6.5.tar.gz", hash = "sha256:6aaf9c79b7cc96c900f0b284061691c5d4e61221640a948fe690b556a6d6d10b"}, +] + +[package.dependencies] +cryptography = "*" + +[[package]] +name = "azure-core" +version = "1.36.0" +description = "Microsoft Azure Core Library for Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"azure\"" +files = [ + {file = "azure_core-1.36.0-py3-none-any.whl", hash = "sha256:fee9923a3a753e94a259563429f3644aaf05c486d45b1215d098115102d91d3b"}, + {file = "azure_core-1.36.0.tar.gz", hash = "sha256:22e5605e6d0bf1d229726af56d9e92bc37b6e726b141a18be0b4d424131741b7"}, +] + +[package.dependencies] +requests = ">=2.21.0" +typing-extensions = ">=4.6.0" + +[package.extras] +aio = ["aiohttp (>=3.0)"] +tracing = ["opentelemetry-api (>=1.26,<2.0)"] + +[[package]] +name = "azure-identity" +version = "1.25.1" +description = "Microsoft Azure Identity Library for Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"azure\"" +files = [ + {file = "azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651"}, + {file = "azure_identity-1.25.1.tar.gz", hash = "sha256:87ca8328883de6036443e1c37b40e8dc8fb74898240f61071e09d2e369361456"}, +] + +[package.dependencies] +azure-core = ">=1.31.0" +cryptography = ">=2.5" +msal = ">=1.30.0" +msal-extensions = ">=1.2.0" +typing-extensions = ">=4.0.0" + +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = true +python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.12\"" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + +[[package]] +name = "bcrypt" +version = "5.0.0" +description = "Modern password hashing for your software and your servers" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5"}, + {file = "bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:744d3c6b164caa658adcb72cb8cc9ad9b4b75c7db507ab4bc2480474a51989da"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a28bc05039bdf3289d757f49d616ab3efe8cf40d8e8001ccdd621cd4f98f4fc9"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7f277a4b3390ab4bebe597800a90da0edae882c6196d3038a73adf446c4f969f"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:79cfa161eda8d2ddf29acad370356b47f02387153b11d46042e93a0a95127493"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a5393eae5722bcef046a990b84dff02b954904c36a194f6cfc817d7dca6c6f0b"}, + {file = "bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4c94dec1b5ab5d522750cb059bb9409ea8872d4494fd152b53cca99f1ddd8c"}, + {file = "bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0cae4cb350934dfd74c020525eeae0a5f79257e8a201c0c176f4b84fdbf2a4b4"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win32.whl", hash = "sha256:b17366316c654e1ad0306a6858e189fc835eca39f7eb2cafd6aaca8ce0c40a2e"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:92864f54fb48b4c718fc92a32825d0e42265a627f956bc0361fe869f1adc3e7d"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dd19cf5184a90c873009244586396a6a884d591a5323f0e8a5922560718d4993"}, + {file = "bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb"}, + {file = "bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538"}, + {file = "bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9"}, + {file = "bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980"}, + {file = "bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172"}, + {file = "bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683"}, + {file = "bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2"}, + {file = "bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7edda91d5ab52b15636d9c30da87d2cc84f426c72b9dba7a9b4fe142ba11f534"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:046ad6db88edb3c5ece4369af997938fb1c19d6a699b9c1b27b0db432faae4c4"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dcd58e2b3a908b5ecc9b9df2f0085592506ac2d5110786018ee5e160f28e0911"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6b8f520b61e8781efee73cba14e3e8c9556ccfb375623f4f97429544734545b4"}, + {file = "bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd"}, +] + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "beartype" +version = "0.22.6" +description = "Unbearably fast near-real-time pure-Python runtime-static type-checker." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "beartype-0.22.6-py3-none-any.whl", hash = "sha256:0584bc46a2ea2a871509679278cda992eadde676c01356ab0ac77421f3c9a093"}, + {file = "beartype-0.22.6.tar.gz", hash = "sha256:97fbda69c20b48c5780ac2ca60ce3c1bb9af29b3a1a0216898ffabdd523e48f4"}, +] + +[package.extras] +dev = ["autoapi (>=0.9.0)", "celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pydata-sphinx-theme (<=0.7.2)", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "setuptools", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +doc-ghp = ["mkdocs-material[imaging] (>=9.6.0)", "mkdocstrings-python (>=1.16.0)", "mkdocstrings-python-xref (>=1.16.0)"] +doc-rtd = ["autoapi (>=0.9.0)", "pydata-sphinx-theme (<=0.7.2)", "setuptools", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)"] +test = ["celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +test-tox = ["celery", "click", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +test-tox-coverage = ["coverage (>=5.5)"] + +[[package]] +name = "black" +version = "25.11.0" +description = "The uncompromising code formatter." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"together\"" +files = [ + {file = "black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e"}, + {file = "black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0"}, + {file = "black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37"}, + {file = "black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03"}, + {file = "black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a"}, + {file = "black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170"}, + {file = "black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc"}, + {file = "black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e"}, + {file = "black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac"}, + {file = "black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96"}, + {file = "black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd"}, + {file = "black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409"}, + {file = "black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b"}, + {file = "black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd"}, + {file = "black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993"}, + {file = "black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c"}, + {file = "black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170"}, + {file = "black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545"}, + {file = "black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda"}, + {file = "black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664"}, + {file = "black-25.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3bb5ce32daa9ff0605d73b6f19da0b0e6c1f8f2d75594db539fdfed722f2b06"}, + {file = "black-25.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9815ccee1e55717fe9a4b924cae1646ef7f54e0f990da39a34fc7b264fcf80a2"}, + {file = "black-25.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92285c37b93a1698dcbc34581867b480f1ba3a7b92acf1fe0467b04d7a4da0dc"}, + {file = "black-25.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:43945853a31099c7c0ff8dface53b4de56c41294fa6783c0441a8b1d9bf668bc"}, + {file = "black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b"}, + {file = "black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +pytokens = ">=0.3.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "boto3" +version = "1.41.4" +description = "The AWS SDK for Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "boto3-1.41.4-py3-none-any.whl", hash = "sha256:77d84b7ce890a9b0c6a8993f8de106d8cf8138f332a4685e6de453965e60cb24"}, + {file = "boto3-1.41.4.tar.gz", hash = "sha256:2c6b8d13df6beb9255d0c8cb60a7a2164f5270580ea5b921a65658a0c28e3223"}, +] + +[package.dependencies] +botocore = ">=1.41.4,<1.42.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.15.0,<0.16.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] + +[[package]] +name = "botocore" +version = "1.41.4" +description = "Low-level, data-driven core of boto 3." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "botocore-1.41.4-py3-none-any.whl", hash = "sha256:7143ef845f1d1400dbbf05d999f8c5e8cfaecd6bd84cbfbe5fa0a40e3a9f6353"}, + {file = "botocore-1.41.4.tar.gz", hash = "sha256:45c78f07b53a64cbe55e5d60297958f151bd4a2c6acb944a8bb65874bc2fd953"}, +] + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} + +[package.extras] +crt = ["awscrt (==0.29.0)"] + +[[package]] +name = "build" +version = "1.3.0" +description = "A simple, correct Python build frontend" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4"}, + {file = "build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "os_name == \"nt\""} +importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} +packaging = ">=19.1" +pyproject_hooks = "*" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +uv = ["uv (>=0.1.18)"] +virtualenv = ["virtualenv (>=20.11) ; python_version < \"3.10\"", "virtualenv (>=20.17) ; python_version >= \"3.10\" and python_version < \"3.14\"", "virtualenv (>=20.31) ; python_version >= \"3.14\""] + +[[package]] +name = "cachetools" +version = "6.2.2" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace"}, + {file = "cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6"}, +] + +[[package]] +name = "cerebras-cloud-sdk" +version = "1.59.0" +description = "The official Python library for the cerebras API" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"cerebras\"" +files = [ + {file = "cerebras_cloud_sdk-1.59.0-py3-none-any.whl", hash = "sha256:89228068a8d649cad0a9231b34bdc2fcdb925241eb3434d788dfea317f274ed7"}, + {file = "cerebras_cloud_sdk-1.59.0.tar.gz", hash = "sha256:0f0af8debc8871d4ec21528dc79b276a31e7a7f578b4a60fae3a1ae27d1f2486"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +typing-extensions = ">=4.10,<5" + +[package.extras] +aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.9)"] + +[[package]] +name = "certifi" +version = "2025.11.12" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b"}, + {file = "certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\" or extra == \"snowflake\"" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win32.whl", hash = "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50"}, + {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, + {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, +] + +[[package]] +name = "chromadb" +version = "1.3.5" +description = "Chroma." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "chromadb-1.3.5-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d4e5b3bd1bf879a4fffa5644ccb175b98ee18799d8447140f3f893d350068d1b"}, + {file = "chromadb-1.3.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:59d35ea15a5765da751e2bc0804054b7ade81f564119c88a1b3310c18c696d92"}, + {file = "chromadb-1.3.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e5fad35a4e686668efa956d576e4daea511a42225dbe9c975d9b2889608f53"}, + {file = "chromadb-1.3.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86d33e9b1153bc1eda48f98fc9c2d54d7dac2a460198a58aec715206d234c7f1"}, + {file = "chromadb-1.3.5-cp39-abi3-win_amd64.whl", hash = "sha256:5ecf6345025abf84095fd9a65bb9855f2019c63e0f42373720aecabadce08cf0"}, + {file = "chromadb-1.3.5.tar.gz", hash = "sha256:ca45b9423b083f5dd49373f89af23ff9d94fe6884233cd826e8b1a50abe74166"}, +] + +[package.dependencies] +bcrypt = ">=4.0.1" +build = ">=1.0.3" +grpcio = ">=1.58.0" +httpx = ">=0.27.0" +importlib-resources = "*" +jsonschema = ">=4.19.0" +kubernetes = ">=28.1.0" +mmh3 = ">=4.0.1" +numpy = ">=1.22.5" +onnxruntime = ">=1.14.1" +opentelemetry-api = ">=1.2.0" +opentelemetry-exporter-otlp-proto-grpc = ">=1.2.0" +opentelemetry-sdk = ">=1.2.0" +orjson = ">=3.9.12" +overrides = ">=7.3.1" +posthog = ">=2.4.0,<6.0.0" +pybase64 = ">=1.4.1" +pydantic = ">=1.9" +pypika = ">=0.48.9" +pyyaml = ">=6.0.0" +rich = ">=10.11.0" +tenacity = ">=8.2.3" +tokenizers = ">=0.13.2" +tqdm = ">=4.65.0" +typer = ">=0.9.0" +typing-extensions = ">=4.5.0" +uvicorn = {version = ">=0.18.3", extras = ["standard"]} + +[package.extras] +dev = ["chroma-hnswlib (==0.7.6)", "fastapi (>=0.115.9)", "opentelemetry-instrumentation-fastapi (>=0.41b0)"] + +[[package]] +name = "click" +version = "8.3.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, + {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + +[[package]] +name = "contextvars" +version = "2.4" +description = "PEP 567 Backport" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "contextvars-2.4.tar.gz", hash = "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"}, +] + +[package.dependencies] +immutables = ">=0.9" + +[[package]] +name = "contourpy" +version = "1.3.2" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, + {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2"}, + {file = "contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0"}, + {file = "contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd"}, + {file = "contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f"}, + {file = "contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e"}, + {file = "contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912"}, + {file = "contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef"}, + {file = "contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f"}, + {file = "contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd"}, + {file = "contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1"}, + {file = "contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"}, + {file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"}, +] + +[package.dependencies] +numpy = ">=1.23" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.15.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "coverage" +version = "7.12.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b"}, + {file = "coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d"}, + {file = "coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef"}, + {file = "coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984"}, + {file = "coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6"}, + {file = "coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4"}, + {file = "coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937"}, + {file = "coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa"}, + {file = "coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a"}, + {file = "coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc"}, + {file = "coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8"}, + {file = "coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07"}, + {file = "coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455"}, + {file = "coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d"}, + {file = "coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c"}, + {file = "coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17"}, + {file = "coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933"}, + {file = "coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe"}, + {file = "coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b"}, + {file = "coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a"}, + {file = "coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291"}, + {file = "coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384"}, + {file = "coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a"}, + {file = "coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "croniter" +version = "5.0.1" +description = "croniter provides iteration for datetime object with cron like format" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.6" +groups = ["main"] +files = [ + {file = "croniter-5.0.1-py2.py3-none-any.whl", hash = "sha256:eb28439742291f6c10b181df1a5ecf421208b1fc62ef44501daec1780a0b09e9"}, + {file = "croniter-5.0.1.tar.gz", hash = "sha256:7d9b1ef25b10eece48fdf29d8ac52f9b6252abff983ac614ade4f3276294019e"}, +] + +[package.dependencies] +python-dateutil = "*" +pytz = ">2021.1" + +[[package]] +name = "cryptography" +version = "46.0.0" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.8" +groups = ["main"] +files = [ + {file = "cryptography-46.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:c9c4121f9a41cc3d02164541d986f59be31548ad355a5c96ac50703003c50fb7"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4f70cbade61a16f5e238c4b0eb4e258d177a2fcb59aa0aae1236594f7b0ae338"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1eccae15d5c28c74b2bea228775c63ac5b6c36eedb574e002440c0bc28750d3"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1b4fba84166d906a22027f0d958e42f3a4dbbb19c28ea71f0fb7812380b04e3c"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:523153480d7575a169933f083eb47b1edd5fef45d87b026737de74ffeb300f69"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f09a3a108223e319168b7557810596631a8cb864657b0c16ed7a6017f0be9433"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c1f6ccd6f2eef3b2eb52837f0463e853501e45a916b3fc42e5d93cf244a4b97b"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:80a548a5862d6912a45557a101092cd6c64ae1475b82cef50ee305d14a75f598"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6c39fd5cd9b7526afa69d64b5e5645a06e1b904f342584b3885254400b63f1b3"}, + {file = "cryptography-46.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d5c0cbb2fb522f7e39b59a5482a1c9c5923b7c506cfe96a1b8e7368c31617ac0"}, + {file = "cryptography-46.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6d8945bc120dcd90ae39aa841afddaeafc5f2e832809dc54fb906e3db829dfdc"}, + {file = "cryptography-46.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:88c09da8a94ac27798f6b62de6968ac78bb94805b5d272dbcfd5fdc8c566999f"}, + {file = "cryptography-46.0.0-cp311-abi3-win32.whl", hash = "sha256:3738f50215211cee1974193a1809348d33893696ce119968932ea117bcbc9b1d"}, + {file = "cryptography-46.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bbaa5eef3c19c66613317dc61e211b48d5f550db009c45e1c28b59d5a9b7812a"}, + {file = "cryptography-46.0.0-cp311-abi3-win_arm64.whl", hash = "sha256:16b5ac72a965ec9d1e34d9417dbce235d45fa04dac28634384e3ce40dfc66495"}, + {file = "cryptography-46.0.0-cp314-abi3-macosx_10_9_universal2.whl", hash = "sha256:91585fc9e696abd7b3e48a463a20dda1a5c0eeeca4ba60fa4205a79527694390"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:65e9117ebed5b16b28154ed36b164c20021f3a480e9cbb4b4a2a59b95e74c25d"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:da7f93551d39d462263b6b5c9056c49f780b9200bf9fc2656d7c88c7bdb9b363"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:be7479f9504bfb46628544ec7cb4637fe6af8b70445d4455fbb9c395ad9b7290"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f85e6a7d42ad60024fa1347b1d4ef82c4df517a4deb7f829d301f1a92ded038c"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:d349af4d76a93562f1dce4d983a4a34d01cb22b48635b0d2a0b8372cdb4a8136"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:35aa1a44bd3e0efc3ef09cf924b3a0e2a57eda84074556f4506af2d294076685"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c457ad3f151d5fb380be99425b286167b358f76d97ad18b188b68097193ed95a"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:399ef4c9be67f3902e5ca1d80e64b04498f8b56c19e1bc8d0825050ea5290410"}, + {file = "cryptography-46.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:378eff89b040cbce6169528f130ee75dceeb97eef396a801daec03b696434f06"}, + {file = "cryptography-46.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c3648d6a5878fd1c9a22b1d43fa75efc069d5f54de12df95c638ae7ba88701d0"}, + {file = "cryptography-46.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fc30be952dd4334801d345d134c9ef0e9ccbaa8c3e1bc18925cbc4247b3e29c"}, + {file = "cryptography-46.0.0-cp314-cp314t-win32.whl", hash = "sha256:b8e7db4ce0b7297e88f3d02e6ee9a39382e0efaf1e8974ad353120a2b5a57ef7"}, + {file = "cryptography-46.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40ee4ce3c34acaa5bc347615ec452c74ae8ff7db973a98c97c62293120f668c6"}, + {file = "cryptography-46.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:07a1be54f995ce14740bf8bbe1cc35f7a37760f992f73cf9f98a2a60b9b97419"}, + {file = "cryptography-46.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:1d2073313324226fd846e6b5fc340ed02d43fd7478f584741bd6b791c33c9fee"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83af84ebe7b6e9b6de05050c79f8cc0173c864ce747b53abce6a11e940efdc0d"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c3cd09b1490c1509bf3892bde9cef729795fae4a2fee0621f19be3321beca7e4"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d14eaf1569d6252280516bedaffdd65267428cdbc3a8c2d6de63753cf0863d5e"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ab3a14cecc741c8c03ad0ad46dfbf18de25218551931a23bca2731d46c706d83"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8e8b222eb54e3e7d3743a7c2b1f7fa7df7a9add790307bb34327c88ec85fe087"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7f3f88df0c9b248dcc2e76124f9140621aca187ccc396b87bc363f890acf3a30"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9aa85222f03fdb30defabc7a9e1e3d4ec76eb74ea9fe1504b2800844f9c98440"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f9aaf2a91302e1490c068d2f3af7df4137ac2b36600f5bd26e53d9ec320412d3"}, + {file = "cryptography-46.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:32670ca085150ff36b438c17f2dfc54146fe4a074ebf0a76d72fb1b419a974bc"}, + {file = "cryptography-46.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0f58183453032727a65e6605240e7a3824fd1d6a7e75d2b537e280286ab79a52"}, + {file = "cryptography-46.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4bc257c2d5d865ed37d0bd7c500baa71f939a7952c424f28632298d80ccd5ec1"}, + {file = "cryptography-46.0.0-cp38-abi3-win32.whl", hash = "sha256:df932ac70388be034b2e046e34d636245d5eeb8140db24a6b4c2268cd2073270"}, + {file = "cryptography-46.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:274f8b2eb3616709f437326185eb563eb4e5813d01ebe2029b61bfe7d9995fbb"}, + {file = "cryptography-46.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:249c41f2bbfa026615e7bdca47e4a66135baa81b08509ab240a2e666f6af5966"}, + {file = "cryptography-46.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fe9ff1139b2b1f59a5a0b538bbd950f8660a39624bbe10cf3640d17574f973bb"}, + {file = "cryptography-46.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:77e3bd53c9c189cea361bc18ceb173959f8b2dd8f8d984ae118e9ac641410252"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:75d2ddde8f1766ab2db48ed7f2aa3797aeb491ea8dfe9b4c074201aec00f5c16"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f9f85d9cf88e3ba2b2b6da3c2310d1cf75bdf04a5bc1a2e972603054f82c4dd5"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:834af45296083d892e23430e3b11df77e2ac5c042caede1da29c9bf59016f4d2"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:c39f0947d50f74b1b3523cec3931315072646286fb462995eb998f8136779319"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6460866a92143a24e3ed68eaeb6e98d0cedd85d7d9a8ab1fc293ec91850b1b38"}, + {file = "cryptography-46.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bf1961037309ee0bdf874ccba9820b1c2f720c2016895c44d8eb2316226c1ad5"}, + {file = "cryptography-46.0.0.tar.gz", hash = "sha256:99f64a6d15f19f3afd78720ad2978f6d8d4c68cd4eb600fab82ab1a7c2071dca"}, +] + +[package.dependencies] +cffi = {version = ">=1.14", markers = "python_full_version < \"3.14.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + +[[package]] +name = "cyclopts" +version = "4.3.0" +description = "Intuitive, easy CLIs based on type hints." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "cyclopts-4.3.0-py3-none-any.whl", hash = "sha256:91a30b69faf128ada7cfeaefd7d9649dc222e8b2a8697f1fc99e4ee7b7ca44f3"}, + {file = "cyclopts-4.3.0.tar.gz", hash = "sha256:e95179cd0a959ce250ecfb2f0262a5996a92c1f9467bccad2f3d829e6833cef5"}, +] + +[package.dependencies] +attrs = ">=23.1.0" +docstring-parser = ">=0.15,<4.0" +rich = ">=13.6.0" +rich-rst = ">=1.3.1,<2.0.0" +tomli = {version = ">=2.0.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.8.0", markers = "python_version < \"3.11\""} + +[package.extras] +debug = ["ipdb (>=0.13.9)", "line-profiler (>=3.5.1)"] +dev = ["coverage[toml] (>=5.1)", "pre-commit (>=2.16.0)", "pydantic (>=2.11.2,<3.0.0)", "pytest (>=8.2.0)", "pytest-cov (>=3.0.0)", "pytest-mock (>=3.7.0)", "pyyaml (>=6.0.1)", "toml (>=0.10.2,<1.0.0)", "trio (>=0.10.0)"] +docs = ["gitpython (>=3.1.31)", "myst-parser[linkify] (>=3.0.1,<5.0.0)", "sphinx (>=7.4.7,<8.2.0)", "sphinx-autodoc-typehints (>=1.25.2,<4.0.0)", "sphinx-copybutton (>=0.5,<1.0)", "sphinx-rtd-dark-mode (>=1.3.0,<2.0.0)", "sphinx-rtd-theme (>=3.0.0,<4.0.0)"] +toml = ["tomli (>=2.0.0) ; python_version < \"3.11\""] +trio = ["trio (>=0.10.0)"] +yaml = ["pyyaml (>=6.0.1)"] + +[[package]] +name = "decorator" +version = "5.2.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, + {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, +] + +[[package]] +name = "deprecated" +version = "1.3.1" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] +files = [ + {file = "deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f"}, + {file = "deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223"}, +] + +[package.dependencies] +wrapt = ">=1.10,<3" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] + +[[package]] +name = "diskcache" +version = "5.6.3" +description = "Disk Cache -- Disk and file backed persistent cache." +optional = false +python-versions = ">=3" +groups = ["main"] +files = [ + {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, + {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, +] + +[[package]] +name = "distro" +version = "1.9.0" +description = "Distro - an OS platform information API" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +description = "DNS toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, + {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, +] + +[package.extras] +dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] +dnssec = ["cryptography (>=45)"] +doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] +doq = ["aioquic (>=1.2.0)"] +idna = ["idna (>=3.10)"] +trio = ["trio (>=0.30)"] +wmi = ["wmi (>=1.5.1) ; platform_system == \"Windows\""] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +description = "Parse Python docstrings in reST, Google and Numpydoc format" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708"}, + {file = "docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912"}, +] + +[package.extras] +dev = ["pre-commit (>=2.16.0) ; python_version >= \"3.9\"", "pydoctor (>=25.4.0)", "pytest"] +docs = ["pydoctor (>=25.4.0)"] +test = ["pytest"] + +[[package]] +name = "docutils" +version = "0.22.3" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "docutils-0.22.3-py3-none-any.whl", hash = "sha256:bd772e4aca73aff037958d44f2be5229ded4c09927fcf8690c577b66234d6ceb"}, + {file = "docutils-0.22.3.tar.gz", hash = "sha256:21486ae730e4ca9f622677b1412b879af1791efcfba517e4c6f60be543fc8cdd"}, +] + +[[package]] +name = "durationpy" +version = "0.10" +description = "Module for converting between datetime.timedelta and Go's Duration strings." +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286"}, + {file = "durationpy-0.10.tar.gz", hash = "sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba"}, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4"}, + {file = "email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + +[[package]] +name = "eval-type-backport" +version = "0.2.2" +description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"together\" or extra == \"mistral\"" +files = [ + {file = "eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"}, + {file = "eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] +markers = {dev = "python_version == \"3.10\""} + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "execnet" +version = "2.1.2" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"}, + {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + +[[package]] +name = "executing" +version = "2.2.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017"}, + {file = "executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] + +[[package]] +name = "fastapi" +version = "0.120.4" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "fastapi-0.120.4-py3-none-any.whl", hash = "sha256:9bdf192308676480d3593e10fd05094e56d6fdc7d9283db26053d8104d5f82a0"}, + {file = "fastapi-0.120.4.tar.gz", hash = "sha256:2d856bc847893ca4d77896d4504ffdec0fb04312b705065fca9104428eca3868"}, +] + +[package.dependencies] +annotated-doc = ">=0.0.2" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.40.0,<0.50.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "fastmcp" +version = "2.13.0" +description = "The fast, Pythonic way to build MCP servers and clients." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "fastmcp-2.13.0-py3-none-any.whl", hash = "sha256:bdff1399d3b7ebb79286edfd43eb660182432514a5ab8e4cbfb45f1d841d2aa0"}, + {file = "fastmcp-2.13.0.tar.gz", hash = "sha256:57f7b7503363e1babc0d1a13af18252b80366a409e1de85f1256cce66a4bee35"}, +] + +[package.dependencies] +authlib = ">=1.5.2" +cyclopts = ">=3.0.0" +exceptiongroup = ">=1.2.2" +httpx = ">=0.28.1" +mcp = ">=1.17.0,<2.0.0" +openapi-core = ">=0.19.5" +openapi-pydantic = ">=0.5.1" +platformdirs = ">=4.0.0" +py-key-value-aio = {version = ">=0.2.6,<0.3.0", extras = ["disk", "keyring", "memory"]} +pydantic = {version = ">=2.11.7", extras = ["email"]} +pyperclip = ">=1.9.0" +python-dotenv = ">=1.1.0" +rich = ">=13.9.4" +websockets = ">=15.0.1" + +[package.extras] +openai = ["openai (>=1.102.0)"] + +[[package]] +name = "fastuuid" +version = "0.14.0" +description = "Python bindings to Rust's UUID library." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"litellm\"" +files = [ + {file = "fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a"}, + {file = "fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00"}, + {file = "fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470"}, + {file = "fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d"}, + {file = "fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8"}, + {file = "fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219"}, + {file = "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6"}, + {file = "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe"}, + {file = "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d"}, + {file = "fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a"}, + {file = "fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4"}, + {file = "fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34"}, + {file = "fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7"}, + {file = "fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1"}, + {file = "fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc"}, + {file = "fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8"}, + {file = "fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7"}, + {file = "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73"}, + {file = "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36"}, + {file = "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94"}, + {file = "fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24"}, + {file = "fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa"}, + {file = "fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a"}, + {file = "fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d"}, + {file = "fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070"}, + {file = "fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796"}, + {file = "fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09"}, + {file = "fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8"}, + {file = "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741"}, + {file = "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057"}, + {file = "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8"}, + {file = "fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176"}, + {file = "fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397"}, + {file = "fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021"}, + {file = "fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc"}, + {file = "fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5"}, + {file = "fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f"}, + {file = "fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87"}, + {file = "fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b"}, + {file = "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022"}, + {file = "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995"}, + {file = "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab"}, + {file = "fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad"}, + {file = "fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed"}, + {file = "fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad"}, + {file = "fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b"}, + {file = "fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714"}, + {file = "fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f"}, + {file = "fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f"}, + {file = "fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75"}, + {file = "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4"}, + {file = "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad"}, + {file = "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8"}, + {file = "fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06"}, + {file = "fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a"}, + {file = "fastuuid-0.14.0-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:47c821f2dfe95909ead0085d4cb18d5149bca704a2b03e03fb3f81a5202d8cea"}, + {file = "fastuuid-0.14.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3964bab460c528692c70ab6b2e469dd7a7b152fbe8c18616c58d34c93a6cf8d4"}, + {file = "fastuuid-0.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c501561e025b7aea3508719c5801c360c711d5218fc4ad5d77bf1c37c1a75779"}, + {file = "fastuuid-0.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dce5d0756f046fa792a40763f36accd7e466525c5710d2195a038f93ff96346"}, + {file = "fastuuid-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193ca10ff553cf3cc461572da83b5780fc0e3eea28659c16f89ae5202f3958d4"}, + {file = "fastuuid-0.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0737606764b29785566f968bd8005eace73d3666bd0862f33a760796e26d1ede"}, + {file = "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0976c0dff7e222513d206e06341503f07423aceb1db0b83ff6851c008ceee06"}, + {file = "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6fbc49a86173e7f074b1a9ec8cf12ca0d54d8070a85a06ebf0e76c309b84f0d0"}, + {file = "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:de01280eabcd82f7542828ecd67ebf1551d37203ecdfd7ab1f2e534edb78d505"}, + {file = "fastuuid-0.14.0-cp38-cp38-win32.whl", hash = "sha256:af5967c666b7d6a377098849b07f83462c4fedbafcf8eb8bc8ff05dcbe8aa209"}, + {file = "fastuuid-0.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3091e63acf42f56a6f74dc65cfdb6f99bfc79b5913c8a9ac498eb7ca09770a8"}, + {file = "fastuuid-0.14.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2ec3d94e13712a133137b2805073b65ecef4a47217d5bac15d8ac62376cefdb4"}, + {file = "fastuuid-0.14.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:139d7ff12bb400b4a0c76be64c28cbe2e2edf60b09826cbfd85f33ed3d0bbe8b"}, + {file = "fastuuid-0.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d55b7e96531216fc4f071909e33e35e5bfa47962ae67d9e84b00a04d6e8b7173"}, + {file = "fastuuid-0.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0eb25f0fd935e376ac4334927a59e7c823b36062080e2e13acbaf2af15db836"}, + {file = "fastuuid-0.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:089c18018fdbdda88a6dafd7d139f8703a1e7c799618e33ea25eb52503d28a11"}, + {file = "fastuuid-0.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fc37479517d4d70c08696960fad85494a8a7a0af4e93e9a00af04d74c59f9e3"}, + {file = "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:73657c9f778aba530bc96a943d30e1a7c80edb8278df77894fe9457540df4f85"}, + {file = "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d31f8c257046b5617fc6af9c69be066d2412bdef1edaa4bdf6a214cf57806105"}, + {file = "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5816d41f81782b209843e52fdef757a361b448d782452d96abedc53d545da722"}, + {file = "fastuuid-0.14.0-cp39-cp39-win32.whl", hash = "sha256:448aa6833f7a84bfe37dd47e33df83250f404d591eb83527fa2cac8d1e57d7f3"}, + {file = "fastuuid-0.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:84b0779c5abbdec2a9511d5ffbfcd2e53079bf889824b32be170c0d8ef5fc74c"}, + {file = "fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26"}, +] + +[[package]] +name = "filelock" +version = "3.20.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2"}, + {file = "filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4"}, +] + +[[package]] +name = "flake8" +version = "7.3.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e"}, + {file = "flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.14.0,<2.15.0" +pyflakes = ">=3.4.0,<3.5.0" + +[[package]] +name = "flatbuffers" +version = "25.9.23" +description = "The FlatBuffers serialization format for Python" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2"}, + {file = "flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12"}, +] + +[[package]] +name = "fonttools" +version = "4.60.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28"}, + {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15"}, + {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c"}, + {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea"}, + {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652"}, + {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a"}, + {file = "fonttools-4.60.1-cp310-cp310-win32.whl", hash = "sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce"}, + {file = "fonttools-4.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038"}, + {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f"}, + {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2"}, + {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914"}, + {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1"}, + {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d"}, + {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa"}, + {file = "fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258"}, + {file = "fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf"}, + {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc"}, + {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877"}, + {file = "fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c"}, + {file = "fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401"}, + {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903"}, + {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed"}, + {file = "fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6"}, + {file = "fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383"}, + {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb"}, + {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4"}, + {file = "fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c"}, + {file = "fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77"}, + {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199"}, + {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c"}, + {file = "fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272"}, + {file = "fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac"}, + {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3"}, + {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85"}, + {file = "fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537"}, + {file = "fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003"}, + {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08"}, + {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99"}, + {file = "fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6"}, + {file = "fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987"}, + {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299"}, + {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01"}, + {file = "fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801"}, + {file = "fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc"}, + {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc"}, + {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed"}, + {file = "fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259"}, + {file = "fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c"}, + {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:122e1a8ada290423c493491d002f622b1992b1ab0b488c68e31c413390dc7eb2"}, + {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a140761c4ff63d0cb9256ac752f230460ee225ccef4ad8f68affc723c88e2036"}, + {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eae96373e4b7c9e45d099d7a523444e3554360927225c1cdae221a58a45b856"}, + {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:596ecaca36367027d525b3b426d8a8208169d09edcf8c7506aceb3a38bfb55c7"}, + {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ee06fc57512144d8b0445194c2da9f190f61ad51e230f14836286470c99f854"}, + {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b42d86938e8dda1cd9a1a87a6d82f1818eaf933348429653559a458d027446da"}, + {file = "fonttools-4.60.1-cp39-cp39-win32.whl", hash = "sha256:8b4eb332f9501cb1cd3d4d099374a1e1306783ff95489a1026bde9eb02ccc34a"}, + {file = "fonttools-4.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:7473a8ed9ed09aeaa191301244a5a9dbe46fe0bf54f9d6cd21d83044c3321217"}, + {file = "fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb"}, + {file = "fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9"}, +] + +[package.extras] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr ; sys_platform == \"darwin\""] +unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""] +woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] + +[[package]] +name = "frozenlist" +version = "1.8.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"together\" or extra == \"litellm\"" +files = [ + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, + {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, + {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, + {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, +] + +[[package]] +name = "fsspec" +version = "2025.10.0" +description = "File-system specification" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d"}, + {file = "fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59"}, +] + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +dev = ["pre-commit", "ruff (>=0.5)"] +doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] +test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard ; python_version < \"3.14\""] +tqdm = ["tqdm"] + +[[package]] +name = "gherkin-official" +version = "29.0.0" +description = "Gherkin parser (official, by Cucumber team)" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "gherkin_official-29.0.0-py3-none-any.whl", hash = "sha256:26967b0d537a302119066742669e0e8b663e632769330be675457ae993e1d1bc"}, + {file = "gherkin_official-29.0.0.tar.gz", hash = "sha256:dbea32561158f02280d7579d179b019160d072ce083197625e2f80a6776bb9eb"}, +] + +[[package]] +name = "google-api-core" +version = "2.28.1" +description = "Google API client core library" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c"}, + {file = "google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8"}, +] + +[package.dependencies] +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.56.2,<2.0.0" +proto-plus = [ + {version = ">=1.22.3,<2.0.0"}, + {version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""}, +] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" +requests = ">=2.18.0,<3.0.0" + +[package.extras] +async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.0)"] +grpc = ["grpcio (>=1.33.2,<2.0.0)", "grpcio (>=1.49.1,<2.0.0) ; python_version >= \"3.11\"", "grpcio (>=1.75.1,<2.0.0) ; python_version >= \"3.14\"", "grpcio-status (>=1.33.2,<2.0.0)", "grpcio-status (>=1.49.1,<2.0.0) ; python_version >= \"3.11\"", "grpcio-status (>=1.75.1,<2.0.0) ; python_version >= \"3.14\""] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] + +[[package]] +name = "google-auth" +version = "2.43.0" +description = "Google Authentication Library" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16"}, + {file = "google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<7.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] +enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] + +[[package]] +name = "google-genai" +version = "1.52.0" +description = "GenAI Python SDK" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "google_genai-1.52.0-py3-none-any.whl", hash = "sha256:c8352b9f065ae14b9322b949c7debab8562982f03bf71d44130cd2b798c20743"}, + {file = "google_genai-1.52.0.tar.gz", hash = "sha256:a74e8a4b3025f23aa98d6a0f84783119012ca6c336fd68f73c5d2b11465d7fc5"}, +] + +[package.dependencies] +anyio = ">=4.8.0,<5.0.0" +google-auth = ">=2.14.1,<3.0.0" +httpx = ">=0.28.1,<1.0.0" +pydantic = ">=2.9.0,<3.0.0" +requests = ">=2.28.1,<3.0.0" +tenacity = ">=8.2.3,<9.2.0" +typing-extensions = ">=4.11.0,<5.0.0" +websockets = ">=13.0.0,<15.1.0" + +[package.extras] +aiohttp = ["aiohttp (<3.13.3)"] +local-tokenizer = ["protobuf", "sentencepiece (>=0.2.0)"] + +[[package]] +name = "googleapis-common-protos" +version = "1.72.0" +description = "Common protobufs used in Google APIs" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038"}, + {file = "googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5"}, +] + +[package.dependencies] +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" + +[package.extras] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] + +[[package]] +name = "grpcio" +version = "1.76.0" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc"}, + {file = "grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3"}, + {file = "grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b"}, + {file = "grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b"}, + {file = "grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a"}, + {file = "grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00"}, + {file = "grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054"}, + {file = "grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d"}, + {file = "grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8"}, + {file = "grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882"}, + {file = "grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958"}, + {file = "grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347"}, + {file = "grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2"}, + {file = "grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42"}, + {file = "grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f"}, + {file = "grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8"}, + {file = "grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62"}, + {file = "grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc"}, + {file = "grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e"}, + {file = "grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e"}, + {file = "grpcio-1.76.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8ebe63ee5f8fa4296b1b8cfc743f870d10e902ca18afc65c68cf46fd39bb0783"}, + {file = "grpcio-1.76.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:3bf0f392c0b806905ed174dcd8bdd5e418a40d5567a05615a030a5aeddea692d"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b7604868b38c1bfd5cf72d768aedd7db41d78cb6a4a18585e33fb0f9f2363fd"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e6d1db20594d9daba22f90da738b1a0441a7427552cc6e2e3d1297aeddc00378"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d099566accf23d21037f18a2a63d323075bebace807742e4b0ac210971d4dd70"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ebea5cc3aa8ea72e04df9913492f9a96d9348db876f9dda3ad729cfedf7ac416"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0c37db8606c258e2ee0c56b78c62fc9dee0e901b5dbdcf816c2dd4ad652b8b0c"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebebf83299b0cb1721a8859ea98f3a77811e35dce7609c5c963b9ad90728f886"}, + {file = "grpcio-1.76.0-cp39-cp39-win32.whl", hash = "sha256:0aaa82d0813fd4c8e589fac9b65d7dd88702555f702fb10417f96e2a2a6d4c0f"}, + {file = "grpcio-1.76.0-cp39-cp39-win_amd64.whl", hash = "sha256:acab0277c40eff7143c2323190ea57b9ee5fd353d8190ee9652369fae735668a"}, + {file = "grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73"}, +] + +[package.dependencies] +typing-extensions = ">=4.12,<5.0" + +[package.extras] +protobuf = ["grpcio-tools (>=1.76.0)"] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "h2" +version = "4.3.0" +description = "Pure-Python HTTP/2 protocol implementation" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"qdrant\"" +files = [ + {file = "h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd"}, + {file = "h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1"}, +] + +[package.dependencies] +hpack = ">=4.1,<5" +hyperframe = ">=6.1,<7" + +[[package]] +name = "hf-xet" +version = "1.2.0" +description = "Fast transfer of large files with the Hugging Face Hub." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\"" +files = [ + {file = "hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649"}, + {file = "hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813"}, + {file = "hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc"}, + {file = "hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5"}, + {file = "hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f"}, + {file = "hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832"}, + {file = "hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382"}, + {file = "hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e"}, + {file = "hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8"}, + {file = "hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0"}, + {file = "hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090"}, + {file = "hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a"}, + {file = "hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f"}, + {file = "hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc"}, + {file = "hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848"}, + {file = "hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4"}, + {file = "hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd"}, + {file = "hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c"}, + {file = "hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737"}, + {file = "hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865"}, + {file = "hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69"}, + {file = "hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "hpack" +version = "4.1.0" +description = "Pure-Python HPACK header encoding" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"qdrant\"" +files = [ + {file = "hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"}, + {file = "hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httptools" +version = "0.7.1" +description = "A collection of framework independent HTTP protocol utils." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78"}, + {file = "httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4"}, + {file = "httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05"}, + {file = "httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed"}, + {file = "httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a"}, + {file = "httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b"}, + {file = "httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568"}, + {file = "httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657"}, + {file = "httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70"}, + {file = "httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df"}, + {file = "httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e"}, + {file = "httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274"}, + {file = "httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec"}, + {file = "httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb"}, + {file = "httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5"}, + {file = "httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5"}, + {file = "httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03"}, + {file = "httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2"}, + {file = "httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362"}, + {file = "httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c"}, + {file = "httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321"}, + {file = "httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3"}, + {file = "httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca"}, + {file = "httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c"}, + {file = "httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66"}, + {file = "httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346"}, + {file = "httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650"}, + {file = "httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6"}, + {file = "httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270"}, + {file = "httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3"}, + {file = "httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1"}, + {file = "httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b"}, + {file = "httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60"}, + {file = "httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca"}, + {file = "httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96"}, + {file = "httptools-0.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac50afa68945df63ec7a2707c506bd02239272288add34539a2ef527254626a4"}, + {file = "httptools-0.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de987bb4e7ac95b99b805b99e0aae0ad51ae61df4263459d36e07cf4052d8b3a"}, + {file = "httptools-0.7.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d169162803a24425eb5e4d51d79cbf429fd7a491b9e570a55f495ea55b26f0bf"}, + {file = "httptools-0.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49794f9250188a57fa73c706b46cb21a313edb00d337ca4ce1a011fe3c760b28"}, + {file = "httptools-0.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aeefa0648362bb97a7d6b5ff770bfb774930a327d7f65f8208394856862de517"}, + {file = "httptools-0.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0d92b10dbf0b3da4823cde6a96d18e6ae358a9daa741c71448975f6a2c339cad"}, + {file = "httptools-0.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:5ddbd045cfcb073db2449563dd479057f2c2b681ebc232380e63ef15edc9c023"}, + {file = "httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9"}, +] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +description = "Consume Server-Sent Event (SSE) messages with HTTPX." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc"}, + {file = "httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d"}, +] + +[[package]] +name = "huggingface-hub" +version = "0.36.0" +description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d"}, + {file = "huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25"}, +] + +[package.dependencies] +filelock = "*" +fsspec = ">=2023.5.0" +hf-xet = {version = ">=1.1.3,<2.0.0", markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""} +packaging = ">=20.9" +pyyaml = ">=5.1" +requests = "*" +tqdm = ">=4.42.1" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "ty", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +cli = ["InquirerPy (==0.3.4)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "ty", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +hf-transfer = ["hf-transfer (>=0.1.4)"] +hf-xet = ["hf-xet (>=1.1.2,<2.0.0)"] +inference = ["aiohttp"] +mcp = ["aiohttp", "mcp (>=1.8.0)", "typer"] +oauth = ["authlib (>=1.3.2)", "fastapi", "httpx", "itsdangerous"] +quality = ["libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "ruff (>=0.9.0)", "ty"] +tensorflow = ["graphviz", "pydot", "tensorflow"] +tensorflow-testing = ["keras (<3.0)", "tensorflow"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["safetensors[torch]", "torch"] +typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + +[[package]] +name = "hyperframe" +version = "6.1.0" +description = "Pure-Python HTTP/2 framing" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"qdrant\"" +files = [ + {file = "hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"}, + {file = "hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08"}, +] + +[[package]] +name = "idna" +version = "3.11" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, + {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "immutables" +version = "0.21" +description = "Immutable Collections" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "immutables-0.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:14cb09d4f4577ad9ab8770a340dc2158e0a5ab5775cb34c75960167a31104212"}, + {file = "immutables-0.21-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:22ba593f95044ac60d2af463f3dc86cd0e223f8c51df85dff65d663d93e19f51"}, + {file = "immutables-0.21-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25afc81a7bcf26c8364f85e52a14e0095344343e79493c73b0e9a765310a0bed"}, + {file = "immutables-0.21-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac6e2868567289f88c6810f296940c328a1d38c9abc841eed04963102a27d12"}, + {file = "immutables-0.21-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ba8bca21a1d034f4577ede1e9553a681dd01199c06b563f1a8316f2623b64985"}, + {file = "immutables-0.21-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:39337bfb42f83dd787a81e2d00e90efa17c4a39a9cf1210b8a50dafe32438aae"}, + {file = "immutables-0.21-cp310-cp310-win32.whl", hash = "sha256:b24aa98f6cdae4ba15baf3aa00e84223bafcd0d3fd7f0443474527ec951845e1"}, + {file = "immutables-0.21-cp310-cp310-win_amd64.whl", hash = "sha256:715f8e5f8e1c35f036f9ac62eaf8b672eec1cdc2b4f9b73864cc64eccc76661c"}, + {file = "immutables-0.21-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5d780c38067047911a2e06a86ba063ba0055618ab5573c8198ef3f368e321303"}, + {file = "immutables-0.21-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9aab9d0f0016f6e0bfe7e4a4cb831ef20063da6468b1bbc71d06ef285781ee9e"}, + {file = "immutables-0.21-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ff83390b05d3372acb9a0c928f6cc20c78e74ca20ed88eb941f84a63b65e444"}, + {file = "immutables-0.21-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01497713e71509c4481ffccdbe3a47b94969345f4e92f814d6626f7c0a4c304"}, + {file = "immutables-0.21-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bc7844c9fbb5bece5bfdf2bf8ea74d308f42f40b0665fd25c58abf56d7db024a"}, + {file = "immutables-0.21-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:984106fa4345efd9f96de22e9949fc97bac8598bdebee03c20b2497a88bff3b7"}, + {file = "immutables-0.21-cp311-cp311-win32.whl", hash = "sha256:1bdb5200518518601377e4877d5034e7c535e9ea8a9d601ed8b0eedef0c7becd"}, + {file = "immutables-0.21-cp311-cp311-win_amd64.whl", hash = "sha256:dd00c34f431c54c95e7b84bfdbdeacb4f039a6a24eb0c1f7aa4b168bb9a6ad0a"}, + {file = "immutables-0.21-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1ed262094b755903122c3c3a83ad0e0d5c3ab7887cda12b2fe878769d1ee0d"}, + {file = "immutables-0.21-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce604f81d9d8f26e60b52ebcb56bb5c0462c8ea50fb17868487d15f048a2f13e"}, + {file = "immutables-0.21-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b48b116aaca4500398058b5a87814857a60c4cb09417fecc12d7da0f5639b73d"}, + {file = "immutables-0.21-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dad7c0c74b285cc0e555ec0e97acbdc6f1862fcd16b99abd612df3243732e741"}, + {file = "immutables-0.21-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e44346e2221a5a676c880ca8e0e6429fa24d1a4ae562573f5c04d7f2e759b030"}, + {file = "immutables-0.21-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b10139b529a460e53fe8be699ebd848c54c8a33ebe67763bcfcc809a475a26f"}, + {file = "immutables-0.21-cp312-cp312-win32.whl", hash = "sha256:fc512d808662614feb17d2d92e98f611d69669a98c7af15910acf1dc72737038"}, + {file = "immutables-0.21-cp312-cp312-win_amd64.whl", hash = "sha256:461dcb0f58a131045155e52a2c43de6ec2fe5ba19bdced6858a3abb63cee5111"}, + {file = "immutables-0.21-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:79674b51aa8dd983f9ac55f7f67b433b1df84a6b4f28ab860588389a5659485b"}, + {file = "immutables-0.21-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93c8350f8f7d0d9693f708229d9d0578e6f3b785ce6da4bced1da97137aacfad"}, + {file = "immutables-0.21-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:583d2a63e444ce1538cc2bda56ae1f4a1a11473dbc0377c82b516bc7eec3b81e"}, + {file = "immutables-0.21-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b274a52da9b106db55eceb93fc1aea858c4e6f4740189e3548e38613eafc2021"}, + {file = "immutables-0.21-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:338bede057250b33716a3e4892e15df0bf5a5ddbf1d67ead996b3e680b49ef9e"}, + {file = "immutables-0.21-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8781c89583b68f604cf30f0978b722165824c3075888639fde771bf1a3e12dc0"}, + {file = "immutables-0.21-cp313-cp313-win32.whl", hash = "sha256:e97ea83befad873712f283c0cccd630f70cba753e207b4868af28d5b85e9dc54"}, + {file = "immutables-0.21-cp313-cp313-win_amd64.whl", hash = "sha256:cfcb23bd898f5a4ef88692b42c51f52ca7373a35ba4dcc215060a668639eb5da"}, + {file = "immutables-0.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07a37d8699255402a10784d4d45f2bcc00ca7dba8da763207a834b15767e6c62"}, + {file = "immutables-0.21-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9139fd80bb05501216f49c4306bb80d0c1a08c3f0f621ed2939bf52d7f762661"}, + {file = "immutables-0.21-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6fc7e917e281361ad243be1a3cb56a7633de88ee67c94cdf5651958ead30d9"}, + {file = "immutables-0.21-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6a577f55eaaf763b685eef9710edbeb7ee95e2e5f54e7e5e0fd0f60ae2eb648"}, + {file = "immutables-0.21-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ca912c1bb35615ccbe361a6bb76e6fd43827394102467967d5599d78b50dd0f4"}, + {file = "immutables-0.21-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:586e88ca7ed44b7bb2cd7b212abd2637b51bd95bdb4856ab111b44715a62071c"}, + {file = "immutables-0.21-cp38-cp38-win32.whl", hash = "sha256:21adc6b478a58692c79c5bf316b39d3fd0552441d2b38eef1782a7555deee484"}, + {file = "immutables-0.21-cp38-cp38-win_amd64.whl", hash = "sha256:ecff5274357dc18aae053e5e10b8eee5e9b4d6cc774d34148c992cb2eb787ec3"}, + {file = "immutables-0.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e2aadf3bdd90daa0e8cb9c3cde4070e1021036e3b57f571a007ce24f323e47a9"}, + {file = "immutables-0.21-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5f8f507731d4d15e0c579aa77d8482471f988dc0f451e4bf3853ec36ccd42627"}, + {file = "immutables-0.21-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb9a378a4480381d7d3d63b0d201cf610eae0bf70e26a9306e3e631c9bd64010"}, + {file = "immutables-0.21-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7b5920bbfcaf038894c8ce4ed2eff0b31c3559810a61806db751be8ab4d703"}, + {file = "immutables-0.21-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8b90702d1fe313e8273ae7abb46fc0f0a87b47c1c9a83aed9a161301146e655c"}, + {file = "immutables-0.21-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:71cbbc6fbe7e7321648047ff9273f4605f8bd5ce456841a65ef151080e9d3481"}, + {file = "immutables-0.21-cp39-cp39-win32.whl", hash = "sha256:c44f286c47dc0d4d7b5bf19fbe975e6d57c56d2878cea413e1ec7a4bfffb2727"}, + {file = "immutables-0.21-cp39-cp39-win_amd64.whl", hash = "sha256:cf15314c39484b8947a4e20c3526021272510592fb2807b5136a2fcd6ab0151b"}, + {file = "immutables-0.21.tar.gz", hash = "sha256:b55ffaf0449790242feb4c56ab799ea7af92801a0a43f9e2f4f8af2ab24dfc4a"}, +] + +[package.extras] +test = ["flake8 (>=5.0,<6.0)", "mypy (>=1.4,<2.0)", "pycodestyle (>=2.9,<3.0)", "pytest (>=7.4,<8.0)"] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +description = "Read resources from Python packages" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, + {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "invoke" +version = "2.2.1" +description = "Pythonic task execution" +optional = true +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"mistral\"" +files = [ + {file = "invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8"}, + {file = "invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707"}, +] + +[[package]] +name = "ipython" +version = "8.37.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, + {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt_toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack_data = "*" +traitlets = ">=5.13.0" +typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"] +kernel = ["ipykernel"] +matplotlib = ["matplotlib"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "isodate" +version = "0.7.2" +description = "An ISO 8601 date/time/duration parser and formatter" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15"}, + {file = "isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6"}, +] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] + +[[package]] +name = "jaraco-functools" +version = "4.3.0" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8"}, + {file = "jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294"}, +] + +[package.dependencies] +more_itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jedi" +version = "0.19.2" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, +] + +[package.dependencies] +parso = ">=0.8.4,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] + +[[package]] +name = "jeepney" +version = "0.9.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "sys_platform == \"linux\"" +files = [ + {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, + {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, +] + +[package.extras] +test = ["async-timeout ; python_version < \"3.11\"", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["trio"] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jiter" +version = "0.12.0" +description = "Fast iterable JSON parser." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65"}, + {file = "jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2"}, + {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025"}, + {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca"}, + {file = "jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4"}, + {file = "jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11"}, + {file = "jiter-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8f8a7e317190b2c2d60eb2e8aa835270b008139562d70fe732e1c0020ec53c9"}, + {file = "jiter-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2218228a077e784c6c8f1a8e5d6b8cb1dea62ce25811c356364848554b2056cd"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9354ccaa2982bf2188fd5f57f79f800ef622ec67beb8329903abf6b10da7d423"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2607185ea89b4af9a604d4c7ec40e45d3ad03ee66998b031134bc510232bb7"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a585a5e42d25f2e71db5f10b171f5e5ea641d3aa44f7df745aa965606111cc2"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9e21d34edff5a663c631f850edcb786719c960ce887a5661e9c828a53a95d9"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a612534770470686cd5431478dc5a1b660eceb410abade6b1b74e320ca98de6"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3985aea37d40a908f887b34d05111e0aae822943796ebf8338877fee2ab67725"}, + {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b1207af186495f48f72529f8d86671903c8c10127cac6381b11dddc4aaa52df6"}, + {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef2fb241de583934c9915a33120ecc06d94aa3381a134570f59eed784e87001e"}, + {file = "jiter-0.12.0-cp311-cp311-win32.whl", hash = "sha256:453b6035672fecce8007465896a25b28a6b59cfe8fbc974b2563a92f5a92a67c"}, + {file = "jiter-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca264b9603973c2ad9435c71a8ec8b49f8f715ab5ba421c85a51cde9887e421f"}, + {file = "jiter-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:cb00ef392e7d684f2754598c02c409f376ddcef857aae796d559e6cacc2d78a5"}, + {file = "jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37"}, + {file = "jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126"}, + {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9"}, + {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86"}, + {file = "jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44"}, + {file = "jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb"}, + {file = "jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789"}, + {file = "jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e"}, + {file = "jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9"}, + {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626"}, + {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c"}, + {file = "jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de"}, + {file = "jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a"}, + {file = "jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60"}, + {file = "jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6"}, + {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4"}, + {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb"}, + {file = "jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7"}, + {file = "jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3"}, + {file = "jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525"}, + {file = "jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a"}, + {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67"}, + {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b"}, + {file = "jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42"}, + {file = "jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf"}, + {file = "jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451"}, + {file = "jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783"}, + {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b"}, + {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6"}, + {file = "jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183"}, + {file = "jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873"}, + {file = "jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473"}, + {file = "jiter-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c9d28b218d5f9e5f69a0787a196322a5056540cb378cac8ff542b4fa7219966c"}, + {file = "jiter-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0ee12028daf8cfcf880dd492349a122a64f42c059b6c62a2b0c96a83a8da820"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b135ebe757a82d67ed2821526e72d0acf87dd61f6013e20d3c45b8048af927b"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15d7fafb81af8a9e3039fc305529a61cd933eecee33b4251878a1c89859552a3"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92d1f41211d8a8fe412faad962d424d334764c01dac6691c44691c2e4d3eedaf"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a64a48d7c917b8f32f25c176df8749ecf08cec17c466114727efe7441e17f6d"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122046f3b3710b85de99d9aa2f3f0492a8233a2f54a64902b096efc27ea747b5"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:27ec39225e03c32c6b863ba879deb427882f243ae46f0d82d68b695fa5b48b40"}, + {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26b9e155ddc132225a39b1995b3b9f0fe0f79a6d5cbbeacf103271e7d309b404"}, + {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ab05b7c58e29bb9e60b70c2e0094c98df79a1e42e397b9bb6eaa989b7a66dd0"}, + {file = "jiter-0.12.0-cp39-cp39-win32.whl", hash = "sha256:59f9f9df87ed499136db1c2b6c9efb902f964bed42a582ab7af413b6a293e7b0"}, + {file = "jiter-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3719596a1ebe7a48a498e8d5d0c4bf7553321d4c3eee1d620628d51351a3928"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c"}, + {file = "jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b"}, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + +[[package]] +name = "jsonfinder" +version = "0.4.2" +description = "Easily handle JSON contained within strings.\nIncludes a command-line tool to format JSON within the input, similar to the builtin json.tool." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "jsonfinder-0.4.2.tar.gz", hash = "sha256:9845ca2d1e54aa007a2a72aaa07dcc90f516587cfe40cb6df214c9cf19bc1f6f"}, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, + {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] + +[[package]] +name = "jsonschema-path" +version = "0.3.4" +description = "JSONSchema Spec with object-oriented paths" +optional = false +python-versions = "<4.0.0,>=3.8.0" +groups = ["main"] +files = [ + {file = "jsonschema_path-0.3.4-py3-none-any.whl", hash = "sha256:f502191fdc2b22050f9a81c9237be9d27145b9001c55842bece5e94e382e52f8"}, + {file = "jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001"}, +] + +[package.dependencies] +pathable = ">=0.4.1,<0.5.0" +PyYAML = ">=5.1" +referencing = "<0.37.0" +requests = ">=2.31.0,<3.0.0" + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, + {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "keyring" +version = "25.7.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f"}, + {file = "keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b"}, +] + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +completion = ["shtab (>=1.1.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=3.4)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy (>=1.0.1)", "shtab", "types-pywin32"] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b"}, + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f"}, + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634"}, + {file = "kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611"}, + {file = "kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464"}, + {file = "kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2"}, + {file = "kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145"}, + {file = "kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54"}, + {file = "kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c"}, + {file = "kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d"}, + {file = "kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce"}, + {file = "kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7"}, + {file = "kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1"}, + {file = "kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d"}, +] + +[[package]] +name = "kubernetes" +version = "33.1.0" +description = "Kubernetes python client" +optional = true +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "kubernetes-33.1.0-py2.py3-none-any.whl", hash = "sha256:544de42b24b64287f7e0aa9513c93cb503f7f40eea39b20f66810011a86eabc5"}, + {file = "kubernetes-33.1.0.tar.gz", hash = "sha256:f64d829843a54c251061a8e7a14523b521f2dc5c896cf6d65ccf348648a88993"}, +] + +[package.dependencies] +certifi = ">=14.05.14" +durationpy = ">=0.7" +google-auth = ">=1.0.1" +oauthlib = ">=3.2.2" +python-dateutil = ">=2.5.3" +pyyaml = ">=5.4.1" +requests = "*" +requests-oauthlib = "*" +six = ">=1.9.0" +urllib3 = ">=1.24.2" +websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0" + +[package.extras] +adal = ["adal (>=1.0.2)"] + +[[package]] +name = "lagom" +version = "2.7.7" +description = "Lagom is a dependency injection container designed to give you 'just enough' help with building your dependencies." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "lagom-2.7.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:09a825e3be03b29120327d8883ad5a2d9fd415c24e4ac72c3ced24ebe100c205"}, + {file = "lagom-2.7.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a0565ead382a74bf2368a6b313302214829a48f6f7014f01fafdc5df2f5803"}, + {file = "lagom-2.7.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5f34d83bf571e4cae1c0631a7a12026685c1055c2988d1524bc60efe5e935d5e"}, + {file = "lagom-2.7.7-cp310-cp310-win32.whl", hash = "sha256:11e513fb2bf7459204c714c361187f3dc441570fe5d4f255676b53877614d152"}, + {file = "lagom-2.7.7-cp310-cp310-win_amd64.whl", hash = "sha256:e68c275b7ecd212502089981f1688808587408fb1349fa896f8ca5518bc51ba7"}, + {file = "lagom-2.7.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5035aa948b5b3fcea4ee89cac5a1aa143506f19b37c3e97d5a34ced6e9ed992"}, + {file = "lagom-2.7.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff5c3312221b69b5ea629d8f3f29563c281d76c23ec0266cbf1a6e898e6ad224"}, + {file = "lagom-2.7.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:46f2b5b3e8533df6b7de28e21278810796e5f76b83e140db412cdf15b389ee1d"}, + {file = "lagom-2.7.7-cp311-cp311-win32.whl", hash = "sha256:063b323c7105665a38f0ca7959f1abcae7ad88b74c02de3b63674e05258f24ca"}, + {file = "lagom-2.7.7-cp311-cp311-win_amd64.whl", hash = "sha256:11dfb34dc6af203cb82f299be18c78d9beccbc6bad7c18d3577db07f2be43f6b"}, + {file = "lagom-2.7.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:57031a288cbd549fc26b4107f1f1fabba1f01632d20de197389ec0948b2d0726"}, + {file = "lagom-2.7.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abeab675e4d3d505254b6eeb9665aa90e79e60f4adc5cc05c2082b0ac899bad4"}, + {file = "lagom-2.7.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e3b54f06ff474a2c82e02c3fbc17a5cd38581560885933c56422d2524a533079"}, + {file = "lagom-2.7.7-cp312-cp312-win32.whl", hash = "sha256:e336733b7fad9397081e736ca3dc3e35b70cc8df11f63df38053921760acf6a7"}, + {file = "lagom-2.7.7-cp312-cp312-win_amd64.whl", hash = "sha256:45874bcb18f08ad92d2356d19ca7c374658b51e68e91ce25885396ee832104b7"}, + {file = "lagom-2.7.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:36961c52a8debcc122ebc5caece4bdca7cf6c1cdf07159e17b84913259b386bd"}, + {file = "lagom-2.7.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a446273396437774a3defff5a9baa4e0d88c9bad4e9cf318d98748005f5a6c57"}, + {file = "lagom-2.7.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0d8f734641a75c4c7ce632f60fd6a65850a3a55d02938acc6d9348812741a167"}, + {file = "lagom-2.7.7-cp313-cp313-win32.whl", hash = "sha256:348c324cac8ad79d670c38b8d1b4de36280032963abd5127e9abce5f396583f5"}, + {file = "lagom-2.7.7-cp313-cp313-win_amd64.whl", hash = "sha256:f3ec6675496579c67057884b6b33cef56eb7867b6a98d500bbbe70cd7071f921"}, + {file = "lagom-2.7.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85c5373e502bc9142c8cbac50cb14072c2bc7cc81593de6bb2b0d97e84d92950"}, + {file = "lagom-2.7.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292ea7d8184c4642e7b1a65e65ff9e8b7bdb05a2303d0e8cb91a0b3059e78df8"}, + {file = "lagom-2.7.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b779317f08d7f8e523ee801e843506f1d34faa14ba3d51b7820b591d8ef1ef9f"}, + {file = "lagom-2.7.7-cp39-cp39-win32.whl", hash = "sha256:1be4c29f2c41a3e11647accad450f034173b4721b1231bb4de4ecd81bf7ef4c6"}, + {file = "lagom-2.7.7-cp39-cp39-win_amd64.whl", hash = "sha256:21bf278ecb4379cf8c30ff2cb6a11a96f8b13acc1e61338407d58811f10212c5"}, + {file = "lagom-2.7.7-py3-none-any.whl", hash = "sha256:704b52f5b028eec84344fb14164c24cec4853c1b699b2cc008b356a7ebc9c8a9"}, +] + +[package.extras] +env = ["pydantic (>=1.0.0,<3.0.0)"] + +[[package]] +name = "lazy-object-proxy" +version = "1.12.0" +description = "A fast and thorough lazy object proxy." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "lazy_object_proxy-1.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61d5e3310a4aa5792c2b599a7a78ccf8687292c8eb09cf187cca8f09cf6a7519"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ca33565f698ac1aece152a10f432415d1a2aa9a42dfe23e5ba2bc255ab91f6"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01c7819a410f7c255b20799b65d36b414379a30c6f1684c7bd7eb6777338c1b"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:029d2b355076710505c9545aef5ab3f750d89779310e26ddf2b7b23f6ea03cd8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc6e3614eca88b1c8a625fc0a47d0d745e7c3255b21dac0e30b3037c5e3deeb8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:be5fe974e39ceb0d6c9db0663c0464669cf866b2851c73971409b9566e880eab"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1cf69cd1a6c7fe2dbcc3edaa017cf010f4192e53796538cc7d5e1fedbfa4bcff"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efff4375a8c52f55a145dc8487a2108c2140f0bec4151ab4e1843e52eb9987ad"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1192e8c2f1031a6ff453ee40213afa01ba765b3dc861302cd91dbdb2e2660b00"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3605b632e82a1cbc32a1e5034278a64db555b3496e0795723ee697006b980508"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a61095f5d9d1a743e1e20ec6d6db6c2ca511961777257ebd9b288951b23b44fa"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:997b1d6e10ecc6fb6fe0f2c959791ae59599f41da61d652f6c903d1ee58b7370"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ee0d6027b760a11cc18281e702c0309dd92da458a74b4c15025d7fc490deede"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ab2c584e3cc8be0dfca422e05ad30a9abe3555ce63e9ab7a559f62f8dbc6ff9"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14e348185adbd03ec17d051e169ec45686dcd840a3779c9d4c10aabe2ca6e1c0"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4fcbe74fb85df8ba7825fa05eddca764138da752904b378f0ae5ab33a36c308"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:563d2ec8e4d4b68ee7848c5ab4d6057a6d703cb7963b342968bb8758dda33a23"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:53c7fd99eb156bbb82cbc5d5188891d8fdd805ba6c1e3b92b90092da2a837073"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86fd61cb2ba249b9f436d789d1356deae69ad3231dc3c0f17293ac535162672e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81d1852fb30fab81696f93db1b1e55a5d1ff7940838191062f5f56987d5fcc3e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9045646d83f6c2664c1330904b245ae2371b5c57a3195e4028aedc9f999655"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67f07ab742f1adfb3966c40f630baaa7902be4222a17941f3d85fd1dae5565ff"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ba769017b944fcacbf6a80c18b2761a1795b03f8899acdad1f1c39db4409be"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b22c2bbfb155706b928ac4d74c1a63ac8552a55ba7fff4445155523ea4067e1"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4a79b909aa16bde8ae606f06e6bbc9d3219d2e57fb3e0076e17879072b742c65"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:338ab2f132276203e404951205fe80c3fd59429b3a724e7b662b2eb539bb1be9"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c40b3c9faee2e32bfce0df4ae63f4e73529766893258eca78548bac801c8f66"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:717484c309df78cedf48396e420fa57fc8a2b1f06ea889df7248fdd156e58847"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b7ea5ea1ffe15059eb44bcbcb258f97bcb40e139b88152c40d07b1a1dfc9ac"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:08c465fb5cd23527512f9bd7b4c7ba6cec33e28aad36fbbe46bf7b858f9f3f7f"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c9defba70ab943f1df98a656247966d7729da2fe9c2d5d85346464bf320820a3"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6763941dbf97eea6b90f5b06eb4da9418cc088fce0e3883f5816090f9afcde4a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdc70d81235fc586b9e3d1aeef7d1553259b62ecaae9db2167a5d2550dcc391a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0a83c6f7a6b2bfc11ef3ed67f8cbe99f8ff500b05655d8e7df9aab993a6abc95"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:256262384ebd2a77b023ad02fbcc9326282bcfd16484d5531154b02bc304f4c5"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7601ec171c7e8584f8ff3f4e440aa2eebf93e854f04639263875b8c2971f819f"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae575ad9b674d0029fc077c5231b3bc6b433a3d1a62a8c363df96974b5534728"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31020c84005d3daa4cc0fa5a310af2066efe6b0d82aeebf9ab199292652ff036"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800f32b00a47c27446a2b767df7538e6c66a3488632c402b4fb2224f9794f3c0"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:15400b18893f345857b9e18b9bd87bd06aba84af6ed086187add70aeaa3f93f1"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3d3964fbd326578bcdfffd017ef101b6fb0484f34e731fe060ba9b8816498c36"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:424a8ab6695400845c39f13c685050eab69fa0bbac5790b201cd27375e5e41d7"}, + {file = "lazy_object_proxy-1.12.0-pp39.pp310.pp311.graalpy311-none-any.whl", hash = "sha256:c3b2e0af1f7f77c4263759c4824316ce458fabe0fceadcd24ef8ca08b2d1e402"}, + {file = "lazy_object_proxy-1.12.0.tar.gz", hash = "sha256:1f5a462d92fd0cfb82f1fab28b51bfb209fabbe6aabf7f0d51472c0c124c0c61"}, +] + +[[package]] +name = "limits" +version = "5.6.0" +description = "Rate limiting utilities" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "limits-5.6.0-py3-none-any.whl", hash = "sha256:b585c2104274528536a5b68864ec3835602b3c4a802cd6aa0b07419798394021"}, + {file = "limits-5.6.0.tar.gz", hash = "sha256:807fac75755e73912e894fdd61e2838de574c5721876a19f7ab454ae1fffb4b5"}, +] + +[package.dependencies] +deprecated = ">=1.2" +packaging = ">=21" +typing-extensions = "*" + +[package.extras] +async-memcached = ["memcachio (>=0.3)"] +async-mongodb = ["motor (>=3,<4)"] +async-redis = ["coredis (>=3.4.0,<6)"] +async-valkey = ["valkey (>=6)"] +memcached = ["pymemcache (>3,<5.0.0)"] +mongodb = ["pymongo (>4.1,<5)"] +redis = ["redis (>3,!=4.5.2,!=4.5.3,<7.0.0)"] +rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] +valkey = ["valkey (>=6)"] + +[[package]] +name = "litellm" +version = "1.80.5" +description = "Library to easily interface with LLM API providers" +optional = true +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "extra == \"litellm\"" +files = [ + {file = "litellm-1.80.5-py3-none-any.whl", hash = "sha256:2ac5f4e88cd57ae056e00da8f872e1c2956653750929fba2fd9b007b400fdb77"}, + {file = "litellm-1.80.5.tar.gz", hash = "sha256:922791c264845d9ed59e540c8fa74a74d237c1b209568a05ffeacd8b51770deb"}, +] + +[package.dependencies] +aiohttp = ">=3.10" +click = "*" +fastuuid = ">=0.13.0" +httpx = ">=0.23.0" +importlib-metadata = ">=6.8.0" +jinja2 = ">=3.1.2,<4.0.0" +jsonschema = ">=4.22.0,<5.0.0" +openai = ">=2.8.0" +pydantic = ">=2.5.0,<3.0.0" +python-dotenv = ">=0.2.0" +tiktoken = ">=0.7.0" +tokenizers = "*" + +[package.extras] +caching = ["diskcache (>=5.6.1,<6.0.0)"] +extra-proxy = ["azure-identity (>=1.15.0,<2.0.0) ; python_version >= \"3.9\"", "azure-keyvault-secrets (>=4.8.0,<5.0.0)", "google-cloud-iam (>=2.19.1,<3.0.0)", "google-cloud-kms (>=2.21.3,<3.0.0)", "prisma (==0.11.0)", "redisvl (>=0.4.1,<0.5.0) ; python_version >= \"3.9\" and python_version < \"3.14\"", "resend (>=0.8.0)"] +mlflow = ["mlflow (>3.1.4) ; python_version >= \"3.10\""] +proxy = ["PyJWT (>=2.10.1,<3.0.0) ; python_version >= \"3.9\"", "apscheduler (>=3.10.4,<4.0.0)", "azure-identity (>=1.15.0,<2.0.0) ; python_version >= \"3.9\"", "azure-storage-blob (>=12.25.1,<13.0.0)", "backoff", "boto3 (==1.36.0)", "cryptography", "fastapi (>=0.120.1)", "fastapi-sso (>=0.16.0,<0.17.0)", "gunicorn (>=23.0.0,<24.0.0)", "litellm-enterprise (==0.1.22)", "litellm-proxy-extras (==0.4.6)", "mcp (>=1.21.2,<2.0.0) ; python_version >= \"3.10\"", "orjson (>=3.9.7,<4.0.0)", "polars (>=1.31.0,<2.0.0) ; python_version >= \"3.10\"", "pynacl (>=1.5.0,<2.0.0)", "python-multipart (>=0.0.18,<0.0.19)", "pyyaml (>=6.0.1,<7.0.0)", "rich (==13.7.1)", "rq", "soundfile (>=0.12.1,<0.13.0)", "uvicorn (>=0.31.1,<0.32.0)", "uvloop (>=0.21.0,<0.22.0) ; sys_platform != \"win32\"", "websockets (>=13.1.0,<14.0.0)"] +semantic-router = ["semantic-router (>=0.1.12) ; python_version >= \"3.9\" and python_version < \"3.14\""] +utils = ["numpydoc"] + +[[package]] +name = "mako" +version = "1.3.10" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"}, + {file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, + {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins (>=0.5.0)"] +profiling = ["gprof2dot"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] + +[[package]] +name = "markupsafe" +version = "3.0.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "matplotlib" +version = "3.10.7" +description = "Python plotting package" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "matplotlib-3.10.7-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ac81eee3b7c266dd92cee1cd658407b16c57eed08c7421fa354ed68234de380"}, + {file = "matplotlib-3.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:667ecd5d8d37813a845053d8f5bf110b534c3c9f30e69ebd25d4701385935a6d"}, + {file = "matplotlib-3.10.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc1c51b846aca49a5a8b44fbba6a92d583a35c64590ad9e1e950dc88940a4297"}, + {file = "matplotlib-3.10.7-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a11c2e9e72e7de09b7b72e62f3df23317c888299c875e2b778abf1eda8c0a42"}, + {file = "matplotlib-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f19410b486fdd139885ace124e57f938c1e6a3210ea13dd29cab58f5d4bc12c7"}, + {file = "matplotlib-3.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:b498e9e4022f93de2d5a37615200ca01297ceebbb56fe4c833f46862a490f9e3"}, + {file = "matplotlib-3.10.7-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:53b492410a6cd66c7a471de6c924f6ede976e963c0f3097a3b7abfadddc67d0a"}, + {file = "matplotlib-3.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9749313deb729f08207718d29c86246beb2ea3fdba753595b55901dee5d2fd6"}, + {file = "matplotlib-3.10.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2222c7ba2cbde7fe63032769f6eb7e83ab3227f47d997a8453377709b7fe3a5a"}, + {file = "matplotlib-3.10.7-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e91f61a064c92c307c5a9dc8c05dc9f8a68f0a3be199d9a002a0622e13f874a1"}, + {file = "matplotlib-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f1851eab59ca082c95df5a500106bad73672645625e04538b3ad0f69471ffcc"}, + {file = "matplotlib-3.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:6516ce375109c60ceec579e699524e9d504cd7578506f01150f7a6bc174a775e"}, + {file = "matplotlib-3.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:b172db79759f5f9bc13ef1c3ef8b9ee7b37b0247f987fbbbdaa15e4f87fd46a9"}, + {file = "matplotlib-3.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a0edb7209e21840e8361e91ea84ea676658aa93edd5f8762793dec77a4a6748"}, + {file = "matplotlib-3.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c380371d3c23e0eadf8ebff114445b9f970aff2010198d498d4ab4c3b41eea4f"}, + {file = "matplotlib-3.10.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d5f256d49fea31f40f166a5e3131235a5d2f4b7f44520b1cf0baf1ce568ccff0"}, + {file = "matplotlib-3.10.7-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11ae579ac83cdf3fb72573bb89f70e0534de05266728740d478f0f818983c695"}, + {file = "matplotlib-3.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4c14b6acd16cddc3569a2d515cfdd81c7a68ac5639b76548cfc1a9e48b20eb65"}, + {file = "matplotlib-3.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:0d8c32b7ea6fb80b1aeff5a2ceb3fb9778e2759e899d9beff75584714afcc5ee"}, + {file = "matplotlib-3.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:5f3f6d315dcc176ba7ca6e74c7768fb7e4cf566c49cb143f6bc257b62e634ed8"}, + {file = "matplotlib-3.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1d9d3713a237970569156cfb4de7533b7c4eacdd61789726f444f96a0d28f57f"}, + {file = "matplotlib-3.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37a1fea41153dd6ee061d21ab69c9cf2cf543160b1b85d89cd3d2e2a7902ca4c"}, + {file = "matplotlib-3.10.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3c4ea4948d93c9c29dc01c0c23eef66f2101bf75158c291b88de6525c55c3d1"}, + {file = "matplotlib-3.10.7-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22df30ffaa89f6643206cf13877191c63a50e8f800b038bc39bee9d2d4957632"}, + {file = "matplotlib-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b69676845a0a66f9da30e87f48be36734d6748024b525ec4710be40194282c84"}, + {file = "matplotlib-3.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:744991e0cc863dd669c8dc9136ca4e6e0082be2070b9d793cbd64bec872a6815"}, + {file = "matplotlib-3.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:fba2974df0bf8ce3c995fa84b79cde38326e0f7b5409e7a3a481c1141340bcf7"}, + {file = "matplotlib-3.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:932c55d1fa7af4423422cb6a492a31cbcbdbe68fd1a9a3f545aa5e7a143b5355"}, + {file = "matplotlib-3.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e38c2d581d62ee729a6e144c47a71b3f42fb4187508dbbf4fe71d5612c3433b"}, + {file = "matplotlib-3.10.7-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:786656bb13c237bbcebcd402f65f44dd61ead60ee3deb045af429d889c8dbc67"}, + {file = "matplotlib-3.10.7-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09d7945a70ea43bf9248f4b6582734c2fe726723204a76eca233f24cffc7ef67"}, + {file = "matplotlib-3.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0b181e9fa8daf1d9f2d4c547527b167cb8838fc587deabca7b5c01f97199e84"}, + {file = "matplotlib-3.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:31963603041634ce1a96053047b40961f7a29eb8f9a62e80cc2c0427aa1d22a2"}, + {file = "matplotlib-3.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:aebed7b50aa6ac698c90f60f854b47e48cd2252b30510e7a1feddaf5a3f72cbf"}, + {file = "matplotlib-3.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d883460c43e8c6b173fef244a2341f7f7c0e9725c7fe68306e8e44ed9c8fb100"}, + {file = "matplotlib-3.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07124afcf7a6504eafcb8ce94091c5898bbdd351519a1beb5c45f7a38c67e77f"}, + {file = "matplotlib-3.10.7-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c17398b709a6cce3d9fdb1595c33e356d91c098cd9486cb2cc21ea2ea418e715"}, + {file = "matplotlib-3.10.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7146d64f561498764561e9cd0ed64fcf582e570fc519e6f521e2d0cfd43365e1"}, + {file = "matplotlib-3.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90ad854c0a435da3104c01e2c6f0028d7e719b690998a2333d7218db80950722"}, + {file = "matplotlib-3.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:4645fc5d9d20ffa3a39361fcdbcec731382763b623b72627806bf251b6388866"}, + {file = "matplotlib-3.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:9257be2f2a03415f9105c486d304a321168e61ad450f6153d77c69504ad764bb"}, + {file = "matplotlib-3.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1e4bbad66c177a8fdfa53972e5ef8be72a5f27e6a607cec0d8579abd0f3102b1"}, + {file = "matplotlib-3.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8eb7194b084b12feb19142262165832fc6ee879b945491d1c3d4660748020c4"}, + {file = "matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d41379b05528091f00e1728004f9a8d7191260f3862178b88e8fd770206318"}, + {file = "matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a74f79fafb2e177f240579bc83f0b60f82cc47d2f1d260f422a0627207008ca"}, + {file = "matplotlib-3.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:702590829c30aada1e8cef0568ddbffa77ca747b4d6e36c6d173f66e301f89cc"}, + {file = "matplotlib-3.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:f79d5de970fc90cd5591f60053aecfce1fcd736e0303d9f0bf86be649fa68fb8"}, + {file = "matplotlib-3.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:cb783436e47fcf82064baca52ce748af71725d0352e1d31564cbe9c95df92b9c"}, + {file = "matplotlib-3.10.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5c09cf8f2793f81368f49f118b6f9f937456362bee282eac575cca7f84cda537"}, + {file = "matplotlib-3.10.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:de66744b2bb88d5cd27e80dfc2ec9f0517d0a46d204ff98fe9e5f2864eb67657"}, + {file = "matplotlib-3.10.7-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53cc80662dd197ece414dd5b66e07370201515a3eaf52e7c518c68c16814773b"}, + {file = "matplotlib-3.10.7-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15112bcbaef211bd663fa935ec33313b948e214454d949b723998a43357b17b0"}, + {file = "matplotlib-3.10.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d2a959c640cdeecdd2ec3136e8ea0441da59bcaf58d67e9c590740addba2cb68"}, + {file = "matplotlib-3.10.7-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3886e47f64611046bc1db523a09dd0a0a6bed6081e6f90e13806dd1d1d1b5e91"}, + {file = "matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=3" +python-dateutil = ">=2.7" + +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76"}, + {file = "matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe"}, +] + +[package.dependencies] +traitlets = "*" + +[package.extras] +test = ["flake8", "nbdime", "nbval", "notebook", "pytest"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mcp" +version = "1.19.0" +description = "Model Context Protocol SDK" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "mcp-1.19.0-py3-none-any.whl", hash = "sha256:f5907fe1c0167255f916718f376d05f09a830a215327a3ccdd5ec8a519f2e572"}, + {file = "mcp-1.19.0.tar.gz", hash = "sha256:213de0d3cd63f71bc08ffe9cc8d4409cc87acffd383f6195d2ce0457c021b5c1"}, +] + +[package.dependencies] +anyio = ">=4.5" +httpx = ">=0.27.1" +httpx-sse = ">=0.4" +jsonschema = ">=4.20.0" +pydantic = ">=2.11.0,<3.0.0" +pydantic-settings = ">=2.5.2" +python-multipart = ">=0.0.9" +pywin32 = {version = ">=310", markers = "sys_platform == \"win32\""} +sse-starlette = ">=1.6.1" +starlette = ">=0.27" +uvicorn = {version = ">=0.31.1", markers = "sys_platform != \"emscripten\""} + +[package.extras] +cli = ["python-dotenv (>=1.0.0)", "typer (>=0.16.0)"] +rich = ["rich (>=13.9.4)"] +ws = ["websockets (>=15.0.1)"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mistralai" +version = "1.9.11" +description = "Python Client SDK for the Mistral AI API." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"mistral\"" +files = [ + {file = "mistralai-1.9.11-py3-none-any.whl", hash = "sha256:7a3dc2b8ef3fceaa3582220234261b5c4e3e03a972563b07afa150e44a25a6d3"}, + {file = "mistralai-1.9.11.tar.gz", hash = "sha256:3df9e403c31a756ec79e78df25ee73cea3eb15f86693773e16b16adaf59c9b8a"}, +] + +[package.dependencies] +eval-type-backport = ">=0.2.0" +httpx = ">=0.28.1" +invoke = ">=2.2.0,<3.0.0" +pydantic = ">=2.10.3" +python-dateutil = ">=2.8.2" +pyyaml = ">=6.0.2,<7.0.0" +typing-inspection = ">=0.4.0" + +[package.extras] +agents = ["authlib (>=1.5.2,<2.0)", "griffe (>=1.7.3,<2.0)", "mcp (>=1.0,<2.0) ; python_version >= \"3.10\""] +gcp = ["google-auth (>=2.27.0)", "requests (>=2.32.3)"] + +[[package]] +name = "mmh3" +version = "5.2.0" +description = "Python extension for MurmurHash (MurmurHash3), a set of fast and robust hash functions." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "mmh3-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:81c504ad11c588c8629536b032940f2a359dda3b6cbfd4ad8f74cb24dcd1b0bc"}, + {file = "mmh3-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b898cecff57442724a0f52bf42c2de42de63083a91008fb452887e372f9c328"}, + {file = "mmh3-5.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be1374df449465c9f2500e62eee73a39db62152a8bdfbe12ec5b5c1cd451344d"}, + {file = "mmh3-5.2.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0d753ad566c721faa33db7e2e0eddd74b224cdd3eaf8481d76c926603c7a00e"}, + {file = "mmh3-5.2.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dfbead5575f6470c17e955b94f92d62a03dfc3d07f2e6f817d9b93dc211a1515"}, + {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7434a27754049144539d2099a6d2da5d88b8bdeedf935180bf42ad59b3607aa3"}, + {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cadc16e8ea64b5d9a47363013e2bea469e121e6e7cb416a7593aeb24f2ad122e"}, + {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d765058da196f68dc721116cab335e696e87e76720e6ef8ee5a24801af65e63d"}, + {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8b0c53fe0994beade1ad7c0f13bd6fec980a0664bfbe5a6a7d64500b9ab76772"}, + {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:49037d417419863b222ae47ee562b2de9c3416add0a45c8d7f4e864be8dc4f89"}, + {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6ecb4e750d712abde046858ee6992b65c93f1f71b397fce7975c3860c07365d2"}, + {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:382a6bb3f8c6532ea084e7acc5be6ae0c6effa529240836d59352398f002e3fc"}, + {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7733ec52296fc1ba22e9b90a245c821adbb943e98c91d8a330a2254612726106"}, + {file = "mmh3-5.2.0-cp310-cp310-win32.whl", hash = "sha256:127c95336f2a98c51e7682341ab7cb0be3adb9df0819ab8505a726ed1801876d"}, + {file = "mmh3-5.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:419005f84ba1cab47a77465a2a843562dadadd6671b8758bf179d82a15ca63eb"}, + {file = "mmh3-5.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:d22c9dcafed659fadc605538946c041722b6d1104fe619dbf5cc73b3c8a0ded8"}, + {file = "mmh3-5.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7901c893e704ee3c65f92d39b951f8f34ccf8e8566768c58103fb10e55afb8c1"}, + {file = "mmh3-5.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5f5536b1cbfa72318ab3bfc8a8188b949260baed186b75f0abc75b95d8c051"}, + {file = "mmh3-5.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cedac4f4054b8f7859e5aed41aaa31ad03fce6851901a7fdc2af0275ac533c10"}, + {file = "mmh3-5.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eb756caf8975882630ce4e9fbbeb9d3401242a72528230422c9ab3a0d278e60c"}, + {file = "mmh3-5.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:097e13c8b8a66c5753c6968b7640faefe85d8e38992703c1f666eda6ef4c3762"}, + {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7c0c7845566b9686480e6a7e9044db4afb60038d5fabd19227443f0104eeee4"}, + {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:61ac226af521a572700f863d6ecddc6ece97220ce7174e311948ff8c8919a363"}, + {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:582f9dbeefe15c32a5fa528b79b088b599a1dfe290a4436351c6090f90ddebb8"}, + {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ebfc46b39168ab1cd44670a32ea5489bcbc74a25795c61b6d888c5c2cf654ed"}, + {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1556e31e4bd0ac0c17eaf220be17a09c171d7396919c3794274cb3415a9d3646"}, + {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81df0dae22cd0da87f1c978602750f33d17fb3d21fb0f326c89dc89834fea79b"}, + {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:eba01ec3bd4a49b9ac5ca2bc6a73ff5f3af53374b8556fcc2966dd2af9eb7779"}, + {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9a011469b47b752e7d20de296bb34591cdfcbe76c99c2e863ceaa2aa61113d2"}, + {file = "mmh3-5.2.0-cp311-cp311-win32.whl", hash = "sha256:bc44fc2b886243d7c0d8daeb37864e16f232e5b56aaec27cc781d848264cfd28"}, + {file = "mmh3-5.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ebf241072cf2777a492d0e09252f8cc2b3edd07dfdb9404b9757bffeb4f2cee"}, + {file = "mmh3-5.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5f317a727bba0e633a12e71228bc6a4acb4f471a98b1c003163b917311ea9a9"}, + {file = "mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be"}, + {file = "mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd"}, + {file = "mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96"}, + {file = "mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094"}, + {file = "mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037"}, + {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773"}, + {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5"}, + {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50"}, + {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765"}, + {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43"}, + {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4"}, + {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3"}, + {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c"}, + {file = "mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49"}, + {file = "mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3"}, + {file = "mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0"}, + {file = "mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065"}, + {file = "mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de"}, + {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044"}, + {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73"}, + {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504"}, + {file = "mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b"}, + {file = "mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05"}, + {file = "mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814"}, + {file = "mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093"}, + {file = "mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54"}, + {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a"}, + {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908"}, + {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5"}, + {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a"}, + {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266"}, + {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5"}, + {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9"}, + {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290"}, + {file = "mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051"}, + {file = "mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081"}, + {file = "mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b"}, + {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078"}, + {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501"}, + {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b"}, + {file = "mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770"}, + {file = "mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110"}, + {file = "mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647"}, + {file = "mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63"}, + {file = "mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12"}, + {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22"}, + {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5"}, + {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07"}, + {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935"}, + {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7"}, + {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5"}, + {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384"}, + {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e"}, + {file = "mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0"}, + {file = "mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b"}, + {file = "mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115"}, + {file = "mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932"}, + {file = "mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c"}, + {file = "mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be"}, + {file = "mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb"}, + {file = "mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65"}, + {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991"}, + {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645"}, + {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3"}, + {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279"}, + {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513"}, + {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db"}, + {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667"}, + {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5"}, + {file = "mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7"}, + {file = "mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d"}, + {file = "mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9"}, + {file = "mmh3-5.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3c6041fd9d5fb5fcac57d5c80f521a36b74aea06b8566431c63e4ffc49aced51"}, + {file = "mmh3-5.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:58477cf9ef16664d1ce2b038f87d2dc96d70fe50733a34a7f07da6c9a5e3538c"}, + {file = "mmh3-5.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be7d3dca9358e01dab1bad881fb2b4e8730cec58d36dd44482bc068bfcd3bc65"}, + {file = "mmh3-5.2.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:931d47e08c9c8a67bf75d82f0ada8399eac18b03388818b62bfa42882d571d72"}, + {file = "mmh3-5.2.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dd966df3489ec13848d6c6303429bbace94a153f43d1ae2a55115fd36fd5ca5d"}, + {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c677d78887244bf3095020b73c42b505b700f801c690f8eaa90ad12d3179612f"}, + {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63830f846797187c5d3e2dae50f0848fdc86032f5bfdc58ae352f02f857e9025"}, + {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c3f563e8901960e2eaa64c8e8821895818acabeb41c96f2efbb936f65dbe486c"}, + {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96f1e1ac44cbb42bcc406e509f70c9af42c594e72ccc7b1257f97554204445f0"}, + {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7bbb0df897944b5ec830f3ad883e32c5a7375370a521565f5fe24443bfb2c4f7"}, + {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1fae471339ae1b9c641f19cf46dfe6ffd7f64b1fba7c4333b99fa3dd7f21ae0a"}, + {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:aa6e5d31fdc5ed9e3e95f9873508615a778fe9b523d52c17fc770a3eb39ab6e4"}, + {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:746a5ee71c6d1103d9b560fa147881b5e68fd35da56e54e03d5acefad0e7c055"}, + {file = "mmh3-5.2.0-cp39-cp39-win32.whl", hash = "sha256:10983c10f5c77683bd845751905ba535ec47409874acc759d5ce3ff7ef34398a"}, + {file = "mmh3-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:fdfd3fb739f4e22746e13ad7ba0c6eedf5f454b18d11249724a388868e308ee4"}, + {file = "mmh3-5.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:33576136c06b46a7046b6d83a3d75fbca7d25f84cec743f1ae156362608dc6d2"}, + {file = "mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8"}, +] + +[package.extras] +benchmark = ["pymmh3 (==0.0.5)", "pyperf (==2.9.0)", "xxhash (==3.5.0)"] +docs = ["myst-parser (==4.0.1)", "shibuya (==2025.7.24)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)"] +lint = ["black (==25.1.0)", "clang-format (==20.1.8)", "isort (==6.0.1)", "pylint (==3.3.7)"] +plot = ["matplotlib (==3.10.3)", "pandas (==2.3.1)"] +test = ["pytest (==8.4.1)", "pytest-sugar (==1.0.0)"] +type = ["mypy (==1.17.0)"] + +[[package]] +name = "more-itertools" +version = "10.8.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b"}, + {file = "more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +description = "Python library for arbitrary-precision floating-point arithmetic" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\"" +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +docs = ["sphinx"] +gmpy = ["gmpy2 (>=2.1.0a4) ; platform_python_implementation != \"PyPy\""] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "msal" +version = "1.34.0" +description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"azure\"" +files = [ + {file = "msal-1.34.0-py3-none-any.whl", hash = "sha256:f669b1644e4950115da7a176441b0e13ec2975c29528d8b9e81316023676d6e1"}, + {file = "msal-1.34.0.tar.gz", hash = "sha256:76ba83b716ea5a6d75b0279c0ac353a0e05b820ca1f6682c0eb7f45190c43c2f"}, +] + +[package.dependencies] +cryptography = ">=2.5,<49" +PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} +requests = ">=2.0.0,<3" + +[package.extras] +broker = ["pymsalruntime (>=0.14,<0.19) ; python_version >= \"3.6\" and platform_system == \"Windows\"", "pymsalruntime (>=0.17,<0.19) ; python_version >= \"3.8\" and platform_system == \"Darwin\"", "pymsalruntime (>=0.18,<0.19) ; python_version >= \"3.8\" and platform_system == \"Linux\""] + +[[package]] +name = "msal-extensions" +version = "1.3.1" +description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"azure\"" +files = [ + {file = "msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"}, + {file = "msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4"}, +] + +[package.dependencies] +msal = ">=1.29,<2" + +[package.extras] +portalocker = ["portalocker (>=1.4,<4)"] + +[[package]] +name = "multidict" +version = "6.7.0" +description = "multidict implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349"}, + {file = "multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e"}, + {file = "multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62"}, + {file = "multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111"}, + {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36"}, + {file = "multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85"}, + {file = "multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7"}, + {file = "multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0"}, + {file = "multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc"}, + {file = "multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721"}, + {file = "multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8"}, + {file = "multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b"}, + {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34"}, + {file = "multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff"}, + {file = "multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81"}, + {file = "multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912"}, + {file = "multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184"}, + {file = "multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45"}, + {file = "multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1"}, + {file = "multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a"}, + {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8"}, + {file = "multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4"}, + {file = "multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b"}, + {file = "multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec"}, + {file = "multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6"}, + {file = "multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159"}, + {file = "multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf"}, + {file = "multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd"}, + {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288"}, + {file = "multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17"}, + {file = "multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390"}, + {file = "multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e"}, + {file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00"}, + {file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb"}, + {file = "multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad"}, + {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762"}, + {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6"}, + {file = "multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d"}, + {file = "multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6"}, + {file = "multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792"}, + {file = "multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842"}, + {file = "multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b"}, + {file = "multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1"}, + {file = "multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f"}, + {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f"}, + {file = "multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885"}, + {file = "multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c"}, + {file = "multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000"}, + {file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63"}, + {file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718"}, + {file = "multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a"}, + {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9"}, + {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0"}, + {file = "multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13"}, + {file = "multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd"}, + {file = "multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827"}, + {file = "multidict-6.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:363eb68a0a59bd2303216d2346e6c441ba10d36d1f9969fcb6f1ba700de7bb5c"}, + {file = "multidict-6.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d874eb056410ca05fed180b6642e680373688efafc7f077b2a2f61811e873a40"}, + {file = "multidict-6.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b55d5497b51afdfde55925e04a022f1de14d4f4f25cdfd4f5d9b0aa96166851"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f8e5c0031b90ca9ce555e2e8fd5c3b02a25f14989cbc310701823832c99eb687"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cf41880c991716f3c7cec48e2f19ae4045fc9db5fc9cff27347ada24d710bb5"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cfc12a8630a29d601f48d47787bd7eb730e475e83edb5d6c5084317463373eb"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3996b50c3237c4aec17459217c1e7bbdead9a22a0fcd3c365564fbd16439dde6"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7f5170993a0dd3ab871c74f45c0a21a4e2c37a2f2b01b5f722a2ad9c6650469e"}, + {file = "multidict-6.7.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ec81878ddf0e98817def1e77d4f50dae5ef5b0e4fe796fae3bd674304172416e"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9281bf5b34f59afbc6b1e477a372e9526b66ca446f4bf62592839c195a718b32"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:68af405971779d8b37198726f2b6fe3955db846fee42db7a4286fc542203934c"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3ba3ef510467abb0667421a286dc906e30eb08569365f5cdb131d7aff7c2dd84"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b61189b29081a20c7e4e0b49b44d5d44bb0dc92be3c6d06a11cc043f81bf9329"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fb287618b9c7aa3bf8d825f02d9201b2f13078a5ed3b293c8f4d953917d84d5e"}, + {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:521f33e377ff64b96c4c556b81c55d0cfffb96a11c194fd0c3f1e56f3d8dd5a4"}, + {file = "multidict-6.7.0-cp39-cp39-win32.whl", hash = "sha256:ce8fdc2dca699f8dbf055a61d73eaa10482569ad20ee3c36ef9641f69afa8c91"}, + {file = "multidict-6.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:7e73299c99939f089dd9b2120a04a516b95cdf8c1cd2b18c53ebf0de80b1f18f"}, + {file = "multidict-6.7.0-cp39-cp39-win_arm64.whl", hash = "sha256:6bdce131e14b04fd34a809b6380dbfd826065c3e2fe8a50dbae659fa0c390546"}, + {file = "multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3"}, + {file = "multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "mypy" +version = "1.18.2" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, + {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, + {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, + {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, + {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, + {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, + {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, + {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, + {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, + {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, + {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, + {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, + {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, + {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, + {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, + {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "nano-vectordb" +version = "0.0.4.3" +description = "A simple, easy-to-hack Vector Database implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "nano_vectordb-0.0.4.3-py3-none-any.whl", hash = "sha256:1b70401a54c02fabf76515b5dfb630076434547ed3c6861828ee8771b6dd7c19"}, + {file = "nano_vectordb-0.0.4.3.tar.gz", hash = "sha256:3d13074476f2b739e51261974ed44aa467725579966219734c03502c929ed3b5"}, +] + +[package.dependencies] +numpy = "*" + +[[package]] +name = "nanoid" +version = "2.0.0" +description = "A tiny, secure, URL-friendly, unique string ID generator for Python" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "nanoid-2.0.0-py3-none-any.whl", hash = "sha256:90aefa650e328cffb0893bbd4c236cfd44c48bc1f2d0b525ecc53c3187b653bb"}, + {file = "nanoid-2.0.0.tar.gz", hash = "sha256:5a80cad5e9c6e9ae3a41fa2fb34ae189f7cb420b2a5d8f82bd9d23466e4efa68"}, +] + +[[package]] +name = "networkx" +version = "3.4.2" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, +] + +[package.dependencies] +matplotlib = {version = ">=3.7", optional = true, markers = "extra == \"default\""} +numpy = {version = ">=1.24", optional = true, markers = "extra == \"default\""} +pandas = {version = ">=2.0", optional = true, markers = "extra == \"default\""} +scipy = {version = ">=1.10,<1.11.0 || >1.11.0,<1.11.1 || >1.11.1", optional = true, markers = "extra == \"default\""} + +[package.extras] +default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + +[[package]] +name = "numpy" +version = "2.2.6" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"}, + {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"}, + {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"}, + {file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"}, + {file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"}, + {file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"}, + {file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"}, + {file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"}, + {file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"}, + {file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"}, + {file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"}, + {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"}, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +description = "CUBLAS native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0"}, + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142"}, + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +description = "CUDA profiling tools runtime libs." +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed"}, + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182"}, + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +description = "NVRTC native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994"}, + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8"}, + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +description = "CUDA Runtime native Libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d"}, + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90"}, + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8"}, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +description = "cuDNN runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8"}, + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8"}, + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +description = "CUFFT native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a"}, + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74"}, + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +description = "cuFile GPUDirect libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc"}, + {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +description = "CURAND native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd"}, + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9"}, + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec"}, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +description = "CUDA solver native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0"}, + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450"}, + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +description = "CUSPARSE native runtime libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc"}, + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b"}, + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +description = "NVIDIA cuSPARSELt" +optional = true +python-versions = "*" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5"}, + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623"}, + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075"}, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a"}, + {file = "nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +description = "Nvidia JIT LTO Library" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88"}, + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7"}, + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f"}, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.3.20" +description = "NVSHMEM creates a global address space that provides efficient and scalable communication for NVIDIA GPU clusters." +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0"}, + {file = "nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +description = "NVIDIA Tools Extension" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615"}, + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f"}, + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e"}, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1"}, + {file = "oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9"}, +] + +[package.extras] +rsa = ["cryptography (>=3.0.0)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] + +[[package]] +name = "ollama" +version = "0.5.4" +description = "The official Python client for Ollama." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"ollama\"" +files = [ + {file = "ollama-0.5.4-py3-none-any.whl", hash = "sha256:6374c9bb4f2a371b3583c09786112ba85b006516745689c172a7e28af4d4d1a2"}, + {file = "ollama-0.5.4.tar.gz", hash = "sha256:75857505a5d42e5e58114a1b78cc8c24596d8866863359d8a2329946a9b6d6f3"}, +] + +[package.dependencies] +httpx = ">=0.27" +pydantic = ">=2.9" + +[[package]] +name = "onnxruntime" +version = "1.23.2" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "onnxruntime-1.23.2-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a7730122afe186a784660f6ec5807138bf9d792fa1df76556b27307ea9ebcbe3"}, + {file = "onnxruntime-1.23.2-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:b28740f4ecef1738ea8f807461dd541b8287d5650b5be33bca7b474e3cbd1f36"}, + {file = "onnxruntime-1.23.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f7d1fe034090a1e371b7f3ca9d3ccae2fabae8c1d8844fb7371d1ea38e8e8d2"}, + {file = "onnxruntime-1.23.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ca88747e708e5c67337b0f65eed4b7d0dd70d22ac332038c9fc4635760018f7"}, + {file = "onnxruntime-1.23.2-cp310-cp310-win_amd64.whl", hash = "sha256:0be6a37a45e6719db5120e9986fcd30ea205ac8103fd1fb74b6c33348327a0cc"}, + {file = "onnxruntime-1.23.2-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:6f91d2c9b0965e86827a5ba01531d5b669770b01775b23199565d6c1f136616c"}, + {file = "onnxruntime-1.23.2-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:87d8b6eaf0fbeb6835a60a4265fde7a3b60157cf1b2764773ac47237b4d48612"}, + {file = "onnxruntime-1.23.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbfd2fca76c855317568c1b36a885ddea2272c13cb0e395002c402f2360429a6"}, + {file = "onnxruntime-1.23.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da44b99206e77734c5819aa2142c69e64f3b46edc3bd314f6a45a932defc0b3e"}, + {file = "onnxruntime-1.23.2-cp311-cp311-win_amd64.whl", hash = "sha256:902c756d8b633ce0dedd889b7c08459433fbcf35e9c38d1c03ddc020f0648c6e"}, + {file = "onnxruntime-1.23.2-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:b8f029a6b98d3cf5be564d52802bb50a8489ab73409fa9db0bf583eabb7c2321"}, + {file = "onnxruntime-1.23.2-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:218295a8acae83905f6f1aed8cacb8e3eb3bd7513a13fe4ba3b2664a19fc4a6b"}, + {file = "onnxruntime-1.23.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76ff670550dc23e58ea9bc53b5149b99a44e63b34b524f7b8547469aaa0dcb8c"}, + {file = "onnxruntime-1.23.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f9b4ae77f8e3c9bee50c27bc1beede83f786fe1d52e99ac85aa8d65a01e9b77"}, + {file = "onnxruntime-1.23.2-cp312-cp312-win_amd64.whl", hash = "sha256:25de5214923ce941a3523739d34a520aac30f21e631de53bba9174dc9c004435"}, + {file = "onnxruntime-1.23.2-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:2ff531ad8496281b4297f32b83b01cdd719617e2351ffe0dba5684fb283afa1f"}, + {file = "onnxruntime-1.23.2-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:162f4ca894ec3de1a6fd53589e511e06ecdc3ff646849b62a9da7489dee9ce95"}, + {file = "onnxruntime-1.23.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45d127d6e1e9b99d1ebeae9bcd8f98617a812f53f46699eafeb976275744826b"}, + {file = "onnxruntime-1.23.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8bace4e0d46480fbeeb7bbe1ffe1f080e6663a42d1086ff95c1551f2d39e7872"}, + {file = "onnxruntime-1.23.2-cp313-cp313-win_amd64.whl", hash = "sha256:1f9cc0a55349c584f083c1c076e611a7c35d5b867d5d6e6d6c823bf821978088"}, + {file = "onnxruntime-1.23.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d2385e774f46ac38f02b3a91a91e30263d41b2f1f4f26ae34805b2a9ddef466"}, + {file = "onnxruntime-1.23.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2b9233c4947907fd1818d0e581c049c41ccc39b2856cc942ff6d26317cee145"}, +] + +[package.dependencies] +coloredlogs = "*" +flatbuffers = "*" +numpy = ">=1.21.6" +packaging = "*" +protobuf = "*" +sympy = "*" + +[[package]] +name = "openai" +version = "2.8.1" +description = "The official Python library for the openai API" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463"}, + {file = "openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +jiter = ">=0.10.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +tqdm = ">4" +typing-extensions = ">=4.11,<5" + +[package.extras] +aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.9)"] +datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] +realtime = ["websockets (>=13,<16)"] +voice-helpers = ["numpy (>=2.0.2)", "sounddevice (>=0.5.1)"] + +[[package]] +name = "openapi-core" +version = "0.19.5" +description = "client-side and server-side support for the OpenAPI Specification v3" +optional = false +python-versions = "<4.0.0,>=3.8.0" +groups = ["main"] +files = [ + {file = "openapi_core-0.19.5-py3-none-any.whl", hash = "sha256:ef7210e83a59394f46ce282639d8d26ad6fc8094aa904c9c16eb1bac8908911f"}, + {file = "openapi_core-0.19.5.tar.gz", hash = "sha256:421e753da56c391704454e66afe4803a290108590ac8fa6f4a4487f4ec11f2d3"}, +] + +[package.dependencies] +isodate = "*" +jsonschema = ">=4.18.0,<5.0.0" +jsonschema-path = ">=0.3.1,<0.4.0" +more-itertools = "*" +openapi-schema-validator = ">=0.6.0,<0.7.0" +openapi-spec-validator = ">=0.7.1,<0.8.0" +parse = "*" +typing-extensions = ">=4.8.0,<5.0.0" +werkzeug = "<3.1.2" + +[package.extras] +aiohttp = ["aiohttp (>=3.0)", "multidict (>=6.0.4,<7.0.0)"] +django = ["django (>=3.0)"] +falcon = ["falcon (>=3.0)"] +fastapi = ["fastapi (>=0.111,<0.116)"] +flask = ["flask"] +requests = ["requests"] +starlette = ["aioitertools (>=0.11,<0.13)", "starlette (>=0.26.1,<0.45.0)"] + +[[package]] +name = "openapi-pydantic" +version = "0.5.1" +description = "Pydantic OpenAPI schema implementation" +optional = false +python-versions = "<4.0,>=3.8" +groups = ["main"] +files = [ + {file = "openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146"}, + {file = "openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d"}, +] + +[package.dependencies] +pydantic = ">=1.8" + +[[package]] +name = "openapi-schema-validator" +version = "0.6.3" +description = "OpenAPI schema validation for Python" +optional = false +python-versions = "<4.0.0,>=3.8.0" +groups = ["main"] +files = [ + {file = "openapi_schema_validator-0.6.3-py3-none-any.whl", hash = "sha256:f3b9870f4e556b5a62a1c39da72a6b4b16f3ad9c73dc80084b1b11e74ba148a3"}, + {file = "openapi_schema_validator-0.6.3.tar.gz", hash = "sha256:f37bace4fc2a5d96692f4f8b31dc0f8d7400fd04f3a937798eaf880d425de6ee"}, +] + +[package.dependencies] +jsonschema = ">=4.19.1,<5.0.0" +jsonschema-specifications = ">=2023.5.2" +rfc3339-validator = "*" + +[[package]] +name = "openapi-spec-validator" +version = "0.7.2" +description = "OpenAPI 2.0 (aka Swagger) and OpenAPI 3 spec validator" +optional = false +python-versions = "<4.0.0,>=3.8.0" +groups = ["main"] +files = [ + {file = "openapi_spec_validator-0.7.2-py3-none-any.whl", hash = "sha256:4bbdc0894ec85f1d1bea1d6d9c8b2c3c8d7ccaa13577ef40da9c006c9fd0eb60"}, + {file = "openapi_spec_validator-0.7.2.tar.gz", hash = "sha256:cc029309b5c5dbc7859df0372d55e9d1ff43e96d678b9ba087f7c56fc586f734"}, +] + +[package.dependencies] +jsonschema = ">=4.18.0,<5.0.0" +jsonschema-path = ">=0.3.1,<0.4.0" +lazy-object-proxy = ">=1.7.1,<2.0.0" +openapi-schema-validator = ">=0.6.0,<0.7.0" + +[[package]] +name = "openapi3-parser" +version = "1.1.21" +description = "OpenAPI v3 parser" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "openapi3_parser-1.1.21-py3-none-any.whl", hash = "sha256:b30f530bc22c0b7b87814eedf957e2b1b507ad914380661114d34f345f103227"}, + {file = "openapi3_parser-1.1.21.tar.gz", hash = "sha256:6ad5a4c307fdabb371c3191dc608968b68db433238f218591ff825c8d28aaa75"}, +] + +[package.dependencies] +openapi-spec-validator = ">=0.7.1" +prance = ">=0.20.2" + +[[package]] +name = "opentelemetry-api" +version = "1.37.0" +description = "OpenTelemetry Python API" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_api-1.37.0-py3-none-any.whl", hash = "sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47"}, + {file = "opentelemetry_api-1.37.0.tar.gz", hash = "sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7"}, +] + +[package.dependencies] +importlib-metadata = ">=6.0,<8.8.0" +typing-extensions = ">=4.5.0" + +[[package]] +name = "opentelemetry-exporter-otlp" +version = "1.37.0" +description = "OpenTelemetry Collector Exporters" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_exporter_otlp-1.37.0-py3-none-any.whl", hash = "sha256:bd44592c6bc7fc3e5c0a9b60f2ee813c84c2800c449e59504ab93f356cc450fc"}, + {file = "opentelemetry_exporter_otlp-1.37.0.tar.gz", hash = "sha256:f85b1929dd0d750751cc9159376fb05aa88bb7a08b6cdbf84edb0054d93e9f26"}, +] + +[package.dependencies] +opentelemetry-exporter-otlp-proto-grpc = "1.37.0" +opentelemetry-exporter-otlp-proto-http = "1.37.0" + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.37.0" +description = "OpenTelemetry Protobuf encoding" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_exporter_otlp_proto_common-1.37.0-py3-none-any.whl", hash = "sha256:53038428449c559b0c564b8d718df3314da387109c4d36bd1b94c9a641b0292e"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.37.0.tar.gz", hash = "sha256:c87a1bdd9f41fdc408d9cc9367bb53f8d2602829659f2b90be9f9d79d0bfe62c"}, +] + +[package.dependencies] +opentelemetry-proto = "1.37.0" + +[[package]] +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.37.0" +description = "OpenTelemetry Collector Protobuf over gRPC Exporter" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_exporter_otlp_proto_grpc-1.37.0-py3-none-any.whl", hash = "sha256:aee5104835bf7993b7ddaaf380b6467472abaedb1f1dbfcc54a52a7d781a3890"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.37.0.tar.gz", hash = "sha256:f55bcb9fc848ce05ad3dd954058bc7b126624d22c4d9e958da24d8537763bec5"}, +] + +[package.dependencies] +googleapis-common-protos = ">=1.57,<2.0" +grpcio = [ + {version = ">=1.63.2,<2.0.0", markers = "python_version < \"3.13\""}, + {version = ">=1.66.2,<2.0.0", markers = "python_version >= \"3.13\""}, +] +opentelemetry-api = ">=1.15,<2.0" +opentelemetry-exporter-otlp-proto-common = "1.37.0" +opentelemetry-proto = "1.37.0" +opentelemetry-sdk = ">=1.37.0,<1.38.0" +typing-extensions = ">=4.6.0" + +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.37.0" +description = "OpenTelemetry Collector Protobuf over HTTP Exporter" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_exporter_otlp_proto_http-1.37.0-py3-none-any.whl", hash = "sha256:54c42b39945a6cc9d9a2a33decb876eabb9547e0dcb49df090122773447f1aef"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.37.0.tar.gz", hash = "sha256:e52e8600f1720d6de298419a802108a8f5afa63c96809ff83becb03f874e44ac"}, +] + +[package.dependencies] +googleapis-common-protos = ">=1.52,<2.0" +opentelemetry-api = ">=1.15,<2.0" +opentelemetry-exporter-otlp-proto-common = "1.37.0" +opentelemetry-proto = "1.37.0" +opentelemetry-sdk = ">=1.37.0,<1.38.0" +requests = ">=2.7,<3.0" +typing-extensions = ">=4.5.0" + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.58b0" +description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_instrumentation-0.58b0-py3-none-any.whl", hash = "sha256:50f97ac03100676c9f7fc28197f8240c7290ca1baa12da8bfbb9a1de4f34cc45"}, + {file = "opentelemetry_instrumentation-0.58b0.tar.gz", hash = "sha256:df640f3ac715a3e05af145c18f527f4422c6ab6c467e40bd24d2ad75a00cb705"}, +] + +[package.dependencies] +opentelemetry-api = ">=1.4,<2.0" +opentelemetry-semantic-conventions = "0.58b0" +packaging = ">=18.0" +wrapt = ">=1.0.0,<2.0.0" + +[[package]] +name = "opentelemetry-proto" +version = "1.37.0" +description = "OpenTelemetry Python Proto" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_proto-1.37.0-py3-none-any.whl", hash = "sha256:8ed8c066ae8828bbf0c39229979bdf583a126981142378a9cbe9d6fd5701c6e2"}, + {file = "opentelemetry_proto-1.37.0.tar.gz", hash = "sha256:30f5c494faf66f77faeaefa35ed4443c5edb3b0aa46dad073ed7210e1a789538"}, +] + +[package.dependencies] +protobuf = ">=5.0,<7.0" + +[[package]] +name = "opentelemetry-sdk" +version = "1.37.0" +description = "OpenTelemetry Python SDK" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_sdk-1.37.0-py3-none-any.whl", hash = "sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c"}, + {file = "opentelemetry_sdk-1.37.0.tar.gz", hash = "sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5"}, +] + +[package.dependencies] +opentelemetry-api = "1.37.0" +opentelemetry-semantic-conventions = "0.58b0" +typing-extensions = ">=4.5.0" + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.58b0" +description = "OpenTelemetry Semantic Conventions" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_semantic_conventions-0.58b0-py3-none-any.whl", hash = "sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28"}, + {file = "opentelemetry_semantic_conventions-0.58b0.tar.gz", hash = "sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25"}, +] + +[package.dependencies] +opentelemetry-api = "1.37.0" +typing-extensions = ">=4.5.0" + +[[package]] +name = "orjson" +version = "3.11.4" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba"}, + {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff"}, + {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac"}, + {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79"}, + {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827"}, + {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b"}, + {file = "orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3"}, + {file = "orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc"}, + {file = "orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39"}, + {file = "orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a"}, + {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be"}, + {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7"}, + {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549"}, + {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905"}, + {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907"}, + {file = "orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c"}, + {file = "orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a"}, + {file = "orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045"}, + {file = "orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50"}, + {file = "orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708"}, + {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210"}, + {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241"}, + {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b"}, + {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c"}, + {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9"}, + {file = "orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa"}, + {file = "orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140"}, + {file = "orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e"}, + {file = "orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534"}, + {file = "orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9"}, + {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73"}, + {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0"}, + {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196"}, + {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a"}, + {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6"}, + {file = "orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839"}, + {file = "orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a"}, + {file = "orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de"}, + {file = "orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803"}, + {file = "orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f"}, + {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf"}, + {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606"}, + {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780"}, + {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23"}, + {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155"}, + {file = "orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394"}, + {file = "orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1"}, + {file = "orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d"}, + {file = "orjson-3.11.4-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:405261b0a8c62bcbd8e2931c26fdc08714faf7025f45531541e2b29e544b545b"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af02ff34059ee9199a3546f123a6ab4c86caf1708c79042caf0820dc290a6d4f"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b2eba969ea4203c177c7b38b36c69519e6067ee68c34dc37081fac74c796e10"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0baa0ea43cfa5b008a28d3c07705cf3ada40e5d347f0f44994a64b1b7b4b5350"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80fd082f5dcc0e94657c144f1b2a3a6479c44ad50be216cf0c244e567f5eae19"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e3704d35e47d5bee811fb1cbd8599f0b4009b14d451c4c57be5a7e25eb89a13"}, + {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa447f2b5356779d914658519c874cf3b7629e99e63391ed519c28c8aea4919"}, + {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bba5118143373a86f91dadb8df41d9457498226698ebdf8e11cbb54d5b0e802d"}, + {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:622463ab81d19ef3e06868b576551587de8e4d518892d1afab71e0fbc1f9cffc"}, + {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e0a700c4b82144b72946b6629968df9762552ee1344bfdb767fecdd634fbd5a"}, + {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e18a5c15e764e5f3fc569b47872450b4bcea24f2a6354c0a0e95ad21045d5a9"}, + {file = "orjson-3.11.4-cp39-cp39-win32.whl", hash = "sha256:fb1c37c71cad991ef4d89c7a634b5ffb4447dbd7ae3ae13e8f5ee7f1775e7ab1"}, + {file = "orjson-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:e2985ce8b8c42d00492d0ed79f2bd2b6460d00f2fa671dfde4bf2e02f49bf5c6"}, + {file = "orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d"}, +] + +[[package]] +name = "overrides" +version = "7.7.0" +description = "A decorator to automatically detect mismatch when overriding a method." +optional = true +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"}, + {file = "overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a"}, +] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pandas" +version = "2.3.3" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, + {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, + {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, + {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, + {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, + {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, + {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, + {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + +[[package]] +name = "parlant-client" +version = "3.0.0" +description = "Python API client for Parlant (https://parlant.io)" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [] +develop = false + +[package.dependencies] +httpx = "^0.28.1" +mypy = "^1.11.1" +nanoid = "^2.0.0" +pydantic = "^2.9.2" + +[package.source] +type = "git" +url = "https://github.com/emcie-co/parlant-client-python.git" +reference = "develop.1763631946" +resolved_reference = "bae59d089a39eca13ff01f58a08013f6ae81b329" + +[[package]] +name = "parse" +version = "1.20.2" +description = "parse() is the opposite of format()" +optional = false +python-versions = "*" +groups = ["main", "dev"] +files = [ + {file = "parse-1.20.2-py2.py3-none-any.whl", hash = "sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558"}, + {file = "parse-1.20.2.tar.gz", hash = "sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce"}, +] + +[[package]] +name = "parse-type" +version = "0.6.6" +description = "Simplifies to build parse types based on the parse module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,>=2.7" +groups = ["dev"] +files = [ + {file = "parse_type-0.6.6-py2.py3-none-any.whl", hash = "sha256:3ca79bbe71e170dfccc8ec6c341edfd1c2a0fc1e5cfd18330f93af938de2348c"}, + {file = "parse_type-0.6.6.tar.gz", hash = "sha256:513a3784104839770d690e04339a8b4d33439fcd5dd99f2e4580f9fc1097bfb2"}, +] + +[package.dependencies] +parse = {version = ">=1.18.0", markers = "python_version >= \"3.0\""} +six = ">=1.15" + +[package.extras] +develop = ["build (>=0.5.1)", "coverage (>=4.4)", "pylint", "pytest (<5.0) ; python_version < \"3.0\"", "pytest (>=5.0) ; python_version >= \"3.0\"", "pytest-cov", "pytest-html (>=1.19.0)", "ruff ; python_version >= \"3.7\"", "setuptools", "setuptools-scm", "tox (>=2.8,<4.0)", "twine (>=1.13.0)", "virtualenv (<20.22.0) ; python_version <= \"3.6\"", "virtualenv (>=20.0.0) ; python_version > \"3.6\"", "wheel"] +docs = ["Sphinx (>=1.6)", "sphinx_bootstrap_theme (>=0.6.0)"] +testing = ["pytest (<5.0) ; python_version < \"3.0\"", "pytest (>=5.0) ; python_version >= \"3.0\"", "pytest-html (>=1.19.0)"] + +[[package]] +name = "parso" +version = "0.8.5" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887"}, + {file = "parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a"}, +] + +[package.extras] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pathable" +version = "0.4.4" +description = "Object-oriented paths" +optional = false +python-versions = "<4.0.0,>=3.7.0" +groups = ["main"] +files = [ + {file = "pathable-0.4.4-py3-none-any.whl", hash = "sha256:5ae9e94793b6ef5a4cbe0a7ce9dbbefc1eec38df253763fd0aeeacf2762dbbc2"}, + {file = "pathable-0.4.4.tar.gz", hash = "sha256:6905a3cd17804edfac7875b5f6c9142a218c7caef78693c2dbbbfbac186d88b2"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pathvalidate" +version = "3.3.1" +description = "pathvalidate is a Python library to sanitize/validate a string such as filenames/file-paths/etc." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pathvalidate-3.3.1-py3-none-any.whl", hash = "sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f"}, + {file = "pathvalidate-3.3.1.tar.gz", hash = "sha256:b18c07212bfead624345bb8e1d6141cdcf15a39736994ea0b94035ad2b1ba177"}, +] + +[package.extras] +docs = ["Sphinx (>=2.4)", "sphinx_rtd_theme (>=1.2.2)", "urllib3 (<2)"] +readme = ["path (>=13,<18)", "readmemaker (>=1.2.0)"] +test = ["Faker (>=1.0.8)", "allpairspy (>=2)", "click (>=6.2)", "pytest (>=6.0.1)", "pytest-md-report (>=0.6.2)"] + +[[package]] +name = "pep8-naming" +version = "0.13.3" +description = "Check PEP-8 naming conventions, plugin for flake8" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971"}, + {file = "pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80"}, +] + +[package.dependencies] +flake8 = ">=5.0.0" + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pillow" +version = "11.3.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, + {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, + {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, + {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, + {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, + {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, + {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, + {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, + {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, + {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, + {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, + {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, + {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, + {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, + {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, + {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, + {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, + {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, + {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, + {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, + {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, + {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, + {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, + {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, + {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, + {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +test-arrow = ["pyarrow"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] +typing = ["typing-extensions ; python_version < \"3.10\""] +xmp = ["defusedxml"] + +[[package]] +name = "platformdirs" +version = "4.5.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, + {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, +] + +[package.extras] +docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] +type = ["mypy (>=1.18.2)"] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "portalocker" +version = "3.2.0" +description = "Wraps the portalocker recipe for easy usage" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"qdrant\"" +files = [ + {file = "portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968"}, + {file = "portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac"}, +] + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["portalocker[tests]"] +redis = ["redis"] +tests = ["coverage-conditional-plugin (>=0.9.0)", "portalocker[redis]", "pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-rerunfailures (>=15.0)", "pytest-timeout (>=2.1.0)", "sphinx (>=6.0.0)", "types-pywin32 (>=310.0.0.20250429)", "types-redis"] + +[[package]] +name = "posthog" +version = "5.4.0" +description = "Integrate PostHog into any python application." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "posthog-5.4.0-py3-none-any.whl", hash = "sha256:284dfa302f64353484420b52d4ad81ff5c2c2d1d607c4e2db602ac72761831bd"}, + {file = "posthog-5.4.0.tar.gz", hash = "sha256:701669261b8d07cdde0276e5bc096b87f9e200e3b9589c5ebff14df658c5893c"}, +] + +[package.dependencies] +backoff = ">=1.10.0" +distro = ">=1.5.0" +python-dateutil = ">=2.2" +requests = ">=2.7,<3.0" +six = ">=1.5" + +[package.extras] +dev = ["django-stubs", "lxml", "mypy", "mypy-baseline", "packaging", "pre-commit", "pydantic", "ruff", "setuptools", "tomli", "tomli_w", "twine", "types-mock", "types-python-dateutil", "types-requests", "types-setuptools", "types-six", "wheel"] +langchain = ["langchain (>=0.2.0)"] +test = ["anthropic", "coverage", "django", "freezegun (==1.5.1)", "google-genai", "langchain-anthropic (>=0.3.15)", "langchain-community (>=0.3.25)", "langchain-core (>=0.3.65)", "langchain-openai (>=0.3.22)", "langgraph (>=0.4.8)", "mock (>=2.0.0)", "openai", "parameterized (>=0.8.1)", "pydantic", "pytest", "pytest-asyncio", "pytest-timeout"] + +[[package]] +name = "prance" +version = "25.4.8.0" +description = "Resolving Swagger/OpenAPI 2.0 and 3.0.0 Parser" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "prance-25.4.8.0-py3-none-any.whl", hash = "sha256:d3c362036d625b12aeee495621cb1555fd50b2af3632af3d825176bfb50e073b"}, + {file = "prance-25.4.8.0.tar.gz", hash = "sha256:2f72d2983d0474b6f53fd604eb21690c1ebdb00d79a6331b7ec95fb4f25a1f65"}, +] + +[package.dependencies] +chardet = ">=5.2" +packaging = ">=24.2" +requests = ">=2.32.3" +"ruamel.yaml" = ">=0.18.10" + +[package.extras] +cli = ["click (>=8.1.8)"] +dev = ["bumpversion (>=0.6.0)", "pytest (>=8.3.5)", "pytest-cov (>=6.0)", "sphinx (>=8.1.3)", "towncrier (>=24.8)", "tox (>=4.23.2)"] +flex = ["flex (>=6.14.1,<6.15.0)"] +icu = ["PyICU (>=2.14,<3.0)"] +osv = ["openapi-spec-validator (>=0.7.1,<0.8.0)"] +ssv = ["swagger-spec-validator (>=3.0.4,<3.1.0)"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "propcache" +version = "0.4.1" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"}, + {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"}, + {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"}, + {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"}, + {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"}, + {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"}, + {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"}, + {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"}, + {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"}, + {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"}, + {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"}, + {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"}, + {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"}, + {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"}, + {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"}, + {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"}, + {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"}, + {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"}, + {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"}, + {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"}, + {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"}, + {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"}, + {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"}, + {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"}, + {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"}, + {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"}, + {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"}, +] + +[[package]] +name = "proto-plus" +version = "1.26.1" +description = "Beautiful, Pythonic protocol buffers" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66"}, + {file = "proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012"}, +] + +[package.dependencies] +protobuf = ">=3.19.0,<7.0.0" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + +[[package]] +name = "protobuf" +version = "6.33.1" +description = "" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "protobuf-6.33.1-cp310-abi3-win32.whl", hash = "sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b"}, + {file = "protobuf-6.33.1-cp310-abi3-win_amd64.whl", hash = "sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed"}, + {file = "protobuf-6.33.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490"}, + {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178"}, + {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53"}, + {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1"}, + {file = "protobuf-6.33.1-cp39-cp39-win32.whl", hash = "sha256:023af8449482fa884d88b4563d85e83accab54138ae098924a985bcbb734a213"}, + {file = "protobuf-6.33.1-cp39-cp39-win_amd64.whl", hash = "sha256:df051de4fd7e5e4371334e234c62ba43763f15ab605579e04c7008c05735cd82"}, + {file = "protobuf-6.33.1-py3-none-any.whl", hash = "sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa"}, + {file = "protobuf-6.33.1.tar.gz", hash = "sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b"}, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "py-key-value-aio" +version = "0.2.8" +description = "Async Key-Value" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "py_key_value_aio-0.2.8-py3-none-any.whl", hash = "sha256:561565547ce8162128fd2bd0b9d70ce04a5f4586da8500cce79a54dfac78c46a"}, + {file = "py_key_value_aio-0.2.8.tar.gz", hash = "sha256:c0cfbb0bd4e962a3fa1a9fa6db9ba9df812899bd9312fa6368aaea7b26008b36"}, +] + +[package.dependencies] +beartype = ">=0.22.2" +cachetools = {version = ">=6.0.0", optional = true, markers = "extra == \"memory\""} +diskcache = {version = ">=5.6.0", optional = true, markers = "extra == \"disk\""} +keyring = {version = ">=25.6.0", optional = true, markers = "extra == \"keyring\""} +pathvalidate = {version = ">=3.3.1", optional = true, markers = "extra == \"disk\""} +py-key-value-shared = "0.2.8" + +[package.extras] +disk = ["diskcache (>=5.6.0)", "pathvalidate (>=3.3.1)"] +dynamodb = ["aioboto3 (>=13.3.0)", "types-aiobotocore-dynamodb (>=2.16.0)"] +elasticsearch = ["aiohttp (>=3.12)", "elasticsearch (>=9.0.0)"] +keyring = ["keyring (>=25.6.0)"] +keyring-linux = ["dbus-python (>=1.4.0)", "keyring (>=25.6.0)"] +memcached = ["aiomcache (>=0.8.0)"] +memory = ["cachetools (>=6.0.0)"] +mongodb = ["pymongo (>=4.15.0)"] +pydantic = ["pydantic (>=2.11.9)"] +redis = ["redis (>=4.3.0)"] +rocksdb = ["rocksdict (>=0.3.0)"] +valkey = ["valkey-glide (>=2.1.0)"] +vault = ["hvac (>=2.3.0)", "types-hvac (>=2.3.0)"] +wrappers-encryption = ["cryptography (>=45.0.0)"] + +[[package]] +name = "py-key-value-shared" +version = "0.2.8" +description = "Shared Key-Value" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "py_key_value_shared-0.2.8-py3-none-any.whl", hash = "sha256:aff1bbfd46d065b2d67897d298642e80e5349eae588c6d11b48452b46b8d46ba"}, + {file = "py_key_value_shared-0.2.8.tar.gz", hash = "sha256:703b4d3c61af124f0d528ba85995c3c8d78f8bd3d2b217377bd3278598070cc1"}, +] + +[package.dependencies] +beartype = ">=0.22.2" +typing-extensions = ">=4.15.0" + +[[package]] +name = "pyasn1" +version = "0.6.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +description = "A collection of ASN.1-based protocols modules" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, +] + +[package.dependencies] +pyasn1 = ">=0.6.1,<0.7.0" + +[[package]] +name = "pybase64" +version = "1.4.2" +description = "Fast Base64 encoding/decoding" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "pybase64-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82b4593b480773b17698fef33c68bae0e1c474ba07663fad74249370c46b46c9"}, + {file = "pybase64-1.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a126f29d29cb4a498db179135dbf955442a0de5b00f374523f5dcceb9074ff58"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:1eef93c29cc5567480d168f9cc1ebd3fc3107c65787aed2019a8ea68575a33e0"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:17b871a34aaeb0644145cb6bf28feb163f593abea11aec3dbcc34a006edfc828"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1f734e16293637a35d282ce594eb05a7a90ea3ae2bc84a3496a5df9e6b890725"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:22bd38db2d990d5545dde83511edeec366630d00679dbd945472315c09041dc6"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:dc65cee686dda72007b7541b2014f33ee282459c781b9b61305bd8b9cfadc8e1"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1e79641c420a22e49c67c046895efad05bf5f8b1dbe0dd78b4af3ab3f2923fe2"}, + {file = "pybase64-1.4.2-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:12f5e7db522ef780a8b333dab5f7d750d270b23a1684bc2235ba50756c7ba428"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a618b1e1a63e75dd40c2a397d875935ed0835464dc55cb1b91e8f880113d0444"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:89b0a51702c7746fa914e75e680ad697b979cdead6b418603f56a6fc9de2f50f"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5161b8b82f8ba5dbbc3f76e0270622a2c2fdb9ffaf092d8f774ad7ec468c027"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2168de920c9b1e57850e9ff681852923a953601f73cc96a0742a42236695c316"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:7a1e3dc977562abe40ab43483223013be71b215a5d5f3c78a666e70a5076eeec"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4cf1e8a57449e48137ef4de00a005e24c3f1cffc0aafc488e36ceb5bb2cbb1da"}, + {file = "pybase64-1.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d8e1a381ba124f26a93d5925efbf6e6c36287fc2c93d74958e8b677c30a53fc0"}, + {file = "pybase64-1.4.2-cp310-cp310-win32.whl", hash = "sha256:8fdd9c5b60ec9a1db854f5f96bba46b80a9520069282dc1d37ff433eb8248b1f"}, + {file = "pybase64-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:37a6c73f14c6539c0ad1aebf0cce92138af25c99a6e7aee637d9f9fc634c8a40"}, + {file = "pybase64-1.4.2-cp310-cp310-win_arm64.whl", hash = "sha256:b3280d03b7b361622c469d005cc270d763d9e29d0a490c26addb4f82dfe71a79"}, + {file = "pybase64-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26284ef64f142067293347bcc9d501d2b5d44b92eab9d941cb10a085fb01c666"}, + {file = "pybase64-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52dd32fe5cbfd8af8f3f034a4a65ee61948c72e5c358bf69d59543fc0dbcf950"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:37f133e8c96427995480bb6d396d9d49e949a3e829591845bb6a5a7f215ca177"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6ee3874b0abbdd4c903d3989682a3f016fd84188622879f6f95a5dc5718d7e5"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c69f177b1e404b22b05802127d6979acf4cb57f953c7de9472410f9c3fdece7"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:80c817e88ef2ca3cc9a285fde267690a1cb821ce0da4848c921c16f0fec56fda"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a4bb6e7e45bfdaea0f2aaf022fc9a013abe6e46ccea31914a77e10f44098688"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2710a80d41a2b41293cb0e5b84b5464f54aa3f28f7c43de88784d2d9702b8a1c"}, + {file = "pybase64-1.4.2-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:aa6122c8a81f6597e1c1116511f03ed42cf377c2100fe7debaae7ca62521095a"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7e22b02505d64db308e9feeb6cb52f1d554ede5983de0befa59ac2d2ffb6a5f"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:edfe4a3c8c4007f09591f49b46a89d287ef5e8cd6630339536fe98ff077263c2"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b79b4a53dd117ffbd03e96953f2e6bd2827bfe11afeb717ea16d9b0893603077"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fd9afa7a61d89d170607faf22287290045757e782089f0357b8f801d228d52c3"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5c17b092e4da677a595178d2db17a5d2fafe5c8e418d46c0c4e4cde5adb8cff3"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:120799274cf55f3f5bb8489eaa85142f26170564baafa7cf3e85541c46b6ab13"}, + {file = "pybase64-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:522e4e712686acec2d25de9759dda0b0618cb9f6588523528bc74715c0245c7b"}, + {file = "pybase64-1.4.2-cp311-cp311-win32.whl", hash = "sha256:bfd828792982db8d787515535948c1e340f1819407c8832f94384c0ebeaf9d74"}, + {file = "pybase64-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7a9e89d40dbf833af481d1d5f1a44d173c9c4b56a7c8dba98e39a78ee87cfc52"}, + {file = "pybase64-1.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:ce5809fa90619b03eab1cd63fec142e6cf1d361731a9b9feacf27df76c833343"}, + {file = "pybase64-1.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2c75d1388855b5a1015b65096d7dbcc708e7de3245dcbedeb872ec05a09326"}, + {file = "pybase64-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b621a972a01841368fdb9dedc55fd3c6e0c7217d0505ba3b1ebe95e7ef1b493"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f48c32ac6a16cbf57a5a96a073fef6ff7e3526f623cd49faa112b7f9980bafba"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ace8b23093a6bb862477080d9059b784096ab2f97541e8bfc40d42f062875149"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1772c7532a7fb6301baea3dd3e010148dbf70cd1136a83c2f5f91bdc94822145"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:f86f7faddcba5cbfea475f8ab96567834c28bf09ca6c7c3d66ee445adac80d8f"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0b8c8e275b5294089f314814b4a50174ab90af79d6a4850f6ae11261ff6a7372"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:864d85a0470c615807ae8b97d724d068b940a2d10ac13a5f1b9e75a3ce441758"}, + {file = "pybase64-1.4.2-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:47254d97ed2d8351e30ecfdb9e2414547f66ba73f8a09f932c9378ff75cd10c5"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:264b65ecc4f0ee73f3298ab83bbd8008f7f9578361b8df5b448f985d8c63e02a"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbcc2b30cd740c16c9699f596f22c7a9e643591311ae72b1e776f2d539e9dd9d"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cda9f79c22d51ee4508f5a43b673565f1d26af4330c99f114e37e3186fdd3607"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0c91c6d2a7232e2a1cd10b3b75a8bb657defacd4295a1e5e80455df2dfc84d4f"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:a370dea7b1cee2a36a4d5445d4e09cc243816c5bc8def61f602db5a6f5438e52"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9aa4de83f02e462a6f4e066811c71d6af31b52d7484de635582d0e3ec3d6cc3e"}, + {file = "pybase64-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83a1c2f9ed00fee8f064d548c8654a480741131f280e5750bb32475b7ec8ee38"}, + {file = "pybase64-1.4.2-cp312-cp312-win32.whl", hash = "sha256:a6e5688b18d558e8c6b8701cc8560836c4bbeba61d33c836b4dba56b19423716"}, + {file = "pybase64-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:c995d21b8bd08aa179cd7dd4db0695c185486ecc72da1e8f6c37ec86cadb8182"}, + {file = "pybase64-1.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:e254b9258c40509c2ea063a7784f6994988f3f26099d6e08704e3c15dfed9a55"}, + {file = "pybase64-1.4.2-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:0f331aa59549de21f690b6ccc79360ffed1155c3cfbc852eb5c097c0b8565a2b"}, + {file = "pybase64-1.4.2-cp313-cp313-android_21_x86_64.whl", hash = "sha256:9dad20bf1f3ed9e6fe566c4c9d07d9a6c04f5a280daebd2082ffb8620b0a880d"}, + {file = "pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:69d3f0445b0faeef7bb7f93bf8c18d850785e2a77f12835f49e524cc54af04e7"}, + {file = "pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2372b257b1f4dd512f317fb27e77d313afd137334de64c87de8374027aacd88a"}, + {file = "pybase64-1.4.2-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:fb794502b4b1ec91c4ca5d283ae71aef65e3de7721057bd9e2b3ec79f7a62d7d"}, + {file = "pybase64-1.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d5c532b03fd14a5040d6cf6571299a05616f925369c72ddf6fe2fb643eb36fed"}, + {file = "pybase64-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f699514dc1d5689ca9cf378139e0214051922732f9adec9404bc680a8bef7c0"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:cd3e8713cbd32c8c6aa935feaf15c7670e2b7e8bfe51c24dc556811ebd293a29"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d377d48acf53abf4b926c2a7a24a19deb092f366a04ffd856bf4b3aa330b025d"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d83c076e78d619b9e1dd674e2bf5fb9001aeb3e0b494b80a6c8f6d4120e38cd9"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:ab9cdb6a8176a5cb967f53e6ad60e40c83caaa1ae31c5e1b29e5c8f507f17538"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:adf0c103ad559dbfb9fe69edfd26a15c65d9c991a5ab0a25b04770f9eb0b9484"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:0d03ef2f253d97ce0685d3624bf5e552d716b86cacb8a6c971333ba4b827e1fc"}, + {file = "pybase64-1.4.2-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e565abf906efee76ae4be1aef5df4aed0fda1639bc0d7732a3dafef76cb6fc35"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3c6a5f15fd03f232fc6f295cce3684f7bb08da6c6d5b12cc771f81c9f125cc6"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bad9e3db16f448728138737bbd1af9dc2398efd593a8bdd73748cc02cd33f9c6"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2683ef271328365c31afee0ed8fa29356fb8fb7c10606794656aa9ffb95e92be"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:265b20089cd470079114c09bb74b101b3bfc3c94ad6b4231706cf9eff877d570"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e53173badead10ef8b839aa5506eecf0067c7b75ad16d9bf39bc7144631f8e67"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5823b8dcf74da7da0f761ed60c961e8928a6524e520411ad05fe7f9f47d55b40"}, + {file = "pybase64-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1237f66c54357d325390da60aa5e21c6918fbcd1bf527acb9c1f4188c62cb7d5"}, + {file = "pybase64-1.4.2-cp313-cp313-win32.whl", hash = "sha256:b0b851eb4f801d16040047f6889cca5e9dfa102b3e33f68934d12511245cef86"}, + {file = "pybase64-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:19541c6e26d17d9522c02680fe242206ae05df659c82a657aabadf209cd4c6c7"}, + {file = "pybase64-1.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:77a191863d576c0a5dd81f8a568a5ca15597cc980ae809dce62c717c8d42d8aa"}, + {file = "pybase64-1.4.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2e194bbabe3fdf9e47ba9f3e157394efe0849eb226df76432126239b3f44992c"}, + {file = "pybase64-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:39aef1dadf4a004f11dd09e703abaf6528a87c8dbd39c448bb8aebdc0a08c1be"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:91cb920c7143e36ec8217031282c8651da3b2206d70343f068fac0e7f073b7f9"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6958631143fb9e71f9842000da042ec2f6686506b6706e2dfda29e97925f6aa0"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dc35f14141ef3f1ac70d963950a278a2593af66fe5a1c7a208e185ca6278fa25"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:5d949d2d677859c3a8507e1b21432a039d2b995e0bd3fe307052b6ded80f207a"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:09caacdd3e15fe7253a67781edd10a6a918befab0052a2a3c215fe5d1f150269"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:e44b0e793b23f28ea0f15a9754bd0c960102a2ac4bccb8fafdedbd4cc4d235c0"}, + {file = "pybase64-1.4.2-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:849f274d0bcb90fc6f642c39274082724d108e41b15f3a17864282bd41fc71d5"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:528dba7ef1357bd7ce1aea143084501f47f5dd0fff7937d3906a68565aa59cfe"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:1da54be743d9a68671700cfe56c3ab8c26e8f2f5cc34eface905c55bc3a9af94"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9b07c0406c3eaa7014499b0aacafb21a6d1146cfaa85d56f0aa02e6d542ee8f3"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:312f2aa4cf5d199a97fbcaee75d2e59ebbaafcd091993eb373b43683498cdacb"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad59362fc267bf15498a318c9e076686e4beeb0dfe09b457fabbc2b32468b97a"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:01593bd064e7dcd6c86d04e94e44acfe364049500c20ac68ca1e708fbb2ca970"}, + {file = "pybase64-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5b81547ad8ea271c79fdf10da89a1e9313cb15edcba2a17adf8871735e9c02a0"}, + {file = "pybase64-1.4.2-cp313-cp313t-win32.whl", hash = "sha256:7edbe70b5654545a37e6e6b02de738303b1bbdfcde67f6cfec374cfb5cc4099e"}, + {file = "pybase64-1.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:385690addf87c25d6366fab5d8ff512eed8a7ecb18da9e8152af1c789162f208"}, + {file = "pybase64-1.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c2070d0aa88580f57fe15ca88b09f162e604d19282915a95a3795b5d3c1c05b5"}, + {file = "pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:4157ad277a32cf4f02a975dffc62a3c67d73dfa4609b2c1978ef47e722b18b8e"}, + {file = "pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e113267dc349cf624eb4f4fbf53fd77835e1aa048ac6877399af426aab435757"}, + {file = "pybase64-1.4.2-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:cea5aaf218fd9c5c23afacfe86fd4464dfedc1a0316dd3b5b4075b068cc67df0"}, + {file = "pybase64-1.4.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:41213497abbd770435c7a9c8123fb02b93709ac4cf60155cd5aefc5f3042b600"}, + {file = "pybase64-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8b522df7ee00f2ac1993ccd5e1f6608ae7482de3907668c2ff96a83ef213925"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:06725022e540c5b098b978a0418ca979773e2cbdbb76f10bd97536f2ad1c5b49"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a3e54dcf0d0305ec88473c9d0009f698cabf86f88a8a10090efeff2879c421bb"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67675cee727a60dc91173d2790206f01aa3c7b3fbccfa84fd5c1e3d883fe6caa"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:753da25d4fd20be7bda2746f545935773beea12d5cb5ec56ec2d2960796477b1"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a78c768ce4ca550885246d14babdb8923e0f4a848dfaaeb63c38fc99e7ea4052"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:51b17f36d890c92f0618fb1c8db2ccc25e6ed07afa505bab616396fc9b0b0492"}, + {file = "pybase64-1.4.2-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f92218d667049ab4f65d54fa043a88ffdb2f07fff1f868789ef705a5221de7ec"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3547b3d1499919a06491b3f879a19fbe206af2bd1a424ecbb4e601eb2bd11fea"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:958af7b0e09ddeb13e8c2330767c47b556b1ade19c35370f6451d139cde9f2a9"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4facc57f6671e2229a385a97a618273e7be36a9ea0a9d1c1b9347f14d19ceba8"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a32fc57d05d73a7c9b0ca95e9e265e21cf734195dc6873829a890058c35f5cfd"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3dc853243c81ce89cc7318e6946f860df28ddb7cd2a0648b981652d9ad09ee5a"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0e6d863a86b3e7bc6ac9bd659bebda4501b9da842521111b0b0e54eb51295df5"}, + {file = "pybase64-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6579475140ff2067903725d8aca47f5747bcb211597a1edd60b58f6d90ada2bd"}, + {file = "pybase64-1.4.2-cp314-cp314-win32.whl", hash = "sha256:373897f728d7b4f241a1f803ac732c27b6945d26d86b2741ad9b75c802e4e378"}, + {file = "pybase64-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:1afe3361344617d298c1d08bc657ef56d0f702d6b72cb65d968b2771017935aa"}, + {file = "pybase64-1.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:f131c9360babe522f3d90f34da3f827cba80318125cf18d66f2ee27e3730e8c4"}, + {file = "pybase64-1.4.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2583ac304131c1bd6e3120b0179333610f18816000db77c0a2dd6da1364722a8"}, + {file = "pybase64-1.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:75a8116be4ea4cdd30a5c4f1a6f3b038e0d457eb03c8a2685d8ce2aa00ef8f92"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:217ea776a098d7c08668e5526b9764f5048bbfd28cac86834217ddfe76a4e3c4"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ec14683e343c95b14248cdfdfa78c052582be7a3865fd570aa7cffa5ab5cf37"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:480ecf21e1e956c5a10d3cf7b3b7e75bce3f9328cf08c101e4aab1925d879f34"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:1fe1ebdc55e9447142e2f6658944aadfb5a4fbf03dbd509be34182585515ecc1"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c793a2b06753accdaf5e1a8bbe5d800aab2406919e5008174f989a1ca0081411"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6acae6e1d1f7ebe40165f08076c7a73692b2bf9046fefe673f350536e007f556"}, + {file = "pybase64-1.4.2-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:88b91cd0949358aadcea75f8de5afbcf3c8c5fb9ec82325bd24285b7119cf56e"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:53316587e1b1f47a11a5ff068d3cbd4a3911c291f2aec14882734973684871b2"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:caa7f20f43d00602cf9043b5ba758d54f5c41707d3709b2a5fac17361579c53c"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2d93817e24fdd79c534ed97705df855af6f1d2535ceb8dfa80da9de75482a8d7"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:63cd769b51474d8d08f7f2ce73b30380d9b4078ec92ea6b348ea20ed1e1af88a"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cd07e6a9993c392ec8eb03912a43c6a6b21b2deb79ee0d606700fe276e9a576f"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:6a8944e8194adff4668350504bc6b7dbde2dab9244c88d99c491657d145b5af5"}, + {file = "pybase64-1.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04ab398ec4b6a212af57f6a21a6336d5a1d754ff4ccb215951366ab9080481b2"}, + {file = "pybase64-1.4.2-cp314-cp314t-win32.whl", hash = "sha256:3b9201ecdcb1c3e23be4caebd6393a4e6615bd0722528f5413b58e22e3792dd3"}, + {file = "pybase64-1.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:36e9b0cad8197136d73904ef5a71d843381d063fd528c5ab203fc4990264f682"}, + {file = "pybase64-1.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f25140496b02db0e7401567cd869fb13b4c8118bf5c2428592ec339987146d8b"}, + {file = "pybase64-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d176c83a9cd45a8b27786372b9b5815803bdf812b7e65be86df75660df3d9443"}, + {file = "pybase64-1.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8aea9abde684d282def3697839163ad5167f9381d5adde6b9d05bf39b1decda"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:39120d4a650d7c66689c226131e2942142a5b1b27ccf190f441b1a602bc1e6a5"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e67579d2081344b2e43a78fe1604a9637056eed2bfb61bf4a1f847e81525cb3"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4142c58d6a7a57eb094725bec40f2cd46488d8f204e956750a6565cd506322d"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:4a6a417a94c2934faa8f84e8279c57092a54045340e26305a07a6691d2890766"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:66071c72417f5cb4640d3291644afc95eba06297cca5dbcacbea5c7181f3a05e"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5257751ff60f9acb2971baf70063dff549fe154ce6be1e7a1808e140d79598d9"}, + {file = "pybase64-1.4.2-cp38-cp38-manylinux_2_31_riscv64.whl", hash = "sha256:86d3294a07c37c8ce8f3eb24c62a5157699ddeb75f4ae7b4922e8765b8fbe3fb"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:bb9e8eba5461acaf5fd69c66e170d9174e3aaae67d42dbc9590e0883e099fd47"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:845c2fa4f0ec45ca48c60c9ed6714c5266f62850c767c86fb0e137b3f5f7585b"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:3bed71e32075895e06b2ca9faf136ee805db2ade4715b4732b119ef0e5ffcb52"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:88bbcab0f58ffc9fd79ab8aa047b64e1e04514194d8e7c9f450451682e7555bf"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b5a1d81b4a10a4b724fa7bc7cbd2d527b21030089940d6acc50bf5ad29849e5e"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5b5694af6f4632633372fcb678c7fe56b953c33961f39d57086abb08ef5dcbf4"}, + {file = "pybase64-1.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:58f0e40d8128c55dee2309d41e027e0cf22f4931b43aa590ee785ea4eff88f8d"}, + {file = "pybase64-1.4.2-cp38-cp38-win32.whl", hash = "sha256:d93691f52e1396abfe93a75bc5da4c029649c004d8eefd08f20340b17db51429"}, + {file = "pybase64-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b9d4a8e6fce1c2943dce37db9b66f7cf88082ef0ef68025183c48fb3b0d8068a"}, + {file = "pybase64-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5f47f00221f6892c6f8532f7c2e449b491e0fd86de73e9306cfe88768570eff1"}, + {file = "pybase64-1.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:514ad5d72b1990453c895015392729521757eca1a984327c0f9e44af6854385d"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2089a72b04a62f63e0eac202ecff4440fb52fd05cd5f4ab9fe7e07839fedb9e9"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bad101c24dcd23ed6fd6ea24c4a1b36ac7abc5eb07447dd7fa98b33859aed871"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:28592c88a9cf6fd27c9f191fb41688c1c27f57493d874cbc50e72e1cc2a3b854"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:0b5639fa2ceb3095393bd56dca8c16079717c361dd3a75439c9a8b8d679f4cf0"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:49630338d4c321336d0dfc4c2c23162a87d9ebc8bb8879348ae019ac8a4366de"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c3d9f9881d7315e1d04d72aa7b3f40e2059bdbfdcec51939016409417725c952"}, + {file = "pybase64-1.4.2-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:8e1226939eac9ce1f080d1b0a8afafee3140e277a4c40ccb306d82de396a41a8"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:69f424a227ec503742bac69b89e232c474dc199cd98c3e58e91020c1c4bad0ad"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:171ae85837de14d3691d5c4f29f5bb551209930c063a2cab6f5feb270aec66db"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a55a13493fd165c3a619080149eda6f31c05c04c0577da9c9ef63d23f3abf374"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:06801fdc7fa83eac5cb7d1c7051bb623a25af8cb40e088671fa51a393d1053ad"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7f2fbd6870228e9c8c3e2e2622ed7615a8d0159125b85e9d6c2d8e9ead74cdf0"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1726017f04da880d10a57f078d117fe62532b5ed7bd58bd3318f3364b9767d91"}, + {file = "pybase64-1.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1264f7fa417de7183732761f37c8ceb4652662a84f04538a28dadd5d84bf9a4a"}, + {file = "pybase64-1.4.2-cp39-cp39-win32.whl", hash = "sha256:8ad0c411898280a924eb41e07389666c89cfe1389cb4c24e3853cb1949872893"}, + {file = "pybase64-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:11c5698b696f681fe04c6ccf11c346d438d05f1a542dbb5e5cdf6c27c348431d"}, + {file = "pybase64-1.4.2-cp39-cp39-win_arm64.whl", hash = "sha256:e64721ae9252a62caf06f2df5d22065d02f28cd2768b610be84c37856ac4a3a8"}, + {file = "pybase64-1.4.2-graalpy311-graalpy242_311_native-macosx_10_9_x86_64.whl", hash = "sha256:b4eed40a5f1627ee65613a6ac834a33f8ba24066656f569c852f98eb16f6ab5d"}, + {file = "pybase64-1.4.2-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:57885fa521e9add235af4db13e9e048d3a2934cd27d7c5efac1925e1b4d6538d"}, + {file = "pybase64-1.4.2-graalpy311-graalpy242_311_native-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eef9255d926c64e2fca021d3aee98023bacb98e1518e5986d6aab04102411b04"}, + {file = "pybase64-1.4.2-graalpy311-graalpy242_311_native-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89614ea2d2329b6708746c540e0f14d692125df99fb1203ff0de948d9e68dfc9"}, + {file = "pybase64-1.4.2-graalpy311-graalpy242_311_native-win_amd64.whl", hash = "sha256:e401cecd2d7ddcd558768b2140fd4430746be4d17fb14c99eec9e40789df136d"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b29c93414ba965777643a9d98443f08f76ac04519ad717aa859113695372a07"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5e0c3353c0bf099c5c3f8f750202c486abee8f23a566b49e9e7b1222fbf5f259"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4f98c5c6152d3c01d933fcde04322cd9ddcf65b5346034aac69a04c1a7cbb012"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9096a4977b7aff7ef250f759fb6a4b6b7b6199d99c84070c7fc862dd3b208b34"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:49d8597e2872966399410502310b1e2a5b7e8d8ba96766ee1fe242e00bd80775"}, + {file = "pybase64-1.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ef16366565389a287df82659e055e88bdb6c36e46a3394950903e0a9cb2e5bf"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0a5393be20b0705870f5a8969749af84d734c077de80dd7e9f5424a247afa85e"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:448f0259a2f1a17eb086f70fe2ad9b556edba1fc5bc4e62ce6966179368ee9f8"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:1159e70cba8e76c3d8f334bd1f8fd52a1bb7384f4c3533831b23ab2df84a6ef3"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d943bc5dad8388971494554b97f22ae06a46cc7779ad0de3d4bfdf7d0bbea30"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10b99182c561d86422c5de4265fd1f8f172fb38efaed9d72c71fb31e279a7f94"}, + {file = "pybase64-1.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bb082c1114f046e59fcbc4f2be13edc93b36d7b54b58605820605be948f8fdf6"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:49ff078c0afd2c6ba355a5b999c321b8554e3673eff5a413d83b40e9cfb53b96"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad9c5ac606cb232dfd6679519c86333d4d665732b6fcaab4653ae531990da8b6"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b30e66969a5bee39d31ede36f5866be59991cdcbb597fe734b02753ca0e18e04"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4eef95fe6adfa5763a79874be77944edde2d16f765eca8841f1cc9f2310eb3b2"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5b315f0d01eb25ec7a6c7e9ea0c69b82165f4653ff4bc17790fdadf7650eb0e1"}, + {file = "pybase64-1.4.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ba8781dad971d657be171c66abd4f45deb6aa982fa8d8bfd552ea48bbd8d2a09"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4dc4e353ff54ea480cf78aa629df927f7280920d35015f402a541fbfcbf2ba6b"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4e8acd1e02aa4b80dd834dd703ef040d5c1127f39e4052011bf5d3f4bc917c41"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:45f078139d76194024e59b4bcfa64d42e5a5f8a5a4ea55ca4d27df46989c5e32"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06305e602f128b289b98490a2d07d9d78e7e781e32e7b0252c2e71084fd19edf"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d58eb4cb50b6466cef2e25761a5c915a8d57feda53165cced537a7ce0421b928"}, + {file = "pybase64-1.4.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21e72a662a62eba34a91e9424b21db99b8fc5cce99932ce736167496965fa154"}, + {file = "pybase64-1.4.2.tar.gz", hash = "sha256:46cdefd283ed9643315d952fe44de80dc9b9a811ce6e3ec97fd1827af97692d0"}, +] + +[[package]] +name = "pycodestyle" +version = "2.14.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d"}, + {file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"}, +] + +[[package]] +name = "pycparser" +version = "2.23" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\" or extra == \"snowflake\"" +files = [ + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2"}, + {file = "pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.12.0" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809"}, + {file = "pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" +typing-inspection = ">=0.4.0" + +[package.extras] +aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + +[[package]] +name = "pyflakes" +version = "3.4.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f"}, + {file = "pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58"}, +] + +[[package]] +name = "pygments" +version = "2.19.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"azure\" or extra == \"zhipu\" or extra == \"snowflake\"" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pymongo" +version = "4.15.4" +description = "PyMongo - the Official MongoDB Python driver" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"mongo\"" +files = [ + {file = "pymongo-4.15.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84c7c7624a1298295487d0dfd8dbec75d14db44c017b5087c7fe7d6996a96e3d"}, + {file = "pymongo-4.15.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71a5ab372ebe4e05453bae86a008f6db98b5702df551219fb2f137c394d71c3a"}, + {file = "pymongo-4.15.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eee407bf1058a8f0d5b203028997b42ea6fc80a996537cc2886f89573bc0770f"}, + {file = "pymongo-4.15.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e286f5b9c13963bcaf9b9241846d388ac5022225a9e11c5364393a8cc3eb49"}, + {file = "pymongo-4.15.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:67c3b84a2a0e1794b2fbfe22dc36711a03c6bc147d9d2e0f8072fabed7a65092"}, + {file = "pymongo-4.15.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:94e50149fb9d982c234d0efa9c0eec4a04db7e82a412d3dae2c4f03a9926360e"}, + {file = "pymongo-4.15.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1903c0966969cf3e7b30922956bd82eb09e6a3f3d7431a727d12f20104f66d3"}, + {file = "pymongo-4.15.4-cp310-cp310-win32.whl", hash = "sha256:20ffcd883b6e187ef878558d0ebf9f09cc46807b6520022592522d3cdd21022d"}, + {file = "pymongo-4.15.4-cp310-cp310-win_amd64.whl", hash = "sha256:68ea93e7d19d3aa3182a6e41ba68288b9b234a3b0a70b368feb95fff3f94413f"}, + {file = "pymongo-4.15.4-cp310-cp310-win_arm64.whl", hash = "sha256:abfe72630190c0dc8f2222b02af7c4e5f72809d06b2ccb3f3ca83f6a7b60e302"}, + {file = "pymongo-4.15.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b2967bda6ccac75aefad26c4ef295f5054181d69928bb9d1159227d6771e8887"}, + {file = "pymongo-4.15.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7df1fad859c61bdbe0e2a0dec8f5893729d99b4407b88568e0e542d25f383f57"}, + {file = "pymongo-4.15.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:990c4898787e706d0ab59141cf5085c981d89c3f86443cd6597939d9f25dd71d"}, + {file = "pymongo-4.15.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad7ff0347e8306fc62f146bdad0635d9eec1d26e246c97c14dd1a189d3480e3f"}, + {file = "pymongo-4.15.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dd8c78c59fd7308239ef9bcafb7cd82f08cbc9466d1cfda22f9025c83468bf6d"}, + {file = "pymongo-4.15.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:44d95677aa23fe479bb531b393a4fad0210f808af52e4ab2b79c0b540c828957"}, + {file = "pymongo-4.15.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ab985e61376ae5a04f162fb6bdddaffc7beec883ffbd9d84ea86a71be794d74"}, + {file = "pymongo-4.15.4-cp311-cp311-win32.whl", hash = "sha256:2f811e93dbcba0c488518ceae7873a40a64b6ad273622a18923ef2442eaab55c"}, + {file = "pymongo-4.15.4-cp311-cp311-win_amd64.whl", hash = "sha256:53bfcd8c11086a2457777cb4b1a6588d9dd6af77aeab47e04f2af02e3a077e59"}, + {file = "pymongo-4.15.4-cp311-cp311-win_arm64.whl", hash = "sha256:2096964b2b93607ed80a62ac6664396a826b7fe34e2b1eed3f20784681a17827"}, + {file = "pymongo-4.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4ab4eef031e722a8027c338c3d71704a8c85c17c64625d61c6effdf8a893b971"}, + {file = "pymongo-4.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e12551e28007a341d15ebca5a024ef487edf304d612fba5efa1fd6b4d9a95a9"}, + {file = "pymongo-4.15.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d21998fb9ccb3ea6d59a9f9971591b9efbcfbbe46350f7f8badef9b107707f3"}, + {file = "pymongo-4.15.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f83e8895d42eb51d259694affa9607c4d56e1c784928ccbbac568dc20df86a8"}, + {file = "pymongo-4.15.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0bd8126a507afa8ce4b96976c8e28402d091c40b7d98e3b5987a371af059d9e7"}, + {file = "pymongo-4.15.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e799e2cba7fcad5ab29f678784f90b1792fcb6393d571ecbe4c47d2888af30f3"}, + {file = "pymongo-4.15.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:563e793ad87633e50ad43a8cd2c740fbb17fca4a4637185996575ddbe99960b8"}, + {file = "pymongo-4.15.4-cp312-cp312-win32.whl", hash = "sha256:39bb3c12c772241778f4d7bf74885782c8d68b309d3c69891fe39c729334adbd"}, + {file = "pymongo-4.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:6f43326f36bc540b04f5a7f1aa8be40b112d7fc9f6e785ae3797cd72a804ffdd"}, + {file = "pymongo-4.15.4-cp312-cp312-win_arm64.whl", hash = "sha256:263cfa2731a4bbafdce2cf06cd511eba8957bd601b3cad9b4723f2543d42c730"}, + {file = "pymongo-4.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ff080f23a12c943346e2bba76cf19c3d14fb3625956792aa22b69767bfb36de"}, + {file = "pymongo-4.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c4690e01d03773f7af21b1a8428029bd534c9fe467c6b594c591d8b992c0a975"}, + {file = "pymongo-4.15.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:78bfe3917d0606b30a91b02ad954c588007f82e2abb2575ac2665259b051a753"}, + {file = "pymongo-4.15.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f53c83c3fd80fdb412ce4177d4f59b70b9bb1add6106877da044cf21e996316b"}, + {file = "pymongo-4.15.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e41d6650c1cd77a8e7556ad65133455f819f8c8cdce3e9cf4bbf14252b7d805"}, + {file = "pymongo-4.15.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b60fd8125f52efffd697490b6ccebc6e09d44069ad9c8795df0a684a9a8f4b3c"}, + {file = "pymongo-4.15.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d1a1a0406acd000377f34ae91cdb501fa73601a2d071e4a661e0c862e1b166e"}, + {file = "pymongo-4.15.4-cp313-cp313-win32.whl", hash = "sha256:9c5710ed5f2af95315db0ee8ae02e9ff1e85e7b068c507d980bc24fe9d025257"}, + {file = "pymongo-4.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:61b0863c7f9b460314db79b7f8541d3b490b453ece49afd56b611b214fc4b3b1"}, + {file = "pymongo-4.15.4-cp313-cp313-win_arm64.whl", hash = "sha256:0255af7d5c23c5e8cb4d9bb12906b142acebab0472117e1d5e3a8e6e689781cb"}, + {file = "pymongo-4.15.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:539f9fa5bb04a09fc2965cdcae3fc91d1c6a1f4f1965b34df377bc7119e3d7cd"}, + {file = "pymongo-4.15.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:68354a77cf78424d27216b1cb7c9b0f67da16aae855045279ba8d73bb61f5ad0"}, + {file = "pymongo-4.15.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a9a90d556c2ef1572d2aef525ef19477a82d659d117eb3a51fa99e617d07dc44"}, + {file = "pymongo-4.15.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1aac57614fb86a3fa707af3537c30eda5e7fd1be712c1f723296292ac057afe"}, + {file = "pymongo-4.15.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6c21b49c5e021d9ce02cac33525c722d4c6887f7cde19a5a9154f66cb845e84"}, + {file = "pymongo-4.15.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e93828768470026099119295c68ed0dbc0a50022558be5e334f6dbda054f1d32"}, + {file = "pymongo-4.15.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11840e9eb5a650ac190f2a3473631073daddbabdbb2779b6709dfddd3ba3b872"}, + {file = "pymongo-4.15.4-cp314-cp314-win32.whl", hash = "sha256:f0907b46df97b01911bf2e10ddbb23c2303629e482d81372031fd7f4313b9013"}, + {file = "pymongo-4.15.4-cp314-cp314-win_amd64.whl", hash = "sha256:111d7f65ccbde908546cb36d14e22f12a73a4de236fd056f41ed515d1365f134"}, + {file = "pymongo-4.15.4-cp314-cp314-win_arm64.whl", hash = "sha256:c689a5d057ef013612b5aa58e6bf52f7fdb186e22039f1a3719985b5d0399932"}, + {file = "pymongo-4.15.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:cdfa57760745387cde93615a48f622bf1eeae8ae28103a8a5100b9389eec22f9"}, + {file = "pymongo-4.15.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4fd6ba610e5a54090c4055a15f38d19ad8bf11e6bbc5a173e945c755a16db455"}, + {file = "pymongo-4.15.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3c7945b8a5563aa3951db26ba534372fba4c781473f5d55ce6340b7523cb0f"}, + {file = "pymongo-4.15.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41e98a31e79d74e9d78bc1638b71c3a10a910eae7d3318e2ae8587c760931451"}, + {file = "pymongo-4.15.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d18d89073b5e752391c237d2ee86ceec1e02a4ad764b3029f24419eedd12723e"}, + {file = "pymongo-4.15.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edbff27a56a80b8fe5c0319200c44e63b1349bf20db27d9734ddcf23c0d72b35"}, + {file = "pymongo-4.15.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1d75f5b51304176631c12e5bf47eed021446669e5f99379b76fd2bd3929c1b4"}, + {file = "pymongo-4.15.4-cp314-cp314t-win32.whl", hash = "sha256:e1bf4e0689cc48e0cfa6aef17f107c298d8898de0c6e782ea5c98450ae93a62f"}, + {file = "pymongo-4.15.4-cp314-cp314t-win_amd64.whl", hash = "sha256:3fc347ea5eda6c3a7177c3a9e4e9b4e570a444a351effda4a898c2d352a1ccd1"}, + {file = "pymongo-4.15.4-cp314-cp314t-win_arm64.whl", hash = "sha256:2d921b84c681c5385a6f7ba2b5740cb583544205a00877aad04b5b12ab86ad26"}, + {file = "pymongo-4.15.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e4c44bb6e781373915c56bc88f3b4849137869284e79c08a5b18f4c0d6adfd26"}, + {file = "pymongo-4.15.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:05e0f2ac285e24de802912908d64dfafca8bea5ab1718a88aab0f197b003dc28"}, + {file = "pymongo-4.15.4-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:94f8e9ab6954899d60babe48418e41217dc510d6fa4305af7aabee244b2a9882"}, + {file = "pymongo-4.15.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9e2f96e7e7a769a7804121c02f3290a39ca4d78a398bc56c6e024728d350897"}, + {file = "pymongo-4.15.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e84c95b185dce012575adc74a18342a2581dc9bb939712125317e03d92148167"}, + {file = "pymongo-4.15.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:649d24ce86f90a8c74897dba35e34c6b86e0d7d7381d7dc18cafbd06dc78fbc3"}, + {file = "pymongo-4.15.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cdab8a71f673b597dbe5cd610913525b59cba34835fc8c6ffb2b62f28028959"}, + {file = "pymongo-4.15.4-cp39-cp39-win32.whl", hash = "sha256:4eb3c2fea850104c41ce3f1f52f6a70f3d1a6998e9c63c197fcaab08c7c89e22"}, + {file = "pymongo-4.15.4-cp39-cp39-win_amd64.whl", hash = "sha256:4ea5dc8a0268ea2e12a6fcfc43bb8f3da969deed46734167238884cbb29c2598"}, + {file = "pymongo-4.15.4-cp39-cp39-win_arm64.whl", hash = "sha256:e6216290982178208b962edc9ba7ebc41b11f276a148ac3b496fc41f86963707"}, + {file = "pymongo-4.15.4.tar.gz", hash = "sha256:6ba7cdf46f03f406f77969a8081cfb659af16c0eee26b79a0a14e25f6c00827b"}, +] + +[package.dependencies] +dnspython = ">=1.16.0,<3.0.0" + +[package.extras] +aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] +docs = ["furo (==2025.7.19)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<9)", "sphinx-autobuild (>=2020.9.1)", "sphinx-rtd-theme (>=2,<4)", "sphinxcontrib-shellcheck (>=1,<2)"] +encryption = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.13.0,<2.0.0)"] +gssapi = ["pykerberos ; os_name != \"nt\"", "winkerberos (>=0.5.0) ; os_name == \"nt\""] +ocsp = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +snappy = ["python-snappy"] +test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"] +zstd = ["zstandard"] + +[[package]] +name = "pyopenssl" +version = "25.3.0" +description = "Python wrapper module around the OpenSSL library" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"snowflake\"" +files = [ + {file = "pyopenssl-25.3.0-py3-none-any.whl", hash = "sha256:1fda6fc034d5e3d179d39e59c1895c9faeaf40a79de5fc4cbbfbe0d36f4a77b6"}, + {file = "pyopenssl-25.3.0.tar.gz", hash = "sha256:c981cb0a3fd84e8602d7afc209522773b94c1c2446a3c710a75b06fe1beae329"}, +] + +[package.dependencies] +cryptography = ">=45.0.7,<47" +typing-extensions = {version = ">=4.9", markers = "python_version < \"3.13\" and python_version >= \"3.8\""} + +[package.extras] +docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx_rtd_theme"] +test = ["pretend", "pytest (>=3.0.1)", "pytest-rerunfailures"] + +[[package]] +name = "pyparsing" +version = "3.2.5" +description = "pyparsing - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e"}, + {file = "pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyperclip" +version = "1.11.0" +description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273"}, + {file = "pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6"}, +] + +[[package]] +name = "pypika" +version = "0.48.9" +description = "A SQL query builder API for Python" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "PyPika-0.48.9.tar.gz", hash = "sha256:838836a61747e7c8380cd1b7ff638694b7a7335345d0f559b04b2cd832ad5378"}, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +description = "Wrappers to call pyproject.toml-based build backend hooks." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}, + {file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"}, +] + +[[package]] +name = "pyreadline3" +version = "3.5.4" +description = "A python implementation of GNU readline." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, + {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, +] + +[package.extras] +dev = ["build", "flake8", "mypy", "pytest", "twine"] + +[[package]] +name = "pytest" +version = "8.4.2" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, + {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.23.8" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, + {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-bdd" +version = "8.1.0" +description = "BDD for pytest" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_bdd-8.1.0-py3-none-any.whl", hash = "sha256:2124051e71a05ad7db15296e39013593f72ebf96796e1b023a40e5453c47e5fb"}, + {file = "pytest_bdd-8.1.0.tar.gz", hash = "sha256:ef0896c5cd58816dc49810e8ff1d632f4a12019fb3e49959b2d349ffc1c9bfb5"}, +] + +[package.dependencies] +gherkin-official = ">=29.0.0,<30.0.0" +Mako = "*" +packaging = "*" +parse = "*" +parse-type = "*" +pytest = ">=7.0.0" +typing-extensions = "*" + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-tap" +version = "3.5" +description = "Test Anything Protocol (TAP) reporting plugin for pytest" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_tap-3.5-py3-none-any.whl", hash = "sha256:bce47102465db4fa09c0948bbf8867543143a9b9d16af77a2efbaffb4ec1072a"}, + {file = "pytest_tap-3.5.tar.gz", hash = "sha256:11b3b475b919e9d5c0e995b441fab0b92c57a46cec818132b71264fdfbd56a32"}, +] + +[package.dependencies] +pytest = ">=3.0" +tap-py = ">=3.2,<4.0" + +[[package]] +name = "pytest-timing" +version = "0.1.4" +description = "A pytest plugin for recording test execution times and results" +optional = false +python-versions = "^3.10" +groups = ["dev"] +files = [] +develop = false + +[package.source] +type = "git" +url = "https://github.com/emcie-co/mc-spitfyre.git" +reference = "timing_v0.1.4" +resolved_reference = "7b965f5df99f2a73458bdc0eafcc68b12ee0294e" +subdirectory = "pytest-timing" + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "1.2.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, + {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-multipart" +version = "0.0.20" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, + {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, +] + +[[package]] +name = "pytokens" +version = "0.3.0" +description = "A Fast, spec compliant Python 3.14+ tokenizer that runs on older Pythons." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"together\"" +files = [ + {file = "pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3"}, + {file = "pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a"}, +] + +[package.extras] +dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] + +[[package]] +name = "pytz" +version = "2025.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, +] + +[[package]] +name = "pywin32" +version = "311" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +groups = ["main"] +markers = "(platform_system == \"Windows\" or sys_platform == \"win32\") and (extra == \"qdrant\" or sys_platform == \"win32\")" +files = [ + {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, + {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, + {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, + {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, + {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, + {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, + {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, + {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, + {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, + {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, + {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, + {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, + {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, + {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, + {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, + {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, + {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, + {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, + {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, + {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, +] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + +[[package]] +name = "qdrant-client" +version = "1.16.1" +description = "Client library for the Qdrant vector search engine" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"qdrant\"" +files = [ + {file = "qdrant_client-1.16.1-py3-none-any.whl", hash = "sha256:1eefe89f66e8a468ba0de1680e28b441e69825cfb62e8fb2e457c15e24ce5e3b"}, + {file = "qdrant_client-1.16.1.tar.gz", hash = "sha256:676c7c10fd4d4cb2981b8fcb32fd764f5f661b04b7334d024034d07212f971fd"}, +] + +[package.dependencies] +grpcio = ">=1.41.0" +httpx = {version = ">=0.20.0", extras = ["http2"]} +numpy = [ + {version = ">=1.21", markers = "python_version >= \"3.10\" and python_version < \"3.12\""}, + {version = ">=2.1.0", markers = "python_version >= \"3.13\""}, + {version = ">=1.26", markers = "python_version == \"3.12\""}, +] +portalocker = ">=2.7.0,<4.0" +protobuf = ">=3.20.0" +pydantic = ">=1.10.8,<2.0.dev0 || >2.2.0" +urllib3 = ">=1.26.14,<3" + +[package.extras] +fastembed = ["fastembed (>=0.7,<0.8)"] +fastembed-gpu = ["fastembed-gpu (>=0.7,<0.8)"] + +[[package]] +name = "referencing" +version = "0.36.2" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, + {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" +typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} + +[[package]] +name = "regex" +version = "2025.11.3" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af"}, + {file = "regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313"}, + {file = "regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5"}, + {file = "regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec"}, + {file = "regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd"}, + {file = "regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eadade04221641516fa25139273505a1c19f9bf97589a05bc4cfcd8b4a618031"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feff9e54ec0dd3833d659257f5c3f5322a12eee58ffa360984b716f8b92983f4"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b30bc921d50365775c09a7ed446359e5c0179e9e2512beec4a60cbcef6ddd50"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f99be08cfead2020c7ca6e396c13543baea32343b7a9a5780c462e323bd8872f"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6dd329a1b61c0ee95ba95385fb0c07ea0d3fe1a21e1349fa2bec272636217118"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c5238d32f3c5269d9e87be0cf096437b7622b6920f5eac4fd202468aaeb34d2"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10483eefbfb0adb18ee9474498c9a32fcf4e594fbca0543bb94c48bac6183e2e"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78c2d02bb6e1da0720eedc0bad578049cad3f71050ef8cd065ecc87691bed2b0"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b49cd2aad93a1790ce9cffb18964f6d3a4b0b3dbdbd5de094b65296fce6e58"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:885b26aa3ee56433b630502dc3d36ba78d186a00cc535d3806e6bfd9ed3c70ab"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd76a9f58e6a00f8772e72cff8ebcff78e022be95edf018766707c730593e1e"}, + {file = "regex-2025.11.3-cp311-cp311-win32.whl", hash = "sha256:3e816cc9aac1cd3cc9a4ec4d860f06d40f994b5c7b4d03b93345f44e08cc68bf"}, + {file = "regex-2025.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:087511f5c8b7dfbe3a03f5d5ad0c2a33861b1fc387f21f6f60825a44865a385a"}, + {file = "regex-2025.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:1ff0d190c7f68ae7769cd0313fe45820ba07ffebfddfaa89cc1eb70827ba0ddc"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0"}, + {file = "regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204"}, + {file = "regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9"}, + {file = "regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7"}, + {file = "regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c"}, + {file = "regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5"}, + {file = "regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2"}, + {file = "regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a"}, + {file = "regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c"}, + {file = "regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed"}, + {file = "regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4"}, + {file = "regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad"}, + {file = "regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379"}, + {file = "regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38"}, + {file = "regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de"}, + {file = "regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:81519e25707fc076978c6143b81ea3dc853f176895af05bf7ec51effe818aeec"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3bf28b1873a8af8bbb58c26cc56ea6e534d80053b41fb511a35795b6de507e6a"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:856a25c73b697f2ce2a24e7968285579e62577a048526161a2c0f53090bea9f9"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a3d571bd95fade53c86c0517f859477ff3a93c3fde10c9e669086f038e0f207"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:732aea6de26051af97b94bc98ed86448821f839d058e5d259c72bf6d73ad0fc0"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:51c1c1847128238f54930edb8805b660305dca164645a9fd29243f5610beea34"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22dd622a402aad4558277305350699b2be14bc59f64d64ae1d928ce7d072dced"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f3b5a391c7597ffa96b41bd5cbd2ed0305f515fcbb367dfa72735679d5502364"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:cc4076a5b4f36d849fd709284b4a3b112326652f3b0466f04002a6c15a0c96c1"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a295ca2bba5c1c885826ce3125fa0b9f702a1be547d821c01d65f199e10c01e2"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b4774ff32f18e0504bfc4e59a3e71e18d83bc1e171a3c8ed75013958a03b2f14"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e7d1cdfa88ef33a2ae6aa0d707f9255eb286ffbd90045f1088246833223aee"}, + {file = "regex-2025.11.3-cp39-cp39-win32.whl", hash = "sha256:74d04244852ff73b32eeede4f76f51c5bcf44bc3c207bc3e6cf1c5c45b890708"}, + {file = "regex-2025.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:7a50cd39f73faa34ec18d6720ee25ef10c4c1839514186fcda658a06c06057a2"}, + {file = "regex-2025.11.3-cp39-cp39-win_arm64.whl", hash = "sha256:43b4fb020e779ca81c1b5255015fe2b82816c76ec982354534ad9ec09ad7c9e3"}, + {file = "regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01"}, +] + +[[package]] +name = "requests" +version = "2.32.5" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +description = "OAuthlib authentication support for Requests." +optional = true +python-versions = ">=3.4" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, +] + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +description = "A pure python RFC3339 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +files = [ + {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, + {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "rich" +version = "14.2.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd"}, + {file = "rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rich-rst" +version = "1.3.2" +description = "A beautiful reStructuredText renderer for rich" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "rich_rst-1.3.2-py3-none-any.whl", hash = "sha256:a99b4907cbe118cf9d18b0b44de272efa61f15117c61e39ebdc431baf5df722a"}, + {file = "rich_rst-1.3.2.tar.gz", hash = "sha256:a1196fdddf1e364b02ec68a05e8ff8f6914fee10fbca2e6b6735f166bb0da8d4"}, +] + +[package.dependencies] +docutils = "*" +rich = ">=12.0.0" + +[package.extras] +docs = ["sphinx"] + +[[package]] +name = "rpds-py" +version = "0.29.0" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "rpds_py-0.29.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4ae4b88c6617e1b9e5038ab3fccd7bac0842fdda2b703117b2aa99bc85379113"}, + {file = "rpds_py-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d9128ec9d8cecda6f044001fde4fb71ea7c24325336612ef8179091eb9596b9"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37812c3da8e06f2bb35b3cf10e4a7b68e776a706c13058997238762b4e07f4f"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66786c3fb1d8de416a7fa8e1cb1ec6ba0a745b2b0eee42f9b7daa26f1a495545"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58f5c77f1af888b5fd1876c9a0d9858f6f88a39c9dd7c073a88e57e577da66d"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:799156ef1f3529ed82c36eb012b5d7a4cf4b6ef556dd7cc192148991d07206ae"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:453783477aa4f2d9104c4b59b08c871431647cb7af51b549bbf2d9eb9c827756"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:24a7231493e3c4a4b30138b50cca089a598e52c34cf60b2f35cebf62f274fdea"}, + {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7033c1010b1f57bb44d8067e8c25aa6fa2e944dbf46ccc8c92b25043839c3fd2"}, + {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0248b19405422573621172ab8e3a1f29141362d13d9f72bafa2e28ea0cdca5a2"}, + {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f9f436aee28d13b9ad2c764fc273e0457e37c2e61529a07b928346b219fcde3b"}, + {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24a16cb7163933906c62c272de20ea3c228e4542c8c45c1d7dc2b9913e17369a"}, + {file = "rpds_py-0.29.0-cp310-cp310-win32.whl", hash = "sha256:1a409b0310a566bfd1be82119891fefbdce615ccc8aa558aff7835c27988cbef"}, + {file = "rpds_py-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5523b0009e7c3c1263471b69d8da1c7d41b3ecb4cb62ef72be206b92040a950"}, + {file = "rpds_py-0.29.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b9c764a11fd637e0322a488560533112837f5334ffeb48b1be20f6d98a7b437"}, + {file = "rpds_py-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fd2164d73812026ce970d44c3ebd51e019d2a26a4425a5dcbdfa93a34abc383"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a097b7f7f7274164566ae90a221fd725363c0e9d243e2e9ed43d195ccc5495c"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cdc0490374e31cedefefaa1520d5fe38e82fde8748cbc926e7284574c714d6b"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89ca2e673ddd5bde9b386da9a0aac0cab0e76f40c8f0aaf0d6311b6bbf2aa311"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5d9da3ff5af1ca1249b1adb8ef0573b94c76e6ae880ba1852f033bf429d4588"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8238d1d310283e87376c12f658b61e1ee23a14c0e54c7c0ce953efdbdc72deed"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2d6fb2ad1c36f91c4646989811e84b1ea5e0c3cf9690b826b6e32b7965853a63"}, + {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:534dc9df211387547267ccdb42253aa30527482acb38dd9b21c5c115d66a96d2"}, + {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d456e64724a075441e4ed648d7f154dc62e9aabff29bcdf723d0c00e9e1d352f"}, + {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a738f2da2f565989401bd6fd0b15990a4d1523c6d7fe83f300b7e7d17212feca"}, + {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a110e14508fd26fd2e472bb541f37c209409876ba601cf57e739e87d8a53cf95"}, + {file = "rpds_py-0.29.0-cp311-cp311-win32.whl", hash = "sha256:923248a56dd8d158389a28934f6f69ebf89f218ef96a6b216a9be6861804d3f4"}, + {file = "rpds_py-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:539eb77eb043afcc45314d1be09ea6d6cafb3addc73e0547c171c6d636957f60"}, + {file = "rpds_py-0.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:bdb67151ea81fcf02d8f494703fb728d4d34d24556cbff5f417d74f6f5792e7c"}, + {file = "rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954"}, + {file = "rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181"}, + {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c"}, + {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7"}, + {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19"}, + {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0"}, + {file = "rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7"}, + {file = "rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977"}, + {file = "rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7"}, + {file = "rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61"}, + {file = "rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b"}, + {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55"}, + {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd"}, + {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea"}, + {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22"}, + {file = "rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7"}, + {file = "rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e"}, + {file = "rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2"}, + {file = "rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c"}, + {file = "rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e"}, + {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb"}, + {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967"}, + {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e"}, + {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a"}, + {file = "rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb"}, + {file = "rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352"}, + {file = "rpds_py-0.29.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:394d27e4453d3b4d82bb85665dc1fcf4b0badc30fc84282defed71643b50e1a1"}, + {file = "rpds_py-0.29.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55d827b2ae95425d3be9bc9a5838b6c29d664924f98146557f7715e331d06df8"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc31a07ed352e5462d3ee1b22e89285f4ce97d5266f6d1169da1142e78045626"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4695dd224212f6105db7ea62197144230b808d6b2bba52238906a2762f1d1e7"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcae1770b401167f8b9e1e3f566562e6966ffa9ce63639916248a9e25fa8a244"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90f30d15f45048448b8da21c41703b31c61119c06c216a1bf8c245812a0f0c17"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a91e0ab77bdc0004b43261a4b8cd6d6b451e8d443754cfda830002b5745b32"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:4aa195e5804d32c682e453b34474f411ca108e4291c6a0f824ebdc30a91c973c"}, + {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7971bdb7bf4ee0f7e6f67fa4c7fbc6019d9850cc977d126904392d363f6f8318"}, + {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8ae33ad9ce580c7a47452c3b3f7d8a9095ef6208e0a0c7e4e2384f9fc5bf8212"}, + {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c661132ab2fb4eeede2ef69670fd60da5235209874d001a98f1542f31f2a8a94"}, + {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb78b3a0d31ac1bde132c67015a809948db751cb4e92cdb3f0b242e430b6ed0d"}, + {file = "rpds_py-0.29.0-cp314-cp314-win32.whl", hash = "sha256:f475f103488312e9bd4000bc890a95955a07b2d0b6e8884aef4be56132adbbf1"}, + {file = "rpds_py-0.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:b9cf2359a4fca87cfb6801fae83a76aedf66ee1254a7a151f1341632acf67f1b"}, + {file = "rpds_py-0.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:9ba8028597e824854f0f1733d8b964e914ae3003b22a10c2c664cb6927e0feb9"}, + {file = "rpds_py-0.29.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e71136fd0612556b35c575dc2726ae04a1669e6a6c378f2240312cf5d1a2ab10"}, + {file = "rpds_py-0.29.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:76fe96632d53f3bf0ea31ede2f53bbe3540cc2736d4aec3b3801b0458499ef3a"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9459a33f077130dbb2c7c3cea72ee9932271fb3126404ba2a2661e4fe9eb7b79"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5c9546cfdd5d45e562cc0444b6dddc191e625c62e866bf567a2c69487c7ad28a"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12597d11d97b8f7e376c88929a6e17acb980e234547c92992f9f7c058f1a7310"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28de03cf48b8a9e6ec10318f2197b83946ed91e2891f651a109611be4106ac4b"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd7951c964069039acc9d67a8ff1f0a7f34845ae180ca542b17dc1456b1f1808"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:c07d107b7316088f1ac0177a7661ca0c6670d443f6fe72e836069025e6266761"}, + {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de2345af363d25696969befc0c1688a6cb5e8b1d32b515ef84fc245c6cddba3"}, + {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:00e56b12d2199ca96068057e1ae7f9998ab6e99cda82431afafd32f3ec98cca9"}, + {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3919a3bbecee589300ed25000b6944174e07cd20db70552159207b3f4bbb45b8"}, + {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7fa2ccc312bbd91e43aa5e0869e46bc03278a3dddb8d58833150a18b0f0283a"}, + {file = "rpds_py-0.29.0-cp314-cp314t-win32.whl", hash = "sha256:97c817863ffc397f1e6a6e9d2d89fe5408c0a9922dac0329672fb0f35c867ea5"}, + {file = "rpds_py-0.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2023473f444752f0f82a58dfcbee040d0a1b3d1b3c2ec40e884bd25db6d117d2"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:acd82a9e39082dc5f4492d15a6b6c8599aa21db5c35aaf7d6889aea16502c07d"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:715b67eac317bf1c7657508170a3e011a1ea6ccb1c9d5f296e20ba14196be6b3"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b1b87a237cb2dba4db18bcfaaa44ba4cd5936b91121b62292ff21df577fc43"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c3c3e8101bb06e337c88eb0c0ede3187131f19d97d43ea0e1c5407ea74c0cbf"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8e54d6e61f3ecd3abe032065ce83ea63417a24f437e4a3d73d2f85ce7b7cfe"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fbd4e9aebf110473a420dea85a238b254cf8a15acb04b22a5a6b5ce8925b760"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fdf53d36e6c72819993e35d1ebeeb8e8fc688d0c6c2b391b55e335b3afba5a"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:ea7173df5d86f625f8dde6d5929629ad811ed8decda3b60ae603903839ac9ac0"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76054d540061eda273274f3d13a21a4abdde90e13eaefdc205db37c05230efce"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f84c549746a5be3bc7415830747a3a0312573afc9f95785eb35228bb17742ec"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0ea962671af5cb9a260489e311fa22b2e97103e3f9f0caaea6f81390af96a9ed"}, + {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f7728653900035fb7b8d06e1e5900545d8088efc9d5d4545782da7df03ec803f"}, + {file = "rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359"}, +] + +[[package]] +name = "rsa" +version = "4.9.1" +description = "Pure-Python RSA implementation" +optional = true +python-versions = "<4,>=3.6" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +name = "ruamel-yaml" +version = "0.18.16" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "ruamel.yaml-0.18.16-py3-none-any.whl", hash = "sha256:048f26d64245bae57a4f9ef6feb5b552a386830ef7a826f235ffb804c59efbba"}, + {file = "ruamel.yaml-0.18.16.tar.gz", hash = "sha256:a6e587512f3c998b2225d68aa1f35111c29fad14aed561a26e73fab729ec5e5a"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.14\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.15" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_python_implementation == \"CPython\"" +files = [ + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88eea8baf72f0ccf232c22124d122a7f26e8a24110a0273d9bcddcb0f7e1fa03"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b6f7d74d094d1f3a4e157278da97752f16ee230080ae331fcc219056ca54f77"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4be366220090d7c3424ac2b71c90d1044ea34fca8c0b88f250064fd06087e614"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f66f600833af58bea694d5892453f2270695b92200280ee8c625ec5a477eed3"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da3d6adadcf55a93c214d23941aef4abfd45652110aed6580e814152f385b862"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9fde97ecb7bb9c41261c2ce0da10323e9227555c674989f8d9eb7572fc2098d"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:05c70f7f86be6f7bee53794d80050a28ae7e13e4a0087c1839dcdefd68eb36b6"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f1d38cbe622039d111b69e9ca945e7e3efebb30ba998867908773183357f3ed"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-win32.whl", hash = "sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f"}, + {file = "ruamel_yaml_clib-0.2.15-cp310-cp310-win_amd64.whl", hash = "sha256:468858e5cbde0198337e6a2a78eda8c3fb148bdf4c6498eaf4bc9ba3f8e780bd"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c583229f336682b7212a43d2fa32c30e643d3076178fb9f7a6a14dde85a2d8bd"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56ea19c157ed8c74b6be51b5fa1c3aff6e289a041575f0556f66e5fb848bb137"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5fea0932358e18293407feb921d4f4457db837b67ec1837f87074667449f9401"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71831bd61fbdb7aa0399d5c4da06bea37107ab5c79ff884cc07f2450910262"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:617d35dc765715fa86f8c3ccdae1e4229055832c452d4ec20856136acc75053f"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b45498cc81a4724a2d42273d6cfc243c0547ad7c6b87b4f774cb7bcc131c98d"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:def5663361f6771b18646620fca12968aae730132e104688766cf8a3b1d65922"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:014181cdec565c8745b7cbc4de3bf2cc8ced05183d986e6d1200168e5bb59490"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-win32.whl", hash = "sha256:d290eda8f6ada19e1771b54e5706b8f9807e6bb08e873900d5ba114ced13e02c"}, + {file = "ruamel_yaml_clib-0.2.15-cp311-cp311-win_amd64.whl", hash = "sha256:bdc06ad71173b915167702f55d0f3f027fc61abd975bd308a0968c02db4a4c3e"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cb15a2e2a90c8475df45c0949793af1ff413acfb0a716b8b94e488ea95ce7cff"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:64da03cbe93c1e91af133f5bec37fd24d0d4ba2418eaf970d7166b0a26a148a2"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f6d3655e95a80325b84c4e14c080b2470fe4f33b6846f288379ce36154993fb1"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71845d377c7a47afc6592aacfea738cc8a7e876d586dfba814501d8c53c1ba60"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e5499db1ccbc7f4b41f0565e4f799d863ea720e01d3e99fa0b7b5fcd7802c9"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b293a37dc97e2b1e8a1aec62792d1e52027087c8eea4fc7b5abd2bdafdd6642"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:512571ad41bba04eac7268fe33f7f4742210ca26a81fe0c75357fa682636c690"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5e9f630c73a490b758bf14d859a39f375e6999aea5ddd2e2e9da89b9953486a"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-win32.whl", hash = "sha256:f4421ab780c37210a07d138e56dd4b51f8642187cdfb433eb687fe8c11de0144"}, + {file = "ruamel_yaml_clib-0.2.15-cp312-cp312-win_amd64.whl", hash = "sha256:2b216904750889133d9222b7b873c199d48ecbb12912aca78970f84a5aa1a4bc"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dcec721fddbb62e60c2801ba08c87010bd6b700054a09998c4d09c08147b8fb"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:65f48245279f9bb301d1276f9679b82e4c080a1ae25e679f682ac62446fac471"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:46895c17ead5e22bea5e576f1db7e41cb273e8d062c04a6a49013d9f60996c25"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3eb199178b08956e5be6288ee0b05b2fb0b5c1f309725ad25d9c6ea7e27f962a"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d1032919280ebc04a80e4fb1e93f7a738129857eaec9448310e638c8bccefcf"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab0df0648d86a7ecbd9c632e8f8d6b21bb21b5fc9d9e095c796cacf32a728d2d"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:331fb180858dd8534f0e61aa243b944f25e73a4dae9962bd44c46d1761126bbf"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-win32.whl", hash = "sha256:bf0846d629e160223805db9fe8cc7aec16aaa11a07310c50c8c7164efa440aec"}, + {file = "ruamel_yaml_clib-0.2.15-cp313-cp313-win_amd64.whl", hash = "sha256:45702dfbea1420ba3450bb3dd9a80b33f0badd57539c6aac09f42584303e0db6"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:753faf20b3a5906faf1fc50e4ddb8c074cb9b251e00b14c18b28492f933ac8ef"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:480894aee0b29752560a9de46c0e5f84a82602f2bc5c6cde8db9a345319acfdf"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d3b58ab2454b4747442ac76fab66739c72b1e2bb9bd173d7694b9f9dbc9c000"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bfd309b316228acecfa30670c3887dcedf9b7a44ea39e2101e75d2654522acd4"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2812ff359ec1f30129b62372e5f22a52936fac13d5d21e70373dbca5d64bb97c"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7e74ea87307303ba91073b63e67f2c667e93f05a8c63079ee5b7a5c8d0d7b043"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:713cd68af9dfbe0bb588e144a61aad8dcc00ef92a82d2e87183ca662d242f524"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:542d77b72786a35563f97069b9379ce762944e67055bea293480f7734b2c7e5e"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-win32.whl", hash = "sha256:424ead8cef3939d690c4b5c85ef5b52155a231ff8b252961b6516ed7cf05f6aa"}, + {file = "ruamel_yaml_clib-0.2.15-cp314-cp314-win_amd64.whl", hash = "sha256:ac9b8d5fa4bb7fd2917ab5027f60d4234345fd366fe39aa711d5dca090aa1467"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:923816815974425fbb1f1bf57e85eca6e14d8adc313c66db21c094927ad01815"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dcc7f3162d3711fd5d52e2267e44636e3e566d1e5675a5f0b30e98f2c4af7974"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5d3c9210219cbc0f22706f19b154c9a798ff65a6beeafbf77fc9c057ec806f7d"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bb7b728fd9f405aa00b4a0b17ba3f3b810d0ccc5f77f7373162e9b5f0ff75d5"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3cb75a3c14f1d6c3c2a94631e362802f70e83e20d1f2b2ef3026c05b415c4900"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:badd1d7283f3e5894779a6ea8944cc765138b96804496c91812b2829f70e18a7"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0ba6604bbc3dfcef844631932d06a1a4dcac3fee904efccf582261948431628a"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8220fd4c6f98485e97aea65e1df76d4fed1678ede1fe1d0eed2957230d287c4"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-win32.whl", hash = "sha256:04d21dc9c57d9608225da28285900762befbb0165ae48482c15d8d4989d4af14"}, + {file = "ruamel_yaml_clib-0.2.15-cp39-cp39-win_amd64.whl", hash = "sha256:27dc656e84396e6d687f97c6e65fb284d100483628f02d95464fd731743a4afe"}, + {file = "ruamel_yaml_clib-0.2.15.tar.gz", hash = "sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600"}, +] + +[[package]] +name = "ruff" +version = "0.9.10" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d"}, + {file = "ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d"}, + {file = "ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8"}, + {file = "ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029"}, + {file = "ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1"}, + {file = "ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69"}, + {file = "ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7"}, +] + +[[package]] +name = "s3transfer" +version = "0.15.0" +description = "An Amazon S3 Transfer Manager" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "s3transfer-0.15.0-py3-none-any.whl", hash = "sha256:6f8bf5caa31a0865c4081186689db1b2534cef721d104eb26101de4b9d6a5852"}, + {file = "s3transfer-0.15.0.tar.gz", hash = "sha256:d36fac8d0e3603eff9b5bfa4282c7ce6feb0301a633566153cbd0b93d11d8379"}, +] + +[package.dependencies] +botocore = ">=1.37.4,<2.0a.0" + +[package.extras] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] + +[[package]] +name = "safetensors" +version = "0.7.0" +description = "" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"vertex\" or extra == \"litellm\"" +files = [ + {file = "safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517"}, + {file = "safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48"}, + {file = "safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981"}, + {file = "safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b"}, + {file = "safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85"}, + {file = "safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0"}, + {file = "safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4"}, + {file = "safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba"}, + {file = "safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755"}, + {file = "safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737"}, + {file = "safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd"}, + {file = "safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2"}, + {file = "safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3"}, + {file = "safetensors-0.7.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b95a3fa7b3abb9b5b0e07668e808364d0d40f6bbbf9ae0faa8b5b210c97b140"}, + {file = "safetensors-0.7.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cfdead2f57330d76aa7234051dadfa7d4eedc0e5a27fd08e6f96714a92b00f09"}, + {file = "safetensors-0.7.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc92bc2db7b45bda4510e4f51c59b00fe80b2d6be88928346e4294ce1c2abe7c"}, + {file = "safetensors-0.7.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6999421eb8ba9df4450a16d9184fcb7bef26240b9f98e95401f17af6c2210b71"}, + {file = "safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0"}, +] + +[package.extras] +all = ["safetensors[jax]", "safetensors[numpy]", "safetensors[paddlepaddle]", "safetensors[pinned-tf]", "safetensors[quality]", "safetensors[testing]", "safetensors[torch]"] +dev = ["safetensors[all]"] +jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "safetensors[numpy]"] +mlx = ["mlx (>=0.0.9)"] +numpy = ["numpy (>=1.21.6)"] +paddlepaddle = ["paddlepaddle (>=2.4.1)", "safetensors[numpy]"] +pinned-tf = ["safetensors[numpy]", "tensorflow (==2.18.0)"] +quality = ["ruff"] +tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"] +testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] +testingfree = ["huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] +torch = ["packaging", "safetensors[numpy]", "torch (>=1.10)"] + +[[package]] +name = "scipy" +version = "1.15.3" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, +] + +[package.dependencies] +numpy = ">=1.23.5,<2.5" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "secretstorage" +version = "3.5.0" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "sys_platform == \"linux\"" +files = [ + {file = "secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137"}, + {file = "secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "semver" +version = "3.0.4" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746"}, + {file = "semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"}, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "(extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and python_version >= \"3.12\"" +files = [ + {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, + {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"together\"" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "snowflake-connector-python" +version = "3.18.0" +description = "Snowflake Connector for Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"snowflake\"" +files = [ + {file = "snowflake_connector_python-3.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e17a9e806823d3a0e578cf9349f6a93810a582b3132903ea9e1683854d08da00"}, + {file = "snowflake_connector_python-3.18.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:1841b60dc376639493dfc520cf39ad4f4da1f30286bba57e878d57414263d628"}, + {file = "snowflake_connector_python-3.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65d37263dd288abb649820b7e34af96dc6b2d2115bf5521a2526245f81ddb0cb"}, + {file = "snowflake_connector_python-3.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fb9fc9d8c2c7d209ba89282d367a32e75b0688afd4a3f02409e24f153c1a32e"}, + {file = "snowflake_connector_python-3.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfa6b234f53ec624149e21156d0a98e43408d194f2e65bcfaf30acefd35a581e"}, + {file = "snowflake_connector_python-3.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5fcb9a25a9b77b6cd86dfc6a6324b9910e15a493a916983229011ce3509b5f"}, + {file = "snowflake_connector_python-3.18.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d89f608fde2fb0597ca5e020c4ac602027dc67f11b61b4d1e5448163bae4edc"}, + {file = "snowflake_connector_python-3.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1afbd9e21180d2b4a76500ac2978b11865fdb3230609f2a9d80ba459fc27f2e4"}, + {file = "snowflake_connector_python-3.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c068c8d3cd0c9736cb0679a9f544d34327e64415303bbfe07ec8ce3c5dae800"}, + {file = "snowflake_connector_python-3.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:b211b4240596a225b895261a4ced2633e0262e82e2e32f6fb8dfc7d4bfedf8ca"}, + {file = "snowflake_connector_python-3.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fee7035f865088f948510b094101c8a0e5b22501891f2115f7fb1cb555de76a"}, + {file = "snowflake_connector_python-3.18.0-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:283366b35df88cd0c71caf0215ba80370ddef4dd37d2adf43b24208c747231ee"}, + {file = "snowflake_connector_python-3.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e4c285cc6a7f6431cff98c8f235a0fe9da2262462dd3dfc2b97120574a95cf9"}, + {file = "snowflake_connector_python-3.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94e041e347b5151b66d19d6cfc3b3172dac1f51e44bbf7cf58f3989427dd464a"}, + {file = "snowflake_connector_python-3.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:7116cfa410d517328fd25fabffb54845b88667586718578c4333ce034fead1ba"}, + {file = "snowflake_connector_python-3.18.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4ed2d593f1983939d5d8d88b212d86fd4f14f0ceefc1df9882b4a18534adbde9"}, + {file = "snowflake_connector_python-3.18.0-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:b99f261c82be92224ac20c8c12bdf26ce3ed5dfd8a3df8a97f15a1e11c46ad27"}, + {file = "snowflake_connector_python-3.18.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51eb789a09dc6c62119cfabd044fba1a6b8378206f05a1e83ddb2e9cb49acc0b"}, + {file = "snowflake_connector_python-3.18.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd1de3038b6d7059ca59f93e105aba2a673151c693cc4292f72f38bfaf147df2"}, + {file = "snowflake_connector_python-3.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:aeeb181a156333480f60b5f8ddbb3d087e288b4509adbef7993236defe4d7570"}, + {file = "snowflake_connector_python-3.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8d3e96e1d09b07edca6c1f6ca675b6fdd05a4a7e428e4cdf6fb697d87b9f60fc"}, + {file = "snowflake_connector_python-3.18.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:0af10b207af3d2de2b130e89018d49a60f2e5cfe841f3bf459e58f2e1c4c4506"}, + {file = "snowflake_connector_python-3.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:783a9ab206563d7b52fdcdd7a72af62de811d3381ca64132fd3445537b4d041b"}, + {file = "snowflake_connector_python-3.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32b1abfea32561d817b0a2f80b06d936cb32712af06bf7b848a428bfd857a10a"}, + {file = "snowflake_connector_python-3.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8c570edff5a4888840dbe1e9e65c5e4d77d55c5c800cd359fe0903a769201e0"}, + {file = "snowflake_connector_python-3.18.0.tar.gz", hash = "sha256:41a46eb9824574c5f8068e3ed5c02a2dc0a733ed08ee81fa1fb3dd0ebe921728"}, +] + +[package.dependencies] +asn1crypto = ">0.24.0,<2.0.0" +boto3 = ">=1.24" +botocore = ">=1.24" +certifi = ">=2017.4.17" +cffi = ">=1.9,<2.0.0" +charset_normalizer = ">=2,<4" +cryptography = ">=3.1.0" +filelock = ">=3.5,<4" +idna = ">=2.5,<4" +packaging = "*" +platformdirs = ">=2.6.0,<5.0.0" +pyjwt = "<3.0.0" +pyOpenSSL = ">=22.0.0,<26.0.0" +pytz = "*" +requests = "<3.0.0" +sortedcontainers = ">=2.4.0" +tomlkit = "*" +typing_extensions = ">=4.3,<5" + +[package.extras] +development = ["Cython", "coverage", "more-itertools", "numpy (<=2.2.4)", "pendulum (!=2.1.1)", "pexpect", "pytest (<7.5.0)", "pytest-cov", "pytest-rerunfailures (<16.0)", "pytest-timeout", "pytest-xdist", "pytzdata"] +pandas = ["pandas (>=2.1.2,<3.0.0)", "pyarrow"] +secure-local-storage = ["keyring (>=23.1.0,<26.0.0)"] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"snowflake\"" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + +[[package]] +name = "sse-starlette" +version = "3.0.3" +description = "SSE plugin for Starlette" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "sse_starlette-3.0.3-py3-none-any.whl", hash = "sha256:af5bf5a6f3933df1d9c7f8539633dc8444ca6a97ab2e2a7cd3b6e431ac03a431"}, + {file = "sse_starlette-3.0.3.tar.gz", hash = "sha256:88cfb08747e16200ea990c8ca876b03910a23b547ab3bd764c0d8eb81019b971"}, +] + +[package.dependencies] +anyio = ">=4.7.0" + +[package.extras] +daphne = ["daphne (>=4.2.0)"] +examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio] (>=2.0.41)", "starlette (>=0.49.1)", "uvicorn (>=0.34.0)"] +granian = ["granian (>=2.3.1)"] +uvicorn = ["uvicorn (>=0.34.0)"] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "starlette" +version = "0.49.3" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f"}, + {file = "starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284"}, +] + +[package.dependencies] +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} + +[package.extras] +full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] + +[[package]] +name = "structlog" +version = "24.4.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, +] + +[package.extras] +dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy (>=1.4)", "rich", "twisted"] + +[[package]] +name = "sympy" +version = "1.14.0" +description = "Computer algebra system (CAS) in Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\"" +files = [ + {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, + {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, +] + +[package.dependencies] +mpmath = ">=1.1.0,<1.4" + +[package.extras] +dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] + +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "tap-py" +version = "3.2.1" +description = "Test Anything Protocol (TAP) tools" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "tap_py-3.2.1-py3-none-any.whl", hash = "sha256:ae2a8a7999529ec568d03462e75968289cee5927dfd52fcc3a6381c8892d10ef"}, + {file = "tap_py-3.2.1.tar.gz", hash = "sha256:d03c9e6af0a56fad994f1c69f14041e676811d73eeeef20bf4077c43d621d608"}, +] + +[package.extras] +yaml = ["more-itertools", "pyyaml (>=5.1)"] + +[[package]] +name = "tenacity" +version = "9.1.2" +description = "Retry code until it succeeds" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"gemini\" or extra == \"vertex\"" +files = [ + {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, + {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, +] + +[package.extras] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] + +[[package]] +name = "tiktoken" +version = "0.12.0" +description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970"}, + {file = "tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16"}, + {file = "tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030"}, + {file = "tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134"}, + {file = "tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a"}, + {file = "tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892"}, + {file = "tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1"}, + {file = "tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb"}, + {file = "tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa"}, + {file = "tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc"}, + {file = "tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded"}, + {file = "tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd"}, + {file = "tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967"}, + {file = "tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def"}, + {file = "tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8"}, + {file = "tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b"}, + {file = "tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37"}, + {file = "tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad"}, + {file = "tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5"}, + {file = "tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3"}, + {file = "tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd"}, + {file = "tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3"}, + {file = "tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160"}, + {file = "tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa"}, + {file = "tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be"}, + {file = "tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a"}, + {file = "tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3"}, + {file = "tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697"}, + {file = "tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16"}, + {file = "tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a"}, + {file = "tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27"}, + {file = "tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb"}, + {file = "tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e"}, + {file = "tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25"}, + {file = "tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f"}, + {file = "tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646"}, + {file = "tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88"}, + {file = "tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff"}, + {file = "tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830"}, + {file = "tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b"}, + {file = "tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b"}, + {file = "tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3"}, + {file = "tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365"}, + {file = "tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e"}, + {file = "tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63"}, + {file = "tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0"}, + {file = "tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a"}, + {file = "tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0"}, + {file = "tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71"}, + {file = "tiktoken-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d51d75a5bffbf26f86554d28e78bfb921eae998edc2675650fd04c7e1f0cdc1e"}, + {file = "tiktoken-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:09eb4eae62ae7e4c62364d9ec3a57c62eea707ac9a2b2c5d6bd05de6724ea179"}, + {file = "tiktoken-0.12.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:df37684ace87d10895acb44b7f447d4700349b12197a526da0d4a4149fde074c"}, + {file = "tiktoken-0.12.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4c9614597ac94bb294544345ad8cf30dac2129c05e2db8dc53e082f355857af7"}, + {file = "tiktoken-0.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:20cf97135c9a50de0b157879c3c4accbb29116bcf001283d26e073ff3b345946"}, + {file = "tiktoken-0.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:15d875454bbaa3728be39880ddd11a5a2a9e548c29418b41e8fd8a767172b5ec"}, + {file = "tiktoken-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cff3688ba3c639ebe816f8d58ffbbb0aa7433e23e08ab1cade5d175fc973fb3"}, + {file = "tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931"}, +] + +[package.dependencies] +regex = ">=2022.1.18" +requests = ">=2.26.0" + +[package.extras] +blobfile = ["blobfile (>=2)"] + +[[package]] +name = "together" +version = "1.5.30" +description = "Python client for Together's Cloud Platform!" +optional = true +python-versions = "<4.0,>=3.10" +groups = ["main"] +markers = "extra == \"together\"" +files = [ + {file = "together-1.5.30-py3-none-any.whl", hash = "sha256:2010bdfc15f14e56fbf2f0d80fd3e281ddc4ecb7e68d8172a7aa7934b7530791"}, + {file = "together-1.5.30.tar.gz", hash = "sha256:194e9b3137b613fca5a20c4e0a90941add48e86b2f9a46a486b721e58714a5fe"}, +] + +[package.dependencies] +aiohttp = ">=3.9.3,<4.0.0" +black = ">=25.9.0,<26.0.0" +click = ">=8.1.7,<9.0.0" +eval-type-backport = ">=0.1.3,<0.3.0" +filelock = ">=3.13.1,<4.0.0" +numpy = [ + {version = ">=1.23.5", markers = "python_version < \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] +pillow = ">=11.1.0,<12.0.0" +pydantic = ">=2.6.3,<3.0.0" +requests = ">=2.31.0,<3.0.0" +rich = ">=13.8.1,<15.0.0" +tabulate = ">=0.9.0,<0.10.0" +tqdm = ">=4.66.2,<5.0.0" +typer = ">=0.9,<0.20" + +[package.extras] +pyarrow = ["pyarrow (>=10.0.1)"] + +[[package]] +name = "tokenizers" +version = "0.21.4" +description = "" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "tokenizers-0.21.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ccc10a7c3bcefe0f242867dc914fc1226ee44321eb618cfe3019b5df3400133"}, + {file = "tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b376f5a1aee67b4d29032ee85511bbd1b99007ec735f7f35c8a2eb104eade5"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2107ad649e2cda4488d41dfd031469e9da3fcbfd6183e74e4958fa729ffbf9c6"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c73012da95afafdf235ba80047699df4384fdc481527448a078ffd00e45a7d9"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f23186c40395fc390d27f519679a58023f368a0aad234af145e0f39ad1212732"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc88bb34e23a54cc42713d6d98af5f1bf79c07653d24fe984d2d695ba2c922a2"}, + {file = "tokenizers-0.21.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b7eabb104f46c1c50b486520555715457ae833d5aee9ff6ae853d1130506ff"}, + {file = "tokenizers-0.21.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:714b05b2e1af1288bd1bc56ce496c4cebb64a20d158ee802887757791191e6e2"}, + {file = "tokenizers-0.21.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:1340ff877ceedfa937544b7d79f5b7becf33a4cfb58f89b3b49927004ef66f78"}, + {file = "tokenizers-0.21.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3c1f4317576e465ac9ef0d165b247825a2a4078bcd01cba6b54b867bdf9fdd8b"}, + {file = "tokenizers-0.21.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c212aa4e45ec0bb5274b16b6f31dd3f1c41944025c2358faaa5782c754e84c24"}, + {file = "tokenizers-0.21.4-cp39-abi3-win32.whl", hash = "sha256:6c42a930bc5f4c47f4ea775c91de47d27910881902b0f20e4990ebe045a415d0"}, + {file = "tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597"}, + {file = "tokenizers-0.21.4.tar.gz", hash = "sha256:fa23f85fbc9a02ec5c6978da172cdcbac23498c3ca9f3645c5c68740ac007880"}, +] + +[package.dependencies] +huggingface-hub = ">=0.16.4,<1.0" + +[package.extras] +dev = ["tokenizers[testing]"] +docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.3.0" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, + {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, + {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"}, + {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"}, + {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"}, + {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"}, + {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"}, + {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"}, + {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"}, + {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"}, + {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"}, + {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"}, + {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"}, + {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"}, + {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"}, + {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"}, + {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"}, + {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"}, + {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"}, + {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"}, + {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"}, + {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"}, + {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"}, + {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"}, + {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"}, + {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"}, + {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"}, + {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"}, + {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"}, + {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"}, + {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"}, + {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"}, + {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"}, + {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"}, + {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"}, + {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"}, + {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"}, + {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"}, + {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"}, + {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"}, + {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, + {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +description = "Style preserving TOML library" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"snowflake\"" +files = [ + {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, + {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, +] + +[[package]] +name = "torch" +version = "2.9.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\"" +files = [ + {file = "torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e"}, + {file = "torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c"}, + {file = "torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65"}, + {file = "torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951"}, + {file = "torch-2.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:62b3fd888277946918cba4478cf849303da5359f0fb4e3bfb86b0533ba2eaf8d"}, + {file = "torch-2.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d033ff0ac3f5400df862a51bdde9bad83561f3739ea0046e68f5401ebfa67c1b"}, + {file = "torch-2.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:0d06b30a9207b7c3516a9e0102114024755a07045f0c1d2f2a56b1819ac06bcb"}, + {file = "torch-2.9.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:52347912d868653e1528b47cafaf79b285b98be3f4f35d5955389b1b95224475"}, + {file = "torch-2.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:da5f6f4d7f4940a173e5572791af238cb0b9e21b1aab592bd8b26da4c99f1cd6"}, + {file = "torch-2.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:27331cd902fb4322252657f3902adf1c4f6acad9dcad81d8df3ae14c7c4f07c4"}, + {file = "torch-2.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:81a285002d7b8cfd3fdf1b98aa8df138d41f1a8334fd9ea37511517cedf43083"}, + {file = "torch-2.9.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:c0d25d1d8e531b8343bea0ed811d5d528958f1dcbd37e7245bc686273177ad7e"}, + {file = "torch-2.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c29455d2b910b98738131990394da3e50eea8291dfeb4b12de71ecf1fdeb21cb"}, + {file = "torch-2.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:524de44cd13931208ba2c4bde9ec7741fd4ae6bfd06409a604fc32f6520c2bc9"}, + {file = "torch-2.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:545844cc16b3f91e08ce3b40e9c2d77012dd33a48d505aed34b7740ed627a1b2"}, + {file = "torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e"}, + {file = "torch-2.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:30a3e170a84894f3652434b56d59a64a2c11366b0ed5776fab33c2439396bf9a"}, + {file = "torch-2.9.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8301a7b431e51764629208d0edaa4f9e4c33e6df0f2f90b90e261d623df6a4e2"}, + {file = "torch-2.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2e1c42c0ae92bf803a4b2409fdfed85e30f9027a66887f5e7dcdbc014c7531db"}, + {file = "torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587"}, + {file = "torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a"}, + {file = "torch-2.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:19d144d6b3e29921f1fc70503e9f2fc572cde6a5115c0c0de2f7ca8b1483e8b6"}, + {file = "torch-2.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c432d04376f6d9767a9852ea0def7b47a7bbc8e7af3b16ac9cf9ce02b12851c9"}, + {file = "torch-2.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:d187566a2cdc726fc80138c3cdb260970fab1c27e99f85452721f7759bbd554d"}, + {file = "torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c"}, + {file = "torch-2.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0a2bd769944991c74acf0c4ef23603b9c777fdf7637f115605a4b2d8023110c7"}, + {file = "torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:07c8a9660bc9414c39cac530ac83b1fb1b679d7155824144a40a54f4a47bfa73"}, + {file = "torch-2.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c88d3299ddeb2b35dcc31753305612db485ab6f1823e37fb29451c8b2732b87e"}, +] + +[package.dependencies] +filelock = "*" +fsspec = ">=0.8.5" +jinja2 = "*" +networkx = ">=2.5.1" +nvidia-cublas-cu12 = {version = "12.8.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.10.2.21", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.3.3.83", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufile-cu12 = {version = "1.13.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.9.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.7.3.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.5.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparselt-cu12 = {version = "0.7.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.27.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvshmem-cu12 = {version = "3.3.20", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} +sympy = ">=1.13.3" +triton = {version = "3.5.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +typing-extensions = ">=4.10.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.13.0)"] +pyyaml = ["pyyaml"] + +[[package]] +name = "tqdm" +version = "4.67.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "traitlets" +version = "5.14.3" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "transformers" +version = "4.55.4" +description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +optional = true +python-versions = ">=3.9.0" +groups = ["main"] +markers = "extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"vertex\" or extra == \"litellm\"" +files = [ + {file = "transformers-4.55.4-py3-none-any.whl", hash = "sha256:df28f3849665faba4af5106f0db4510323277c4bb595055340544f7e59d06458"}, + {file = "transformers-4.55.4.tar.gz", hash = "sha256:574a30559bc273c7a4585599ff28ab6b676e96dc56ffd2025ecfce2fd0ab915d"}, +] + +[package.dependencies] +filelock = "*" +huggingface-hub = ">=0.34.0,<1.0" +numpy = ">=1.17" +packaging = ">=20.0" +pyyaml = ">=5.1" +regex = "!=2019.12.17" +requests = "*" +safetensors = ">=0.4.3" +tokenizers = ">=0.21,<0.22" +tqdm = ">=4.27" + +[package.extras] +accelerate = ["accelerate (>=0.26.0)"] +all = ["Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "av", "codecarbon (>=2.8.1)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "librosa", "mistral-common[opencv] (>=1.6.3)", "num2words", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.21,<0.22)", "torch (>=2.1)", "torchaudio", "torchvision"] +audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +benchmark = ["optimum-benchmark (>=0.3.0)"] +codecarbon = ["codecarbon (>=2.8.1)"] +deepspeed = ["accelerate (>=0.26.0)", "deepspeed (>=0.9.3)"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "optuna", "parameterized (>=0.9)", "protobuf", "psutil", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "av", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.21,<0.22)", "torch (>=2.1)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "onnxconverter-common", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "tf2onnx", "timeout-decorator", "tokenizers (>=0.21,<0.22)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "kenlm", "kernels (>=0.6.1,<=0.9)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.21,<0.22)", "torch (>=2.1)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)", "urllib3 (<2.0.0)"] +flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] +flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +ftfy = ["ftfy"] +hf-xet = ["hf_xet"] +hub-kernels = ["kernels (>=0.6.1,<=0.9)"] +integrations = ["kernels (>=0.6.1,<=0.9)", "optuna", "ray[tune] (>=2.7.0)", "sigopt"] +ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "rhoknp (>=1.1.0,<1.3.1)", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)"] +mistral-common = ["mistral-common[opencv] (>=1.6.3)"] +modelcreation = ["cookiecutter (==1.7.3)"] +natten = ["natten (>=0.14.6,<0.15.0)"] +num2words = ["num2words"] +onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] +onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] +open-telemetry = ["opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk"] +optuna = ["optuna"] +quality = ["GitPython (<3.1.19)", "datasets (>=2.15.0)", "libcst", "pandas (<2.3.0)", "rich", "ruff (==0.11.2)", "urllib3 (<2.0.0)"] +ray = ["ray[tune] (>=2.7.0)"] +retrieval = ["datasets (>=2.15.0)", "faiss-cpu"] +ruff = ["ruff (==0.11.2)"] +sagemaker = ["sagemaker (>=2.31.0)"] +sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] +serving = ["accelerate (>=0.26.0)", "fastapi", "openai (>=1.98.0)", "pydantic (>=2)", "starlette", "torch (>=2.1)", "uvicorn"] +sigopt = ["sigopt"] +sklearn = ["scikit-learn"] +speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "parameterized (>=0.9)", "psutil", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +tf = ["keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +tiktoken = ["blobfile", "tiktoken"] +timm = ["timm (!=1.0.18,<=1.0.19)"] +tokenizers = ["tokenizers (>=0.21,<0.22)"] +torch = ["accelerate (>=0.26.0)", "torch (>=2.1)"] +torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] +torchhub = ["filelock", "huggingface-hub (>=0.34.0,<1.0)", "importlib_metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.21,<0.22)", "torch (>=2.1)", "tqdm (>=4.27)"] +video = ["av"] +vision = ["Pillow (>=10.0.1,<=15.0)"] + +[[package]] +name = "triton" +version = "3.5.1" +description = "A language and compiler for custom Deep Learning operations" +optional = true +python-versions = "<3.15,>=3.10" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"anthropic\" or extra == \"aws\" or extra == \"together\" or extra == \"cerebras\" or extra == \"deepseek\" or extra == \"gemini\" or extra == \"vertex\" or extra == \"litellm\") and platform_system == \"Linux\"" +files = [ + {file = "triton-3.5.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f63e34dcb32d7bd3a1d0195f60f30d2aee8b08a69a0424189b71017e23dfc3d2"}, + {file = "triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94"}, + {file = "triton-3.5.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da47169e30a779bade679ce78df4810fca6d78a955843d2ddb11f226adc517dc"}, + {file = "triton-3.5.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61413522a48add32302353fdbaaf92daaaab06f6b5e3229940d21b5207f47579"}, + {file = "triton-3.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:275a045b6ed670dd1bd005c3e6c2d61846c74c66f4512d6f33cc027b11de8fd4"}, + {file = "triton-3.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2c6b915a03888ab931a9fd3e55ba36785e1fe70cbea0b40c6ef93b20fc85232"}, + {file = "triton-3.5.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56765ffe12c554cd560698398b8a268db1f616c120007bfd8829d27139abd24a"}, + {file = "triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba"}, + {file = "triton-3.5.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02c770856f5e407d24d28ddc66e33cf026e6f4d360dcb8b2fabe6ea1fc758621"}, + {file = "triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8"}, + {file = "triton-3.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f617aa7925f9ea9968ec2e1adaf93e87864ff51549c8f04ce658f29bbdb71e2d"}, + {file = "triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60"}, + {file = "triton-3.5.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8932391d7f93698dfe5bc9bead77c47a24f97329e9f20c10786bb230a9083f56"}, + {file = "triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478"}, +] + +[package.extras] +build = ["cmake (>=3.20,<4.0)", "lit"] +tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + +[[package]] +name = "typer" +version = "0.19.2" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"chroma\" or extra == \"together\"" +files = [ + {file = "typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9"}, + {file = "typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + +[[package]] +name = "types-aiofiles" +version = "24.1.0.20250822" +description = "Typing stubs for aiofiles" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "types_aiofiles-24.1.0.20250822-py3-none-any.whl", hash = "sha256:0ec8f8909e1a85a5a79aed0573af7901f53120dd2a29771dd0b3ef48e12328b0"}, + {file = "types_aiofiles-24.1.0.20250822.tar.gz", hash = "sha256:9ab90d8e0c307fe97a7cf09338301e3f01a163e39f3b529ace82466355c84a7b"}, +] + +[[package]] +name = "types-cachetools" +version = "6.2.0.20251022" +description = "Typing stubs for cachetools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "types_cachetools-6.2.0.20251022-py3-none-any.whl", hash = "sha256:698eb17b8f16b661b90624708b6915f33dbac2d185db499ed57e4997e7962cad"}, + {file = "types_cachetools-6.2.0.20251022.tar.gz", hash = "sha256:f1d3c736f0f741e89ec10f0e1b0138625023e21eb33603a930c149e0318c0cef"}, +] + +[[package]] +name = "types-croniter" +version = "4.0.0.20241030" +description = "Typing stubs for croniter" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "types-croniter-4.0.0.20241030.tar.gz", hash = "sha256:d71369cc042813026e2d6b8f94a2916a161eb62389edf53873edcd1741dda6c0"}, + {file = "types_croniter-4.0.0.20241030-py3-none-any.whl", hash = "sha256:e32006e0c9890163fc5123a1bba21efa00a88294c9c9519e502b3400a39bde5b"}, +] + +[[package]] +name = "types-jsonschema" +version = "4.25.1.20251009" +description = "Typing stubs for jsonschema" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "types_jsonschema-4.25.1.20251009-py3-none-any.whl", hash = "sha256:f30b329037b78e7a60146b1146feb0b6fb0b71628637584409bada83968dad3e"}, + {file = "types_jsonschema-4.25.1.20251009.tar.gz", hash = "sha256:75d0f5c5dd18dc23b664437a0c1a625743e8d2e665ceaf3aecb29841f3a5f97f"}, +] + +[package.dependencies] +referencing = "*" + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20251115" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_python_dateutil-2.9.0.20251115-py3-none-any.whl", hash = "sha256:9cf9c1c582019753b8639a081deefd7e044b9fa36bd8217f565c6c4e36ee0624"}, + {file = "types_python_dateutil-2.9.0.20251115.tar.gz", hash = "sha256:8a47f2c3920f52a994056b8786309b43143faa5a64d4cbb2722d6addabdf1a58"}, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20250913" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1"}, + {file = "types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d"}, +] + +[package.dependencies] +urllib3 = ">=2" + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "tzdata" +version = "2025.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +files = [ + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.38.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02"}, + {file = "uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +uvloop = {version = ">=0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.22.1" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = true +python-versions = ">=3.8.1" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\" and extra == \"chroma\" and sys_platform != \"win32\" and sys_platform != \"cygwin\"" +files = [ + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c"}, + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:80eee091fe128e425177fbd82f8635769e2f32ec9daf6468286ec57ec0313efa"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:017bd46f9e7b78e81606329d07141d3da446f8798c6baeec124260e22c262772"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3e5c6727a57cb6558592a95019e504f605d1c54eb86463ee9f7a2dbd411c820"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:57df59d8b48feb0e613d9b1f5e57b7532e97cbaf0d61f7aa9aa32221e84bc4b6"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:55502bc2c653ed2e9692e8c55cb95b397d33f9f2911e929dc97c4d6b26d04242"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4a968a72422a097b09042d5fa2c5c590251ad484acf910a651b4b620acd7f193"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b45649628d816c030dba3c80f8e2689bab1c89518ed10d426036cdc47874dfc4"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea721dd3203b809039fcc2983f14608dae82b212288b346e0bfe46ec2fab0b7c"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ae676de143db2b2f60a9696d7eca5bb9d0dd6cc3ac3dad59a8ae7e95f9e1b54"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17d4e97258b0172dfa107b89aa1eeba3016f4b1974ce85ca3ef6a66b35cbf659"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05e4b5f86e621cf3927631789999e697e58f0d2d32675b67d9ca9eb0bca55743"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:286322a90bea1f9422a470d5d2ad82d38080be0a29c4dd9b3e6384320a4d11e7"}, + {file = "uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f"}, +] + +[package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx_rtd_theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=6.1,<7.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=25.3.0,<25.4.0)", "pycodestyle (>=2.11.0,<2.12.0)"] + +[[package]] +name = "watchfiles" +version = "1.1.1" +description = "Simple, modern and high performance file watching and code reload in python." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"chroma\"" +files = [ + {file = "watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c"}, + {file = "watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863"}, + {file = "watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab"}, + {file = "watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82"}, + {file = "watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4"}, + {file = "watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844"}, + {file = "watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e"}, + {file = "watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5"}, + {file = "watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff"}, + {file = "watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606"}, + {file = "watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701"}, + {file = "watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10"}, + {file = "watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849"}, + {file = "watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4"}, + {file = "watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e"}, + {file = "watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d"}, + {file = "watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb"}, + {file = "watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803"}, + {file = "watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94"}, + {file = "watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43"}, + {file = "watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9"}, + {file = "watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9"}, + {file = "watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404"}, + {file = "watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18"}, + {file = "watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae"}, + {file = "watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d"}, + {file = "watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b"}, + {file = "watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374"}, + {file = "watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0"}, + {file = "watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42"}, + {file = "watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18"}, + {file = "watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da"}, + {file = "watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04"}, + {file = "watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77"}, + {file = "watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef"}, + {file = "watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf"}, + {file = "watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5"}, + {file = "watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510"}, + {file = "watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05"}, + {file = "watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6"}, + {file = "watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81"}, + {file = "watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b"}, + {file = "watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a"}, + {file = "watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02"}, + {file = "watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21"}, + {file = "watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc"}, + {file = "watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c"}, + {file = "watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099"}, + {file = "watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01"}, + {file = "watchfiles-1.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c882d69f6903ef6092bedfb7be973d9319940d56b8427ab9187d1ecd73438a70"}, + {file = "watchfiles-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6ff426a7cb54f310d51bfe83fe9f2bbe40d540c741dc974ebc30e6aa238f52e"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79ff6c6eadf2e3fc0d7786331362e6ef1e51125892c75f1004bd6b52155fb956"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1f5210f1b8fc91ead1283c6fd89f70e76fb07283ec738056cf34d51e9c1d62c"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9c4702f29ca48e023ffd9b7ff6b822acdf47cb1ff44cb490a3f1d5ec8987e9c"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acb08650863767cbc58bca4813b92df4d6c648459dcaa3d4155681962b2aa2d3"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08af70fd77eee58549cd69c25055dc344f918d992ff626068242259f98d598a2"}, + {file = "watchfiles-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c3631058c37e4a0ec440bf583bc53cdbd13e5661bb6f465bc1d88ee9a0a4d02"}, + {file = "watchfiles-1.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cf57a27fb986c6243d2ee78392c503826056ffe0287e8794503b10fb51b881be"}, + {file = "watchfiles-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d7e7067c98040d646982daa1f37a33d3544138ea155536c2e0e63e07ff8a7e0f"}, + {file = "watchfiles-1.1.1-cp39-cp39-win32.whl", hash = "sha256:6c9c9262f454d1c4d8aaa7050121eb4f3aea197360553699520767daebf2180b"}, + {file = "watchfiles-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:74472234c8370669850e1c312490f6026d132ca2d396abfad8830b4f1c096957"}, + {file = "watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3"}, + {file = "watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2"}, + {file = "watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d"}, + {file = "watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b"}, + {file = "watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88"}, + {file = "watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336"}, + {file = "watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24"}, + {file = "watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49"}, + {file = "watchfiles-1.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdab464fee731e0884c35ae3588514a9bcf718d0e2c82169c1c4a85cc19c3c7f"}, + {file = "watchfiles-1.1.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3dbd8cbadd46984f802f6d479b7e3afa86c42d13e8f0f322d669d79722c8ec34"}, + {file = "watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5524298e3827105b61951a29c3512deb9578586abf3a7c5da4a8069df247cccc"}, + {file = "watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b943d3668d61cfa528eb949577479d3b077fd25fb83c641235437bc0b5bc60e"}, + {file = "watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "wcwidth" +version = "0.2.14" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, + {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef"}, + {file = "websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98"}, +] + +[package.extras] +docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx_rtd_theme (>=1.1.0)"] +optional = ["python-socks", "wsaccel"] +test = ["pytest", "websockets"] + +[[package]] +name = "websockets" +version = "15.0.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, +] + +[[package]] +name = "werkzeug" +version = "3.1.1" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "werkzeug-3.1.1-py3-none-any.whl", hash = "sha256:a71124d1ef06008baafa3d266c02f56e1836a5984afd6dd6c9230669d60d9fb5"}, + {file = "werkzeug-3.1.1.tar.gz", hash = "sha256:8cd39dfbdfc1e051965f156163e2974e52c210f130810e9ad36858f0fd3edad4"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + +[[package]] +name = "wrapt" +version = "1.17.3" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, + {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, + {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, + {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, + {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, + {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, + {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, + {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, + {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, + {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, + {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, + {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, + {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4"}, + {file = "wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10"}, + {file = "wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6"}, + {file = "wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804"}, + {file = "wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22"}, + {file = "wrapt-1.17.3-cp38-cp38-win32.whl", hash = "sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c"}, + {file = "wrapt-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b"}, + {file = "wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81"}, + {file = "wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f"}, + {file = "wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f"}, + {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, + {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, +] + +[[package]] +name = "yarl" +version = "1.22.0" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e"}, + {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f"}, + {file = "yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf"}, + {file = "yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a"}, + {file = "yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c"}, + {file = "yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147"}, + {file = "yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb"}, + {file = "yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6"}, + {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0"}, + {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda"}, + {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc"}, + {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737"}, + {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467"}, + {file = "yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea"}, + {file = "yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca"}, + {file = "yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b"}, + {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511"}, + {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6"}, + {file = "yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028"}, + {file = "yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d"}, + {file = "yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503"}, + {file = "yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65"}, + {file = "yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e"}, + {file = "yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d"}, + {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7"}, + {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967"}, + {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed"}, + {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6"}, + {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e"}, + {file = "yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca"}, + {file = "yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b"}, + {file = "yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376"}, + {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f"}, + {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2"}, + {file = "yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74"}, + {file = "yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df"}, + {file = "yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb"}, + {file = "yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2"}, + {file = "yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82"}, + {file = "yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a"}, + {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124"}, + {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa"}, + {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7"}, + {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d"}, + {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520"}, + {file = "yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8"}, + {file = "yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c"}, + {file = "yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74"}, + {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53"}, + {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a"}, + {file = "yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c"}, + {file = "yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601"}, + {file = "yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a"}, + {file = "yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df"}, + {file = "yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2"}, + {file = "yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b"}, + {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273"}, + {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a"}, + {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d"}, + {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02"}, + {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67"}, + {file = "yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95"}, + {file = "yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d"}, + {file = "yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b"}, + {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10"}, + {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3"}, + {file = "yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9"}, + {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f"}, + {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0"}, + {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e"}, + {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708"}, + {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f"}, + {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d"}, + {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8"}, + {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5"}, + {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f"}, + {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62"}, + {file = "yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03"}, + {file = "yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249"}, + {file = "yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b"}, + {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4"}, + {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683"}, + {file = "yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b"}, + {file = "yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e"}, + {file = "yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590"}, + {file = "yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2"}, + {file = "yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da"}, + {file = "yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784"}, + {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b"}, + {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694"}, + {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d"}, + {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd"}, + {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da"}, + {file = "yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2"}, + {file = "yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79"}, + {file = "yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33"}, + {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1"}, + {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca"}, + {file = "yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53"}, + {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c"}, + {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf"}, + {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face"}, + {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b"}, + {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486"}, + {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138"}, + {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a"}, + {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529"}, + {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093"}, + {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c"}, + {file = "yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e"}, + {file = "yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27"}, + {file = "yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1"}, + {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748"}, + {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859"}, + {file = "yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9"}, + {file = "yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054"}, + {file = "yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b"}, + {file = "yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60"}, + {file = "yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890"}, + {file = "yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba"}, + {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca"}, + {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba"}, + {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b"}, + {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e"}, + {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8"}, + {file = "yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b"}, + {file = "yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed"}, + {file = "yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2"}, + {file = "yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff"}, + {file = "yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.1" + +[[package]] +name = "zhipuai" +version = "2.1.5.20250825" +description = "A SDK library for accessing big model apis from ZhipuAI" +optional = true +python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" +groups = ["main"] +markers = "extra == \"zhipu\"" +files = [ + {file = "zhipuai-2.1.5.20250825-py3-none-any.whl", hash = "sha256:aaad19881e514a4682598f07503b82d60b8b9a91cd83f9bcda988b94853c830d"}, + {file = "zhipuai-2.1.5.20250825.tar.gz", hash = "sha256:50fc3982565ee631bd640b1166a1d223de227958026a74a1dd0e26dbd58d729c"}, +] + +[package.dependencies] +cachetools = ">=4.2.2" +httpx = ">=0.23.0" +pydantic = ">=1.9.0,<3.0" +pydantic-core = ">=2.14.6" +pyjwt = ">=2.8.0,<2.9.0" + +[[package]] +name = "zipp" +version = "3.23.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[extras] +anthropic = ["anthropic", "torch", "transformers"] +aws = ["anthropic", "torch", "transformers"] +azure = ["azure-identity"] +cerebras = ["cerebras-cloud-sdk", "torch", "transformers"] +chroma = ["chromadb"] +deepseek = ["torch", "transformers"] +fireworks = [] +gemini = ["google-api-core", "google-genai", "torch"] +litellm = ["litellm", "torch", "transformers"] +mistral = ["mistralai"] +mongo = ["pymongo"] +ollama = ["ollama"] +qdrant = ["qdrant-client"] +snowflake = ["snowflake-connector-python"] +together = ["together", "torch", "transformers"] +vertex = ["anthropic", "google-api-core", "google-auth", "google-genai", "torch", "transformers"] +zhipu = ["zhipuai"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<3.14" +content-hash = "e2c35f34c8bcb500eb3765455e201baff8789cd5fbdcc79994ab5aa5e6f53492" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..acbc64b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,164 @@ +[project] +name = "parlant" +version = "3.3.1" +description = "" +readme = "README.md" +license = "Apache-2.0" +authors = [ + {name = "Yam Marcovitz", email = "yam@emcie.co"}, + {name = "Dor Zohar", email = "dor@emcie.co"}, +] +requires-python = ">=3.10,<3.15" # Restricted for torch 2.8+ compatibility with triton +dependencies = [ + "aiofiles>=24.1.0", + "aiopenapi3>=0.8.1,<0.9.0", # 0.9.0 hard-pins pydantic==2.11.9, which conflicts with downstream pydantic>=2.12 consumers + "aiorwlock>=1.5.0", + "authlib>=1.6.11", + "boto3>=1.35.70", + "cachetools>=6.0.0", + "click>=8.1.7", + "colorama>=0.4.6", + "coloredlogs>=15.0.1", + "contextvars>=2.4", + "croniter>=5.0.1", + "fastapi>=0.120.0", + "fastmcp>=3.2.0", + "griffe<2", # Pinned to <2 because fastmcp (at least v3.2.4) is not compatible with griffe 2.0+ due to breaking changes. Can be removed in case of future fastmcp updates. + "httpx>=0.28.1", + "jinja2>=3.1.6", + "jsonfinder>=0.4.2", + "jsonschema>=4.23.0", + "lagom>=2.6.0", + "limits>=5.5.0", + "mcp>=1.23.0", + "more-itertools>=10.3.0", + "nano-vectordb>=0.0.4.3", + "nanoid>=2.0.0", + "networkx[default]>=3.3", + "openai>=2.8.0", + "openapi3-parser==1.1.21", + "opentelemetry-api>=1.37.0", + "opentelemetry-exporter-otlp>=1.37.0", + "opentelemetry-instrumentation>=0.58b0", + "opentelemetry-sdk>=1.37.0", + "parlant-client @ git+https://github.com/emcie-co/parlant-client-python.git@v3.2.0", + "python-dateutil>=2.8.2", + "python-dotenv>=1.0.1", + "requests>=2.33.0", + "rich>=14.0.0", + "semver>=3.0.2", + "starlette>=0.49.0", # Specified for fix vulnerability of lower versions. Can be removed in case of future conflicts. + "structlog>=24.4.0", + "tabulate>=0.9.0", + "tiktoken>=0.12", + "tokenizers>=0.21", + "toml>=0.10.2", + "types-aiofiles>=24.1.0.20240626", + "types-cachetools>=6.0.0.20250525", + "types-croniter>=4.0.0.20241030", + "types-jsonschema>=4.22.0.20240610", + "uvicorn>=0.38.0", + "websocket-client>=1.5.3", + "wsproto>=1.2.0", + "xxhash>=3.5.0", +] + +[project.scripts] +parlant = "parlant.bin.client:main" +parlant-server = "parlant.bin.server:main" +parlant-prepare-migration = "parlant.bin.prepare_migration:main" + +[project.optional-dependencies] +chroma = ["chromadb>=1.1.1"] +qdrant = ["qdrant-client>=1.7.0"] +mongo = ["pymongo>=4.11.1"] + +anthropic = ["anthropic>=0.60.0", "torch>=2.8.0", "transformers>=4.53.0"] + +aws = ["anthropic>=0.60.0", "transformers>=4.53.0", "torch>=2.8.0"] + +together = ["torch>=2.8.0", "together>=1.5.26", "transformers>=4.53.0"] + +cerebras = ["cerebras-cloud-sdk>=1.25.0", "torch>=2.8.0", "transformers>=4.53.0"] + +deepseek = ["torch>=2.8.0", "transformers>=4.53.0"] + +gemini = ["google-genai>=1.36.0", "google-api-core>=2.24.2", "torch>=2.8.0"] + +vertex = [ + "google-genai>=1.36.0", + "google-api-core>=2.24.2", + "google-auth>=2.40.0", + "torch>=2.8.0", + "anthropic>=0.60.0", + "transformers>=4.53.0", +] + +ollama = ["ollama>=0.5.0"] + +litellm = ["litellm>=1.83.10", "torch>=2.8.0", "transformers>=4.53.0"] + +azure = ["azure-identity>=1.20.0"] + +# fireworks = ["fireworks-ai>=0.19.19"] # Disabled: pins protobuf=5.29.3 which has CVE-2025-4565 + +mistral = ["mistralai>=1.0.0"] + +snowflake = ["snowflake-connector-python>=3.12.0"] + +zhipu = ["zhipuai>=2.0.0"] + +[dependency-groups] +dev = [ + "ipython>=8.26.0", + "mypy>=1.18.1", + "pep8-naming>=0.13.3", + "pytest>=9.0.3", + "pytest-asyncio>=0.23.5", + "pytest-bdd>=8.1.0", + "pytest-cov>=5.0.0", + "pytest-tap>=3.4", + "pytest-timing @ git+https://github.com/emcie-co/mc-spitfyre.git@timing_v0.1.4#subdirectory=pytest-timing", + "python-dotenv>=1.0.1", + "ruff>=0.9.1", + "types-python-dateutil>=2.8.19.20240106", + "types-requests>=2.32.0.20240712", + "types-toml>=0.10.8", + "pytest-xdist>=3.6.1", +] + +[tool.uv] +override-dependencies = [ + "pyjwt>=2.11.1", # Override zhipuai's pyjwt<2.9.0 cap to allow mcp>=1.23.0 (CVE-2025-66416, CVE-2026-32597) + "onnxruntime<1.24; python_full_version < '3.11'", # 1.24+ dropped Python 3.10 support +] +constraint-dependencies = [ + # Minimum safe versions for transitive dependencies with known CVEs. + # These constraints only affect resolution — they do not force installation. + "aiohttp>=3.13.4", + "azure-core>=1.38.0", + "cryptography>=46.0.7", + "diskcache>=5.6.4", + "filelock>=3.20.3", + "fonttools>=4.60.2", + "Mako>=1.3.12", + "orjson>=3.11.6", + "pillow>=12.2.0", + "protobuf>=6.33.5", + "pyasn1>=0.6.3", + "Pygments>=2.20.0", + "pyopenssl>=26.0.0", + "python-multipart>=0.0.27", + "urllib3>=2.7.0", + "werkzeug>=3.1.6", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["src/parlant"] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..2390583 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,10 @@ +[pytest] +asyncio_mode = auto +bdd_features_base_dir = tests/ +filterwarnings = + ignore::pytest.PytestDeprecationWarning:pytest_bdd.* + ignore::pytest.PytestWarning:.*usefixtures.*has no effect +addopts = "--import-mode=importlib" +markers = + engine: marks tests related to engine behavior + evaluation: marks tests related to preprocessing evaluations \ No newline at end of file diff --git a/pytest_stochastics.json b/pytest_stochastics.json new file mode 100644 index 0000000..a3dd7db --- /dev/null +++ b/pytest_stochastics.json @@ -0,0 +1,118 @@ +{ + "test_plan_list": [ + { + "plan": "complete", + "_comment": "utility plan equivalent to running all the other plans. used for vscode test explorer.", + "policy_tests": [ + { + "policy": "default", + "tests": [ + "tests/(?!core)" + ] + }, + { + "policy": "strict3", + "tests": [ + "tests/core/stable" + ] + }, + { + "policy": "majority3", + "tests": [ + "tests/core/unstable" + ] + } + ] + }, + { + "plan": "default_disabled", + "_comment": "baseline plan to disbale all tests that are not specifically enabled by using it as a base for other plans", + "policy_tests": [ + { + "policy": "disable", + "tests": [ + "tests/" + ] + } + ] + }, + { + "plan": "deterministic", + "_comment": "Plan to test all the non-stochastic tests. All should pass.", + "policy_tests": [ + { + "policy": "default", + "tests": [ + "tests/(?!core)" + ] + } + ] + }, + { + "plan": "core_stable", + "_comment": "Stable stochastic tests should pass 3 out of 3 runs.", + "policy_tests": [ + { + "policy": "strict3", + "tests": [ + "tests/core/stable" + ] + } + ] + }, + { + "plan": "core_unstable", + "_comment": "Unstable test are allowed one failure out of 3 runs. (Temporarily encompases all of `core`)", + "policy_tests": [ + { + "policy": "majority3", + "tests": [ + "tests/core/unstable" + ] + } + ] + } + ], + "policy_list": [ + { + "policy": "disable", + "at_least": 0, + "out_of": 0 + }, + { + "policy": "default", + "at_least": 1, + "out_of": 1 + }, + { + "policy": "experimental", + "at_least": 0, + "out_of": 3, + "pass_fast": false + }, + { + "policy": "majority3", + "at_least": 2, + "out_of": 3 + }, + { + "policy": "strict3", + "at_least": 3, + "out_of": 3 + } + ], + "plan_fallback_list": [ + { + "plan": "deterministic", + "overrides": "default_disabled" + }, + { + "plan": "core_stable", + "overrides": "default_disabled" + }, + { + "plan": "core_unstable", + "overrides": "default_disabled" + } + ] +} \ No newline at end of file diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..3c13b71 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,75 @@ +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Same as Black. +line-length = 100 +indent-width = 4 + +# Assume Python 3.8 +target-version = "py312" + +[lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +select = [ + "E4", + "E7", + "E9", + "F", + "W293", + "PLR1722", + "PTH204", + "PLW2901", + #"ASYNC230", TODO: don't use sync open() in async methods + #"PTH123", TODO: prefer Path.open() over open() + #"UP035", TODO: preferred import sources + #"UP017", TODO: prefer datetimc.UTC + #"I001", TODO: sort imports +] +ignore = ["E203"] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" diff --git a/scripts/ci/github_action_ubuntu_2404_free_space.sh b/scripts/ci/github_action_ubuntu_2404_free_space.sh new file mode 100644 index 0000000..72416fc --- /dev/null +++ b/scripts/ci/github_action_ubuntu_2404_free_space.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +# Print initial disk space usage +df -h / | awk 'NR==2 {printf "Before cleanup: %s used, %s free\n", $3, $4}' + +# Remove docker images +sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true + +# Remove development toolchains and SDK directories +sudo rm -rf \ + /opt/hostedtoolcache/* \ + /usr/local/lib/android \ + /usr/share/dotnet \ + /usr/local/share/powershell \ + /usr/share/swift \ + /opt/ghc \ + /usr/local/.ghcup \ + /usr/lib/jvm \ + /usr/local/julia* \ + /usr/local/n \ + /usr/local/share/chromium \ + /usr/local/share/vcpkg \ + >/dev/null 2>&1 || true + +# Remove unnecessary packages +sudo apt-get remove -y \ + azure-cli \ + google-cloud-sdk \ + firefox \ + google-chrome-stable \ + microsoft-edge-stable \ + mysql* \ + mongodb-org* \ + dotnet* \ + php* \ + >/dev/null 2>&1 || true + +# Clean up package system +sudo apt-get autoremove -y >/dev/null 2>&1 +sudo apt-get clean -y >/dev/null 2>&1 + +# Clean up package caches and data +sudo rm -rf \ + /var/lib/docker/* \ + /var/lib/gems/* \ + /var/lib/apt/lists/* \ + /var/cache/* \ + /var/lib/snapd \ + >/dev/null 2>&1 || true + +# Print final disk space usage and difference +df -h / | awk -v before="$(df -h / | awk 'NR==2 {print $3}')" \ + 'NR==2 {printf "After cleanup: %s used, %s free (freed %s)\n", + $3, $4, substr(before,1,length(before)-1) - substr($3,1,length($3)-1) "G"}' \ No newline at end of file diff --git a/scripts/fern/docs.yml b/scripts/fern/docs.yml new file mode 100644 index 0000000..9bbbb4c --- /dev/null +++ b/scripts/fern/docs.yml @@ -0,0 +1,8 @@ +instances: + - url: https://docs.parlant.io +title: Parlant | Documentation +navigation: + - api: API Reference +colors: + accentPrimary: '#ffffff' + background: '#000000' diff --git a/scripts/fern/fern.config.json b/scripts/fern/fern.config.json new file mode 100644 index 0000000..752ffd9 --- /dev/null +++ b/scripts/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "parlant", + "version": "0.61.22" +} \ No newline at end of file diff --git a/scripts/fern/generators.yml b/scripts/fern/generators.yml new file mode 100644 index 0000000..04fbe40 --- /dev/null +++ b/scripts/fern/generators.yml @@ -0,0 +1,21 @@ +api: + specs: + - openapi: openapi/parlant.openapi.json +default-group: local +groups: + local: + generators: + - name: fernapi/fern-typescript-node-sdk + version: 0.49.2 + config: + namespaceExport: Parlant + output: + location: local-file-system + path: ../sdks/typescript + - name: fernapi/fern-python-sdk + version: 4.3.3 + config: + client_class_name: ParlantClient + output: + location: local-file-system + path: ../sdks/python diff --git a/scripts/generate_client_sdk.py b/scripts/generate_client_sdk.py new file mode 100644 index 0000000..c693cff --- /dev/null +++ b/scripts/generate_client_sdk.py @@ -0,0 +1,127 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!python + +import os +from pathlib import Path +import re +import subprocess +import shutil +import sys +import time + + +DIR_SCRIPT_ROOT = Path(__file__).parent +DIR_FERN = DIR_SCRIPT_ROOT / "fern" +DIR_SDKS = DIR_SCRIPT_ROOT / "sdks" +DIR_PROJECTS_WORKSPACE = DIR_SCRIPT_ROOT / ".." / ".." / "parlant-sdks" + + +PATHDICT_SDK_REPO_TARGETS = { + "python": DIR_PROJECTS_WORKSPACE / "parlant-client-python" / "src" / "parlant" / "client", + "typescript": DIR_PROJECTS_WORKSPACE / "parlant-client-typescript" / "src", +} + + +def replace_in_files(rootdir: Path, search: str, replace: str) -> None: + rewrites: dict[str, str] = {} + for subdir, _dirs, files in os.walk(rootdir): + for file in files: + file_path = os.path.join(subdir, file) + + with open(file_path, "r") as current_file: + current_file_content = current_file.read() + if "from parlant import" not in current_file_content: + continue + + current_file_content = re.sub(search, replace, current_file_content) + rewrites[file_path] = current_file_content + + for path, content in rewrites.items(): + with open(path, "w") as current_file: + current_file.write(content) + + +if __name__ == "__main__": + DEFAULT_PORT = 8800 + port = DEFAULT_PORT + if len(sys.argv) >= 2: + port = int(sys.argv[1]) + + print(f"The script will now try to fetch the latest openapi.json from http://localhost:{port}.") + input( + f"Ensure that parlant-server is running on port {port} and then press any key to continue..." + ) + + output_openapi_json = DIR_FERN / "openapi/parlant.openapi.json" + output_openapi_json.parent.mkdir(exist_ok=True) + output_openapi_json.touch() + + status, output = subprocess.getstatusoutput( + f"curl -m 3 -o {output_openapi_json} http://localhost:{port}/openapi.json" + ) + + if status != 0: + print(f"Failed to fetch openapi.json from http://localhost:{port}", file=sys.stderr) + print("Please ensure that the desired Parlant server is accessible there.", file=sys.stderr) + sys.exit(1) + + for sdk, repo in PATHDICT_SDK_REPO_TARGETS.items(): + if os.path.isdir(repo): + continue + + raise Exception(f"Missing dir for {sdk}: {repo}") + + print(f"Fetched openapi.json from http://localhost:{port}.") + + if not DIR_FERN.is_dir(): + raise Exception("fern directory not found where expected") + for sdk in PATHDICT_SDK_REPO_TARGETS: + sdk_path = DIR_SDKS / sdk + if not sdk_path.is_dir(): + continue + + print(f"Deleting old {sdk} sdk") + print(f"> rm -rf {sdk_path}") + shutil.rmtree(sdk_path) + + os.chdir(DIR_SCRIPT_ROOT) + + print("Invoking fern generation") + print("> fern generate --log-level=debug") + exit_code, generate_output = subprocess.getstatusoutput("fern generate --log-level=debug") + with open("fern.generate.log", "w") as fern_log: + fern_log.write(generate_output) + if exit_code != os.EX_OK: + raise Exception(generate_output) + + print("Renaming `parlant` to `parlant.client` in python imports") + replace_in_files(DIR_SDKS / "python", "from parlant import", "from parlant.client import") + + print("touching python typing") + + print(f"> touch {DIR_SDKS}/python/py.typed") + open(DIR_SDKS / "python/py.typed", "w") + + for sdk, repo in PATHDICT_SDK_REPO_TARGETS.items(): + print(f"!DANGER! Deleting local `{repo}` directory and all of its contents!") + time.sleep(3) + print(f"> rm -rf {repo}") + shutil.rmtree(repo) + + for sdk, repo in PATHDICT_SDK_REPO_TARGETS.items(): + print(f"copying newly generated {sdk} files to {repo}") + print(f"> cp -rp {DIR_SDKS}/{sdk} {repo}") + shutil.copytree(DIR_SDKS / sdk, repo) diff --git a/scripts/initialize_repo.py b/scripts/initialize_repo.py new file mode 100644 index 0000000..27139c9 --- /dev/null +++ b/scripts/initialize_repo.py @@ -0,0 +1,31 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess +from pathlib import Path + +SCRIPTS_DIR = Path("./scripts") + + +def install_packages() -> None: + subprocess.run(["python", SCRIPTS_DIR / "install_packages.py"]) + + +def install_hooks() -> None: + subprocess.run(["git", "config", "core.hooksPath", ".githooks"], check=True) + + +if __name__ == "__main__": + install_packages() + install_hooks() diff --git a/scripts/install_packages.py b/scripts/install_packages.py new file mode 100644 index 0000000..5463a23 --- /dev/null +++ b/scripts/install_packages.py @@ -0,0 +1,36 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess +import sys + +from utils import Package, die, for_each_package + + +def install_package(package: Package) -> None: + if not package.uses_uv: + print(f"Skipping {package.path}...") + return + + print(f"Installing {package.path}...") + + status, output = subprocess.getstatusoutput(f"uv sync --all-extras --directory {package.path}") + + if status != 0: + print(output, file=sys.stderr) + die(f"error: failed to install package: {package.path}") + + +if __name__ == "__main__": + for_each_package(install_package) diff --git a/scripts/lint.py b/scripts/lint.py new file mode 100755 index 0000000..679f309 --- /dev/null +++ b/scripts/lint.py @@ -0,0 +1,47 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +from functools import partial + +from utils import Package, die, for_each_package + + +def run_cmd_or_die( + cmd: str, + description: str, + package: Package, +) -> None: + print(f"Running {cmd} on {package.name}...") + + status, output = package.run_cmd(cmd) + + if status != 0: + print(output, file=sys.stderr) + die(f"error: package '{package.path}': {description}") + + +def lint_package(mypy: bool, ruff: bool, package: Package) -> None: + if mypy: + run_cmd_or_die("mypy", "Please fix MyPy lint errors", package) + if ruff: + run_cmd_or_die("ruff check", "Please fix Ruff lint errors", package) + run_cmd_or_die("ruff format --check", "Please format files with Ruff", package) + + +if __name__ == "__main__": + mypy = "--mypy" in sys.argv + ruff = "--ruff" in sys.argv + + for_each_package(partial(lint_package, mypy, ruff)) diff --git a/scripts/publish.py b/scripts/publish.py new file mode 100644 index 0000000..0ed4105 --- /dev/null +++ b/scripts/publish.py @@ -0,0 +1,112 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/usr/bin/python3 +import semver # type: ignore +import sys +import subprocess +import toml # type: ignore + +from utils import die, for_each_package, Package, get_packages + + +def get_server_version() -> str: + server_package = next(p for p in get_packages() if p.name == "parlant") + project_file = server_package.path / "pyproject.toml" + pyproject = toml.load(project_file) + version = str(pyproject["tool"]["poetry"]["version"]) + return version + + +def run_command(args: list[str]) -> None: + cmd = " ".join(args) + + print(f"Running {cmd}") + + build_process = subprocess.Popen( + args=args, + stdout=sys.stdout, + stderr=sys.stderr, + ) + + status = build_process.wait() + + if status != 0: + die(f"error: command failed: {cmd}") + + +def publish_docker() -> None: + version = get_server_version() + version_info = semver.parse_version_info(version) + + tag_versions = [ + f"{version_info.major}.{version_info.minor}.{version_info.patch}.{version_info.prerelease}", + ] + + if not version_info.prerelease: + tag_versions = [ + "latest", + f"{version_info.major}", + f"{version_info.major}.{version_info.minor}", + f"{version_info.major}.{version_info.minor}.{version_info.patch}", + ] + else: + tag_versions = [ + f"{version_info.major}.{version_info.minor}.{version_info.patch}.{version_info.prerelease}", + ] + + platforms = [ + "linux/amd64", + "linux/arm64", + ] + + for version in tag_versions: + run_command( + [ + "docker", + "buildx", + "build", + "--platform", + ",".join(platforms), + "-t", + f"ghcr.io/emcie-co/parlant:{version}", + "-f", + "Dockerfile", + "--push", + ".", + ] + ) + + +def publish_package(package: Package) -> None: + if not package.uses_uv or not package.publish: + print(f"Skipping {package.path}...") + return + + status, output = package.run_cmd("uv build") + + if status != 0: + print(output, file=sys.stderr) + die(f"error: package '{package.path}': build failed") + + status, output = package.run_cmd("uv publish") + + if status != 0: + print(output, file=sys.stderr) + die(f"error: package '{package.path}': publish failed") + + +if __name__ == "__main__": + for_each_package(publish_package) + publish_docker() diff --git a/scripts/utils.py b/scripts/utils.py new file mode 100644 index 0000000..75ca39c --- /dev/null +++ b/scripts/utils.py @@ -0,0 +1,80 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import os +from pathlib import Path +import subprocess +import sys +from typing import Callable, NoReturn + + +@dataclass(frozen=True) +class Package: + name: str + path: Path + uses_uv: bool + cmd_prefix: str + publish: bool + + def run_cmd(self, cmd: str) -> tuple[int, str]: + print(f"Running command: {self.cmd_prefix} {cmd}") + return subprocess.getstatusoutput(f"{self.cmd_prefix} {cmd}") + + +def get_repo_root() -> Path: + status, output = subprocess.getstatusoutput("git rev-parse --show-toplevel") + + if status != 0: + print(output, file=sys.stderr) + print("error: failed to get repo root", file=sys.stderr) + sys.exit(1) + + return Path(output.strip()) + + +def get_packages() -> list[Package]: + root = get_repo_root() + + return [ + Package( + name="parlant", + path=root / ".", + cmd_prefix="uv run", + uses_uv=True, + publish=True, + ), + ] + + +def for_each_package( + f: Callable[[Package], None], + enter_dir: bool = True, +) -> None: + for package in get_packages(): + original_cwd = os.getcwd() + + if enter_dir: + print(f"Entering {package.path}...") + os.chdir(package.path) + + try: + f(package) + finally: + os.chdir(original_cwd) + + +def die(message: str) -> NoReturn: + print(message, file=sys.stderr) + sys.exit(1) diff --git a/scripts/version.py b/scripts/version.py new file mode 100644 index 0000000..26da42b --- /dev/null +++ b/scripts/version.py @@ -0,0 +1,172 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/usr/bin/python3 +from functools import partial +from pathlib import Path +import semver # type: ignore +import subprocess +import sys +import re +import toml # type: ignore + +from utils import die, for_each_package, Package, get_packages + + +def get_project_file(package: Package) -> Path: + return package.path / "pyproject.toml" + + +def get_current_version(package: Package) -> str: + content = toml.load(get_project_file(package)) + return str(content["project"]["version"]) + + +def set_package_version(version: str, package: Package) -> None: + if not package.uses_uv: + print(f"Skipping {package.path}...") + return + + current_version = get_current_version(package) + + print(f"Setting {package.name} from version {current_version} to version {version}") + + project_file = get_project_file(package) + + project_file_content = project_file.read_text() + + with open(project_file, "w") as file: + project_file_content = re.sub( + f'\nversion = "{current_version}"\n', + f'\nversion = "{version}"\n', + project_file_content, + count=1, + ) + + project_file_content = re.sub( + f'\nparlant-(.+?) = "{current_version}"\n', + f'\nparlant-\\1 = "{version}"\n', + project_file_content, + ) + + file.write(project_file_content) + + status, output = package.run_cmd("uv lock") + + if status != 0: + print(output, file=sys.stderr) + die("error: failed to re-hash uv lock file") + + +def update_version_variable_in_code(version: str) -> None: + server_package = next(p for p in get_packages() if p.name == "parlant") + version_file: Path = server_package.path / "src/parlant/core/version.py" + + version_file_content = version_file.read_text() + current_version = get_current_version(server_package) + + version_file_content = re.sub( + f'VERSION = "{current_version}"', + f'VERSION = "{version}"', + version_file_content, + ) + + version_file.write_text(version_file_content) + + +def tag_repo(version: str) -> None: + status, output = subprocess.getstatusoutput(f'git tag "v{version}"') + + if status != 0: + print(output, file=sys.stderr) + die(f"error: failed to tag repo: v{version}") + + +def get_current_server_version() -> str: + server_package = next(p for p in get_packages() if p.name == "parlant") + return get_current_version(server_package) + + +def update_version( + current_version: str, + major: bool, + minor: bool, + patch: bool, + rc: bool, + beta: bool, + alpha: bool, +) -> str: + assert sum((major, minor, patch)) <= 1, "Only one component can be bumped" + assert sum((rc, beta, alpha)) <= 1, "Only one pre-release label can be used" + + version = semver.parse_version_info(current_version) + + if major: + version = version.bump_major() + if minor: + version = version.bump_minor() + if patch: + version = version.bump_patch() + + if rc: + version = version.bump_prerelease("rc") + elif beta: + version = version.bump_prerelease("beta") + elif alpha: + version = version.bump_prerelease("alpha") + else: + version = version.finalize_version() + + return str(version) + + +def there_are_pending_git_changes() -> bool: + status, _ = subprocess.getstatusoutput( + "git diff --quiet && git diff --cached --quiet && git ls-files --others --exclude-standard" + ) + return status != 0 + + +def commit_version(version: str) -> bool: + status, _ = subprocess.getstatusoutput(f"git commit -am 'Release {version}' --no-verify") + return status != 0 + + +if __name__ == "__main__": + if there_are_pending_git_changes(): + die("error: version bumps must take place on a clean tree with no pending changes") + + current_version = get_current_server_version() + + major = "--major" in sys.argv + minor = "--minor" in sys.argv + patch = "--patch" in sys.argv + rc = "--rc" in sys.argv + beta = "--beta" in sys.argv + alpha = "--alpha" in sys.argv + + new_version = update_version(current_version, major, minor, patch, rc, beta, alpha) + + if current_version == new_version: + die("error: no component was selected to be bumped") + + answer = input(f"Proceed with bumping {current_version} to {new_version} [N/y]?") + + if answer not in "yY": + die("Canceled.") + + update_version_variable_in_code(new_version) + for_each_package(partial(set_package_version, new_version)) + commit_version(new_version) + tag_repo(new_version) diff --git a/src/parlant/adapters/db/json_file.py b/src/parlant/adapters/db/json_file.py new file mode 100644 index 0000000..6a9c356 --- /dev/null +++ b/src/parlant/adapters/db/json_file.py @@ -0,0 +1,457 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import json +from pathlib import Path +from typing import Any, Awaitable, Callable, Mapping, Optional, Sequence, cast +from typing_extensions import override, Self +import aiofiles + +from parlant.core.persistence.common import ( + Cursor, + SortDirection, + Where, + matches_filters, + ensure_is_total, + ObjectId, +) +from parlant.core.async_utils import ReaderWriterLock +from parlant.core.persistence.document_database import ( + CollectionIndex, + CollectionSort, + BaseDocument, + DeleteResult, + DocumentCollection, + DocumentDatabase, + FindResult, + InsertResult, + TDocument, + UpdateResult, + identity_loader, +) +from parlant.core.loggers import Logger + + +class JSONFileDocumentDatabase(DocumentDatabase): + def __init__( + self, + logger: Logger, + file_path: Path, + ) -> None: + self.file_path = file_path + + self._logger = logger + self._op_counter = 0 + + self._lock = ReaderWriterLock() + + if not self.file_path.exists(): + self.file_path.write_text(json.dumps({})) + + self._raw_data: dict[str, Any] = {} + self._collections: dict[str, JSONFileDocumentCollection[BaseDocument]] = {} + + async def flush(self) -> None: + async with self._lock.writer_lock: + await self._flush_unlocked() + + async def __aenter__(self) -> Self: + async with self._lock.reader_lock: + self._raw_data = await self._load_raw_data() + + return self + + async def __aexit__( + self, + exc_type: Optional[type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[object], + ) -> bool: + async with self._lock.writer_lock: + await self._flush_unlocked() + return False + + async def _load_raw_data( + self, + ) -> dict[str, Any]: + # Return an empty JSON object if the file is empty + if self.file_path.stat().st_size == 0: + return {} + + async with aiofiles.open(self.file_path, "r", encoding="utf-8") as file: + return cast(dict[str, Any], json.loads(await file.read())) + + async def _save_data( + self, + data: Mapping[str, Sequence[Mapping[str, Any]]], + ) -> None: + async with aiofiles.open(self.file_path, mode="w", encoding="utf-8") as file: + json_string = json.dumps( + { + **self._raw_data, + **data, + }, + ensure_ascii=False, + indent=2, + ) + await file.write(json_string) + + async def load_documents_with_loader( + self, + name: str, + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + documents: Sequence[BaseDocument] | None = None, + ) -> Sequence[TDocument]: + data: list[TDocument] = [] + failed_migrations: list[BaseDocument] = [] + + collection_documents = documents or self._raw_data.get(name, []) + + for doc in collection_documents: + try: + if loaded_doc := await document_loader(doc): + data.append(loaded_doc) + else: + self._logger.warning(f'Failed to load document "{doc}"') + failed_migrations.append(doc) + except Exception as e: + self._logger.error( + f"Failed to load document '{doc}' with error: {e}. Added to failed migrations collection." + ) + failed_migrations.append(doc) + + if failed_migrations: + failed_migrations_collection = await self.get_or_create_collection( + "failed_migrations", BaseDocument, identity_loader + ) + + for doc in failed_migrations: + await failed_migrations_collection.insert_one(doc) + + return data + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + ) -> JSONFileDocumentCollection[TDocument]: + self._collections[name] = JSONFileDocumentCollection( + database=self, + name=name, + schema=schema, + ) + + return cast(JSONFileDocumentCollection[TDocument], self._collections[name]) + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> JSONFileDocumentCollection[TDocument]: + if collection := self._collections.get(name): + return cast(JSONFileDocumentCollection[TDocument], collection) + + elif name in self._raw_data: + self._collections[name] = JSONFileDocumentCollection( + database=self, + name=name, + schema=schema, + data=await self.load_documents_with_loader(name, document_loader), + ) + return cast(JSONFileDocumentCollection[TDocument], self._collections[name]) + + raise ValueError(f'Collection "{name}" does not exists') + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> JSONFileDocumentCollection[TDocument]: + if collection := self._collections.get(name): + return cast(JSONFileDocumentCollection[TDocument], collection) + + elif name in self._raw_data: + self._collections[name] = JSONFileDocumentCollection( + database=self, + name=name, + schema=schema, + data=await self.load_documents_with_loader(name, document_loader), + ) + return cast(JSONFileDocumentCollection[TDocument], self._collections[name]) + + self._collections[name] = JSONFileDocumentCollection( + database=self, + name=name, + schema=schema, + data=await self.load_documents_with_loader(name, document_loader), + ) + + return cast(JSONFileDocumentCollection[TDocument], self._collections[name]) + + @override + async def delete_collection( + self, + name: str, + ) -> None: + if name in self._collections: + del self._collections[name] + return + + raise ValueError(f'Collection "{name}" does not exists') + + async def _flush_unlocked(self) -> None: + data = {} + for collection_name in self._collections: + data[collection_name] = self._collections[collection_name].documents + await self._save_data(data) + + +class JSONFileDocumentCollection(DocumentCollection[TDocument]): + def __init__( + self, + database: JSONFileDocumentDatabase, + name: str, + schema: type[TDocument], + data: Sequence[TDocument] | None = None, + ) -> None: + self._database = database + self._name = name + self._schema = schema + self._op_counter = 0 + + self._lock = ReaderWriterLock() + + self.documents = list(data) if data else [] + + @override + async def find( + self, + filters: Where, + limit: Optional[int] = None, + cursor: Optional[Cursor] = None, + sort_direction: Optional[SortDirection] = None, + ) -> FindResult[TDocument]: + async with self._lock.reader_lock: + # First, filter documents + filtered_docs = [doc for doc in self.documents if matches_filters(filters, doc)] + + # Sort by creation_utc with id as tiebreaker according to sort_direction + sort_direction = sort_direction or SortDirection.ASC + filtered_docs = self._apply_sort(filtered_docs, sort_direction) + + # Apply cursor-based pagination if cursor is provided + if cursor: + filtered_docs = self._apply_cursor_filter(filtered_docs, cursor, sort_direction) + + total_count = len(filtered_docs) + + # Apply limit + has_more = False + next_cursor = None + + if limit is not None and len(filtered_docs) > limit: + # There are more items beyond the limit + has_more = True + result_docs = filtered_docs[:limit] + + # Generate next cursor from the last item if we have results + if result_docs: + last_doc = result_docs[-1] + next_cursor = Cursor( + creation_utc=str(last_doc.get("creation_utc", "")), + id=ObjectId(str(last_doc.get("id", ""))), + ) + else: + result_docs = filtered_docs + + return FindResult( + items=result_docs, + total_count=total_count, + has_more=has_more, + next_cursor=next_cursor, + ) + + def _apply_sort( + self, + documents: list[TDocument], + sort_direction: SortDirection, + ) -> list[TDocument]: + docs = list(documents) # don't mutate input + + # Sort by creation_utc with id as tiebreaker according to sort_direction + reverse_order = sort_direction == SortDirection.DESC + docs.sort( + key=lambda d: ( + d.get("creation_utc") or "", # Primary sort: creation_utc + d.get("id") or "", # Tiebreaker: id + ), + reverse=reverse_order, + ) + + return docs + + def _apply_field_sort( + self, + documents: Sequence[TDocument], + sort: CollectionSort, + ) -> list[TDocument]: + docs = list(documents) + + for field_name, direction in reversed(sort): + docs.sort( + key=lambda d: cast(Any, d.get(field_name)), + reverse=direction == SortDirection.DESC, + ) + + return docs + + def _apply_cursor_filter( + self, + documents: list[TDocument], + cursor: Cursor, + sort_direction: SortDirection, + ) -> list[TDocument]: + result = [] + + for doc in documents: + doc_creation_utc = str(doc.get("creation_utc", "")) + doc_id = str(doc.get("id", "")) + + if sort_direction == SortDirection.DESC: + # For descending order pagination, include documents that come after the cursor + # This matches the MongoDB query pattern: + # { "$or": [ + # { "creation_utc": { "$lt": cursor.creation_utc } }, + # { "creation_utc": cursor.creation_utc, "id": { "$lt": cursor.id } } + # ]} + if doc_creation_utc < cursor.creation_utc or ( + doc_creation_utc == cursor.creation_utc and doc_id < cursor.id + ): + result.append(doc) + else: # SortDirection.ASC + # For ascending order pagination, include documents that come after the cursor + # { "$or": [ + # { "creation_utc": { "$gt": cursor_creation_utc } }, + # { "creation_utc": cursor.creation_utc, "id": { "$gt": cursor.id } } + # ]} + if doc_creation_utc > cursor.creation_utc or ( + doc_creation_utc == cursor.creation_utc and doc_id > cursor.id + ): + result.append(doc) + + return result + + @override + async def find_one( + self, + filters: Where, + sort: Optional[CollectionSort] = None, + ) -> Optional[TDocument]: + async with self._lock.reader_lock: + matching_documents = [doc for doc in self.documents if matches_filters(filters, doc)] + + if sort: + matching_documents = self._apply_field_sort(matching_documents, sort) + + for doc in matching_documents: + return doc + + return None + + @override + async def ensure_indexes( + self, + indexes: Sequence[CollectionIndex], + ) -> None: + return None + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + async with self._lock.writer_lock: + self.documents.append(document) + + await self._database.flush() + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + async with self._lock.writer_lock: + for i, d in enumerate(self.documents): + if matches_filters(filters, d): + self.documents[i] = cast(TDocument, {**self.documents[i], **params}) + + await self._database.flush() + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=self.documents[i], + ) + + if upsert: + await self.insert_one(params) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + async with self._lock.writer_lock: + for i, d in enumerate(self.documents): + if matches_filters(filters, d): + document = self.documents.pop(i) + + await self._database.flush() + + return DeleteResult( + deleted_count=1, acknowledged=True, deleted_document=document + ) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) diff --git a/src/parlant/adapters/db/mongo_db.py b/src/parlant/adapters/db/mongo_db.py new file mode 100644 index 0000000..c3f9b84 --- /dev/null +++ b/src/parlant/adapters/db/mongo_db.py @@ -0,0 +1,310 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Any, Awaitable, Callable, Optional, Sequence +from bson import CodecOptions +from typing_extensions import Self +from parlant.core.loggers import Logger +from parlant.core.persistence.common import Cursor, SortDirection, Where, ObjectId +from parlant.core.persistence.document_database import ( + CollectionIndex, + CollectionSort, + BaseDocument, + DeleteResult, + DocumentCollection, + DocumentDatabase, + FindResult, + InsertResult, + TDocument, + UpdateResult, +) +from pymongo import AsyncMongoClient +from pymongo.asynchronous.database import AsyncDatabase +from pymongo.asynchronous.collection import AsyncCollection + + +class MongoDocumentDatabase(DocumentDatabase): + def __init__( + self, + mongo_client: AsyncMongoClient[Any], + database_name: str, + logger: Logger, + ): + self.mongo_client: AsyncMongoClient[Any] = mongo_client + self.database_name = database_name + + self._logger = logger + + self._database: Optional[AsyncDatabase[Any]] = None + self._collections: dict[str, MongoDocumentCollection[Any]] = {} + + async def create_collection( + self, + name: str, + schema: type[TDocument], + ) -> DocumentCollection[TDocument]: + if self._database is None: + raise Exception("underlying database missing.") + + collection = await self._database.create_collection( + name=name, + codec_options=CodecOptions(document_class=schema), + ) + + self._collections[name] = MongoDocumentCollection(self, collection) + await self._collections[name].ensure_indexes( + [ + CollectionIndex( + fields=( + ("creation_utc", SortDirection.ASC), + ("id", SortDirection.ASC), + ) + ) + ] + ) + return self._collections[name] + + async def get_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[TDocument | None]], + ) -> DocumentCollection[TDocument]: + if self._database is None: + raise Exception("underlying database missing.") + + result_collection = self._database.get_collection( + name=name, + codec_options=CodecOptions(document_class=schema), + ) + + failed_migrations_collection_name = f"{self.database_name}_{name}_failed_migrations" + collection_existing_documents = result_collection.find({}) + if failed_migrations_collection_name in await self._database.list_collection_names(): + self._logger.info(f"deleting old `{failed_migrations_collection_name}` collection") + await self.delete_collection(failed_migrations_collection_name) + + failed_migration_collection: Optional[DocumentCollection[TDocument]] = None + async for doc in collection_existing_documents: + try: + original_version = doc.get("version") + if loaded_doc := await document_loader(doc): + # Only rewrite if the document was actually migrated (version changed or new dict created) + if loaded_doc is not doc or loaded_doc.get("version") != original_version: + # Use _id for efficient lookup instead of the full document + await result_collection.replace_one({"_id": doc["_id"]}, loaded_doc) + continue + + if failed_migration_collection is None: + self._logger.warning( + f"creating: `{failed_migrations_collection_name}` collection to store failed migrations..." + ) + failed_migration_collection = await self.create_collection( + failed_migrations_collection_name, schema + ) + + self._logger.warning(f'failed to load document "{doc}"') + await failed_migration_collection.insert_one(doc) + await result_collection.delete_one(doc) + except Exception as e: + if failed_migration_collection is None: + self._logger.warning( + f"creating: `{failed_migrations_collection_name}` collection to store failed migrations..." + ) + failed_migration_collection = await self.create_collection( + failed_migrations_collection_name, schema + ) + + self._logger.error( + f"failed to load document '{doc}' with error: {e}. Added to `{failed_migrations_collection_name}` collection." + ) + await failed_migration_collection.insert_one(doc) + + self._collections[name] = MongoDocumentCollection(self, result_collection) + await self._collections[name].ensure_indexes( + [ + CollectionIndex( + fields=( + ("creation_utc", SortDirection.ASC), + ("id", SortDirection.ASC), + ) + ) + ] + ) + return self._collections[name] + + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[TDocument | None]], + ) -> DocumentCollection[TDocument]: + return await self.get_collection(name, schema, document_loader) + + async def delete_collection(self, name: str) -> None: + if self._database is None: + raise Exception("underlying database missing.") + + await self._database.drop_collection(name) + + async def __aenter__(self) -> Self: + self._database = self.mongo_client[self.database_name] + return self + + async def __aexit__( + self, + exc_type: Optional[type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[object], + ) -> bool: + if self._database is not None: + self._database = None + + return False + + +class MongoDocumentCollection(DocumentCollection[TDocument]): + def __init__( + self, + mongo_document_database: MongoDocumentDatabase, + mongo_collection: AsyncCollection[TDocument], + ) -> None: + self._database = mongo_document_database + self._collection = mongo_collection + + async def find( + self, + filters: Where, + limit: Optional[int] = None, + cursor: Optional[Cursor] = None, + sort_direction: Optional[SortDirection] = None, + ) -> FindResult[TDocument]: + query = dict(filters) if filters else {} + sort_direction = sort_direction or SortDirection.ASC + + if cursor is not None: + if sort_direction == SortDirection.DESC: + cursor_conditions = [ + {"creation_utc": {"$lt": cursor.creation_utc}}, + { + "$and": [ + {"creation_utc": cursor.creation_utc}, + {"id": {"$lt": cursor.id}}, + ] + }, + ] + else: + cursor_conditions = [ + {"creation_utc": {"$gt": cursor.creation_utc}}, + { + "$and": [ + {"creation_utc": cursor.creation_utc}, + {"id": {"$gt": cursor.id}}, + ] + }, + ] + query["$or"] = cursor_conditions + + # Sort by creation_utc with id as tiebreaker according to sort_direction + sort_order = -1 if sort_direction == SortDirection.DESC else 1 + sort_spec = [("creation_utc", sort_order), ("id", sort_order)] + + # Get one extra document to check if there are more + query_limit = (limit + 1) if limit else None + + mongo_cursor = self._collection.find(query).sort(sort_spec) + if query_limit: + mongo_cursor = mongo_cursor.limit(query_limit) + + items = await mongo_cursor.to_list(length=query_limit) + + # Calculate pagination metadata + has_more = False + next_cursor = None + total_count = len(items) + + if limit and len(items) > limit: + has_more = True + items = items[:limit] # Remove the extra item + + # Create cursor from the last item + if items: + last_item = items[-1] + next_cursor = Cursor( + creation_utc=str(last_item.get("creation_utc", "")), + id=ObjectId(str(last_item.get("id", ""))), + ) + + return FindResult( + items=items, total_count=total_count, has_more=has_more, next_cursor=next_cursor + ) + + def _translate_sort( + self, + sort: CollectionSort, + ) -> list[tuple[str, int]]: + return [ + (field_name, -1 if direction == SortDirection.DESC else 1) + for field_name, direction in sort + ] + + async def find_one( + self, + filters: Where, + sort: Optional[CollectionSort] = None, + ) -> TDocument | None: + mongo_sort = self._translate_sort(sort) if sort else None + result = await self._collection.find_one(filters, sort=mongo_sort) + return result + + async def ensure_indexes( + self, + indexes: Sequence[CollectionIndex], + ) -> None: + for index in indexes: + await self._collection.create_index( + self._translate_sort(index.fields), + unique=index.unique, + ) + + async def insert_one(self, document: TDocument) -> InsertResult: + insert_result = await self._collection.insert_one(document) + return InsertResult(acknowledged=insert_result.acknowledged) + + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + update_result = await self._collection.update_one(filters, {"$set": params}, upsert) + result_document = await self._collection.find_one(filters) + return UpdateResult[TDocument]( + update_result.acknowledged, + update_result.matched_count, + update_result.modified_count, + result_document, + ) + + async def delete_one(self, filters: Where) -> DeleteResult[TDocument]: + result_document = await self._collection.find_one(filters) + if result_document is None: + return DeleteResult(True, 0, None) + + delete_result = await self._collection.delete_one(filters) + return DeleteResult( + delete_result.acknowledged, + deleted_count=delete_result.deleted_count, + deleted_document=result_document, + ) diff --git a/src/parlant/adapters/db/snowflake_db.py b/src/parlant/adapters/db/snowflake_db.py new file mode 100644 index 0000000..a56defa --- /dev/null +++ b/src/parlant/adapters/db/snowflake_db.py @@ -0,0 +1,771 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Maintainer: Tao Tang + +from __future__ import annotations + +import asyncio +import importlib +import json +import os +import re +from typing import ( + Any, + Awaitable, + Callable, + Literal, + Mapping, + MutableMapping, + Optional, + Sequence, + cast, +) + +from typing_extensions import Self + +from parlant.core.loggers import Logger +from parlant.core.persistence.common import Cursor, ObjectId, SortDirection, Where, ensure_is_total +from parlant.core.persistence.document_database import ( + CollectionIndex, + CollectionSort, + BaseDocument, + DeleteResult, + DocumentCollection, + DocumentDatabase, + FindResult, + InsertResult, + TDocument, + UpdateResult, +) + + +class SnowflakeAdapterError(Exception): + """Raised for recoverable adapter errors.""" + + +_IDENTIFIER_RE = re.compile(r"[^0-9A-Za-z_]") + + +def _sanitize_identifier(raw: str) -> str: + sanitized = _IDENTIFIER_RE.sub("_", raw).upper() + if not sanitized: + raise SnowflakeAdapterError("Snowflake identifier cannot be empty") + + if sanitized[0].isdigit(): + return f"_{sanitized}" + + return sanitized + + +def _stringify(value: Any) -> Optional[str]: + if value is None: + return None + + object_id_type = getattr(ObjectId, "__supertype__", str) + if isinstance(value, object_id_type): + return str(value) + + return str(value) + + +def _load_connection_params_from_env() -> dict[str, Any]: + env = os.environ + required = [ + "SNOWFLAKE_ACCOUNT", + "SNOWFLAKE_USER", + "SNOWFLAKE_WAREHOUSE", + "SNOWFLAKE_DATABASE", + "SNOWFLAKE_SCHEMA", + ] + + missing = [key for key in required if not env.get(key)] + if missing: + raise SnowflakeAdapterError( + "Missing Snowflake configuration. Set the following environment variables: " + + ", ".join(missing) + ) + + params: dict[str, Any] = { + "account": env["SNOWFLAKE_ACCOUNT"], + "user": env["SNOWFLAKE_USER"], + "warehouse": env["SNOWFLAKE_WAREHOUSE"], + "database": env["SNOWFLAKE_DATABASE"], + "schema": env["SNOWFLAKE_SCHEMA"], + } + + if env.get("SNOWFLAKE_ROLE"): + params["role"] = env["SNOWFLAKE_ROLE"] + + token = env.get("SNOWFLAKE_TOKEN") + password = env.get("SNOWFLAKE_PASSWORD") + + if token: + params["authenticator"] = "oauth" + params["token"] = token + elif password: + params["authenticator"] = env.get("SNOWFLAKE_AUTHENTICATOR", "snowflake") + params["password"] = password + else: + raise SnowflakeAdapterError( + "Provide either SNOWFLAKE_PASSWORD or SNOWFLAKE_TOKEN for authentication" + ) + + return params + + +FetchMode = Literal["none", "all", "one"] + + +class SnowflakeDocumentDatabase(DocumentDatabase): + def __init__( + self, + logger: Logger, + connection_params: Mapping[str, Any] | None = None, + *, + table_prefix: str | None = None, + connection_factory: Callable[[Mapping[str, Any]], Any] | None = None, + ) -> None: + self._logger = logger + self._connection_params = ( + dict(connection_params) + if connection_params is not None + else _load_connection_params_from_env() + ) + self._table_prefix = _sanitize_identifier(table_prefix) if table_prefix else "PARLANT_" + self._connection_factory = connection_factory + + self._connector_module: Any | None = None + self._snowflake_error: type[BaseException] | None = None + self._dict_cursor_cls: Any | None = None + self._connection: Any | None = None + + self._collections: dict[str, SnowflakeDocumentCollection[Any]] = {} + self._initialized: set[str] = set() + self._init_locks: dict[str, asyncio.Lock] = {} + + self._connection_lock = asyncio.Lock() + self._operation_lock = asyncio.Lock() + + async def __aenter__(self) -> Self: + await self._ensure_connection() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: object | None, + ) -> bool: + if self._connection is not None: + await asyncio.to_thread(self._connection.close) + self._connection = None + + return False + + async def create_collection( + self, + name: str, + schema: type[TDocument], + ) -> SnowflakeDocumentCollection[TDocument]: + return await self._get_or_create_initialized_collection( + name, + schema, + document_loader=None, + ) + + async def get_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> SnowflakeDocumentCollection[TDocument]: + return await self._get_or_create_initialized_collection( + name, + schema, + document_loader=document_loader, + ) + + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> SnowflakeDocumentCollection[TDocument]: + return await self.get_collection(name, schema, document_loader) + + async def delete_collection(self, name: str) -> None: + table = self._table_identifier(name) + failed_table = self._failed_table_identifier(name) + await self._execute(f"DROP TABLE IF EXISTS {table}") + await self._execute(f"DROP TABLE IF EXISTS {failed_table}") + self._collections.pop(name, None) + + async def _get_or_create_initialized_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]] | None, + ) -> SnowflakeDocumentCollection[TDocument]: + if name not in self._collections: + self._collections[name] = SnowflakeDocumentCollection( + database=self, + name=name, + schema=schema, + logger=self._logger, + ) + + collection = cast(SnowflakeDocumentCollection[TDocument], self._collections[name]) + + if name in self._initialized: + return collection + + lock = self._init_locks.setdefault(name, asyncio.Lock()) + async with lock: + if name in self._initialized: + return collection + + create_stmt = f""" + CREATE TABLE IF NOT EXISTS {collection._table} ( + ID STRING NOT NULL, + VERSION STRING, + CREATION_UTC STRING, + DATA VARIANT, + PRIMARY KEY (ID) + ) + """ + + await self._execute(create_stmt) + await self._execute( + f""" + CREATE TABLE IF NOT EXISTS {collection._failed_table} ( + ID STRING, + DATA VARIANT + ) + """ + ) + + if document_loader is not None: + await self.load_documents_with_loader(collection, document_loader) + + self._initialized.add(name) + return collection + + async def load_documents_with_loader( + self, + collection: SnowflakeDocumentCollection[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> None: + rows = await self._execute( + f"SELECT DATA FROM {collection._table}", + fetch="all", + ) + + failed: list[BaseDocument] = [] + for row in rows or []: + doc = collection._row_to_document(row) + try: + migrated = await document_loader(doc) + except Exception as exc: # pragma: no cover + self._logger.error( + f"Failed to load document '{doc.get('id')}' in collection '{collection._name}': {exc}" + ) + failed.append(doc) + continue + + if migrated is None: + failed.append(doc) + continue + + if migrated is not doc: + await collection._replace_document(migrated) + + if failed: + await collection._persist_failed_documents(failed) + await collection._delete_documents([doc["id"] for doc in failed if "id" in doc]) + + async def _execute( + self, + sql: str, + params: Mapping[str, Any] | Sequence[Any] | None = None, + *, + fetch: FetchMode = "none", + ) -> Any: + await self._ensure_connection() + + async with self._operation_lock: + return await asyncio.to_thread(self._run_query, sql, params, fetch) + + def _run_query( + self, + sql: str, + params: Mapping[str, Any] | Sequence[Any] | None, + fetch: FetchMode, + ) -> Any: + assert self._connection is not None + cursor = ( + self._connection.cursor(self._dict_cursor_cls) + if self._dict_cursor_cls is not None + else self._connection.cursor() + ) + + try: + cursor.execute(sql, params) + if fetch == "all": + return cursor.fetchall() + if fetch == "one": + return cursor.fetchone() + return None + except Exception as exc: # pragma: no cover - wrapped below + if self._snowflake_error and isinstance(exc, self._snowflake_error): + raise SnowflakeAdapterError(f"Snowflake query failed: {exc}") from exc + raise + finally: + cursor.close() + + async def _ensure_connection(self) -> None: + if self._connection is not None: + return + + async with self._connection_lock: + if self._connection is not None: + return + + self._import_connector() + + if self._connection_factory is not None: + self._connection = self._connection_factory(self._connection_params) + else: + assert self._connector_module is not None + self._connection = await asyncio.to_thread( + self._connector_module.connect, + **self._connection_params, + ) + + def _import_connector(self) -> None: + if self._connector_module is not None: + return + + try: + connector_module = importlib.import_module("snowflake.connector") + except ImportError as exc: # pragma: no cover - exercised when dependency missing + raise SnowflakeAdapterError( + "Snowflake adapter requires snowflake-connector-python. Install parlant[snowflake]." + ) from exc + + self._connector_module = connector_module + self._dict_cursor_cls = getattr(connector_module, "DictCursor", None) + + try: + errors_module = importlib.import_module("snowflake.connector.errors") + self._snowflake_error = getattr(errors_module, "Error", None) + except ImportError: + self._snowflake_error = None + + def _table_identifier(self, name: str) -> str: + return f'"{_sanitize_identifier(self._table_prefix + name)}"' + + def _failed_table_identifier(self, name: str) -> str: + return f'"{_sanitize_identifier(self._table_prefix + name + "_failed_migrations")}"' + + +class SnowflakeDocumentCollection(DocumentCollection[TDocument]): + INDEXED_FIELDS = { + "id", + "version", + "creation_utc", + } + + def __init__( + self, + database: SnowflakeDocumentDatabase, + name: str, + schema: type[TDocument], + logger: Logger, + ) -> None: + self._database = database + self._name = name + self._schema = schema + self._logger = logger + + self._table = self._database._table_identifier(name) + self._failed_table = self._database._failed_table_identifier(name) + + async def find( + self, + filters: Where, + limit: Optional[int] = None, + cursor: Optional[Cursor] = None, + sort_direction: Optional[SortDirection] = None, + ) -> FindResult[TDocument]: + sort_direction = sort_direction or SortDirection.ASC + + base_clause, base_params = _build_where_clause(filters, self.INDEXED_FIELDS) + params: dict[str, Any] = dict(base_params) + + cursor_clause, cursor_params = _build_cursor_clause(cursor, sort_direction) + clause = base_clause + if cursor_clause: + clause = f"{clause} AND {cursor_clause}" if clause else f"WHERE {cursor_clause}" + params.update(cursor_params) + + order_direction = "DESC" if sort_direction == SortDirection.DESC else "ASC" + order_by = f"ORDER BY CREATION_UTC {order_direction}, ID {order_direction}" + + query_limit = (limit + 1) if limit else None + limit_sql = f" LIMIT {query_limit}" if query_limit else "" + + sql = f"SELECT DATA FROM {self._table}" + if clause: + sql += f" {clause}" + sql += f" {order_by}{limit_sql}" + + rows = await self._database._execute(sql, params or None, fetch="all") + documents = [cast(TDocument, self._row_to_document(row)) for row in rows or []] + + total_count = len(documents) + has_more = False + next_cursor = None + + if limit and len(documents) > limit: + has_more = True + documents = documents[:limit] + + if documents: + last_doc = documents[-1] + creation_utc = last_doc.get("creation_utc") + identifier = last_doc.get("id") + + if creation_utc is not None and identifier is not None: + next_cursor = Cursor( + creation_utc=str(creation_utc), + id=ObjectId(str(identifier)), + ) + + return FindResult( + items=documents, + total_count=total_count, + has_more=has_more, + next_cursor=next_cursor, + ) + + def _apply_field_sort( + self, + documents: Sequence[TDocument], + sort: CollectionSort, + ) -> list[TDocument]: + docs = list(documents) + + for field_name, direction in reversed(sort): + docs.sort( + key=lambda d: cast(Any, d.get(field_name)), + reverse=direction == SortDirection.DESC, + ) + + return docs + + async def find_one( + self, + filters: Where, + sort: Optional[CollectionSort] = None, + ) -> Optional[TDocument]: + if sort: + matching_documents = list((await self.find(filters=filters)).items) + sorted_documents = self._apply_field_sort(matching_documents, sort) + return sorted_documents[0] if sorted_documents else None + + clause, params = _build_where_clause(filters, self.INDEXED_FIELDS) + sql = f"SELECT DATA FROM {self._table} {clause} LIMIT 1" + row = await self._database._execute(sql, params, fetch="one") + if not row: + return None + + return cast(TDocument, self._row_to_document(row)) + + async def ensure_indexes( + self, + indexes: Sequence[CollectionIndex], + ) -> None: + return None + + async def insert_one(self, document: TDocument) -> InsertResult: + ensure_is_total(document, self._schema) + + params = self._serialize_document(document) + sql = f""" + INSERT INTO {self._table} + (ID, VERSION, CREATION_UTC, DATA) + SELECT + V.ID, + V.VERSION, + V.CREATION_UTC, + PARSE_JSON(V.DATA_RAW) + FROM VALUES ( + %(id)s, + %(version)s, + %(creation_utc)s, + %(data)s + ) AS V(ID, VERSION, CREATION_UTC, DATA_RAW) + """ + + await self._database._execute(sql, params) + return InsertResult(acknowledged=True) + + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + existing = await self.find_one(filters) + + if existing: + updated_document = cast(TDocument, {**existing, **params}) + await self._replace_document(updated_document) + return UpdateResult( + True, + matched_count=1, + modified_count=1, + updated_document=updated_document, + ) + + if upsert: + await self.insert_one(params) + return UpdateResult(True, matched_count=0, modified_count=0, updated_document=params) + + return UpdateResult(True, matched_count=0, modified_count=0, updated_document=None) + + async def delete_one(self, filters: Where) -> DeleteResult[TDocument]: + existing = await self.find_one(filters) + if not existing: + return DeleteResult(True, deleted_count=0, deleted_document=None) + + identifier = existing.get("id") + if identifier is None: + return DeleteResult(True, deleted_count=0, deleted_document=None) + + await self._delete_documents([identifier]) + + return DeleteResult(True, deleted_count=1, deleted_document=existing) + + def _row_to_document(self, row: Any) -> BaseDocument: + if isinstance(row, Mapping): + data = row.get("DATA") + else: + data = row[0] + + if isinstance(data, str): + return cast(BaseDocument, json.loads(data)) + + return cast(BaseDocument, data) + + async def _replace_document(self, document: TDocument) -> None: + params = self._serialize_document(document) + sql = f""" + UPDATE {self._table} + SET VERSION=%(version)s, + CREATION_UTC=%(creation_utc)s, + DATA=PARSE_JSON(%(data)s) + WHERE ID=%(id)s + """ + await self._database._execute(sql, params) + + async def _delete_documents(self, identifiers: Sequence[Any]) -> None: + if not identifiers: + return + + placeholders = ", ".join(f"%(id_{i})s" for i in range(len(identifiers))) + params = {f"id_{i}": _stringify(value) for i, value in enumerate(identifiers)} + sql = f"DELETE FROM {self._table} WHERE ID IN ({placeholders})" + await self._database._execute(sql, params) + + async def _persist_failed_documents(self, documents: Sequence[BaseDocument]) -> None: + if not documents: + return + + for doc in documents: + params = { + "id": _stringify(doc.get("id")), + "data": json.dumps(doc, ensure_ascii=False), + } + + sql = f""" + INSERT INTO {self._failed_table} (ID, DATA) + SELECT + V.ID, + PARSE_JSON(V.DATA_RAW) + FROM VALUES (%(id)s, %(data)s) AS V(ID, DATA_RAW) + """ + await self._database._execute(sql, params) + + def _serialize_document(self, document: TDocument) -> MutableMapping[str, Any]: + return { + "id": _stringify(document["id"]), + "version": document.get("version"), + "creation_utc": document.get("creation_utc"), + "data": json.dumps(document, ensure_ascii=False), + } + + +def _build_where_clause(filters: Where, indexed_fields: set[str]) -> tuple[str, Mapping[str, Any]]: + if not filters: + return "", {} + + translator = _WhereTranslator(indexed_fields) + clause = translator.render(filters) + if not clause: + return "", {} + + return f"WHERE {clause}", translator.params + + +def _build_cursor_clause( + cursor: Cursor | None, + sort_direction: SortDirection, +) -> tuple[str, Mapping[str, Any]]: + if cursor is None: + return "", {} + + creation_operator = "<" if sort_direction == SortDirection.DESC else ">" + id_operator = "<" if sort_direction == SortDirection.DESC else ">" + + clause = ( + f"(CREATION_UTC {creation_operator} %(cursor_creation)s " + f"OR (CREATION_UTC = %(cursor_creation)s AND ID {id_operator} %(cursor_id)s))" + ) + + params = { + "cursor_creation": cursor.creation_utc, + "cursor_id": str(cursor.id), + } + + return clause, params + + +class _WhereTranslator: + def __init__(self, indexed_fields: set[str]) -> None: + self._indexed_fields = indexed_fields + self._params: dict[str, Any] = {} + self._counter = 0 + + @property + def params(self) -> Mapping[str, Any]: + return self._params + + def render(self, filters: Where) -> str: + return self._render(filters) + + def _render(self, filters: Where) -> str: + if not filters: + return "" + + if isinstance(filters, Mapping): + fragments: list[str] = [] + for key, value in filters.items(): + if key == "$and": + parts = [self._render(part) for part in cast(Sequence[Where], value)] + parts = [part for part in parts if part] + if parts: + fragments.append("(" + " AND ".join(parts) + ")") + elif key == "$or": + parts = [self._render(part) for part in cast(Sequence[Where], value)] + parts = [part for part in parts if part] + if parts: + fragments.append("(" + " OR ".join(parts) + ")") + else: + fragments.append(self._render_field(key, value)) + + return " AND ".join(part for part in fragments if part) + + raise SnowflakeAdapterError("Unsupported filter format for Snowflake adapter") + + def _render_field(self, field: str, condition: Any) -> str: + if not isinstance(condition, Mapping): + return self._equality_clause(field, condition) + + clauses: list[str] = [] + for operator, operand in condition.items(): + if operator == "$eq": + clauses.append(self._equality_clause(field, operand)) + elif operator in {"$gt", "$gte", "$lt", "$lte", "$ne"}: + clauses.append(self._comparison_clause(field, operator, operand)) + elif operator == "$in": + clauses.append(self._membership_clause(field, operand, negate=False)) + elif operator == "$nin": + clauses.append(self._membership_clause(field, operand, negate=True)) + else: + raise SnowflakeAdapterError( + f"Unsupported operator '{operator}' in Snowflake filter" + ) + + return " AND ".join(clauses) + + def _membership_clause(self, field: str, operand: Any, *, negate: bool) -> str: + values = list(operand or []) + if not values: + return "1=1" if negate else "1=0" + + column, needs_variant = self._column_expr(field) + placeholders: list[str] = [] + for value in values: + name = self._add_param(value) + placeholders.append(self._wrap_value(name, needs_variant)) + + operator = "NOT IN" if negate else "IN" + return f"{column} {operator} (" + ", ".join(placeholders) + ")" + + def _equality_clause(self, field: str, operand: Any) -> str: + name = self._add_param(operand) + column, needs_variant = self._column_expr(field) + return f"{column} = {self._wrap_value(name, needs_variant)}" + + def _column_expr(self, field: str) -> tuple[str, bool]: + sanitized = _sanitize_identifier(field) + if field in self._indexed_fields: + return f'"{sanitized}"', False + + json_path = json.dumps(field) + return f"DATA:{json_path}", True + + def _wrap_value(self, placeholder: str, needs_variant: bool) -> str: + return f"TO_VARIANT({placeholder})" if needs_variant else placeholder + + def _comparison_clause(self, field: str, operator: str, operand: Any) -> str: + sql_operator = { + "$gt": ">", + "$gte": ">=", + "$lt": "<", + "$lte": "<=", + "$ne": "!=", + }[operator] + + name = self._add_param(operand) + column, needs_variant = self._column_expr(field) + return f"{column} {sql_operator} {self._wrap_value(name, needs_variant)}" + + def _add_param(self, value: Any) -> str: + name = f"param_{self._counter}" + self._counter += 1 + object_id_type = getattr(ObjectId, "__supertype__", str) + if isinstance(value, object_id_type): + value = str(value) + self._params[name] = value + return f"%({name})s" + + +__all__ = [ + "SnowflakeAdapterError", + "SnowflakeDocumentCollection", + "SnowflakeDocumentDatabase", +] diff --git a/src/parlant/adapters/db/transient.py b/src/parlant/adapters/db/transient.py new file mode 100644 index 0000000..27bfef6 --- /dev/null +++ b/src/parlant/adapters/db/transient.py @@ -0,0 +1,316 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +from typing import Any, Awaitable, Callable, Optional, Sequence, cast +from typing_extensions import override +from typing_extensions import get_type_hints + +from parlant.core.persistence.common import ( + Cursor, + SortDirection, + matches_filters, + Where, + ObjectId, + ensure_is_total, +) +from parlant.core.persistence.document_database import ( + CollectionIndex, + CollectionSort, + BaseDocument, + DeleteResult, + DocumentCollection, + DocumentDatabase, + FindResult, + InsertResult, + TDocument, + UpdateResult, +) + + +class TransientDocumentDatabase(DocumentDatabase): + def __init__(self) -> None: + self._collections: dict[str, TransientDocumentCollection[BaseDocument]] = {} + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + ) -> TransientDocumentCollection[TDocument]: + annotations = get_type_hints(schema) + assert "id" in annotations and annotations["id"] == ObjectId + + self._collections[name] = TransientDocumentCollection( + name=name, + schema=schema, + ) + + return cast(TransientDocumentCollection[TDocument], self._collections[name]) + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> TransientDocumentCollection[TDocument]: + if name in self._collections: + return cast(TransientDocumentCollection[TDocument], self._collections[name]) + raise ValueError(f'Collection "{name}" does not exist') + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> TransientDocumentCollection[TDocument]: + if collection := self._collections.get(name): + return cast(TransientDocumentCollection[TDocument], collection) + + annotations = get_type_hints(schema) + assert "id" in annotations and annotations["id"] == ObjectId + + return await self.create_collection( + name=name, + schema=schema, + ) + + @override + async def delete_collection( + self, + name: str, + ) -> None: + if name in self._collections: + del self._collections[name] + else: + raise ValueError(f'Collection "{name}" does not exist') + + +class TransientDocumentCollection(DocumentCollection[TDocument]): + def __init__( + self, + name: str, + schema: type[TDocument], + data: Optional[Sequence[TDocument]] = None, + ) -> None: + self._name = name + self._schema = schema + self._documents = list(data) if data else [] + + @override + async def find( + self, + filters: Where, + limit: Optional[int] = None, + cursor: Optional[Cursor] = None, + sort_direction: Optional[SortDirection] = None, + ) -> FindResult[TDocument]: + # First, filter documents + filtered_docs = [doc for doc in self._documents if matches_filters(filters, doc)] + + # Sort by creation_utc with id as tiebreaker according to sort_direction + sort_direction = sort_direction or SortDirection.ASC + filtered_docs = self._apply_sort(filtered_docs, sort_direction) + + # Apply cursor-based pagination if cursor is provided + if cursor: + filtered_docs = self._apply_cursor_filter(filtered_docs, cursor, sort_direction) + + total_count = len(filtered_docs) + + # Apply limit + has_more = False + next_cursor = None + + if limit is not None and len(filtered_docs) > limit: + # There are more items beyond the limit + has_more = True + result_docs = filtered_docs[:limit] + + # Generate next cursor from the last item if we have results + if result_docs: + last_doc = result_docs[-1] + next_cursor = Cursor( + creation_utc=str(last_doc.get("creation_utc", "")), + id=ObjectId(str(last_doc.get("id", ""))), + ) + else: + result_docs = filtered_docs + + return FindResult( + items=result_docs, + total_count=total_count, + has_more=has_more, + next_cursor=next_cursor, + ) + + def _apply_sort( + self, + documents: list[TDocument], + sort_direction: SortDirection, + ) -> list[TDocument]: + docs = list(documents) # don't mutate input + + # Sort by creation_utc with id as tiebreaker according to sort_direction + reverse_order = sort_direction == SortDirection.DESC + docs.sort( + key=lambda d: ( + d.get("creation_utc") or "", # Primary sort: creation_utc + d.get("id") or "", # Tiebreaker: id + ), + reverse=reverse_order, + ) + + return docs + + def _apply_field_sort( + self, + documents: Sequence[TDocument], + sort: CollectionSort, + ) -> list[TDocument]: + docs = list(documents) + + for field_name, direction in reversed(sort): + docs.sort( + key=lambda d: cast(Any, d.get(field_name)), + reverse=direction == SortDirection.DESC, + ) + + return docs + + def _apply_cursor_filter( + self, + documents: list[TDocument], + cursor: Cursor, + sort_direction: SortDirection, + ) -> list[TDocument]: + cursor_creation_utc = str(cursor.creation_utc) + cursor_id = str(cursor.id) + + result = [] + for doc in documents: + doc_creation_utc = str(doc.get("creation_utc", "")) + doc_id = str(doc.get("id", "")) + + if sort_direction == SortDirection.DESC: + # For descending order pagination, include documents that come after the cursor + # This matches the MongoDB query pattern: + # { "$or": [ + # { "creation_utc": { "$lt": cursor_creation_utc } }, + # { "creation_utc": cursor_creation_utc, "id": { "$lt": cursor_id } } + # ]} + if doc_creation_utc < cursor_creation_utc or ( + doc_creation_utc == cursor_creation_utc and doc_id < cursor_id + ): + result.append(doc) + else: # SortDirection.ASC + # For ascending order pagination, include documents that come after the cursor + # { "$or": [ + # { "creation_utc": { "$gt": cursor_creation_utc } }, + # { "creation_utc": cursor_creation_utc, "id": { "$gt": cursor_id } } + # ]} + if doc_creation_utc > cursor_creation_utc or ( + doc_creation_utc == cursor_creation_utc and doc_id > cursor_id + ): + result.append(doc) + + return result + + @override + async def find_one( + self, + filters: Where, + sort: Optional[CollectionSort] = None, + ) -> Optional[TDocument]: + matching_documents = [doc for doc in self._documents if matches_filters(filters, doc)] + + if sort: + matching_documents = self._apply_field_sort(matching_documents, sort) + + for doc in matching_documents: + return doc + + return None + + @override + async def ensure_indexes( + self, + indexes: Sequence[CollectionIndex], + ) -> None: + return None + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + self._documents.append(document) + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + for i, d in enumerate(self._documents): + if matches_filters(filters, d): + self._documents[i] = cast(TDocument, {**self._documents[i], **params}) + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=self._documents[i], + ) + + if upsert: + await self.insert_one(params) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + for i, d in enumerate(self._documents): + if matches_filters(filters, d): + document = self._documents.pop(i) + + return DeleteResult(deleted_count=1, acknowledged=True, deleted_document=document) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) diff --git a/src/parlant/adapters/loggers/opentelemetry.py b/src/parlant/adapters/loggers/opentelemetry.py new file mode 100644 index 0000000..7584bb6 --- /dev/null +++ b/src/parlant/adapters/loggers/opentelemetry.py @@ -0,0 +1,156 @@ +import os +from typing import Any, MutableMapping +import structlog +from types import TracebackType +from typing_extensions import Self, override + +from opentelemetry.sdk.resources import Resource +from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler +from opentelemetry.sdk._logs.export import BatchLogRecordProcessor +from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( + OTLPLogExporter as GrpcOTLPLogExporter, +) +from opentelemetry.exporter.otlp.proto.http._log_exporter import ( + OTLPLogExporter as HttpOTLPLogExporter, +) +from parlant.core.loggers import LogLevel, TracingLogger +from parlant.core.tracer import Tracer + + +class OpenTelemetryLogger(TracingLogger): + """TracingLogger with OpenTelemetry log export via OTLP (gRPC or HTTP).""" + + def __init__( + self, + tracer: Tracer, + log_level: LogLevel = LogLevel.DEBUG, + logger_id: str | None = None, + ) -> None: + super().__init__(tracer=tracer, log_level=log_level, logger_id=logger_id) + + self._service_name = os.getenv("OTEL_SERVICE_NAME", "parlant") + + self._logger_provider: LoggerProvider + self._log_exporter: GrpcOTLPLogExporter | HttpOTLPLogExporter + self._log_processor: BatchLogRecordProcessor + self._logging_handler: LoggingHandler + + async def __aenter__(self) -> Self: + resource = Resource.create({"service.name": self._service_name}) + + endpoint = os.environ["OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"] + insecure = os.getenv("OTEL_EXPORTER_OTLP_INSECURE", "false").lower() == "true" + protocol = os.getenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc").lower() + + match protocol: + case "http/protobuf": + self._log_exporter = HttpOTLPLogExporter(endpoint=endpoint) + case "http/json": + raise ValueError( + "http/json protocol is not supported for logs exporter. please use http/protobuf or grpc." + ) + case "grpc": + self._log_exporter = GrpcOTLPLogExporter( + endpoint=endpoint, + insecure=insecure, + ) + case _: + raise ValueError(f"Unsupported OTLP protocol: {protocol}") + + self._logger_provider = LoggerProvider(resource=resource) + self._log_processor = BatchLogRecordProcessor( + exporter=self._log_exporter, + schedule_delay_millis=2000, + ) + self._logger_provider.add_log_record_processor(self._log_processor) + + self._logging_handler = LoggingHandler( + level=self.log_level.to_logging_level(), + logger_provider=self._logger_provider, + ) + + self.raw_logger.addHandler(self._logging_handler) + + self._inject_structlog_processors() + + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool: + self._logger_provider.shutdown() # type: ignore + self.raw_logger.removeHandler(self._logging_handler) + + return False + + @override + def set_level(self, log_level: LogLevel) -> None: + super().set_level(log_level) + if self._logging_handler is not None: + self._logging_handler.setLevel(log_level.to_logging_level()) + + def _inject_structlog_processors(self) -> None: + """Add trace_id/scopes as structured fields (OTEL attributes).""" + + def _add_attributes( + _: Any, # logger + method: str, + event_dict: MutableMapping[str, Any], + ) -> MutableMapping[str, Any]: + level = event_dict.get("actual_level", event_dict.get("level", method)) + event_dict.pop("actual_level", None) + event_dict.pop("level", None) + + event_dict["severity_text"] = str(level).upper() + event_dict["trace_id"] = self._tracer.trace_id + event_dict["span_id"] = self._tracer.span_id + + if scope := self.current_scope: + event_dict["scope"] = scope + + return event_dict + + self._logger = structlog.wrap_logger( + self.raw_logger, + processors=[ + structlog.stdlib.add_log_level, + _add_attributes, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.stdlib.render_to_log_kwargs, + ], + wrapper_class=structlog.make_filtering_bound_logger( + 0 + ), # Avoids doing the level check twice. + ) + + @override + def trace(self, message: str) -> None: + if self.log_level != LogLevel.TRACE: + return + + self._logger.debug(message, actual_level="trace") + + @override + def debug(self, message: str) -> None: + self._logger.debug(message) + + @override + def info(self, message: str) -> None: + self._logger.info(message) + + @override + def warning(self, message: str) -> None: + self._logger.warning(message) + + @override + def error(self, message: str) -> None: + self._logger.error(message) + + @override + def critical(self, message: str) -> None: + self._logger.critical(message) diff --git a/src/parlant/adapters/loggers/websocket.py b/src/parlant/adapters/loggers/websocket.py new file mode 100644 index 0000000..efd52c2 --- /dev/null +++ b/src/parlant/adapters/loggers/websocket.py @@ -0,0 +1,129 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +from collections import deque +from dataclasses import dataclass +from typing import Any +from fastapi import WebSocket +from typing_extensions import override + +from parlant.core.engines.alpha.entity_context import EntityContext +from parlant.core.common import UniqueId, generate_id +from parlant.core.tracer import Tracer +from parlant.core.loggers import TracingLogger, LogLevel + + +@dataclass(frozen=True) +class WebSocketSubscription: + socket: WebSocket + expiration: asyncio.Event + + +class WebSocketLogger(TracingLogger): + def __init__( + self, + tracer: Tracer, + log_level: LogLevel = LogLevel.DEBUG, + logger_id: str | None = None, + ) -> None: + super().__init__(tracer, log_level, logger_id) + + self._message_queue = deque[Any]() + self._messages_in_queue = asyncio.Semaphore(0) + self._socket_subscriptions: dict[UniqueId, WebSocketSubscription] = {} + self._lock = asyncio.Lock() + + def _enqueue_message(self, timestamp: str, level: str, message: str) -> None: + payload = { + "level": level, + "trace_id": self._tracer.trace_id, + "message": message, + } + + if context_creation := EntityContext.get_context_creation(): + payload["message"] = f"[T+{round(context_creation.elapsed, 3)}s]{message}" + + self._message_queue.append(payload) + self._messages_in_queue.release() + + async def subscribe(self, web_socket: WebSocket) -> WebSocketSubscription: + socket_id = generate_id() + + subscription = WebSocketSubscription(web_socket, asyncio.Event()) + + async with self._lock: + self._socket_subscriptions[socket_id] = subscription + + return subscription + + def _timestamp(self) -> str: + return round(asyncio.get_event_loop().time(), 3).__str__() + + @override + def trace(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "TRACE", f"{self.current_scope} {message}") + + @override + def debug(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "DEBUG", f"{self.current_scope} {message}") + + @override + def info(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "INFO", f"{self.current_scope} {message}") + + @override + def warning(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "WARNING", f"{self.current_scope} {message}") + + @override + def error(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "ERROR", f"{self.current_scope} {message}") + + @override + def critical(self, message: str) -> None: + self._enqueue_message(self._timestamp(), "CRITICAL", f"{self.current_scope} {message}") + + async def start(self) -> None: + try: + while True: + try: + await self._messages_in_queue.acquire() + payload = self._message_queue.popleft() + + if not self._socket_subscriptions: + await asyncio.sleep(0) + continue + + async with self._lock: + socket_subscriptions = dict(self._socket_subscriptions) + + expired_ids = set() + + for socket_id, subscription in socket_subscriptions.items(): + try: + await subscription.socket.send_json(payload) + except Exception: + expired_ids.add(socket_id) + + async with self._lock: + for socket_id in expired_ids: + subscription = self._socket_subscriptions.pop(socket_id) + subscription.expiration.set() + except asyncio.CancelledError: + return + finally: + async with self._lock: + for socket_id, subscription in self._socket_subscriptions.items(): + subscription.expiration.set() diff --git a/src/parlant/adapters/meter/opentelemetry.py b/src/parlant/adapters/meter/opentelemetry.py new file mode 100644 index 0000000..2136327 --- /dev/null +++ b/src/parlant/adapters/meter/opentelemetry.py @@ -0,0 +1,158 @@ +from __future__ import annotations +import asyncio +import os +from types import TracebackType +from typing import AsyncGenerator, Mapping +from typing_extensions import override, Self +from contextlib import asynccontextmanager + +from opentelemetry import metrics +from opentelemetry.metrics import Counter as OTelCounter, Histogram as OTelHistogram +from opentelemetry.sdk.metrics import ( + MeterProvider, +) +from opentelemetry.sdk.metrics.export import ( + PeriodicExportingMetricReader, +) +from opentelemetry.sdk.resources import Resource +from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import ( + OTLPMetricExporter as GrpcOTLPMetricExporter, +) +from opentelemetry.exporter.otlp.proto.http.metric_exporter import ( + OTLPMetricExporter as HttpOTLPMetricExporter, +) + +from parlant.core.meter import Counter, DurationHistogram, Meter + + +class OpenTelemetryCounter(Counter): + def __init__(self, otel_counter: OTelCounter) -> None: + self._otel_counter = otel_counter + + @override + async def increment( + self, + value: int, + attributes: Mapping[str, str] | None = None, + ) -> None: + self._otel_counter.add(value, attributes) + + +class OpenTelemetryHistogram(DurationHistogram): + def __init__(self, otel_histogram: OTelHistogram) -> None: + self._otel_histogram = otel_histogram + + @override + async def record( + self, + value: float, + attributes: Mapping[str, str] | None = None, + ) -> None: + self._otel_histogram.record(value, attributes) + + @override + @asynccontextmanager + async def measure( + self, + attributes: Mapping[str, str] | None = None, + ) -> AsyncGenerator[None, None]: + start_time = asyncio.get_running_loop().time() + try: + yield + finally: + duration = ( + asyncio.get_running_loop().time() - start_time + ) * 1000 # Convert to milliseconds + await self.record(duration, attributes) + + +class OpenTelemetryMeter(Meter): + def __init__(self) -> None: + self._service_name = os.getenv("OTEL_SERVICE_NAME", "parlant") + + self._meter: metrics.Meter + self._metric_exporter: GrpcOTLPMetricExporter | HttpOTLPMetricExporter + self._meter_provider: MeterProvider + + async def __aenter__(self) -> Self: + resource = Resource.create({"service.name": self._service_name}) + + endpoint = os.environ["OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"] + insecure = os.getenv("OTEL_EXPORTER_OTLP_INSECURE", "false").lower() == "true" + protocol = os.getenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc").lower() + + match protocol: + case "http/protobuf": + self._metric_exporter = HttpOTLPMetricExporter(endpoint=endpoint) + case "http/json": + raise ValueError( + "http/json protocol is not supported for metrics exporter. please use http/protobuf or grpc." + ) + case "grpc": + self._metric_exporter = GrpcOTLPMetricExporter( + endpoint=endpoint, + insecure=insecure, + ) + case _: + raise ValueError(f"Unsupported OTLP protocol: {protocol}") + + metric_reader = PeriodicExportingMetricReader( + exporter=self._metric_exporter, + export_interval_millis=int(os.getenv("OTEL_METRIC_EXPORT_INTERVAL", "3000")), + ) + self._meter_provider = MeterProvider( + resource=resource, + metric_readers=[metric_reader], + ) + metrics.set_meter_provider(self._meter_provider) + + self._meter = metrics.get_meter(__name__) + + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool: + self._meter_provider.force_flush() + self._meter_provider.shutdown() + + return False + + @override + def create_counter( + self, + name: str, + description: str, + ) -> Counter: + otel_counter = self._meter.create_counter( + name=name, + description=description, + ) + + return OpenTelemetryCounter(otel_counter) + + @override + def create_custom_histogram( + self, + name: str, + description: str, + unit: str, + ) -> OpenTelemetryHistogram: + otel_histogram = self._meter.create_histogram( + name=name, + description=description, + unit=unit, + ) + + return OpenTelemetryHistogram(otel_histogram) + + @override + def create_duration_histogram( + self, + name: str, + description: str, + ) -> OpenTelemetryHistogram: + return self.create_custom_histogram(name, description, "ms") diff --git a/src/parlant/adapters/nlp/anthropic_service.py b/src/parlant/adapters/nlp/anthropic_service.py new file mode 100644 index 0000000..f2895eb --- /dev/null +++ b/src/parlant/adapters/nlp/anthropic_service.py @@ -0,0 +1,301 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +from pydantic import ValidationError +from anthropic import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncAnthropic, + InternalServerError, + RateLimitError, +) # type: ignore +from typing import Any, Mapping +from typing_extensions import override +import jsonfinder # type: ignore +import os + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.canned_response_generator import CannedResponseSelectionSchema +from parlant.core.engines.alpha.guideline_matching.generic.disambiguation_batch import ( + DisambiguationGuidelineMatchesSchema, +) + +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_backtrack_node_selection import ( + JourneyBacktrackNodeSelectionSchema, +) +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.generation import StreamingTextGenerator +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.health import HealthReporter + + +class AnthropicEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, client: AsyncAnthropic, model_name: str) -> None: + self._client = client + self.model_name = model_name + + @override + async def estimate_token_count(self, prompt: str) -> int: + result = await self._client.messages.count_tokens( + model=self.model_name, + messages=[{"role": "assistant", "content": prompt}], + ) + + return result.input_tokens # type: ignore[no-any-return] + + +class AnthropicAISchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) + self._estimating_tokenizer = AnthropicEstimatingTokenizer(self._client, model_name) + + @property + @override + def id(self) -> str: + return f"anthropic/{self.model_name}" + + @property + @override + def tokenizer(self) -> AnthropicEstimatingTokenizer: + return self._estimating_tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + RateLimitError, + APIResponseValidationError, + ) + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Anthropic LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + anthropic_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = await self._client.messages.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=4096, + **anthropic_api_arguments, + ) + except RateLimitError: + self.logger.error( + ( + "Anthropic API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Anthropic account balance and billing status.\n" + "- Review your API usage limits in Anthropic's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://docs.anthropic.com/claude/reference/rate-limits \n" + ), + ) + raise + + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.content[0].text + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Claude_Sonnet_3_5(AnthropicAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="claude-3-5-sonnet-20241022", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 200 * 1024 + + +class Claude_Sonnet_4(AnthropicAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="claude-sonnet-4-20250514", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 200 * 1024 + + +class Claude_Opus_4_1(AnthropicAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="claude-opus-4-1-20250805", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 200 * 1024 + + +class AnthropicService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("ANTHROPIC_API_KEY"): + return """\ +You're using the Anthropic NLP service, but ANTHROPIC_API_KEY is not set. +Please set ANTHROPIC_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self.logger.info("Initialized AnthropicService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> AnthropicAISchematicGenerator[T]: + if ( + t == JourneyBacktrackNodeSelectionSchema + or t == DisambiguationGuidelineMatchesSchema + or t == CannedResponseSelectionSchema + ): + return Claude_Opus_4_1[t](self.logger, self._tracer, self._meter, self._health_reporter) # type: ignore + return Claude_Sonnet_4[t](self.logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self.logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/aws_service.py b/src/parlant/adapters/nlp/aws_service.py new file mode 100644 index 0000000..a315c4c --- /dev/null +++ b/src/parlant/adapters/nlp/aws_service.py @@ -0,0 +1,256 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +from anthropic import ( + AsyncAnthropicBedrock, + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + InternalServerError, + RateLimitError, +) # type: ignore +from pydantic import ValidationError +from typing import Any, Mapping +from typing_extensions import override +import jsonfinder # type: ignore +import os +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.health import HealthReporter + + +class AnthropicBedrockEstimatingTokenizer(EstimatingTokenizer): + def __init__(self) -> None: + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return int(len(tokens) * 1.15) + + +class AnthropicBedrockAISchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncAnthropicBedrock( + aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], + aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], + aws_region=os.environ["AWS_REGION"], + aws_session_token=os.environ.get("AWS_SESSION_TOKEN", None), + ) + + self._estimating_tokenizer = AnthropicBedrockEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"bedrock/{self.model_name}" + + @property + @override + def tokenizer(self) -> AnthropicBedrockEstimatingTokenizer: + return self._estimating_tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + RateLimitError, + APIResponseValidationError, + ) + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"AWS LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + anthropic_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = await self._client.messages.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=4096, + **anthropic_api_arguments, + ) + except RateLimitError: + self.logger.error( + "AWS Bedrock API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your AWS Bedrock account balance and billing status.\n" + "- Review your API usage limits in AWS Bedrock's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://us-east-1.console.aws.amazon.com/servicequotas/home/services/bedrock/quotas", + ) + raise + + t_end = time.time() + + raw_content = response.content[0].text + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Claude_Sonnet_3_5(AnthropicBedrockAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="anthropic.claude-3-5-sonnet-20240620-v1:0", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @override + @property + def max_tokens(self) -> int: + return 200 * 1024 + + +class BedrockService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("ANTHROPIC_API_KEY"): + return """\ +You're using the AWS Bedrock NLP service, but some environment variables are missing. +Please consider setting the following your environment before running Parlant. + +- AWS_ACCESS_KEY_ID +- AWS_SECRET_ACCESS_KEY +- AWS_REGION +- AWS_SESSION_TOKEN +""" + return None + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> AnthropicBedrockAISchematicGenerator[T]: + return Claude_Sonnet_3_5[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/azure_service.py b/src/parlant/adapters/nlp/azure_service.py new file mode 100644 index 0000000..053cdd5 --- /dev/null +++ b/src/parlant/adapters/nlp/azure_service.py @@ -0,0 +1,672 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from openai import ( + AsyncAzureOpenAI, + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + InternalServerError, + RateLimitError, +) # type: ignore +from azure.identity.aio import DefaultAzureCredential # type: ignore +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.health import HealthReporter + + +class AzureEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model(model_name) + + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class AzureSchematicGenerator(BaseSchematicGenerator[T]): + supported_azure_params = ["temperature", "logit_bias", "max_tokens"] + supported_hints = supported_azure_params + ["strict"] + unsupported_params_by_model: dict[str, list[str]] = { + "gpt-5": ["temperature"], + } + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + client: AsyncAzureOpenAI, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = client + self._tokenizer = AzureEstimatingTokenizer(model_name=self.model_name) + + @property + def id(self) -> str: + return f"azure/{self.model_name}" + + @property + def tokenizer(self) -> AzureEstimatingTokenizer: + return self._tokenizer + + def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]: + exclude_params = [ + k + for k in self.supported_azure_params + for prefix, excluded in self.unsupported_params_by_model.items() + if self.model_name.startswith(prefix) and k in excluded + ] + + return { + k: v + for k, v in hints.items() + if k in self.supported_azure_params and k not in exclude_params + } + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + RateLimitError, + APIResponseValidationError, + ) + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Azure LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + azure_api_arguments = self._list_arguments(hints) + + if hints.get("strict", False): + t_start = time.time() + try: + response = await self._client.beta.chat.completions.parse( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format=self.schema, + **azure_api_arguments, + ) + except RateLimitError: + self.logger.error( + "Azure API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Azure account balance and billing status.\n" + "- Review your API usage limits in Azure's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits\n", + ) + raise + + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + parsed_object = response.choices[0].message.parsed + assert parsed_object + + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=response.usage.prompt_tokens_details.cached_tokens or 0 + if response.usage.prompt_tokens_details + else 0, + ) + + return SchematicGenerationResult[T]( + content=parsed_object, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra=( + { + "cached_input_tokens": response.usage.prompt_tokens_details.cached_tokens + or 0 + } + if response.usage.prompt_tokens_details + else {} + ), + ), + ), + ) + + else: + t_start = time.time() + + try: + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={"type": "json_object"}, + **azure_api_arguments, + ) + except RateLimitError: + self.logger.error( + "Azure API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Azure account balance and billing status.\n" + "- Review your API usage limits in Azure's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits\n", + ) + raise + + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra=( + { + "cached_input_tokens": response.usage.prompt_tokens_details.cached_tokens + or 0 + } + if response.usage.prompt_tokens_details + else {} + ), + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +def create_azure_client() -> AsyncAzureOpenAI: + """Create an Azure OpenAI client with appropriate authentication.""" + azure_endpoint = os.environ["AZURE_ENDPOINT"] + + # Check if API key is provided (backward compatibility) + if os.environ.get("AZURE_API_KEY"): + return AsyncAzureOpenAI( + api_key=os.environ["AZURE_API_KEY"], + azure_endpoint=azure_endpoint, + api_version=os.environ.get("AZURE_API_VERSION", "2024-08-01-preview"), + ) + else: + # Use Azure AD authentication + try: + credential = DefaultAzureCredential() + + async def token_provider() -> str: + """Token provider that requests tokens with the correct scope for Azure OpenAI.""" + try: + token = await credential.get_token( + "https://cognitiveservices.azure.com/.default" + ) + return str(token.token) + except Exception as e: + raise RuntimeError( + f"Failed to get Azure AD token: {e}\n\n" + "Please ensure you are authenticated with Azure AD using one of:\n" + "1. Azure CLI: `az login`\n" + "2. Service Principal environment variables:\n" + " - AZURE_CLIENT_ID\n" + " - AZURE_CLIENT_SECRET\n" + " - AZURE_TENANT_ID\n" + "3. Managed Identity (if running on Azure)\n\n" + "For more details, see: https://docs.microsoft.com/en-us/python/api/overview/azure/identity-readme" + ) from e + + return AsyncAzureOpenAI( + azure_ad_token_provider=token_provider, + azure_endpoint=azure_endpoint, + api_version=os.environ.get("AZURE_API_VERSION", "2024-08-01-preview"), + ) + except Exception as e: + raise RuntimeError( + f"Failed to initialize Azure AD authentication: {e}\n\n" + "Please ensure you are authenticated with Azure AD using one of:\n" + "1. Azure CLI: `az login`\n" + "2. Service Principal environment variables:\n" + " - AZURE_CLIENT_ID\n" + " - AZURE_CLIENT_SECRET\n" + " - AZURE_TENANT_ID\n" + "3. Managed Identity (if running on Azure)\n\n" + "For more details, see: https://docs.microsoft.com/en-us/python/api/overview/azure/identity-readme" + ) from e + + +class CustomAzureSchematicGenerator(AzureSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + _client = create_azure_client() + + super().__init__( + model_name=os.environ["AZURE_GENERATIVE_MODEL_NAME"], + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + client=_client, + ) + + @property + def max_tokens(self) -> int: + return int(os.environ.get("AZURE_GENERATIVE_MODEL_WINDOW", 4096)) + + +class GPT_4o(AzureSchematicGenerator[T]): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + _client = create_azure_client() + super().__init__( + model_name="gpt-4o", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, client=_client + ) + + @property + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4o_Mini(AzureSchematicGenerator[T]): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + _client = create_azure_client() + super().__init__( + model_name="gpt-4o-mini", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, client=_client + ) + self._token_estimator = AzureEstimatingTokenizer(model_name=self.model_name) + + @property + def max_tokens(self) -> int: + return 128 * 1024 + + +class AzureEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + client: AsyncAzureOpenAI, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = client + self._tokenizer = AzureEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"azure/{self.model_name}" + + @property + @override + def tokenizer(self) -> AzureEstimatingTokenizer: + return self._tokenizer + + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + filtered_hints = {k: v for k, v in hints.items() if k in self.supported_arguments} + + try: + response = await self._client.embeddings.create( + model=self.model_name, + input=texts, + **filtered_hints, + ) + except RateLimitError: + self.logger.error( + "Azure API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Azure account balance and billing status.\n" + "- Review your API usage limits in Azure's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits\n", + ) + raise + + vectors = [data_point.embedding for data_point in response.data] + return EmbeddingResult(vectors=vectors) + + +class CustomAzureEmbedder(AzureEmbedder): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + _client = create_azure_client() + super().__init__( + model_name=os.environ["AZURE_EMBEDDING_MODEL_NAME"], + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + client=_client, + ) + + @property + @override + def max_tokens(self) -> int: + return int(os.environ["AZURE_EMBEDDING_MODEL_WINDOW"]) + + @property + def dimensions(self) -> int: + return int(os.environ["AZURE_EMBEDDING_MODEL_DIMS"]) + + +class AzureTextEmbedding3Large(AzureEmbedder): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + _client = create_azure_client() + super().__init__( + model_name="text-embedding-3-large", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + client=_client, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 3072 + + +class AzureTextEmbedding3Small(AzureEmbedder): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + _client = create_azure_client() + super().__init__( + model_name="text-embedding-3-small", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + client=_client, + ) + + @property + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1536 + + +class AzureService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("AZURE_ENDPOINT"): + return """\ +You're using the Azure NLP service, but AZURE_ENDPOINT is not set. +Please set AZURE_ENDPOINT in your environment before running Parlant. + +Required environment variables: +- AZURE_ENDPOINT + +Authentication options (choose one): +1. Azure AD (recommended): + - Ensure you're authenticated via Azure CLI: `az login` + - Or set up managed identity/service principal authentication + +2. API Key (legacy): + - AZURE_API_KEY + +You can also set any specific models you'd like to use, using a few more variables: + +- AZURE_GENERATIVE_MODEL_NAME (e.g., gpt-4o) +- AZURE_GENERATIVE_MODEL_WINDOW (size of the generative model's context window) + +- AZURE_EMBEDDING_MODEL_NAME (e.g., text-embedding-3-large) +- AZURE_EMBEDDING_MODEL_DIMS (dimensions of the embedding model) +- AZURE_EMBEDDING_MODEL_WINDOW (size of of the embedding model's context window) + +For Azure AD authentication, ensure your identity has the "Cognitive Services OpenAI User" role +on the Azure OpenAI resource. +""" + + # Check authentication method + has_api_key = bool(os.environ.get("AZURE_API_KEY")) + + if has_api_key: + # API key authentication is configured + return None + + # Check Azure AD authentication + try: + from azure.identity import DefaultAzureCredential # type: ignore + + credential = DefaultAzureCredential() + + # Try to get a token to verify authentication works + import asyncio + + async def test_auth() -> bool: + try: + token = credential.get_token("https://cognitiveservices.azure.com/.default") + return token is not None + except Exception: + return False + + # Run the async test + try: + loop = asyncio.get_event_loop() + if loop.is_running(): + # If we're already in an async context, we can't test synchronously + # Just check if we can create the credential + return None + else: + auth_works = loop.run_until_complete(test_auth()) + if auth_works: + return None + except RuntimeError: + # No event loop, create a new one + auth_works = asyncio.run(test_auth()) + if auth_works: + return None + + except Exception: + pass + + # If we get here, neither authentication method is working + return """\ +Azure authentication is not properly configured. + +Please choose one of the following authentication methods: + +1. API Key Authentication (Legacy): + Set the AZURE_API_KEY environment variable with your Azure OpenAI API key. + +2. Azure AD Authentication (Recommended): + Ensure you're authenticated using one of these methods: + + a) Azure CLI (for development): + Run: az login + + b) Service Principal (for production): + Set these environment variables: + - AZURE_CLIENT_ID + - AZURE_CLIENT_SECRET + - AZURE_TENANT_ID + + c) Managed Identity (if running on Azure): + Ensure your Azure resource has managed identity enabled + + d) Environment Credential: + Set these environment variables: + - AZURE_CLIENT_ID + - AZURE_CLIENT_SECRET + - AZURE_TENANT_ID + + e) Workload Identity (for Kubernetes): + Set these environment variables: + - AZURE_CLIENT_ID + - AZURE_TENANT_ID + - AZURE_FEDERATED_TOKEN_FILE + +Important: For Azure AD authentication, ensure your identity has the +"Cognitive Services OpenAI User" role on the Azure OpenAI resource. + +For more details on Azure AD authentication options, see: +https://docs.microsoft.com/en-us/python/api/overview/azure/identity-readme +""" + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> AzureSchematicGenerator[T]: + if os.environ.get("AZURE_GENERATIVE_MODEL_NAME"): + return CustomAzureSchematicGenerator[t]( # type: ignore + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + return GPT_4o[t](self.logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + if os.environ.get("AZURE_EMBEDDING_MODEL_NAME"): + return CustomAzureEmbedder(self.logger, self._tracer, self._meter, self._health_reporter) + return AzureTextEmbedding3Large(self.logger, self._tracer, self._meter, self._health_reporter) + + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/cerebras_service.py b/src/parlant/adapters/nlp/cerebras_service.py new file mode 100644 index 0000000..06412ad --- /dev/null +++ b/src/parlant/adapters/nlp/cerebras_service.py @@ -0,0 +1,281 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +from pydantic import ValidationError +from cerebras.cloud.sdk import AsyncCerebras +from cerebras.cloud.sdk import ( + RateLimitError, + APIConnectionError, + APITimeoutError, + InternalServerError, +) +from typing import Any, Mapping +from typing_extensions import override +import jsonfinder # type: ignore +import os +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.health import HealthReporter + + +class LlamaEstimatingTokenizer(EstimatingTokenizer): + def __init__(self) -> None: + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + 36 + + +class CerebrasSchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncCerebras(api_key=os.environ.get("CEREBRAS_API_KEY")) + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + RateLimitError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Cerebras LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + cerebras_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={ + "type": "json_schema", + "json_schema": { + "schema": self.schema.model_json_schema(), + "name": self.schema.__name__, + "strict": True, + }, + }, + **cerebras_api_arguments, + ) + except RateLimitError: + self.logger.error( + "Cerebras API rate limit exceeded.\n" + "Your account may have reached the maximum number of requests allowed per minute for the tier you are using.\n" + "Please contact with Cerebras support for more information." + ) + raise + + t_end = time.time() + + if response.usage: # type: ignore + self.logger.trace(response.usage.model_dump_json(indent=2)) # type: ignore + + raw_content = response.choices[0].message.content or "{}" # type: ignore + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + input_tokens=response.usage.prompt_tokens, # type: ignore + output_tokens=response.usage.completion_tokens, # type: ignore + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, # type: ignore + output_tokens=response.usage.completion_tokens, # type: ignore + extra={}, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Llama3_3_8B(CerebrasSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="llama3.1-8b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + self._estimating_tokenizer = LlamaEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + @override + def tokenizer(self) -> LlamaEstimatingTokenizer: + return self._estimating_tokenizer + + +class Llama3_3_70B(CerebrasSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="llama3.3-70b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + self._estimating_tokenizer = LlamaEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def tokenizer(self) -> LlamaEstimatingTokenizer: + return self._estimating_tokenizer + + @property + @override + def max_tokens(self) -> int: + return 32 * 1024 + + +class CerebrasService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("CEREBRAS_API_KEY"): + return """\ +You're using the OpenAI NLP service, but CEREBRAS_API_KEY is not set. +Please set CEREBRAS_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + self.logger = logger + self._tracer = tracer + self.meter = meter + self._health_reporter = health_reporter + self.logger.info("Initialized CerebrasService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> CerebrasSchematicGenerator[T]: + return Llama3_3_70B[t](self.logger, self._tracer, self.meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self.logger, self._tracer, self.meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/common.py b/src/parlant/adapters/nlp/common.py new file mode 100644 index 0000000..b21417a --- /dev/null +++ b/src/parlant/adapters/nlp/common.py @@ -0,0 +1,83 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from parlant.core.meter import Counter, Meter + + +def normalize_json_output(raw_output: str) -> str: + json_start = raw_output.find("```json") + + if json_start != -1: + json_start = json_start + 7 + else: + json_start = 0 + + json_end = raw_output[json_start:].rfind("```") + + if json_end == -1: + json_end = len(raw_output[json_start:]) + + return raw_output[json_start : json_start + json_end].strip() + + +_INPUT_TOKENS_COUNTER: Counter +_OUTPUT_TOKENS_COUNTER: Counter +_CACHED_TOKENS_COUNTER: Counter +_COUNTERS_INITIALIZED = False + + +async def record_llm_metrics( + meter: Meter, + model_name: str, + schema_name: str, + input_tokens: int, + output_tokens: int, + cached_input_tokens: int = 0, +) -> None: + global _COUNTERS_INITIALIZED + global _INPUT_TOKENS_COUNTER + global _OUTPUT_TOKENS_COUNTER + global _CACHED_TOKENS_COUNTER + + if not _COUNTERS_INITIALIZED: + _INPUT_TOKENS_COUNTER = meter.create_counter( + name="input_tokens", + description="Number of input tokens sent to a LLM model", + ) + _OUTPUT_TOKENS_COUNTER = meter.create_counter( + name="output_tokens", + description="Number of output tokens received from a LLM model", + ) + _CACHED_TOKENS_COUNTER = meter.create_counter( + name="cached_input_tokens", + description="Number of input tokens served from cache for a LLM model", + ) + + _COUNTERS_INITIALIZED = True + + await _INPUT_TOKENS_COUNTER.increment( + input_tokens, + {"model_name": model_name, "schema_name": schema_name}, + ) + + await _OUTPUT_TOKENS_COUNTER.increment( + output_tokens, + {"model_name": model_name, "schema_name": schema_name}, + ) + + await _CACHED_TOKENS_COUNTER.increment( + cached_input_tokens, + {"model_name": model_name, "schema_name": schema_name}, + ) diff --git a/src/parlant/adapters/nlp/deepseek_service.py b/src/parlant/adapters/nlp/deepseek_service.py new file mode 100644 index 0000000..da9779e --- /dev/null +++ b/src/parlant/adapters/nlp/deepseek_service.py @@ -0,0 +1,263 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + ConflictError, + InternalServerError, + RateLimitError, +) +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.health import HealthReporter + + +class DeepSeekEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class DeepSeekSchematicGenerator(BaseSchematicGenerator[T]): + supported_deepseek_params = ["temperature", "logit_bias", "max_tokens"] + supported_hints = supported_deepseek_params + ["strict"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url="https://api.deepseek.com", + api_key=os.environ["DEEPSEEK_API_KEY"], + ) + + self._tokenizer = DeepSeekEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"deepseek/{self.model_name}" + + @property + @override + def tokenizer(self) -> DeepSeekEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"DeepSeek LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + deepseek_api_arguments = { + k: v for k, v in hints.items() if k in self.supported_deepseek_params + } + + t_start = time.time() + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=8192, + response_format={"type": "json_object"}, + **deepseek_api_arguments, + ) + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ), + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ) + }, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class DeepSeek_Chat(DeepSeekSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="deepseek-chat", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class DeepSeekService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("DEEPSEEK_API_KEY"): + return """\ +You're using the DeepSeek NLP service, but DEEPSEEK_API_KEY is not set. +Please set DEEPSEEK_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info("Initialized DeepSeekService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> DeepSeekSchematicGenerator[T]: + return DeepSeek_Chat[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/emcie_service.py b/src/parlant/adapters/nlp/emcie_service.py new file mode 100644 index 0000000..5634cec --- /dev/null +++ b/src/parlant/adapters/nlp/emcie_service.py @@ -0,0 +1,774 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +from pprint import pformat +import re +import time +from typing import Any, AsyncIterator, Callable, Mapping, TypeAlias, cast +from httpx import AsyncClient +import httpx +from typing_extensions import Literal, override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.meter import Meter +from parlant.core.services.indexing.common import ProgressReport +from parlant.core.services.indexing.indexer import IndexRequest, Indexer +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + ModelSize, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + BaseStreamingTextGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.tracer import Tracer +from parlant.core.version import VERSION +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Emcie API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Emcie account balance and billing status.\n" + "- Review your API usage limits in Emcie's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://docs.emcie.co\n" +) + +GenerationModelTier: TypeAlias = Literal["jackal", "bison"] +EmbeddingModelTier: TypeAlias = Literal["jackal-embedding", "bison-embedding"] +ModelRole: TypeAlias = Literal["teacher", "student", "auto"] + +BASE_URL = os.environ.get("EMCIE_API_URL", "https://api.emcie.co/inference") + +# Pattern to detect word boundaries for chunking +# Matches after any whitespace character +_WORD_BOUNDARY_PATTERN = re.compile(r"(?<=\s)") + +# Number of words to buffer before yielding a chunk +_WORDS_PER_CHUNK = 3 + + +class EmcieEstimatingTokenizer(EstimatingTokenizer): + def __init__(self) -> None: + self.encoding = tiktoken.encoding_for_model("gpt-4.1") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class EmcieAPIError(Exception): + pass + + +class InsufficientCreditsError(EmcieAPIError): + pass + + +class RateLimitError(EmcieAPIError): + pass + + +class UnauthorizedError(EmcieAPIError): + pass + + +def _get_error_detail(response: httpx.Response) -> tuple[str, str]: + try: + error_message = ( + response.json().get("detail", {}).get("error", {}).get("message", "Unknown error") + ) + request_id = response.json().get("detail", {}).get("request_id", "N/A") + except Exception: + try: + error_message = response.text + except Exception: + error_message = "Unknown error (failed to parse error message)" + + request_id = "N/A" + + return error_message, request_id + + +class EmcieSchematicGenerator(BaseSchematicGenerator[T]): + supported_emcie_params = ["temperature"] + + def __init__(self, + model_name: str, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._model_role = model_role + self._tokenizer = EmcieEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"emcie/{self.model_name}" + + @property + @override + def tokenizer(self) -> EmcieEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry(exceptions=(RateLimitError)), + retry(EmcieAPIError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Emcie LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + props = prompt.props + prompt = prompt.build() + else: + props = {} + + try: + t_start = time.time() + + timeout = httpx.Timeout( + connect=30.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + async with AsyncClient(timeout=timeout) as client: + response = await client.post( + f"{BASE_URL}/v1/completions", + headers={ + "Authorization": f"Bearer {os.environ['EMCIE_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "model_role": self._model_role, + "prompt": prompt, + "schema_name": self.schema.__name__, + "hints": { + k: v for k, v in hints.items() if k in self.supported_emcie_params + }, + "payload": props, + }, + ) + + if response.is_error: + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + raise RateLimitError( + f"Emcie API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + raise InsufficientCreditsError( + f"Insufficient API credits for Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise EmcieAPIError( + f"Emcie API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + + t_end = time.time() + except (InsufficientCreditsError, RateLimitError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + except EmcieAPIError as e: + self.logger.error(f"Emcie API error occurred: {e}") + raise + except Exception as e: + self.logger.error(f"Unexpected error during Emcie API call: {e}") + raise + + response_data = response.json() + + usage = response_data["usage"] + cost = response_data["cost"] + + self.logger.trace(f"Emcie usage data:\n{pformat({**usage, **cost})}") + + raw_content = response_data["completion"] + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=int(usage["input_tokens"]), + output_tokens=int(usage["output_tokens"]), + cached_input_tokens=0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=int(usage["input_tokens"]), + output_tokens=int(usage["output_tokens"]), + extra={}, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"Error: {e.json(indent=2)}\nJSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Jackal(EmcieSchematicGenerator[T]): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + model_role: ModelRole, + ) -> None: + super().__init__( + model_name="jackal", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + model_role=model_role, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class Bison(EmcieSchematicGenerator[T]): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + model_role: ModelRole, + ) -> None: + super().__init__( + model_name="bison", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + model_role=model_role, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +# ============================================================================ +# Streaming Text Generators +# ============================================================================ + + +class EmcieStreamingTextGenerator(BaseStreamingTextGenerator): + """Streaming text generator using Emcie's streaming API. + + Buffers tokens into word-sized chunks for smoother frontend rendering. + """ + + supported_emcie_params = ["temperature"] + + def __init__(self, + model_name: str, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + self._model_role = model_role + self._tokenizer = EmcieEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"emcie-streaming/{self.model_name}" + + @property + @override + def tokenizer(self) -> EmcieEstimatingTokenizer: + return self._tokenizer + + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> tuple[AsyncIterator[str | None], Callable[[], UsageInfo]]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + # Track usage from the done event + usage_info: UsageInfo | None = None + + async def chunk_generator() -> AsyncIterator[str | None]: + nonlocal usage_info + + timeout = httpx.Timeout( + connect=30.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + # Buffer for accumulating tokens into word-sized chunks + buffer = "" + + async with AsyncClient(timeout=timeout) as client: + async with client.stream( + "POST", + f"{BASE_URL}/v1/completions", + headers={ + "Authorization": f"Bearer {os.environ['EMCIE_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "model_role": self._model_role, + "prompt": prompt, + "stream": True, + "hints": { + k: v for k, v in hints.items() if k in self.supported_emcie_params + }, + }, + ) as response: + # Check status before iterating to catch auth/rate-limit errors early + if response.is_error: + await response.aread() + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise RateLimitError( + f"Emcie API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise InsufficientCreditsError( + f"Insufficient API credits for Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise EmcieAPIError( + f"Emcie API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + + # Parse SSE events + event_type: str | None = None + + async for line in response.aiter_lines(): + if line.startswith("event: "): + event_type = line[7:] + elif line.startswith("data: ") and event_type: + data = json.loads(line[6:]) + + if event_type == "chunk": + text = data.get("text", "") + if text: + buffer += text + + # Count word boundaries in buffer + boundaries = list(_WORD_BOUNDARY_PATTERN.finditer(buffer)) + if len(boundaries) >= _WORDS_PER_CHUNK: + # Yield up to the last complete word boundary + last_boundary = boundaries[_WORDS_PER_CHUNK - 1] + chunk_text = buffer[: last_boundary.end()] + buffer = buffer[last_boundary.end() :] + yield chunk_text + + elif event_type == "done": + usage = data.get("usage", {}) + usage_info = UsageInfo( + input_tokens=int(usage.get("input_tokens", 0)), + output_tokens=int(usage.get("output_tokens", 0)), + extra={}, + ) + + self.logger.trace(f"Emcie streaming usage data:\n{pformat(data)}") + + # Yield any remaining content in the buffer + if buffer: + yield buffer + buffer = "" + + elif event_type == "error": + error_msg = data.get("error", {}).get("message", "Unknown error") + raise EmcieAPIError(f"Emcie streaming error: {error_msg}") + + # Record metrics if we have usage info + if usage_info is not None: + await record_llm_metrics( + self.meter, + self.model_name, + schema_name="streaming", + input_tokens=usage_info.input_tokens, + output_tokens=usage_info.output_tokens, + cached_input_tokens=0, + ) + + # Signal completion + yield None + + def get_usage() -> UsageInfo: + if usage_info is None: + return UsageInfo(input_tokens=0, output_tokens=0, extra={}) + return usage_info + + return chunk_generator(), get_usage + + +class JackalStreaming(EmcieStreamingTextGenerator): + def __init__(self, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name="jackal", + model_role=model_role, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class BisonStreaming(EmcieStreamingTextGenerator): + def __init__(self, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name="bison", + model_role=model_role, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +# ============================================================================ +# Embedders +# ============================================================================ + + +class EmcieEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + self._tokenizer = EmcieEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"emcie/{self.model_name}" + + @property + @override + def tokenizer(self) -> EmcieEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry(exceptions=(RateLimitError)), + retry(EmcieAPIError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + try: + timeout = httpx.Timeout( + connect=5.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + async with AsyncClient(timeout=timeout) as client: + response = await client.post( + f"{BASE_URL}/v1/embeddings", + headers={ + "Authorization": f"Bearer {os.environ['EMCIE_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "inputs": texts, + "hints": {k: v for k, v in hints.items() if k in self.supported_arguments}, + }, + ) + + if response.is_error: + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + raise RateLimitError( + f"Emcie API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + raise InsufficientCreditsError( + f"Insufficient API credits for Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Emcie API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise EmcieAPIError( + f"Emcie API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + except (RateLimitError, InsufficientCreditsError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + except Exception as e: + self.logger.error(f"Unexpected error during Emcie API call: {e}") + raise + + response_data = response.json() + vectors = [data_point["embedding"] for data_point in response_data["data"]] + return EmbeddingResult(vectors=vectors) + + +class BisonEmbedding(EmcieEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="bison-embedding", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 3072 + + +class JackalEmbedding(EmcieEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="jackal-embedding", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1536 + + +class EmcieIndexer(Indexer): + @override + async def index( + self, + payload: Mapping[str, Mapping[str, IndexRequest]], + progress_report: ProgressReport, + ) -> None: + return + + +class EmcieService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("EMCIE_API_KEY"): + return """\ +You're using Emcie's optimized NLP service, but EMCIE_API_KEY is not set. +Please set EMCIE_API_KEY in your environment before running Parlant. + +For alternative providers, see https://parlant.io/docs/quickstart/installation. + +Get an API key for Emcie by signing up at https://www.emcie.co.""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + model_tier: GenerationModelTier | None = None, + model_role: ModelRole | None = None, + ) -> None: + self._logger = logger + self._meter = meter + + self._health_reporter = health_reporter + self._tracer = tracer + + self._model_tier = model_tier or os.environ.get("EMCIE_MODEL_TIER", "jackal") + self._model_role = model_role or os.environ.get("EMCIE_MODEL_ROLE", "auto") + + assert self._model_tier in ("jackal", "bison"), "Invalid EMCIE_MODEL_TIER" + assert self._model_role in ("teacher", "student", "auto"), "Invalid EMCIE_MODEL_ROLE" + + self._logger.info("Initialized EmcieService") + + @property + @override + def supports_streaming(self) -> bool: + return True + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + match self._model_tier: + case "bison": + return BisonStreaming( + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case _: + return JackalStreaming( + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> EmcieSchematicGenerator[T]: + match self._model_tier: + case "jackal": + return Jackal[t]( # type: ignore + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case "bison": + return Bison[t]( # type: ignore + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case _: + raise ValueError(f"Unsupported model tier: {self._model_tier}") + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + match hints.get("model_size", ModelSize.AUTO): + case ModelSize.AUTO | ModelSize.LARGE: + return BisonEmbedding(self._logger, self._tracer, self._meter, self._health_reporter) + case _: + return JackalEmbedding(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/fireworks_service.py b/src/parlant/adapters/nlp/fireworks_service.py new file mode 100644 index 0000000..e5f019f --- /dev/null +++ b/src/parlant/adapters/nlp/fireworks_service.py @@ -0,0 +1,452 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +import os +import tiktoken +import jsonfinder # type: ignore +from pydantic import ValidationError +from fireworks.client import AsyncFireworks # type: ignore +from typing import Any, Mapping +from typing_extensions import override +from fireworks.client.error import RateLimitError # type: ignore + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Fireworks API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Fireworks account balance and billing status.\n" + "- Review your API usage limits in Fireworks dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://fireworks.ai/docs/guides/quotas_usage/rate-limits" +) + + +class FireworksEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + 36 + + +class FireworksSchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature", "max_tokens"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncFireworks(api_key=os.environ.get("FIREWORKS_API_KEY")) + self._tokenizer = FireworksEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + Exception, # Will handle specific Fireworks exceptions + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ) + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Fireworks LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + fireworks_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={ + "type": "json_schema", + "json_schema": { + "schema": self.schema.model_json_schema(), + "name": self.schema.__name__, + "strict": True, + }, + }, + **fireworks_api_arguments, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + if response.usage: # type: ignore + self.logger.trace(f"Usage: {response.usage.model_dump_json(indent=2)}") # type: ignore + + raw_content = response.choices[0].message.content or "{}" # type: ignore + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + input_tokens=response.usage.prompt_tokens, # type: ignore + output_tokens=response.usage.completion_tokens, # type: ignore + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, # type: ignore + output_tokens=response.usage.completion_tokens, # type: ignore + extra={}, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class FireworksLlama3_1_8B(FireworksSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="accounts/fireworks/models/llama-v3p1-8b-instruct", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +class FireworksLlama3_1_70B(FireworksSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="accounts/fireworks/models/llama-v3p1-70b-instruct", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +class FireworksLlama3_1_405B(FireworksSchematicGenerator[T]): + """ + @warn: This is an extremely large model (405B parameters). + Only suitable for high-performance workloads with significant budget considerations. + """ + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="accounts/fireworks/models/llama-v3p1-405b-instruct", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +class FireworksMythoMax(FireworksSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="accounts/fireworks/models/mythomax-l2-13b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 4096 + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +class FireworksGemma2_9B(FireworksSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="accounts/fireworks/models/gemma2-9b-it", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +class CustomFireworksSchematicGenerator(FireworksSchematicGenerator[T]): + """Generic Fireworks generator that accepts any model name.""" + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 # Default conservative limit + + @property + @override + def tokenizer(self) -> FireworksEstimatingTokenizer: + return self._tokenizer + + +# Using JinaAIEmbedder for embeddings since Fireworks focuses on inference + + +class FireworksService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + required_vars = { + "FIREWORKS_API_KEY": "", + "FIREWORKS_MODEL": "accounts/fireworks/models/llama-v3p1-8b-instruct", + } + + missing_vars = [] + for var_name, default_value in required_vars.items(): + if not os.environ.get(var_name): + if default_value: + missing_vars.append(f'export {var_name}="{default_value}"') + else: + missing_vars.append(f'export {var_name}=""') + + if missing_vars: + return f"""\ +You're using the Fireworks NLP service, but the following environment variables are not set: + +{chr(10).join(missing_vars)} + +Please set these environment variables before running Parlant. +You can get your API key from: https://app.fireworks.ai/settings/users/api-keys +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._model_name = os.environ.get( + "FIREWORKS_MODEL", "accounts/fireworks/models/llama-v3p1-8b-instruct" + ) + self._embedding_model = os.environ.get( # Need to be implemented + "FIREWORKS_EMBEDDING_MODEL", "accounts/fireworks/models/qwen3-embedding-8b" + ) + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info(f"Initialized FireworksService with {self._model_name}") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _get_specialized_generator_class( + self, + model_name: str, + schema_type: type[T], + ) -> type[FireworksSchematicGenerator[T]] | None: + model_to_class: dict[str, type[FireworksSchematicGenerator[T]]] = { + "accounts/fireworks/models/llama-v3p1-8b-instruct": FireworksLlama3_1_8B[schema_type], # type: ignore + "accounts/fireworks/models/llama-v3p1-70b-instruct": FireworksLlama3_1_70B[schema_type], # type: ignore + "accounts/fireworks/models/llama-v3p1-405b-instruct": FireworksLlama3_1_405B[ + schema_type # type: ignore + ], + "accounts/fireworks/models/mythomax-l2-13b": FireworksMythoMax[schema_type], # type: ignore + "accounts/fireworks/models/gemma2-9b-it": FireworksGemma2_9B[schema_type], # type: ignore + } + + return model_to_class.get(model_name) + + def _log_model_warnings(self, model_name: str) -> None: + """Log warnings for resource-intensive models.""" + if "405b" in model_name.lower(): + self._logger.warning( + f"Using {model_name} - This is an extremely large model with significant cost implications. " + "Consider using smaller models for development and testing." + ) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> FireworksSchematicGenerator[T]: + """Get a schematic generator for the specified type.""" + self._log_model_warnings(self._model_name) + + specialized_class = self._get_specialized_generator_class(self._model_name, schema_type=t) + + if specialized_class: + self._logger.debug(f"Using specialized generator for model: {self._model_name}") + return specialized_class( + model_name=self._model_name, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + else: + self._logger.debug(f"Using custom generator for model: {self._model_name}") + return CustomFireworksSchematicGenerator[t]( # type: ignore + model_name=self._model_name, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + """Fireworks doesn't provide moderation services, so we use no moderation.""" + return NoModeration() + + +MODEL_RECOMMENDATIONS = { + "accounts/fireworks/models/llama-v3p1-8b-instruct": "Fast and cost-effective for most use cases", + "accounts/fireworks/models/llama-v3p1-70b-instruct": "High accuracy for complex reasoning tasks", + "accounts/fireworks/models/llama-v3p1-405b-instruct": "@warn: Extremely expensive, use only for critical workloads", + "accounts/fireworks/models/gemma2-9b-it": "Good balance of speed and accuracy", + "accounts/fireworks/models/mythomax-l2-13b": "Creative writing and roleplay scenarios", +} diff --git a/src/parlant/adapters/nlp/gemini_service.py b/src/parlant/adapters/nlp/gemini_service.py new file mode 100644 index 0000000..d04db63 --- /dev/null +++ b/src/parlant/adapters/nlp/gemini_service.py @@ -0,0 +1,602 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import enum +import inspect +import os +import time +import types +from google.api_core.exceptions import NotFound, TooManyRequests, ResourceExhausted, ServerError +import google.genai # type: ignore +import google.genai.types # type: ignore +from collections.abc import Mapping as MappingABC, Sequence as SequenceABC +from typing import Any, Literal, Mapping, Sequence, Union, cast +from typing_extensions import get_args, get_origin, override +from pydantic import BaseModel, Field, ValidationError +from pydantic.fields import FieldInfo + +from parlant.core.common import DefaultBaseModel +from parlant.adapters.nlp.common import record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.service import ( + EmbedderHints, + ModelSize, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + FallbackSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + +RATE_LIMIT_ERROR_MESSAGE = ( + "Google API rate limit exceeded.\n\n" + "Possible reasons:\n" + "1. Insufficient API credits in your account.\n" + "2. Using a free-tier account with limited request capacity.\n" + "3. Exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Google API account balance and billing status.\n" + "- Review your API usage limits in the Google Cloud Console.\n" + "- Learn more about quotas and limits:\n" + " https://cloud.google.com/docs/quota-and-billing/quotas/quotas-overview" +) + + +class GoogleEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, client: google.genai.Client, model_name: str) -> None: + self._client = client + self._model_name = model_name + + @override + async def estimate_token_count(self, prompt: str) -> int: + model_approximation = { + "gemini-embedding-001": "gemini-2.5-flash", + }.get(self._model_name, self._model_name) + + result = await self._client.aio.models.count_tokens( + model=model_approximation, + contents=prompt, + ) + + return int(result.total_tokens or 0) + + +class GeminiSchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature", "thinking_config"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = google.genai.Client(api_key=os.environ.get("GEMINI_API_KEY")) + + self._tokenizer = GoogleEstimatingTokenizer(client=self._client, model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"google/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + NotFound, + TooManyRequests, + ResourceExhausted, + ) + ), + retry(ServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Gemini LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + gemini_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + fd = self._get_schema_function_declaration() + + config = google.genai.types.GenerateContentConfig( + tools=[google.genai.types.Tool(function_declarations=[fd])], + tool_config=google.genai.types.ToolConfig( + function_calling_config=google.genai.types.FunctionCallingConfig( + mode=google.genai.types.FunctionCallingConfigMode.ANY, + allowed_function_names=[fd.name], + ) + ), + **gemini_api_arguments, # type: ignore + ) + + t_start = time.time() + try: + response = await self._client.aio.models.generate_content( + model=self.model_name, + contents=prompt, + config=config, + ) + except TooManyRequests: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + assert response.candidates + assert response.candidates[0].content + assert response.candidates[0].content.parts + assert response.candidates[0].content.parts[0].function_call + assert response.candidates[0].content.parts[0].function_call.args + + json_result = ( + response.candidates[0].content.parts[0].function_call.args.get("log_data", {}) or {} + ) + + if response.usage_metadata: + self.logger.trace(response.usage_metadata.model_dump_json(indent=2)) + + try: + model_content = self.schema.model_validate(json_result) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage_metadata.prompt_token_count or 0 + if response.usage_metadata + else 0, + output_tokens=response.usage_metadata.candidates_token_count or 0 + if response.usage_metadata + else 0, + cached_input_tokens=response.usage_metadata.cached_content_token_count or 0 + if response.usage_metadata + else 0, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage_metadata.prompt_token_count or 0, + output_tokens=response.usage_metadata.candidates_token_count or 0, + extra={ + "cached_input_tokens": ( + response.usage_metadata.cached_content_token_count or 0 + if response.usage_metadata + else 0 + ) + or 0 + }, + ) + if response.usage_metadata + else UsageInfo(input_tokens=0, output_tokens=0, extra={}), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{json_result}" + ) + raise + + def _get_schema_function_declaration(self) -> google.genai.types.FunctionDeclaration: + # Create a signature from parameters + sig = inspect.Signature( + parameters=[ + inspect.Parameter( + name="log_data", + kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, + annotation=convert_model_to_gemini_compatible_schema(self.schema), + ) + ], + return_annotation=bool, + ) + + # Create a fake callable + def log_data() -> None: + pass + + # Attach the signature + log_data.__signature__ = sig # type: ignore + + fd = google.genai.types.FunctionDeclaration.from_callable( + callable=log_data, + client=self._client, # type: ignore + ) + + return fd + + +class Gemini_2_0_Flash(GeminiSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-2.0-flash", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 1024 * 1024 + + +class Gemini_2_0_Flash_Lite(GeminiSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-2.0-flash-lite-preview-02-05", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 1024 * 1024 + + +class Gemini_2_5_Flash(GeminiSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-2.5-flash", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @override + async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + return await super().generate( + prompt, + {"thinking_config": {"thinking_budget": 0}, **hints}, + ) + + @property + @override + def max_tokens(self) -> int: + return 1024 * 1024 + + +class Gemini_2_5_Flash_Lite(GeminiSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-2.5-flash-lite", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @override + async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + return await super().generate( + prompt, + {"thinking_config": {"thinking_budget": 0}, **hints}, + ) + + @property + @override + def max_tokens(self) -> int: + return 1024 * 1024 + + +class Gemini_2_5_Pro(GeminiSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-2.5-pro", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 1024 * 1024 + + +class GoogleEmbedder(BaseEmbedder): + supported_hints = ["title", "task_type"] + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + + self._client = google.genai.Client(api_key=os.environ.get("GEMINI_API_KEY")) + self._tokenizer = GoogleEstimatingTokenizer(client=self._client, model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"google/{self.model_name}" + + @property + @override + def tokenizer(self) -> GoogleEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + NotFound, + TooManyRequests, + ResourceExhausted, + ) + ), + retry(ServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + gemini_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + try: + response = await self._client.aio.models.embed_content( # type: ignore + model=self.model_name, + contents=texts, # type: ignore + config=cast(google.genai.types.EmbedContentConfigDict, gemini_api_arguments), + ) + except TooManyRequests: + self.logger.error( + ( + "Google API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Google API account balance and billing status.\n" + "- Review your API usage limits in Google's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://cloud.google.com/docs/quota-and-billing/quotas/quotas-overview" + ), + ) + raise + + vectors = [ + data_point.values for data_point in response.embeddings or [] if data_point.values + ] + return EmbeddingResult(vectors=vectors) + + +class GeminiTextEmbedding_001(GoogleEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gemini-embedding-001", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 2048 + + @property + def dimensions(self) -> int: + return 3072 + + +class GeminiService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("GEMINI_API_KEY"): + return """\ +You're using the GEMINI NLP service, but GEMINI_API_KEY is not set. +Please set GEMINI_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self.logger.info("Initialized GeminiService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> GeminiSchematicGenerator[T]: + match hints.get("model_size", ModelSize.AUTO): + case ModelSize.NANO: + return Gemini_2_5_Flash_Lite[t](self.logger, self._tracer, self._meter) # type: ignore + case ModelSize.MINI: + return Gemini_2_5_Flash[t](self.logger, self._tracer, self._meter) # type: ignore + case ModelSize.LARGE: + return Gemini_2_5_Pro[t](self.logger, self._tracer, self._meter) # type: ignore + case _: + return FallbackSchematicGenerator[t]( # type: ignore + Gemini_2_5_Flash[t](self.logger, self._tracer, self._meter), # type: ignore + Gemini_2_5_Pro[t](self.logger, self._tracer, self._meter), # type: ignore + logger=self.logger, + ) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return GeminiTextEmbedding_001(self.logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() + + +def convert_type_annotation_to_gemini_compatible_schema(annotation: Any) -> Any: + origin = get_origin(annotation) + + # If not a generic type, check if it's a BaseModel or Enum + if origin is None: + # If it's an Enum class, convert to Literal of its values + if inspect.isclass(annotation) and issubclass(annotation, enum.Enum): + enum_values = tuple(member.value for member in annotation) + if len(enum_values) == 1: + return Literal[enum_values[0]] + return Literal.__getitem__(enum_values) + + # If it's a BaseModel class, recursively convert it + if inspect.isclass(annotation) and issubclass(annotation, DefaultBaseModel): + return convert_model_to_gemini_compatible_schema(annotation) + + return annotation + + # Get the type arguments + args = get_args(annotation) + + # Convert nested types recursively + converted_args = tuple(convert_type_annotation_to_gemini_compatible_schema(arg) for arg in args) + + # Check if origin is Mapping or Sequence + if origin is Mapping or origin is MappingABC: + return dict[converted_args] if converted_args else dict # type: ignore + + if origin is Sequence or origin is SequenceABC: + return list[converted_args] if converted_args else list # type: ignore + + # Handle UnionType (X | Y syntax) - not subscriptable! + if origin is types.UnionType: + return Union[converted_args] + + # For other generic types, preserve the origin with converted args + if converted_args: + return origin[converted_args] + + return annotation + + +def convert_model_to_gemini_compatible_schema(model_cls: type[DefaultBaseModel]) -> type[BaseModel]: + """ + Create a new BaseModel class with converted annotations. + Returns a new class without modifying the original. + """ + # Avoid infinite recursion - check if already converted + if hasattr(model_cls, "_conversion_cache"): + return cast(type[BaseModel], model_cls._conversion_cache) + + # Build new annotations + new_annotations = {} + new_fields = {} + + for field_name, field_info in model_cls.model_fields.items(): + # Convert the annotation + converted_annotation = convert_type_annotation_to_gemini_compatible_schema( + field_info.annotation + ) + new_annotations[field_name] = converted_annotation + + # Preserve field metadata (default, description, etc.) + # We need to recreate the field with the new annotation + field_kwargs = {} + + if field_info.default is not None and field_info.default is not FieldInfo: + field_kwargs["default"] = field_info.default + elif field_info.default_factory is not None: + field_kwargs["default_factory"] = field_info.default_factory + + if field_info.description is not None: + field_kwargs["description"] = field_info.description + + if field_info.title is not None: + field_kwargs["title"] = field_info.title + + if field_info.examples is not None: + field_kwargs["examples"] = field_info.examples + + # Add other field properties as needed + if field_kwargs: + new_fields[field_name] = Field(**field_kwargs) + + # Create new model class + new_model_attrs = {"__annotations__": new_annotations, **new_fields} + + # Preserve model config if present + if hasattr(model_cls, "model_config"): + new_model_attrs["model_config"] = model_cls.model_config + + # Create the new class + converted_model = type(f"{model_cls.__name__}Converted", (DefaultBaseModel,), new_model_attrs) + + # Cache the conversion to avoid infinite recursion + setattr(model_cls, "_conversion_cache", converted_model) + + return converted_model diff --git a/src/parlant/adapters/nlp/hugging_face.py b/src/parlant/adapters/nlp/hugging_face.py new file mode 100644 index 0000000..90427e3 --- /dev/null +++ b/src/parlant/adapters/nlp/hugging_face.py @@ -0,0 +1,181 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from collections.abc import Mapping +import os +from pathlib import Path +from typing import Any +from typing_extensions import override +import torch # type: ignore +from typing import cast +from transformers import AutoModel, AutoTokenizer, PreTrainedTokenizerBase, PreTrainedModel # type: ignore +from huggingface_hub.errors import ( # type: ignore + InferenceTimeoutError, + InferenceEndpointError, + InferenceEndpointTimeoutError, + TextGenerationError, +) + +from tempfile import gettempdir + +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.embedding import BaseEmbedder, EmbeddingResult +from parlant.core.health import HealthReporter + + +_TOKENIZER_MODELS: dict[str, PreTrainedTokenizerBase] = {} +_AUTO_MODELS: dict[str, PreTrainedModel] = {} +_DEVICE: torch.device | None = None + + +def _model_temp_dir() -> str: + return str(Path(gettempdir()) / "parlant_data" / "hf_models") + + +def _create_tokenizer(model_name: str) -> PreTrainedTokenizerBase: + if model_name in _TOKENIZER_MODELS: + return _TOKENIZER_MODELS[model_name] + + save_dir = os.environ.get("PARLANT_HOME", _model_temp_dir()) + os.makedirs(save_dir, exist_ok=True) + + tokenizer: PreTrainedTokenizerBase = AutoTokenizer.from_pretrained( + model_name, trust_remote_code=True + ) # type: ignore + tokenizer.save_pretrained(save_dir) + + _TOKENIZER_MODELS[model_name] = tokenizer + + return tokenizer + + +def _get_device() -> torch.device: + global _DEVICE + + if _DEVICE: + return _DEVICE + + if torch.backends.mps.is_available(): + _DEVICE = torch.device("mps") + elif torch.cuda.is_available(): + _DEVICE = torch.device("cuda") + else: + _DEVICE = torch.device("cpu") + + return _DEVICE + + +def _create_auto_model(model_name: str) -> PreTrainedModel: + if model_name in _AUTO_MODELS: + return _AUTO_MODELS[model_name] + + save_dir = os.environ.get("PARLANT_HOME", _model_temp_dir()) + os.makedirs(save_dir, exist_ok=True) + + model = AutoModel.from_pretrained( + pretrained_model_name_or_path=model_name, + attn_implementation="eager", + trust_remote_code=True, + ).to(_get_device()) + model = cast(PreTrainedModel, model) + + model.save_pretrained(save_dir) + model.eval() # type: ignore + + _AUTO_MODELS[model_name] = model + + return model + + +class HuggingFaceEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self._tokenizer = _create_tokenizer(model_name) + + @override + async def estimate_token_count(self, prompt: str) -> int: + # Use encode to get token ids, which is always available + tokens = self._tokenizer.encode(prompt) + return len(tokens) + + +class HuggingFaceEmbedder(BaseEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, model_name: str) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._model = _create_auto_model(model_name) + self._tokenizer = HuggingFaceEstimatingTokenizer(model_name=model_name) + + @property + @override + def id(self) -> str: + return f"hugging-face/{self.model_name}" + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + @override + def tokenizer(self) -> HuggingFaceEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + InferenceTimeoutError, + InferenceEndpointError, + InferenceEndpointTimeoutError, + ), + max_exceptions=2, + ), + retry(exceptions=(TextGenerationError), max_exceptions=3), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + tokenized_texts = self._tokenizer._tokenizer.batch_encode_plus( + texts, padding=True, truncation=True, return_tensors="pt" + ) + tokenized_texts = {key: value.to(_get_device()) for key, value in tokenized_texts.items()} + + with torch.no_grad(): + embeddings = self._model(**tokenized_texts).last_hidden_state[:, 0, :] + + return EmbeddingResult(vectors=embeddings.tolist()) + + +class JinaAIEmbedder(HuggingFaceEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + logger=logger, + meter=meter, health_reporter=health_reporter, + tracer=tracer, + model_name="jinaai/jina-embeddings-v2-base-en", + ) + + @property + @override + def dimensions(self) -> int: + return 768 diff --git a/src/parlant/adapters/nlp/lakera.py b/src/parlant/adapters/nlp/lakera.py new file mode 100644 index 0000000..eab4b3d --- /dev/null +++ b/src/parlant/adapters/nlp/lakera.py @@ -0,0 +1,93 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from itertools import chain +import os +from typing_extensions import override +import httpx + +from parlant.core.health import HealthReporter +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ( + CustomerModerationContext, + ModerationCheck, + BaseModerationService, + ModerationTag, +) +from parlant.core.meter import Meter + + +class LakeraGuard(BaseModerationService): + def __init__(self, logger: Logger, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger, meter, health_reporter) + + @override + async def do_moderate(self, context: CustomerModerationContext) -> ModerationCheck: + api_key: str | None = os.environ.get("LAKERA_API_KEY") + + if not api_key: + self.logger.warning( + "LakeraGuard is enabled but LAKERA_API_KEY is missing. Skipping check..." + ) + return ModerationCheck(flagged=False, tags=[]) + + def extract_tags(category: str) -> list[ModerationTag]: + mapping: dict[str, list[ModerationTag]] = { + "moderated_content_crime": ["illicit"], + "moderated_content_hate": ["hate"], + "moderated_content_profanity": ["harassment"], + "moderated_content_sexual": ["sexual"], + "moderated_content_violence": ["violence"], + "prompt_attack": ["jailbreak"], + } + + return mapping.get(category.replace("/", "_").replace("-", "_"), []) + + with self.logger.scope("Lakera Moderation Request"): + async with httpx.AsyncClient(follow_redirects=True, timeout=30) as client: + response = await client.post( + "https://api.lakera.ai/v2/guard/results", + json={"messages": [{"content": context.message, "role": "user"}]}, + headers={"Authorization": f"Bearer {api_key}"}, + ) + + if response.is_error: + raise Exception("Moderation service failure (Lakera Guard)") + + data = response.json() + + results = [ + ( + r["detector_type"], + { + "l1_confident": True, + "l2_very_likely": True, + "l3_likely": True, + "l4_less_likely": False, + "l5_unlikely": False, + }.get(r["result"], False), + ) + for r in data["results"] + ] + + return ModerationCheck( + flagged=any(detected for _category, detected in results), + tags=list( + set( + chain.from_iterable( + extract_tags(category) for category, detected in results if detected + ) + ) + ), + ) diff --git a/src/parlant/adapters/nlp/litellm_service.py b/src/parlant/adapters/nlp/litellm_service.py new file mode 100644 index 0000000..cddc5cf --- /dev/null +++ b/src/parlant/adapters/nlp/litellm_service.py @@ -0,0 +1,348 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +import litellm + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.health import HealthReporter + +RATE_LIMIT_ERROR_MESSAGE = ( + "LiteLLM to provider API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your LLM Provider account balance and billing status.\n" + "- Review your API usage limits in Provider's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " Your Provider's API documentation." +) + + +class LiteLLMEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class LiteLLMSchematicGenerator(BaseSchematicGenerator[T]): + supported_litellm_params = [ + "temperature", + "max_tokens", + "logit_bias", + "adapter_id", + "adapter_source", + ] + supported_hints = supported_litellm_params + ["strict"] + + def __init__(self, + base_url: str | None, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self.base_url = base_url + self._client = litellm + + self._tokenizer = LiteLLMEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"litellm/{self.model_name}" + + @property + @override + def tokenizer(self) -> LiteLLMEstimatingTokenizer: + return self._tokenizer + + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + litellm_api_arguments = { + k: v for k, v in hints.items() if k in self.supported_litellm_params + } + + # Only pass api_key if explicitly set; otherwise let LiteLLM auto-detect + # provider-specific keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) + api_key = os.environ.get("LITELLM_PROVIDER_API_KEY") + + t_start = time.time() + + response = await self._client.acompletion( + base_url=self.base_url, + api_key=api_key, + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=5000, + response_format={"type": "json_object"}, + **litellm_api_arguments, + ) + + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning( + f"Invalid JSON returned by litellm/{self.model_name}:\n{raw_content})" + ) + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ), + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ) + }, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by litellm/{self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class LiteLLM_Default(LiteLLMSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str | None, model_name: str + ) -> None: + super().__init__( + base_url=base_url, + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 5000 + + # 8192 16381 + + +class LiteLLMEmbedder(BaseEmbedder): + """Embedder that uses LiteLLM to access various embedding providers.""" + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + base_url: str | None = None, + ) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + self._base_url = base_url + self._client = litellm + self._tokenizer = LiteLLMEstimatingTokenizer(model_name=model_name) + + @property + @override + def id(self) -> str: + return f"litellm/{self.model_name}" + + @property + @override + def tokenizer(self) -> LiteLLMEstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + return int(os.environ.get("LITELLM_EMBEDDING_MAX_TOKENS", 8192)) + + @property + @override + def dimensions(self) -> int: + return int(os.environ.get("LITELLM_EMBEDDING_DIMENSIONS", 1536)) + + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + api_key = os.environ.get("LITELLM_PROVIDER_API_KEY") + + response = await self._client.aembedding( + model=self.model_name, + input=texts, + api_key=api_key, + api_base=self._base_url, + ) + + vectors = [data["embedding"] for data in response.data] + return EmbeddingResult(vectors=vectors) + + +class LiteLLMService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("LITELLM_PROVIDER_MODEL_NAME"): + return """\ +You're using the LITELLM NLP service, but LITELLM_PROVIDER_MODEL_NAME is not set. +Please set LITELLM_PROVIDER_MODEL_NAME in your environment before running Parlant. +""" + # Note: LITELLM_PROVIDER_API_KEY is optional. If not set, LiteLLM will + # auto-detect provider-specific keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) + + return None + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self._base_url = os.environ.get("LITELLM_PROVIDER_BASE_URL") + self._model_name = os.environ["LITELLM_PROVIDER_MODEL_NAME"] + self._embedding_model_name = os.environ.get("LITELLM_EMBEDDING_MODEL_NAME") + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + log_msg = f"Initialized LiteLLMService with {self._model_name}" + if self._embedding_model_name: + log_msg += f" (embeddings: {self._embedding_model_name})" + if self._base_url: + log_msg += f" at {self._base_url}" + self.logger.info(log_msg) + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> LiteLLMSchematicGenerator[T]: + return LiteLLM_Default[t]( # type: ignore + self.logger, + self._tracer, + self._meter, + self._health_reporter, + self._base_url, + self._model_name, + ) + + def create_embedder(self) -> Embedder: + if self._embedding_model_name: + return LiteLLMEmbedder( + model_name=self._embedding_model_name, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + base_url=self._base_url, + ) + return JinaAIEmbedder(self.logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return self.create_embedder() + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/mistral_service.py b/src/parlant/adapters/nlp/mistral_service.py new file mode 100644 index 0000000..d764ef1 --- /dev/null +++ b/src/parlant/adapters/nlp/mistral_service.py @@ -0,0 +1,422 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.canned_response_generator import CannedResponseSelectionSchema +from parlant.core.engines.alpha.guideline_matching.generic.disambiguation_batch import ( + DisambiguationGuidelineMatchesSchema, +) +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_backtrack_node_selection import ( + JourneyBacktrackNodeSelectionSchema, +) +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + BaseModerationService, + CustomerModerationContext, + ModerationCheck, + ModerationService, + ModerationTag, +) +from parlant.core.health import HealthReporter + +try: + from mistralai import Mistral + from mistralai.models import SDKError, HTTPValidationError +except ImportError: + Mistral = None # type: ignore + SDKError = Exception # type: ignore + HTTPValidationError = Exception # type: ignore + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Mistral AI API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Mistral AI account balance and billing status.\n" + "- Review your API usage limits in Mistral AI's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://docs.mistral.ai/api/\n" +) + + +class MistralEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + # Use GPT-4o encoding as approximation for Mistral models + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class MistralSchematicGenerator(BaseSchematicGenerator[T]): + supported_mistral_params = ["temperature", "max_tokens"] + supported_hints = supported_mistral_params + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = Mistral(api_key=os.environ["MISTRAL_API_KEY"]) + self._tokenizer = MistralEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"mistral/{self.model_name}" + + @property + @override + def tokenizer(self) -> MistralEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + ConnectionError, + TimeoutError, + SDKError, + HTTPValidationError, + ), + ), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Mistral LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + mistral_api_arguments = { + k: v for k, v in hints.items() if k in self.supported_mistral_params + } + + t_start = time.time() + try: + response = await self._client.chat.complete_async( + messages=[{"role": "user", "content": prompt}], # type: ignore[arg-type] + model=self.model_name, + response_format={"type": "json_object"}, # type: ignore[arg-type] + **mistral_api_arguments, + ) + except SDKError as e: + if "rate" in str(e).lower() or "429" in str(e): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + if response.usage: + self.logger.trace( + f"Usage: input_tokens={response.usage.prompt_tokens}, " + f"output_tokens={response.usage.completion_tokens}" + ) + + raw_content = response.choices[0].message.content or "{}" + + try: + # Convert content to string if needed + content_str = raw_content if isinstance(raw_content, str) else str(raw_content) + json_content = json.loads(normalize_json_output(content_str)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens or 0, + output_tokens=response.usage.completion_tokens or 0, + cached_input_tokens=0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens or 0, + output_tokens=response.usage.completion_tokens or 0, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"Error: {e.json(indent=2)}\nJSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Mistral_Large_2411(MistralSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="mistral-large-2411", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class Mistral_Medium_2508(MistralSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="mistral-medium-2508", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class Mistral_Small_2506(MistralSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="mistral-small-2506", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class MistralEmbedder(BaseEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name="mistral-embed") + self._client = Mistral(api_key=os.environ["MISTRAL_API_KEY"]) + self._tokenizer = MistralEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"mistral/{self.model_name}" + + @property + @override + def tokenizer(self) -> MistralEstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1024 + + @policy( + [ + retry( + exceptions=( + ConnectionError, + TimeoutError, + SDKError, + HTTPValidationError, + ), + ), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + try: + response = await self._client.embeddings.create_async( + model=self.model_name, + inputs=texts, + ) + except SDKError as e: + if "rate" in str(e).lower() or "429" in str(e): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + vectors = [ + data_point.embedding if data_point.embedding else [] for data_point in response.data + ] + return EmbeddingResult(vectors=vectors) + + +class MistralModerationService(BaseModerationService): + def __init__(self, logger: Logger, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger=logger, meter=meter, health_reporter=health_reporter) + + self.model_name = "mistral-moderation-2411" + self._client = Mistral(api_key=os.environ["MISTRAL_API_KEY"]) + + @override + async def do_moderate(self, context: CustomerModerationContext) -> ModerationCheck: + def extract_tags(category: str) -> list[ModerationTag]: + mapping: dict[str, list[ModerationTag]] = { + "sexual": ["sexual"], + "hate_and_discrimination": ["hate"], + "violence_and_threats": ["violence"], + "dangerous_and_criminal_content": ["illicit"], + "selfharm": ["self-harm"], + "health": ["illicit"], + "financial": ["illicit"], + "law": ["illicit"], + "pii": ["illicit"], + } + + return mapping.get(category.replace("-", "_").replace(" ", "_").lower(), []) + + response = await self._client.classifiers.moderate_chat_async( + model=self.model_name, + inputs=[{"role": "user", "content": context.message}], # type: ignore[arg-type] + ) + + result = response.results[0] + + flagged = False + all_tags: list[ModerationTag] = [] + + if result.categories: + for category_result in result.categories: + # Type check since the API may return different formats + if hasattr(category_result, "category_scores") and category_result.category_scores: + # Check if any score indicates flagged content (threshold can be adjusted) + for score_item in category_result.category_scores: + if ( + hasattr(score_item, "score") + and score_item.score + and score_item.score > 0.5 + ): + flagged = True + if hasattr(category_result, "category"): + all_tags.extend(extract_tags(str(category_result.category))) + break + + return ModerationCheck( + flagged=flagged, + tags=list(set(all_tags)), + ) + + +class MistralService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("MISTRAL_API_KEY"): + return """\ +You're using the Mistral NLP service, but MISTRAL_API_KEY is not set. +Please set MISTRAL_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info("Initialized MistralService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> MistralSchematicGenerator[T]: + if ( + t == JourneyBacktrackNodeSelectionSchema + or t == DisambiguationGuidelineMatchesSchema + or t == CannedResponseSelectionSchema + ): + return Mistral_Large_2411[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + return Mistral_Medium_2508[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return MistralEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return MistralModerationService(self._logger, self._meter, self._health_reporter) diff --git a/src/parlant/adapters/nlp/modelscope_service.py b/src/parlant/adapters/nlp/modelscope_service.py new file mode 100644 index 0000000..e0754ff --- /dev/null +++ b/src/parlant/adapters/nlp/modelscope_service.py @@ -0,0 +1,263 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Maintainer: Rongkun Yan <2493404415@qq.com> + +from __future__ import annotations +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + ConflictError, + InternalServerError, + RateLimitError, +) +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.health import HealthReporter + + +class ModelScopeEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class ModelScopeSchematicGenerator(BaseSchematicGenerator[T]): + supported_modelscope_params = ["temperature", "logit_bias", "max_tokens"] + supported_hints = supported_modelscope_params + ["strict"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url="https://api-inference.modelscope.cn/v1", + api_key=os.environ["MODELSCOPE_API_KEY"], + ) + + self._tokenizer = ModelScopeEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"modelscope/{self.model_name}" + + @property + @override + def tokenizer(self) -> ModelScopeEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"ModelScope LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + modelscope_api_arguments = { + k: v for k, v in hints.items() if k in self.supported_modelscope_params + } + + t_start = time.time() + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + stream=True, + extra_body={"enable_thinking": False}, + max_tokens=8192, + response_format={"type": "json_object"}, + **modelscope_api_arguments, + ) + t_end = time.time() + + raw_content = "" + async for chunk in response: + if chunk.choices and chunk.choices[0].delta and chunk.choices[0].delta.content: + raw_content += chunk.choices[0].delta.content + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + input_tokens = await self.tokenizer.estimate_token_count(prompt) + output_tokens = await self.tokenizer.estimate_token_count(raw_content) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=input_tokens, + output_tokens=output_tokens, + cached_input_tokens=0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=input_tokens, + output_tokens=output_tokens, + extra={}, + ), + ), + ) + except ValidationError as ve: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + self.logger.error(f"Validation error details: {str(ve)}") + raise + + +class ModelScopeChat(ModelScopeSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + model_name = os.environ["MODELSCOPE_MODEL_NAME"] + super().__init__(model_name=model_name, logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class ModelScopeService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("MODELSCOPE_MODEL_NAME"): + return """\ +You're using the ModelScope NLP service, but MODELSCOPE_MODEL_NAME is not set. +Please set MODELSCOPE_MODEL_NAME in your environment before running Parlant. +""" + if not os.environ.get("MODELSCOPE_API_KEY"): + return """\ +You're using the ModelScope NLP service, but MODELSCOPE_API_KEY is not set. +Please set MODELSCOPE_API_KEY in your environment before running Parlant. +""" + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info("Initialized ModelScopeService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> ModelScopeSchematicGenerator[T]: + return ModelScopeChat[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/novita_service.py b/src/parlant/adapters/nlp/novita_service.py new file mode 100644 index 0000000..7ca33fd --- /dev/null +++ b/src/parlant/adapters/nlp/novita_service.py @@ -0,0 +1,494 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + ConflictError, + InternalServerError, + RateLimitError, +) +import re +from typing import Any, AsyncIterator, Callable, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import JinaAIEmbedder +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import Embedder +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + BaseStreamingTextGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.health import HealthReporter + + +NOVITA_BASE_URL = "https://api.novita.ai/openai" +NOVITA_DEFAULT_MODEL = "moonshotai/kimi-k2.5" + + +class NovitaEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class NovitaSchematicGenerator(BaseSchematicGenerator[T]): + supported_novita_params = ["temperature", "logit_bias", "max_tokens"] + supported_hints = supported_novita_params + ["strict"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url=NOVITA_BASE_URL, + api_key=os.environ["NOVITA_API_KEY"], + ) + + self._tokenizer = NovitaEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"novita/{self.model_name}" + + @property + @override + def tokenizer(self) -> NovitaEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Novita LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + novita_api_arguments = {k: v for k, v in hints.items() if k in self.supported_novita_params} + + t_start = time.time() + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=8192, + response_format={"type": "json_object"}, + **novita_api_arguments, + ) + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=getattr( + response.usage, + "prompt_cache_hit_tokens", + 0, + ), + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": getattr( + response.usage, + "prompt_cache_hit_tokens", + 0, + ) + }, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Novita_KimiK2(NovitaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="moonshotai/kimi-k2.5", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 262_144 + + +class Novita_DeepSeekV3(NovitaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="deepseek/deepseek-v3.2", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 163_840 + + +class Novita_GLM5(NovitaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="zai-org/glm-5.1", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 204_800 + + +class Novita_MinimaxM2(NovitaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="minimax/minimax-m2.7", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 204_800 + + +class CustomNovitaSchematicGenerator(NovitaSchematicGenerator[T]): + """Generic Novita AI generator that accepts any model name.""" + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +# ============================================================================ +# Streaming Text Generators +# ============================================================================ + +# Pattern to detect word boundaries for chunking +# Matches after any whitespace character +_WORD_BOUNDARY_PATTERN = re.compile(r"(?<=\s)") + +# Number of words to buffer before yielding a chunk +_WORDS_PER_CHUNK = 3 + + +class NovitaStreamingTextGenerator(BaseStreamingTextGenerator): + """Streaming text generator using Novita AI's OpenAI-compatible streaming API. + + Buffers tokens into word-sized chunks for smoother frontend rendering. + """ + + supported_novita_params = ["temperature", "max_tokens"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url=NOVITA_BASE_URL, + api_key=os.environ["NOVITA_API_KEY"], + ) + self._tokenizer = NovitaEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"novita-streaming/{self.model_name}" + + @property + @override + def tokenizer(self) -> NovitaEstimatingTokenizer: + return self._tokenizer + + def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]: + return {k: v for k, v in hints.items() if k in self.supported_novita_params} + + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> tuple[AsyncIterator[str | None], Callable[[], UsageInfo]]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + novita_api_arguments = self._list_arguments(hints) + + stream = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + stream=True, + stream_options={"include_usage": True}, + **novita_api_arguments, + ) + + # Track usage from final chunk + usage_info: UsageInfo | None = None + + async def chunk_generator() -> AsyncIterator[str | None]: + nonlocal usage_info + + # Buffer for accumulating tokens into word-sized chunks + buffer = "" + + async for chunk in stream: + # Check for usage in final chunk (when stream_options include_usage is set) + if chunk.usage is not None: + self.logger.trace(chunk.usage.model_dump_json(indent=2)) + + cached_tokens = ( + getattr( + chunk.usage, + "prompt_cache_hit_tokens", + 0, + ) + or 0 + ) + + usage_info = UsageInfo( + input_tokens=chunk.usage.prompt_tokens, + output_tokens=chunk.usage.completion_tokens, + extra={"cached_input_tokens": cached_tokens}, + ) + + if chunk.choices and chunk.choices[0].delta.content: + token = chunk.choices[0].delta.content + buffer += token + + # Count word boundaries in buffer + boundaries = list(_WORD_BOUNDARY_PATTERN.finditer(buffer)) + if len(boundaries) >= _WORDS_PER_CHUNK: + # Yield up to the last complete word boundary + last_boundary = boundaries[_WORDS_PER_CHUNK - 1] + chunk_text = buffer[: last_boundary.end()] + buffer = buffer[last_boundary.end() :] + yield chunk_text + + # Yield any remaining content in the buffer + if buffer: + yield buffer + + # Record metrics if we have usage info + if usage_info is not None: + await record_llm_metrics( + self.meter, + self.model_name, + schema_name="streaming", + input_tokens=usage_info.input_tokens, + output_tokens=usage_info.output_tokens, + cached_input_tokens=usage_info.extra.get("cached_input_tokens", 0) + if usage_info.extra + else 0, + ) + + # Signal completion + yield None + + def get_usage() -> UsageInfo: + if usage_info is None: + # Fallback if usage wasn't available + return UsageInfo(input_tokens=0, output_tokens=0) + return usage_info + + return chunk_generator(), get_usage + + +class NovitaService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("NOVITA_API_KEY"): + return """\ +You're using the Novita AI NLP service, but NOVITA_API_KEY is not set. +Please set NOVITA_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.model_name = os.environ.get("NOVITA_MODEL", NOVITA_DEFAULT_MODEL) + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info(f"Initialized NovitaService with model: {self.model_name}") + + @property + @override + def supports_streaming(self) -> bool: + return True + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + return NovitaStreamingTextGenerator( + model_name=self.model_name, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + def _get_specialized_generator_class( + self, + model_name: str, + schema_type: type[T], + ) -> Callable[[Logger, Tracer, Meter, HealthReporter], NovitaSchematicGenerator[T]] | None: + """Returns the specialized generator class for known models, or None for custom models.""" + model_to_class: dict[ + str, Callable[[Logger, Tracer, Meter, HealthReporter], NovitaSchematicGenerator[T]] + ] = { + "moonshotai/kimi-k2.5": Novita_KimiK2[schema_type], # type: ignore + "deepseek/deepseek-v3.2": Novita_DeepSeekV3[schema_type], # type: ignore + "zai-org/glm-5.1": Novita_GLM5[schema_type], # type: ignore + "minimax/minimax-m2.7": Novita_MinimaxM2[schema_type], # type: ignore + } + + return model_to_class.get(model_name) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> NovitaSchematicGenerator[T]: + specialized_class = self._get_specialized_generator_class(self.model_name, schema_type=t) + + if specialized_class: + self._logger.debug(f"Using specialized generator for model: {self.model_name}") + return specialized_class(self._logger, self._tracer, self._meter, self._health_reporter) + else: + self._logger.debug(f"Using custom generator for model: {self.model_name}") + return CustomNovitaSchematicGenerator[t]( # type: ignore + model_name=self.model_name, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return JinaAIEmbedder(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/ollama_service.py b/src/parlant/adapters/nlp/ollama_service.py new file mode 100644 index 0000000..5d034f1 --- /dev/null +++ b/src/parlant/adapters/nlp/ollama_service.py @@ -0,0 +1,771 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Maintainer: Agam Dubey + +import os +import time +from typing import Any, Callable, Mapping +from typing_extensions import override +import asyncio +import tiktoken +import ollama +import jsonfinder # type: ignore +from pydantic import ValidationError + +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + + +class OllamaError(Exception): + """Base exception for Ollama-related errors.""" + + pass + + +class OllamaConnectionError(OllamaError): + """Raised when unable to connect to Ollama server.""" + + pass + + +class OllamaModelError(OllamaError): + """Raised when there are issues with the Ollama model.""" + + pass + + +class OllamaTimeoutError(OllamaError): + """Raised when Ollama request times out.""" + + pass + + +class OllamaModelVerifier: + """Utility class for verifying Ollama model availability.""" + + @staticmethod + def verify_models(base_url: str, generation_model: str, embedding_model: str) -> str | None: + """ + Returns an error string if required Ollama models are missing, + or None if all are available. + """ + client = ollama.Client(host=base_url.rstrip("/")) + try: + models = client.list() + + model_names = [] + for model in models.get("models", []): + if hasattr(model, "model"): + model_names.append(model.model) + elif isinstance(model, dict) and "model" in model: + model_names.append(model["model"]) + elif isinstance(model, dict) and "name" in model: + model_names.append(model["name"]) + + missing_models = [] + + gen_model_found = any(generation_model in model for model in model_names) + if not gen_model_found and generation_model not in model_names: + missing_models.append(f" ollama pull {generation_model}") + + embed_model_found = any(embedding_model in model for model in model_names) + if not embed_model_found and embedding_model not in model_names: + missing_models.append(f" ollama pull {embedding_model}") + + if missing_models: + return f"""\ +The following required models are not available in Ollama: + +{chr(10).join(missing_models)} + +Please pull the missing models using the commands above. + +Available models: {", ".join(model_names) if model_names else "None"} +""" + return None + + except ollama.ResponseError as e: + if e.status_code in [502, 503, 504]: + return f"""\ +Cannot connect to Ollama server at {base_url}. + +Please ensure Ollama is running: + ollama serve + +Or check if the OLLAMA_BASE_URL is correct: {base_url} +""" + else: + return f"Error checking Ollama models: {e.error}" + + except Exception as e: + return f"Error connecting to Ollama: {str(e)}" + + +class OllamaEstimatingTokenizer(EstimatingTokenizer): + """Simple tokenizer that estimates token count for Ollama models.""" + + def __init__(self, model_name: str): + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + """Estimate token count using tiktoken""" + tokens = self.encoding.encode(prompt) + return int(len(tokens) * 1.15) + + +class OllamaSchematicGenerator(BaseSchematicGenerator[T]): + """Schematic generator that uses Ollama models.""" + + supported_hints = ["temperature", "max_tokens", "top_p", "top_k", "repeat_penalty", "timeout"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + base_url: str = "http://localhost:11434", + default_timeout: int | str = 300, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self.base_url = base_url.rstrip("/") + self._tokenizer = OllamaEstimatingTokenizer(model_name) + self._default_timeout = default_timeout + + self._client = ollama.AsyncClient(host=base_url) + + @property + @override + def id(self) -> str: + return f"ollama/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + if "1b" in self.model_name.lower(): + return 12288 + elif "4b" in self.model_name.lower(): + return 16384 + elif "8b" in self.model_name.lower(): + return 16384 + elif "12b" in self.model_name.lower() or "70b" in self.model_name.lower(): + return 16384 + elif "27b" in self.model_name.lower() or "405b" in self.model_name.lower(): + return 32768 + else: + return 16384 + + def _create_options(self, hints: Mapping[str, Any]) -> dict[str, Any]: + """Create options dict from hints for Ollama.""" + options = {} + + if "temperature" in hints: + options["temperature"] = hints["temperature"] + if "max_tokens" in hints: + options["num_predict"] = hints["max_tokens"] + if "top_p" in hints: + options["top_p"] = hints["top_p"] + if "top_k" in hints: + options["top_k"] = hints["top_k"] + if "repeat_penalty" in hints: + options["repeat_penalty"] = hints["repeat_penalty"] + + options.setdefault("temperature", 0.3) + options.setdefault("top_p", 0.9) + options.setdefault("repeat_penalty", 1.1) + options.setdefault("num_ctx", self.max_tokens) + + if "1b" in self.model_name.lower(): + options["temperature"] = 0.1 + options["top_p"] = 0.5 + + return options + + @policy( + [ + retry( + exceptions=(OllamaConnectionError, OllamaTimeoutError, ollama.ResponseError), + max_exceptions=3, + wait_times=(2.0, 4.0, 8.0), + ) + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Ollama LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + timeout = hints.get("timeout", self._default_timeout) + + options = self._create_options(hints) + + t_start = time.time() + + try: + self.logger.debug(f"Sending request to Ollama with timeout={timeout}s") + + response = await asyncio.wait_for( + self._client.generate( + model=self.model_name, + prompt=prompt, + format=self.schema.model_json_schema(), + options=options, + stream=False, + ), + timeout=timeout, + ) + + except asyncio.TimeoutError: + elapsed = time.time() - t_start + self.logger.error(f"Ollama request timed out after {elapsed:.1f}s (timeout={timeout}s)") + raise OllamaTimeoutError( + f"Request timed out after {elapsed:.1f}s. Consider increasing timeout or using a smaller model." + ) + + except ollama.ResponseError as e: + if e.status_code == 404: + raise OllamaModelError( + f"Model {self.model_name} not found. Please pull it first with: ollama pull {self.model_name}" + ) + elif e.status_code in [502, 503, 504]: + raise OllamaConnectionError(f"Cannot connect to Ollama server at {self.base_url}") + else: + self.logger.error(f"Ollama API error {e.status_code}: {e.error}") + raise OllamaError(f"API request failed: {e.error}") + + except Exception as e: + self.logger.error(f"Unexpected error calling Ollama: {e}") + raise OllamaConnectionError(f"Unexpected error: {e}") + + t_end = time.time() + + raw_content = response.get("response", "") + if not raw_content: + raise ValueError("No content in response") + + json_object = None + + try: + normalized = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(normalized)[2] + + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + prompt_eval_count = response.get("prompt_eval_count", 0) + eval_count = response.get("eval_count", 0) + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=prompt_eval_count, + output_tokens=eval_count, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__ if hasattr(self, "schema") else "unknown", + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=prompt_eval_count, + output_tokens=eval_count, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"JSON content from {self.model_name} does not match expected schema. " + f"Validation errors: {e.errors()}" + ) + + if "1b" in self.model_name.lower(): + self.logger.warning( + "The 1B model often struggles with complex schemas. " + "Consider using gemma3:4b or larger for better reliability." + ) + + raise + + +class OllamaGemma3_1B(OllamaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="gemma3:1b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaGemma3_4B(OllamaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="gemma3:4b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaGemma3_12B(OllamaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="gemma3:12b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaGemma3_27B(OllamaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="gemma3:27b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaLlama31_8B(OllamaSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="llama3.1:8b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaLlama31_70B(OllamaSchematicGenerator[T]): + """ + @warn: This is a very large model (70B parameters) that requires significant GPU memory. + Recommended for use with cloud providers or high-end hardware only. + Consider using llama3.1:8b or smaller models for local development. + """ + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="llama3.1:70b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaLlama31_405B(OllamaSchematicGenerator[T]): + """ + @warn: This is an extremely large model (405B parameters) that requires massive GPU memory. + Only suitable for high-end cloud providers with multiple high-memory GPUs. + Not recommended for local use. Consider llama3.1:8b or llama3.1:70b instead. + """ + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter, base_url: str = "http://localhost:11434" + ) -> None: + super().__init__( + model_name="llama3.1:405b", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class CustomOllamaSchematicGenerator(OllamaSchematicGenerator[T]): + """Generic Ollama generator that accepts any model name.""" + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + base_url: str = "http://localhost:11434", + ) -> None: + super().__init__( + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + base_url=base_url, + ) + + +class OllamaEmbedder(BaseEmbedder): + """Embedder that uses Ollama embedding models.""" + + supported_arguments = ["dimensions"] + + def __init__( + self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + model_name=model_name, + ) + self.base_url = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434").rstrip("/") + + self._tokenizer = OllamaEstimatingTokenizer(self.model_name) + self._client = ollama.AsyncClient(host=self.base_url) + + @property + @override + def id(self) -> str: + return f"ollama/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @policy( + [ + retry( + exceptions=(OllamaConnectionError, ollama.ResponseError), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ) + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + filtered_hints = {k: v for k, v in hints.items() if k in self.supported_arguments} + + try: + response = await self._client.embed( + model=self.model_name, input=texts, **filtered_hints + ) + + vectors = response.get("embeddings", []) + + return EmbeddingResult(vectors=vectors) + + except ollama.ResponseError as e: + if e.status_code == 404: + raise OllamaModelError( + f"Embedding model {self.model_name} not found. Please pull it first with: ollama pull {self.model_name}" + ) + elif e.status_code in [502, 503, 504]: + raise OllamaConnectionError(f"Cannot connect to Ollama server at {self.base_url}") + else: + raise OllamaError(f"Embedding request failed: {e.error}") + + except Exception as e: + self.logger.error(f"Error during embedding: {e}") + raise OllamaConnectionError(f"Unexpected error: {e}") + + +class OllamaNomicEmbedding(OllamaEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="nomic-embed-text", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 768 + + +class OllamaMxbiEmbeddingLarge(OllamaEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="mxbai-embed-large", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1024 + + +class OllamaBgeM3EmbeddingLarge(OllamaEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="bge-m3", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1024 + + +class OllamaCustomEmbedding(OllamaEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self.model_name = os.environ.get("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text") + self.vector_size = int(os.environ.get("OLLAMA_EMBEDDING_VECTOR_SIZE", "768")) + super().__init__(model_name=self.model_name, logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return self.vector_size + + +class OllamaService(NLPService): + """NLP Service that uses Ollama models.""" + + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + required_vars = { + "OLLAMA_BASE_URL": "http://localhost:11434", + "OLLAMA_MODEL": "gemma3", + "OLLAMA_EMBEDDING_MODEL": "nomic-embed-text", + "OLLAMA_API_TIMEOUT": "300", + } + + missing_vars = [] + for var_name, default_value in required_vars.items(): + if not os.environ.get(var_name): + missing_vars.append(f'export {var_name}="{default_value}"') + + if missing_vars: + return f"""\ +You're using the Ollama NLP service, but the following environment variables are not set: + +{chr(10).join(missing_vars)} + +Please set these environment variables before running Parlant. +""" + + return None + + @staticmethod + def verify_models() -> str | None: + """ + Verify that the required models are available in Ollama. + Returns an error message if models are missing, None if all are available. + """ + base_url = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434").rstrip("/") + embedding_model = os.environ.get("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text") + generation_model = os.environ.get("OLLAMA_MODEL", "gemma3:4b") + + if error := OllamaModelVerifier.verify_models(base_url, generation_model, embedding_model): + return f"Model Verification Issue:\n{error}" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.base_url = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434").rstrip("/") + self.model_name = os.environ.get("OLLAMA_MODEL", "gemma3:4b") + self.embedding_model = os.environ.get("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text") + self.default_timeout = int( + os.environ.get("OLLAMA_API_TIMEOUT", 300) + ) # always convert to int + + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self.logger.info(f"Initialized OllamaService with {self.model_name} at {self.base_url}") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _get_specialized_generator_class( + self, + model_name: str, + schema_type: type[T], + ) -> Callable[..., OllamaSchematicGenerator[T]] | None: + """ + Returns the specialized generator class for known models, or None for custom models. + """ + model_to_class: dict[str, type[OllamaSchematicGenerator[T]]] = { + "gemma3:1b": OllamaGemma3_1B[schema_type], # type: ignore + "gemma3:4b": OllamaGemma3_4B[schema_type], # type: ignore + "gemma3:12b": OllamaGemma3_12B[schema_type], # type: ignore + "gemma3:27b": OllamaGemma3_27B[schema_type], # type: ignore + "llama3.1:8b": OllamaLlama31_8B[schema_type], # type: ignore + "llama3.1:70b": OllamaLlama31_70B[schema_type], # type: ignore + "llama3.1:405b": OllamaLlama31_405B[schema_type], # type: ignore + } + + if generator_class := model_to_class.get(model_name): + return generator_class + else: + return None + + def _log_model_warnings(self, model_name: str) -> None: + """Log warnings for resource-intensive models.""" + if "70b" in model_name.lower(): + self.logger.warning( + f"Using {model_name} - This is a very large model requiring significant GPU memory. " + "Consider using smaller models for local development." + ) + elif "405b" in model_name.lower(): + self.logger.warning( + f"Using {model_name} - This is an extremely large model requiring massive GPU resources. " + "Only suitable for high-end cloud providers. Consider smaller alternatives." + ) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> SchematicGenerator[T]: + """Get a schematic generator for the specified type.""" + self._log_model_warnings(self.model_name) + + specialized_class = self._get_specialized_generator_class(self.model_name, schema_type=t) + + if specialized_class: + self.logger.debug(f"Using specialized generator for model: {self.model_name}") + generator = specialized_class(logger=self.logger, base_url=self.base_url) + else: + self.logger.debug(f"Using custom generator for model: {self.model_name}") + generator = CustomOllamaSchematicGenerator[t]( # type: ignore + model_name=self.model_name, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + base_url=self.base_url, + ) + + generator._default_timeout = self.default_timeout + return generator + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + if "nomic" in self.embedding_model.lower(): + return OllamaNomicEmbedding(self.logger, self._tracer, self._meter, self._health_reporter) + elif "mxbai" in self.embedding_model.lower(): + return OllamaMxbiEmbeddingLarge(self.logger, self._tracer, self._meter, self._health_reporter) + elif "bge" in self.embedding_model.lower(): + return OllamaBgeM3EmbeddingLarge(self.logger, self._tracer, self._meter, self._health_reporter) + else: # its a custom embedding model + return OllamaCustomEmbedding(self.logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + """Get a moderation service (using no moderation for local models).""" + return NoModeration() + + +# Model size recommendations +MODEL_RECOMMENDATIONS = { + "gemma3:1b": "Fast but may struggle with complex schemas", + "gemma3:4b": "Recommended for most use cases - good balance of speed and accuracy", + "llama3.1:8b": "Better reasoning capabilities", + "gemma3:12b": "High accuracy for complex tasks", + "gemma3:27b": "Very high accuracy but slower", + "llama3.1:70b": "@warn: Requires significant GPU memory (40GB+)", + "llama3.1:405b": "@warn: Requires massive GPU resources (200GB+), cloud-only", +} diff --git a/src/parlant/adapters/nlp/openai_service.py b/src/parlant/adapters/nlp/openai_service.py new file mode 100644 index 0000000..fd704e4 --- /dev/null +++ b/src/parlant/adapters/nlp/openai_service.py @@ -0,0 +1,811 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +from itertools import chain +import re +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + ConflictError, + InternalServerError, + RateLimitError, +) +from typing import Any, AsyncIterator, Callable, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.canned_response_generator import ( + CannedResponseDraftSchema, + CannedResponseSelectionSchema, +) + +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_backtrack_check import ( + JourneyBacktrackCheckSchema, +) +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_backtrack_node_selection import ( + JourneyBacktrackNodeSelectionSchema, +) +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_next_step_selection import ( + JourneyNextStepSelectionSchema, +) +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.engines.alpha.tool_calling.single_tool_batch import ( + NonConsequentialToolBatchSchema, + SingleToolBatchSchema, +) +from parlant.core.loggers import Logger +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + ModelSize, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + BaseStreamingTextGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + CustomerModerationContext, + BaseModerationService, + ModerationCheck, + ModerationService, + ModerationTag, +) +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "OpenAI API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your OpenAI account balance and billing status.\n" + "- Review your API usage limits in OpenAI's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://platform.openai.com/docs/guides/rate-limits/usage-tiers\n" +) + + +class OpenAIEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + + if "5.1" in model_name: + model_name_query = model_name.replace("5.1", "5") + else: + model_name_query = model_name + + self.encoding = tiktoken.encoding_for_model(model_name_query) + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class OpenAISchematicGenerator(BaseSchematicGenerator[T]): + supported_openai_params = ["temperature", "logit_bias", "max_tokens"] + supported_hints = supported_openai_params + ["strict"] + unsupported_params_by_model: dict[str, list[str]] = { + "gpt-5": ["temperature"], + } + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + tokenizer_model_name: str | None = None, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient(api_key=os.environ["OPENAI_API_KEY"]) + + self._tokenizer = OpenAIEstimatingTokenizer( + model_name=tokenizer_model_name or self.model_name + ) + + @property + @override + def id(self) -> str: + return f"openai/{self.model_name}" + + @property + @override + def tokenizer(self) -> OpenAIEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"OpenAI LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]: + exclude_params = [ + k + for k in self.supported_openai_params + for prefix, excluded in self.unsupported_params_by_model.items() + if self.model_name.startswith(prefix) and k in excluded + ] + + return { + k: v + for k, v in hints.items() + if k in self.supported_openai_params and k not in exclude_params + } + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + openai_api_arguments = self._list_arguments(hints) + + if hints.get("strict", False): + t_start = time.time() + try: + response = await self._client.beta.chat.completions.parse( + messages=[{"role": "developer", "content": prompt}], + model=self.model_name, + response_format=self.schema, + **openai_api_arguments, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + parsed_object = response.choices[0].message.parsed + assert parsed_object + + assert response.usage + assert response.usage.prompt_tokens_details + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=response.usage.prompt_tokens_details.cached_tokens or 0, + ) + + return SchematicGenerationResult[T]( + content=parsed_object, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": response.usage.prompt_tokens_details.cached_tokens + or 0 + }, + ), + ), + ) + + else: + try: + t_start = time.time() + response = await self._client.chat.completions.create( + messages=[{"role": "developer", "content": prompt}], + model=self.model_name, + response_format={"type": "json_object"}, + **openai_api_arguments, + ) + t_end = time.time() + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + assert response.usage.prompt_tokens_details + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=response.usage.prompt_tokens_details.cached_tokens or 0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": response.usage.prompt_tokens_details.cached_tokens + or 0 + }, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"Error: {e.json(indent=2)}\nJSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class GPT_4o(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-4o-2024-11-20", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4o_24_08_06(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-4o-2024-08-06", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4_1(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gpt-4.1", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + tokenizer_model_name="gpt-4o-2024-11-20", + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4o_Mini(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-4o-mini", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4_1_Mini(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-4.1-mini", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_4_1_Nano(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-4.1-nano", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class GPT_5_1(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-5.1", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 400_000 + + +class GPT_5_Mini(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-5-mini", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 400_000 + + +class GPT_5_Nano(OpenAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="gpt-5-nano", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._token_estimator = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def max_tokens(self) -> int: + return 400_000 + + +# ============================================================================ +# Streaming Text Generators +# ============================================================================ + +# Pattern to detect word boundaries for chunking +# Matches after any whitespace character +_WORD_BOUNDARY_PATTERN = re.compile(r"(?<=\s)") + +# Number of words to buffer before yielding a chunk +_WORDS_PER_CHUNK = 3 + + +class OpenAIStreamingTextGenerator(BaseStreamingTextGenerator): + """Streaming text generator using OpenAI's streaming API. + + Buffers tokens into word-sized chunks for smoother frontend rendering. + """ + + supported_openai_params = ["temperature", "max_tokens"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + tokenizer_model_name: str | None = None, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient(api_key=os.environ["OPENAI_API_KEY"]) + self._tokenizer = OpenAIEstimatingTokenizer( + model_name=tokenizer_model_name or self.model_name + ) + + @property + @override + def id(self) -> str: + return f"openai-streaming/{self.model_name}" + + @property + @override + def tokenizer(self) -> OpenAIEstimatingTokenizer: + return self._tokenizer + + def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]: + return {k: v for k, v in hints.items() if k in self.supported_openai_params} + + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> tuple[AsyncIterator[str | None], Callable[[], UsageInfo]]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + openai_api_arguments = self._list_arguments(hints) + + try: + stream = await self._client.chat.completions.create( + messages=[{"role": "developer", "content": prompt}], + model=self.model_name, + stream=True, + stream_options={"include_usage": True}, + **openai_api_arguments, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + # Track usage from final chunk + usage_info: UsageInfo | None = None + + async def chunk_generator() -> AsyncIterator[str | None]: + nonlocal usage_info + + # Buffer for accumulating tokens into word-sized chunks + buffer = "" + + async for chunk in stream: + # Check for usage in final chunk (when stream_options include_usage is set) + if chunk.usage is not None: + self.logger.trace(chunk.usage.model_dump_json(indent=2)) + + cached_tokens = 0 + if chunk.usage.prompt_tokens_details: + cached_tokens = chunk.usage.prompt_tokens_details.cached_tokens or 0 + + usage_info = UsageInfo( + input_tokens=chunk.usage.prompt_tokens, + output_tokens=chunk.usage.completion_tokens, + extra={"cached_input_tokens": cached_tokens}, + ) + + if chunk.choices and chunk.choices[0].delta.content: + token = chunk.choices[0].delta.content + buffer += token + + # Count word boundaries in buffer + boundaries = list(_WORD_BOUNDARY_PATTERN.finditer(buffer)) + if len(boundaries) >= _WORDS_PER_CHUNK: + # Yield up to the last complete word boundary + last_boundary = boundaries[_WORDS_PER_CHUNK - 1] + chunk_text = buffer[: last_boundary.end()] + buffer = buffer[last_boundary.end() :] + yield chunk_text + + # Yield any remaining content in the buffer + if buffer: + yield buffer + + # Record metrics if we have usage info + if usage_info is not None: + await record_llm_metrics( + self.meter, + self.model_name, + schema_name="streaming", + input_tokens=usage_info.input_tokens, + output_tokens=usage_info.output_tokens, + cached_input_tokens=usage_info.extra.get("cached_input_tokens", 0) + if usage_info.extra + else 0, + ) + + # Signal completion + yield None + + def get_usage() -> UsageInfo: + if usage_info is None: + # Fallback if usage wasn't available + return UsageInfo(input_tokens=0, output_tokens=0) + return usage_info + + return chunk_generator(), get_usage + + +class GPT_4_1_Streaming(OpenAIStreamingTextGenerator): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="gpt-4.1", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + tokenizer_model_name="gpt-4o-2024-11-20", + ) + + +# ============================================================================ +# Embedders +# ============================================================================ + + +class OpenAIEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + + self._client = AsyncClient(api_key=os.environ["OPENAI_API_KEY"]) + self._tokenizer = OpenAIEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"openai/{self.model_name}" + + @property + @override + def tokenizer(self) -> OpenAIEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + filtered_hints = {k: v for k, v in hints.items() if k in self.supported_arguments} + try: + response = await self._client.embeddings.create( + model=self.model_name, + input=texts, + **filtered_hints, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + vectors = [data_point.embedding for data_point in response.data] + return EmbeddingResult(vectors=vectors) + + +class OpenAITextEmbedding3Large(OpenAIEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="text-embedding-3-large", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 3072 + + +class OpenAITextEmbedding3Small(OpenAIEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="text-embedding-3-small", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1536 + + +class OpenAIModerationService(BaseModerationService): + def __init__(self, model_name: str, logger: Logger, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger, meter, health_reporter) + + self.model_name = model_name + + self._client = AsyncClient(api_key=os.environ["OPENAI_API_KEY"]) + + self._hist_moderation_request_duration = meter.create_duration_histogram( + name="moderation", + description="Duration of moderation requests in milliseconds", + ) + + @override + async def do_moderate(self, context: CustomerModerationContext) -> ModerationCheck: + def extract_tags(category: str) -> list[ModerationTag]: + mapping: dict[str, list[ModerationTag]] = { + "sexual": ["sexual"], + "sexual_minors": ["sexual", "illicit"], + "harassment": ["harassment"], + "harassment_threatening": ["harassment", "illicit"], + "hate": ["hate"], + "hate_threatening": ["hate", "illicit"], + "illicit": ["illicit"], + "illicit_violent": ["illicit", "violence"], + "self_harm": ["self-harm"], + "self_harm_intent": ["self-harm", "violence"], + "self_harm_instructions": ["self-harm", "illicit"], + "violence": ["violence"], + "violence_graphic": ["violence", "harassment"], + } + + return mapping.get(category.replace("/", "_").replace("-", "_"), []) + + response = await self._client.moderations.create( + input=context.message, + model=self.model_name, + ) + + result = response.results[0] + + return ModerationCheck( + flagged=result.flagged, + tags=list( + set( + chain.from_iterable( + extract_tags(category) + for category, detected in result.categories + if detected + ) + ) + ), + ) + + +class OmniModeration(OpenAIModerationService): + def __init__(self, logger: Logger, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="omni-moderation-latest", logger=logger, meter=meter, health_reporter=health_reporter) + + +class OpenAIService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("OPENAI_API_KEY"): + return """\ +You're using the OpenAI NLP service, but OPENAI_API_KEY is not set. +Please set OPENAI_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self._logger.info("Initialized OpenAIService") + + @property + @override + def supports_streaming(self) -> bool: + return True + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + return GPT_4_1_Streaming(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> OpenAISchematicGenerator[T]: + match hints.get("model_size", ModelSize.AUTO): + case ModelSize.AUTO: + return { + SingleToolBatchSchema: GPT_4o[SingleToolBatchSchema], + NonConsequentialToolBatchSchema: GPT_4_1[NonConsequentialToolBatchSchema], + JourneyBacktrackNodeSelectionSchema: GPT_4_1[ + JourneyBacktrackNodeSelectionSchema + ], + CannedResponseDraftSchema: GPT_4_1[CannedResponseDraftSchema], + CannedResponseSelectionSchema: GPT_4_1[CannedResponseSelectionSchema], + JourneyNextStepSelectionSchema: GPT_4_1[JourneyNextStepSelectionSchema], + JourneyBacktrackCheckSchema: GPT_4_1_Mini[JourneyBacktrackCheckSchema], + }.get(t, GPT_4o_24_08_06[t])(self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case ModelSize.NANO: + match hints.get("model_generation", "auto"): + case "auto" | "stable": + match hints.get("model_type", "auto"): + case "auto" | "standard": + return GPT_4_1_Nano[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "reasoning": + return GPT_5_Nano[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "latest": + match hints.get("model_type", "auto"): + case "standard": + return GPT_4_1_Nano[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "auto" | "reasoning": + return GPT_5_Nano[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case ModelSize.MINI: + match hints.get("model_generation", "auto"): + case "auto" | "stable": + match hints.get("model_type", "auto"): + case "auto" | "standard": + return GPT_4_1_Mini[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "reasoning": + return GPT_5_Mini[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "latest": + match hints.get("model_type", "auto"): + case "standard": + return GPT_4_1_Mini[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case "auto" | "reasoning": + return GPT_5_Mini[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case _: + match hints.get("model_type", "auto"): + case "reasoning": + return GPT_5_1[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + case _: + return GPT_4o_24_08_06[t](self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + match hints.get("model_size", ModelSize.AUTO): + case ModelSize.AUTO | ModelSize.LARGE: + return OpenAITextEmbedding3Large(self._logger, self._tracer, self._meter, self._health_reporter) + case _: + return OpenAITextEmbedding3Small(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> ModerationService: + return OmniModeration(self._logger, self._meter, self._health_reporter) diff --git a/src/parlant/adapters/nlp/openrouter_service.py b/src/parlant/adapters/nlp/openrouter_service.py new file mode 100644 index 0000000..fef864a --- /dev/null +++ b/src/parlant/adapters/nlp/openrouter_service.py @@ -0,0 +1,683 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + BadRequestError, + ConflictError, + InternalServerError, + RateLimitError, +) +from typing import Any, Callable, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + +RATE_LIMIT_ERROR_MESSAGE = """\ +OpenRouter API rate limit exceeded. Possible reasons: +1. Your account may have insufficient API credits. +2. You may be using a free-tier account with limited request capacity. +3. You might have exceeded the requests-per-minute limit for your account. + +Recommended actions: +- Check your OpenRouter account balance and billing status. +- Review your API usage limits in OpenRouter's dashboard. +- For more details on rate limits and usage tiers, visit: + https://openrouter.ai/docs/api-reference/limits +""" + + +class OpenRouterEmptyEmbeddingResponseError(Exception): + """Raised when OpenRouter returns an embedding response with no vectors.""" + + +class OpenRouterEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + # Use gpt-4 encoding as default for token estimation + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class OpenRouterSchematicGenerator(BaseSchematicGenerator[T]): + supported_openrouter_params = ["temperature", "max_tokens"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + self._logger = logger + + # Build extra headers from environment variables + extra_headers = {} + if "OPENROUTER_HTTP_REFERER" in os.environ: + extra_headers["HTTP-Referer"] = os.environ["OPENROUTER_HTTP_REFERER"] + if "OPENROUTER_SITE_NAME" in os.environ: + extra_headers["X-Title"] = os.environ["OPENROUTER_SITE_NAME"] + + self._client = AsyncClient( + base_url="https://openrouter.ai/api/v1", + api_key=os.environ["OPENROUTER_API_KEY"], + default_headers=extra_headers if extra_headers else None, + ) + + self._tokenizer = OpenRouterEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"openrouter/{self.model_name}" + + @property + @override + def tokenizer(self) -> OpenRouterEstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + # Default implementation - should be overridden by subclasses + return 8192 + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + OpenRouterEmptyEmbeddingResponseError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + openrouter_api_arguments = { + k: v for k, v in hints.items() if k in self.supported_openrouter_params + } + + t_start = time.time() + + # Try with JSON mode first, but catch errors gracefully + response = None + + try: + # Try with JSON mode + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={"type": "json_object"}, + **openrouter_api_arguments, + ) + except BadRequestError as e: + # Check if it's a JSON mode error + error_str = str(e) + if "JSON mode" in error_str or "json_object" in error_str.lower(): + self._logger.error( + f"\nModel '{self.model_name}' does not support JSON mode.\n" + f"Please switch to a model that supports JSON mode (e.g., 'openai/gpt-4o', 'anthropic/claude-3.5-sonnet').\n" + f"Attempting to continue without JSON mode enforcement, but results may be less reliable.\n" + ) + # Retry without JSON mode with a system message to instruct JSON output + try: + # Add system message to instruct the model to output JSON + json_instruction = "IMPORTANT: You must respond with ONLY valid JSON. No explanatory text before or after the JSON. The response must be a valid JSON object." + response = await self._client.chat.completions.create( + messages=[ + {"role": "system", "content": json_instruction}, + {"role": "user", "content": prompt}, + ], + model=self.model_name, + **openrouter_api_arguments, + ) + except Exception as retry_error: + self._logger.error( + f"\nFailed to use model '{self.model_name}' even without JSON mode.\n" + f"Error: {retry_error}\n" + f"Please change your model to one that supports JSON mode or use a different model entirely.\n" + ) + raise + else: + # Some other BadRequest error - just log it once and raise + self._logger.error(f"OpenRouter API BadRequest: {e}") + raise + except RateLimitError: + self._logger.error( + f"\nRate limit exceeded for model '{self.model_name}'.\n" + f"{RATE_LIMIT_ERROR_MESSAGE}\n" + f"Consider:\n" + f" - Using a different model\n" + f" - Waiting a moment before retrying\n" + f" - Adding your own API key for higher limits\n" + ) + raise + except Exception as e: + self._logger.error( + f"\nOpenRouter API error with model '{self.model_name}': {type(e).__name__}\n" + f"{e}\n" + f"Consider switching to a more compatible model.\n" + ) + raise + + t_end = time.time() + + if response.usage: + self._logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + # Check if we got empty response + if not raw_content.strip() or raw_content.strip() == "{}": + self._logger.error( + f"\nModel '{self.model_name}' returned empty or invalid JSON.\n" + f"Response: {raw_content}\n" + f"This model may not be compatible with structured output requirements.\n" + f"Please switch to a model that supports JSON mode (e.g., 'openai/gpt-4o', 'anthropic/claude-3.5-sonnet').\n" + ) + # Set empty JSON as fallback + json_content = {} + else: + try: + json_content = json.loads(normalize_json_output(raw_content)) + # Check if parsed JSON is empty + if not json_content or json_content == {}: + self._logger.warning( + "Model returned empty JSON object. Attempting to find JSON in response..." + ) + # Try to find JSON in the response + try: + json_content = jsonfinder.only_json(raw_content)[2] + if json_content and json_content != {}: + self._logger.info("Found valid JSON content within response.") + except Exception: + self._logger.error( + f"Could not extract valid JSON from response: {raw_content}" + ) + except json.JSONDecodeError: + self._logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content}") + try: + # Try to extract JSON using jsonfinder + json_content = jsonfinder.only_json(raw_content)[2] + self._logger.warning("Found JSON content within model response; continuing...") + except Exception as finder_error: + self._logger.error( + f"\nCould not parse JSON from model response.\n" + f"Raw response: {raw_content}\n" + f"Error: {finder_error}\n" + f"Model '{self.model_name}' may not be compatible.\n" + f"Consider switching to a model that supports structured output.\n" + ) + json_content = {} + + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": getattr( + response.usage, + "prompt_cache_hit_tokens", + 0, + ) + }, + ), + ), + ) + except ValidationError as e: + self._logger.error( + f"\nJSON content returned by '{self.model_name}' does not match expected schema.\n" + f"Schema: {self.schema.__name__}\n" + f"Raw response: {raw_content}\n" + f"Parsed JSON: {json.dumps(json_content, indent=2) if json_content else 'Empty'}\n" + f"Validation errors: {str(e)}\n" + f"This model may not be producing valid structured output.\n" + f"Consider switching to a model that supports JSON mode.\n" + ) + raise + + +class OpenRouterGPT4O(OpenRouterSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="openai/gpt-4o", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class OpenRouterGPT4OMini(OpenRouterSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="openai/gpt-4o-mini", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class OpenRouterClaude35Sonnet(OpenRouterSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="anthropic/claude-3.5-sonnet", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + +class OpenRouterLlama33_70B(OpenRouterSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="meta-llama/llama-3.3-70b-instruct", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + +class OpenRouterEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + # Known embedding model dimensions + _KNOWN_DIMENSIONS: dict[str, int] = { + "openai/text-embedding-3-large": 3072, + "openai/text-embedding-3-small": 1536, + "openai/text-embedding-ada-002": 1536, + "qwen/qwen3-embedding-8b": 4096, + "qwen/qwen-embedding-v2": 1536, + } + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + + # Build extra headers from environment variables + extra_headers = {} + if "OPENROUTER_HTTP_REFERER" in os.environ: + extra_headers["HTTP-Referer"] = os.environ["OPENROUTER_HTTP_REFERER"] + if "OPENROUTER_SITE_NAME" in os.environ: + extra_headers["X-Title"] = os.environ["OPENROUTER_SITE_NAME"] + + self._client = AsyncClient( + base_url="https://openrouter.ai/api/v1", + api_key=os.environ["OPENROUTER_API_KEY"], + default_headers=extra_headers if extra_headers else None, + ) + self._tokenizer = OpenRouterEstimatingTokenizer(model_name=self.model_name) + # Cache dimensions after first API call if not known + self._cached_dimensions: int | None = None + + @property + @override + def id(self) -> str: + return f"openrouter/{self.model_name}" + + @property + @override + def tokenizer(self) -> OpenRouterEstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + # Default max tokens for embedding models + return 8192 + + @property + @override + def dimensions(self) -> int: + # Check environment variable override first + if "OPENROUTER_EMBEDDER_DIMENSIONS" in os.environ: + return int(os.environ["OPENROUTER_EMBEDDER_DIMENSIONS"]) + + # Return cached dimensions if available + if self._cached_dimensions is not None: + return self._cached_dimensions + + # Check known dimensions lookup + for model_key, dims in self._KNOWN_DIMENSIONS.items(): + if model_key in self.model_name: + return dims + + # Default fallback - most embedding models use 1536 or 3072 + # This will be updated after first API call + return 1536 + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + OpenRouterEmptyEmbeddingResponseError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + filtered_hints = {k: v for k, v in hints.items() if k in self.supported_arguments} + try: + response = await self._client.embeddings.create( + model=self.model_name, + input=texts, + **filtered_hints, + ) + except ValueError as exc: + if "No embedding data received" in str(exc): + raise OpenRouterEmptyEmbeddingResponseError(str(exc)) from exc + raise + except RateLimitError: + self.logger.error( + f"\nRate limit exceeded for embedder model '{self.model_name}'.\n" + f"{RATE_LIMIT_ERROR_MESSAGE}\n" + f"Consider:\n" + f" - Using a different embedder model\n" + f" - Waiting a moment before retrying\n" + f" - Adding your own API key for higher limits\n" + ) + raise + + if not response.data: + raise OpenRouterEmptyEmbeddingResponseError("No embedding data received") + + vectors = [data_point.embedding for data_point in response.data] + + # Cache dimensions from first response if not already cached and not in known list + if self._cached_dimensions is None and vectors: + actual_dims = len(vectors[0]) + # Only cache if different from default or if not found in known dimensions + if actual_dims != 1536 or not any( + key in self.model_name for key in self._KNOWN_DIMENSIONS + ): + self._cached_dimensions = actual_dims + self.logger.debug( + f"Detected embedding dimensions for '{self.model_name}': {actual_dims}" + ) + + return EmbeddingResult(vectors=vectors) + + +class OpenRouterTextEmbedding3Large(OpenRouterEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="openai/text-embedding-3-large", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + @override + def dimensions(self) -> int: + return 3072 + + +class OpenRouterService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("OPENROUTER_API_KEY"): + return """\ +You're using the OpenRouter NLP service, but OPENROUTER_API_KEY is not set. +Please set OPENROUTER_API_KEY in your environment before running Parlant. +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info("Initialized OpenRouterService") + # Get model_name from environment variable + self.model_name = os.environ.get("OPENROUTER_MODEL", "openai/gpt-4o") + # Get embedder_model_name from environment variable + self.embedder_model_name = os.environ.get( + "OPENROUTER_EMBEDDER_MODEL", "openai/text-embedding-3-large" + ) + self._logger.info(f"OpenRouter model name: {self.model_name}") + self._logger.info(f"OpenRouter embedder model name: {self.embedder_model_name}") + + # Create dynamic embedder class that can be resolved from the container + # This captures embedder_model_name in a closure so the container can resolve it + embedder_model = self.embedder_model_name + + class DynamicOpenRouterEmbedder(OpenRouterEmbedder): + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name=embedder_model, + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + self._dynamic_embedder_class = DynamicOpenRouterEmbedder + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _get_specialized_generator_class( + self, + model_name: str, + t: type[T], + ) -> Callable[[Logger, Tracer, Meter, HealthReporter], OpenRouterSchematicGenerator[T]]: + """ + Returns the specialized generator class for known models. + For unknown models, creates a dynamic generator that works with any OpenRouter model. + """ + model_mapping: dict[ + str, Callable[[Logger, Tracer, Meter, HealthReporter], OpenRouterSchematicGenerator[T]] + ] = { + "openai/gpt-4o": lambda logger, tracer, meter, health_reporter: OpenRouterGPT4O[t]( # type: ignore + logger, tracer, meter, health_reporter + ), + "openai/gpt-4o-mini": lambda logger, tracer, meter, health_reporter: OpenRouterGPT4OMini[t]( # type: ignore + logger, tracer, meter, health_reporter + ), + "anthropic/claude-3.5-sonnet": lambda logger, tracer, meter, health_reporter: OpenRouterClaude35Sonnet[ + t # type: ignore + ](logger, tracer, meter, health_reporter), + "meta-llama/llama-3.3-70b-instruct": lambda logger, tracer, meter, health_reporter: ( + OpenRouterLlama33_70B[t]( # type: ignore + logger, tracer, meter, health_reporter + ) + ), + } + + # Check if we have a predefined generator for this model + if generator_factory := model_mapping.get(model_name): + return generator_factory + + # Create a dynamic generator for any OpenRouter model + # Get max_tokens from environment variable or use sensible defaults based on model name + max_tokens_str = os.environ.get("OPENROUTER_MAX_TOKENS") + if max_tokens_str: + max_tokens = int(max_tokens_str) + else: + # Provide sensible defaults based on model family + if "gpt-4" in model_name: + max_tokens = 128 * 1024 + elif "claude" in model_name: + max_tokens = 8192 + elif "llama" in model_name or "gemma" in model_name: + max_tokens = 8192 + else: + max_tokens = 8192 # Safe default for unknown models + + # Create dynamic generator class with the specific max_tokens + final_max_tokens = max_tokens + + class DynamicOpenRouterGenerator(OpenRouterSchematicGenerator[T]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return final_max_tokens + + # Return a factory function that creates the properly typed instance + def create_generator( + logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> OpenRouterSchematicGenerator[T]: + return DynamicOpenRouterGenerator[t](logger, tracer, meter, health_reporter) # type: ignore + + return create_generator + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> OpenRouterSchematicGenerator[T]: + generator_factory = self._get_specialized_generator_class(self.model_name, t) + return generator_factory(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + # Use OpenRouter embedder with the configured embedder model name + # Default to text-embedding-3-large if not specified + if self.embedder_model_name == "openai/text-embedding-3-large": + return OpenRouterTextEmbedding3Large( + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + else: + # Return instance of dynamic embedder class that can be resolved from container + return self._dynamic_embedder_class( + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/parlant_cloud_service.py b/src/parlant/adapters/nlp/parlant_cloud_service.py new file mode 100644 index 0000000..943f601 --- /dev/null +++ b/src/parlant/adapters/nlp/parlant_cloud_service.py @@ -0,0 +1,946 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import asyncio +from pprint import pformat +import re +import time +from typing import Any, AsyncIterator, Callable, Mapping, TypeAlias, cast +from httpx import AsyncClient +import httpx +from typing_extensions import Literal, override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.agents import AgentStore +from parlant.core.application_context import ApplicationContext +from parlant.core.canned_responses import CannedResponseStore +from parlant.core.context_variables import ContextVariableStore +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.glossary import GlossaryStore +from parlant.core.guidelines import GuidelineStore +from parlant.core.journeys import JourneyStore +from parlant.core.loggers import Logger +from parlant.core.relationships import RelationshipStore +from parlant.core.services.tools.service_registry import ServiceRegistry +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + ModelSize, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + BaseStreamingTextGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.services.indexing.common import ProgressReport +from parlant.core.services.indexing.indexer import IndexRequest, Indexer +from parlant.core.tracer import Tracer +from parlant.core.version import VERSION +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Parlant Cloud API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Parlant Cloud account balance and billing status.\n" + "- Review your API usage limits in Parlant Cloud's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://parlant.io\n" +) + +GenerationModelTier: TypeAlias = Literal["jackal", "bison"] +EmbeddingModelTier: TypeAlias = Literal["jackal-embedding", "bison-embedding"] +ModelRole: TypeAlias = Literal["teacher", "student", "auto"] + +BASE_URL = os.environ.get("PARLANT_CLOUD_API_URL", "https://api.parlant.cloud/inference") + +# Pattern to detect word boundaries for chunking +# Matches after any whitespace character +_WORD_BOUNDARY_PATTERN = re.compile(r"(?<=\s)") + +# Number of words to buffer before yielding a chunk +_WORDS_PER_CHUNK = 3 + + +class ParlantCloudEstimatingTokenizer(EstimatingTokenizer): + def __init__(self) -> None: + self.encoding = tiktoken.encoding_for_model("gpt-4.1") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class ParlantCloudAPIError(Exception): + pass + + +class InsufficientCreditsError(ParlantCloudAPIError): + pass + + +class RateLimitError(ParlantCloudAPIError): + pass + + +class UnauthorizedError(ParlantCloudAPIError): + pass + + +def _get_error_detail(response: httpx.Response) -> tuple[str, str]: + try: + error_message = ( + response.json().get("detail", {}).get("error", {}).get("message", "Unknown error") + ) + request_id = response.json().get("detail", {}).get("request_id", "N/A") + except Exception: + try: + error_message = response.text + except Exception: + error_message = "Unknown error (failed to parse error message)" + + request_id = "N/A" + + return error_message, request_id + + +class ParlantCloudSchematicGenerator(BaseSchematicGenerator[T]): + supported_parlant_cloud_params = ["temperature"] + + def __init__( + self, + model_name: str, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + model_name=model_name, + ) + + self._model_role = model_role + self._tokenizer = ParlantCloudEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"parlant-cloud/{self.model_name}" + + @property + @override + def tokenizer(self) -> ParlantCloudEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry(exceptions=(RateLimitError)), + retry(ParlantCloudAPIError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Parlant Cloud LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + props = prompt.props + prompt = prompt.build() + else: + props = {} + + try: + t_start = time.time() + + timeout = httpx.Timeout( + connect=30.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + async with AsyncClient(timeout=timeout) as client: + response = await client.post( + f"{BASE_URL}/v1/completions", + headers={ + "Authorization": f"Bearer {os.environ['PARLANT_CLOUD_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "model_role": self._model_role, + "prompt": prompt, + "schema_name": self.schema.__name__, + "hints": { + k: v + for k, v in hints.items() + if k in self.supported_parlant_cloud_params + }, + "payload": props, + }, + ) + + if response.is_error: + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + raise RateLimitError( + f"Parlant Cloud API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + raise InsufficientCreditsError( + f"Insufficient API credits for Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise ParlantCloudAPIError( + f"Parlant Cloud API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + + t_end = time.time() + except (InsufficientCreditsError, RateLimitError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + except ParlantCloudAPIError as e: + self.logger.error(f"Parlant Cloud API error occurred: {e}") + raise + except Exception as e: + self.logger.error(f"Unexpected error during Parlant Cloud API call: {e}") + raise + + response_data = response.json() + + usage = response_data["usage"] + cost = response_data["cost"] + + self.logger.trace(f"Parlant Cloud usage data:\n{pformat({**usage, **cost})}") + + raw_content = response_data["completion"] + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=int(usage["input_tokens"]), + output_tokens=int(usage["output_tokens"]), + cached_input_tokens=0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=int(usage["input_tokens"]), + output_tokens=int(usage["output_tokens"]), + extra={}, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"Error: {e.json(indent=2)}\nJSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Jackal(ParlantCloudSchematicGenerator[T]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + model_role: ModelRole, + ) -> None: + super().__init__( + model_name="jackal", + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + model_role=model_role, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class Bison(ParlantCloudSchematicGenerator[T]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + model_role: ModelRole, + ) -> None: + super().__init__( + model_name="bison", + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + model_role=model_role, + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +# ============================================================================ +# Streaming Text Generators +# ============================================================================ + + +class ParlantCloudStreamingTextGenerator(BaseStreamingTextGenerator): + """Streaming text generator using Parlant Cloud's streaming API. + + Buffers tokens into word-sized chunks for smoother frontend rendering. + """ + + supported_parlant_cloud_params = ["temperature"] + + def __init__( + self, + model_name: str, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + model_name=model_name, + ) + self._model_role = model_role + self._tokenizer = ParlantCloudEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"parlant-cloud-streaming/{self.model_name}" + + @property + @override + def tokenizer(self) -> ParlantCloudEstimatingTokenizer: + return self._tokenizer + + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> tuple[AsyncIterator[str | None], Callable[[], UsageInfo]]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + # Track usage from the done event + usage_info: UsageInfo | None = None + + async def chunk_generator() -> AsyncIterator[str | None]: + nonlocal usage_info + + timeout = httpx.Timeout( + connect=30.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + # Buffer for accumulating tokens into word-sized chunks + buffer = "" + + async with AsyncClient(timeout=timeout) as client: + async with client.stream( + "POST", + f"{BASE_URL}/v1/completions", + headers={ + "Authorization": f"Bearer {os.environ['PARLANT_CLOUD_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "model_role": self._model_role, + "prompt": prompt, + "stream": True, + "hints": { + k: v + for k, v in hints.items() + if k in self.supported_parlant_cloud_params + }, + }, + ) as response: + # Check status before iterating to catch auth/rate-limit errors early + if response.is_error: + await response.aread() + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise RateLimitError( + f"Parlant Cloud API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise InsufficientCreditsError( + f"Insufficient API credits for Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise ParlantCloudAPIError( + f"Parlant Cloud API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + + # Parse SSE events + event_type: str | None = None + + async for line in response.aiter_lines(): + if line.startswith("event: "): + event_type = line[7:] + elif line.startswith("data: ") and event_type: + data = json.loads(line[6:]) + + if event_type == "chunk": + text = data.get("text", "") + if text: + buffer += text + + # Count word boundaries in buffer + boundaries = list(_WORD_BOUNDARY_PATTERN.finditer(buffer)) + if len(boundaries) >= _WORDS_PER_CHUNK: + # Yield up to the last complete word boundary + last_boundary = boundaries[_WORDS_PER_CHUNK - 1] + chunk_text = buffer[: last_boundary.end()] + buffer = buffer[last_boundary.end() :] + yield chunk_text + + elif event_type == "done": + usage = data.get("usage", {}) + usage_info = UsageInfo( + input_tokens=int(usage.get("input_tokens", 0)), + output_tokens=int(usage.get("output_tokens", 0)), + extra={}, + ) + + self.logger.trace( + f"Parlant Cloud streaming usage data:\n{pformat(data)}" + ) + + # Yield any remaining content in the buffer + if buffer: + yield buffer + buffer = "" + + elif event_type == "error": + error_msg = data.get("error", {}).get("message", "Unknown error") + raise ParlantCloudAPIError( + f"Parlant Cloud streaming error: {error_msg}" + ) + + # Record metrics if we have usage info + if usage_info is not None: + await record_llm_metrics( + self.meter, + self.model_name, + schema_name="streaming", + input_tokens=usage_info.input_tokens, + output_tokens=usage_info.output_tokens, + cached_input_tokens=0, + ) + + # Signal completion + yield None + + def get_usage() -> UsageInfo: + if usage_info is None: + return UsageInfo(input_tokens=0, output_tokens=0, extra={}) + return usage_info + + return chunk_generator(), get_usage + + +class JackalStreaming(ParlantCloudStreamingTextGenerator): + def __init__( + self, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name="jackal", + model_role=model_role, + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + +class BisonStreaming(ParlantCloudStreamingTextGenerator): + def __init__( + self, + model_role: ModelRole, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__( + model_name="bison", + model_role=model_role, + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + +# ============================================================================ +# Embedders +# ============================================================================ + + +class ParlantCloudEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + def __init__( + self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + ) -> None: + super().__init__(logger, tracer, meter, model_name, health_reporter) + self._tokenizer = ParlantCloudEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return f"parlant-cloud/{self.model_name}" + + @property + @override + def tokenizer(self) -> ParlantCloudEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry(exceptions=(RateLimitError)), + retry(ParlantCloudAPIError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + try: + timeout = httpx.Timeout( + connect=5.0, + read=120.0, + write=30.0, + pool=5.0, + ) + + async with AsyncClient(timeout=timeout) as client: + response = await client.post( + f"{BASE_URL}/v1/embeddings", + headers={ + "Authorization": f"Bearer {os.environ['PARLANT_CLOUD_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json={ + "model_tier": self.model_name, + "inputs": texts, + "hints": {k: v for k, v in hints.items() if k in self.supported_arguments}, + }, + ) + + if response.is_error: + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + raise RateLimitError( + f"Parlant Cloud API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + raise InsufficientCreditsError( + f"Insufficient API credits for Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code >= 500: + raise ParlantCloudAPIError( + f"Parlant Cloud API error: {response.status_code} {error_message} (RID={request_id})" + ) + + response.raise_for_status() + except (RateLimitError, InsufficientCreditsError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + except Exception as e: + self.logger.error(f"Unexpected error during Parlant Cloud API call: {e}") + raise + + response_data = response.json() + vectors = [data_point["embedding"] for data_point in response_data["data"]] + return EmbeddingResult(vectors=vectors) + + +class BisonEmbedding(ParlantCloudEmbedder): + def __init__( + self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + model_name="bison-embedding", + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 3072 + + +class JackalEmbedding(ParlantCloudEmbedder): + def __init__( + self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + model_name="jackal-embedding", + logger=logger, + tracer=tracer, + meter=meter, + health_reporter=health_reporter, + ) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1536 + + +class ParlantCloudIndexer(Indexer): + def __init__( + self, + agent_store: AgentStore, + guideline_store: GuidelineStore, + journey_store: JourneyStore, + relationship_store: RelationshipStore, + glossary_store: GlossaryStore, + context_variable_store: ContextVariableStore, + canned_response_store: CannedResponseStore, + service_registry: ServiceRegistry, + application_context: ApplicationContext, + logger: Logger, + ) -> None: + super().__init__( + agent_store=agent_store, + guideline_store=guideline_store, + journey_store=journey_store, + relationship_store=relationship_store, + glossary_store=glossary_store, + context_variable_store=context_variable_store, + canned_response_store=canned_response_store, + service_registry=service_registry, + ) + self._application_context = application_context + self._logger = logger + + @override + async def index( + self, + payload: Mapping[str, Mapping[str, IndexRequest]], + progress_report: ProgressReport, + ) -> None: + serialized_entities: dict[str, dict[str, dict[str, Any]]] = { + category: { + entity_id: { + "type": request.type, + "id": request.id, + "last_modification_utc": request.last_modification_utc.isoformat(), + "checksum": request.checksum, + "data": request.data, + } + for entity_id, request in entities.items() + } + for category, entities in payload.items() + } + + body = { + "instance_id": self._application_context.instance_id, + "entities": serialized_entities, + } + + timeout = httpx.Timeout(connect=30.0, read=60.0, write=120.0, pool=5.0) + + async with AsyncClient(timeout=timeout) as client: + response = await client.post( + f"{BASE_URL}/v1/index", + headers={ + "Authorization": f"Bearer {os.environ['PARLANT_CLOUD_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + json=body, + ) + + if response.is_error: + error_message, request_id = _get_error_detail(response) + + if response.status_code == 429: + raise RateLimitError( + f"Parlant Cloud API rate limit exceeded: {error_message} (RID={request_id})" + ) + elif response.status_code == 402: + raise InsufficientCreditsError( + f"Insufficient API credits for Parlant Cloud API: {error_message} (RID={request_id})" + ) + elif response.status_code == 403: + raise UnauthorizedError( + f"Unauthorized access to Parlant Cloud API: {error_message} (RID={request_id})" + ) + else: + raise ParlantCloudAPIError( + f"Parlant Cloud API error: {response.status_code} {error_message} (RID={request_id})" + ) + + status_url = response.json()["status_url"] + if not status_url.startswith("http"): + status_url = f"{BASE_URL}{status_url}" + + last_completed = 0 + + while True: + status_response = await client.get( + status_url, + headers={ + "Authorization": f"Bearer {os.environ['PARLANT_CLOUD_API_KEY']}", + "X-Parlant-Version": VERSION, + }, + ) + + if status_response.is_error: + error_message, request_id = _get_error_detail(status_response) + raise ParlantCloudAPIError( + f"Parlant Cloud indexing status error: {status_response.status_code} {error_message} (RID={request_id})" + ) + + status_data = status_response.json() + completed = int(status_data.get("completed", 0)) + delta = completed - last_completed + if delta > 0: + await progress_report.increment(delta) + last_completed = completed + + status = status_data.get("status") + if status == "completed": + return + if status == "failed": + raise ParlantCloudAPIError(f"Parlant Cloud indexing failed: {status_data}") + + await asyncio.sleep(2) + + +class ParlantCloudService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("PARLANT_CLOUD_API_KEY"): + return """\ +You're using Parlant Cloud's optimized NLP service, but PARLANT_CLOUD_API_KEY is not set. +Please set PARLANT_CLOUD_API_KEY in your environment before running Parlant. + +For alternative providers, see https://parlant.io/docs/quickstart/installation. + +Get an API key for Parlant Cloud by signing up at https://www.parlant.io.""" + + return None + + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + health_reporter: HealthReporter, + model_tier: GenerationModelTier | None = None, + model_role: ModelRole | None = None, + ) -> None: + self._logger = logger + self._tracer = tracer + self._meter = meter + self._health_reporter = health_reporter + + self._model_tier = model_tier or os.environ.get("PARLANT_CLOUD_MODEL_TIER", "jackal") + self._model_role = model_role or os.environ.get("PARLANT_CLOUD_MODEL_ROLE", "auto") + + assert self._model_tier in ("jackal", "bison"), "Invalid PARLANT_CLOUD_MODEL_TIER" + assert self._model_role in ("teacher", "student", "auto"), ( + "Invalid PARLANT_CLOUD_MODEL_ROLE" + ) + + self._logger.info("Initialized ParlantCloudService") + + @property + @override + def supports_streaming(self) -> bool: + return True + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + match self._model_tier: + case "bison": + return BisonStreaming( + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case _: + return JackalStreaming( + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> ParlantCloudSchematicGenerator[T]: + match self._model_tier: + case "jackal": + return Jackal[t]( # type: ignore + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case "bison": + return Bison[t]( # type: ignore + model_role=cast(ModelRole, self._model_role), + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + case _: + raise ValueError(f"Unsupported model tier: {self._model_tier}") + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + match hints.get("model_size", ModelSize.AUTO): + case ModelSize.AUTO | ModelSize.LARGE: + return BisonEmbedding( + self._logger, self._tracer, self._meter, self._health_reporter + ) + case _: + return JackalEmbedding( + self._logger, self._tracer, self._meter, self._health_reporter + ) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/qwen_service.py b/src/parlant/adapters/nlp/qwen_service.py new file mode 100644 index 0000000..903d494 --- /dev/null +++ b/src/parlant/adapters/nlp/qwen_service.py @@ -0,0 +1,421 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Maintainer: Ji Qing + +from __future__ import annotations +import time +from openai import ( + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + AsyncClient, + ConflictError, + InternalServerError, + RateLimitError, +) +from typing import Any, Callable, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + ModerationService, + NoModeration, +) +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + +RATE_LIMIT_ERROR_MESSAGE = """\ +Qwen API rate limit exceeded. Possible reasons: +1. Your account may have insufficient API credits. +2. You may be using a free-tier account with limited request capacity. +3. You might have exceeded the requests-per-minute limit for your account. + +Recommended actions: +- Check your Qwen account balance and billing status. +- Review your API usage limits in Qwen's dashboard. +- For more details on rate limits and usage tiers, visit: + https://help.aliyun.com/zh/model-studio/ +""" + +QWEN_REGION_BASE_URLS = { + "international": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", + "domestic": "https://dashscope.aliyuncs.com/compatible-mode/v1", +} + + +def get_qwen_base_url() -> str: + """Get the base URL for Qwen API based on region configuration. + + Priority: + 1. QWEN_BASE_URL environment variable (explicit override) + 2. QWEN_REGION environment variable (international/domestic) + 3. Default to international region + """ + if base_url := os.environ.get("QWEN_BASE_URL"): + return base_url + + region = os.environ.get("QWEN_REGION", "international").lower() + if region not in QWEN_REGION_BASE_URLS: + raise ValueError(f"Invalid QWEN_REGION '{region}'. Must be 'international' or 'domestic'.") + return QWEN_REGION_BASE_URLS[region] + + +class QwenEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: str) -> None: + self.model_name = model_name + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class QwenEmbedder(BaseEmbedder): + supported_arguments = ["dimensions"] + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url=get_qwen_base_url(), + api_key=os.environ.get("DASHSCOPE_API_KEY", ""), + ) + self._tokenizer = QwenEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"qwen/{self.model_name}" + + @property + @override + def tokenizer(self) -> QwenEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + filtered_hints = {k: v for k, v in hints.items() if k in self.supported_arguments} + try: + response = await self._client.embeddings.create( + model=self.model_name, + input=texts, + **filtered_hints, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + vectors = [data_point.embedding for data_point in response.data] + return EmbeddingResult(vectors=vectors) + + +class QwenTextEmbedding_V4(QwenEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="text-embedding-v4", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @property + def dimensions(self) -> int: + return 1024 + + +class QwenSchematicGenerator(BaseSchematicGenerator[T]): + supported_qwen_params = ["temperature", "max_tokens"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncClient( + base_url=get_qwen_base_url(), + api_key=os.environ["DASHSCOPE_API_KEY"], + ) + + self._tokenizer = QwenEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + return f"Qwen/{self.model_name}" + + @property + @override + def tokenizer(self) -> QwenEstimatingTokenizer: + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + ConflictError, + RateLimitError, + APIResponseValidationError, + ), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Qwen LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + qwen_api_arguments = {k: v for k, v in hints.items() if k in self.supported_qwen_params} + + t_start = time.time() + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=8 * 1024, + response_format={"type": "json_object"}, + **qwen_api_arguments, + ) + t_end = time.time() + + if response.usage: + self.logger.trace(response.usage.model_dump_json(indent=2)) + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + try: + content = self.schema.model_validate(json_content) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + cached_input_tokens=getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ), + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={ + "cached_input_tokens": getattr( + response, + "usage.prompt_cache_hit_tokens", + 0, + ) + }, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Qwen_MAX(QwenSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="qwen-max", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 32 * 1024 + + +class Qwen_Plus(QwenSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="qwen-plus", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class Qwen_2_5_72b(QwenSchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="qwen2.5-72b-instruct", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter + ) + + @property + @override + def max_tokens(self) -> int: + return 128 * 1024 + + +class QwenService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + if not os.environ.get("DASHSCOPE_API_KEY"): + return """\ +You're using the Qwen NLP service, but DASHSCOPE_API_KEY is not set. +Please set DASHSCOPE_API_KEY in your environment before running Parlant. +""" + + if region := os.environ.get("QWEN_REGION"): + if region.lower() not in QWEN_REGION_BASE_URLS: + return f"""\ +Invalid QWEN_REGION '{region}'. +Must be one of: {", ".join(QWEN_REGION_BASE_URLS.keys())} +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self.model_name = os.environ.get("QWEN_MODEL", "qwen-plus") + + self.logger.info(f"Initialized QwenService with model: {self.model_name}") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _get_specialized_generator_class( + self, + model_name: str, + t: type[T], + ) -> Callable[..., QwenSchematicGenerator[T]] | None: + """ + Returns the specialized generator class for known models + """ + model_mapping: dict[str, type[QwenSchematicGenerator[T]]] = { + "qwen-max": Qwen_MAX[t], # type: ignore + "qwen-plus": Qwen_Plus[t], # type: ignore + "qwen2.5-72b-instruct": Qwen_2_5_72b[t], # type: ignore + } + + if generator_class := model_mapping.get(model_name): + return generator_class + else: + return None + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> QwenSchematicGenerator[T]: + qwen_generator = self._get_specialized_generator_class(self.model_name, t) + assert qwen_generator is not None, f"Unsupported Qwen model: {self.model_name}" + return qwen_generator(self.logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return QwenTextEmbedding_V4( + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/snowflake_cortex_service.py b/src/parlant/adapters/nlp/snowflake_cortex_service.py new file mode 100644 index 0000000..214a43b --- /dev/null +++ b/src/parlant/adapters/nlp/snowflake_cortex_service.py @@ -0,0 +1,420 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Maintainer: Tao Tang + +from __future__ import annotations + +import os +import time +import json +from typing import Any, Mapping, Optional, Type, cast + +import httpx +import tiktoken +from typing_extensions import override +from pydantic import ValidationError + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.loggers import Logger +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.tracer import Tracer +from parlant.core.health import HealthReporter + +HTTPX_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0, read=60.0, write=60.0) + + +class CortexEstimatingTokenizer(EstimatingTokenizer): + def __init__(self, model_name: Optional[str] = None) -> None: + self.model_name = model_name or "cl100k_base" + try: + self.encoding = tiktoken.encoding_for_model(self.model_name) + except Exception: + self.encoding = tiktoken.get_encoding("cl100k_base") + + @override + async def estimate_token_count(self, prompt: str) -> int: + return int(len(self.encoding.encode(prompt)) * 1.05) + + +class CortexSchematicGenerator(BaseSchematicGenerator[T]): + """ + Snowflake Cortex chat generator via REST: + POST {BASE}/api/v2/cortex/inference:complete + """ + + _provider_params = ["temperature", "top_p", "top_k", "max_tokens", "stop"] + supported_hints = _provider_params + ["strict"] + + def __init__(self, *, schema: type[T], logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self.schema = schema + self._base_url = os.environ["SNOWFLAKE_CORTEX_BASE_URL"].rstrip("/") + self._token = os.environ["SNOWFLAKE_AUTH_TOKEN"] + model_name = os.environ["SNOWFLAKE_CORTEX_CHAT_MODEL"] + + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._tokenizer = CortexEstimatingTokenizer(self.model_name) + self._client = httpx.AsyncClient(timeout=HTTPX_TIMEOUT) + self._max_tokens_hint = int(os.environ.get("SNOWFLAKE_CORTEX_MAX_TOKENS", "8192")) + + @property + @override + def id(self) -> str: + return f"snowflake-cortex/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + return self._max_tokens_hint + + def _headers(self) -> dict[str, str]: + return { + "Authorization": f"Bearer {self._token}", + "Accept": "application/json", + "Content-Type": "application/json", + } + + @policy( + [ + retry( + exceptions=( + httpx.ReadTimeout, + httpx.ConnectTimeout, + httpx.RemoteProtocolError, + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ), + retry(httpx.HTTPStatusError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Cortex LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + schema: Type[T] = self.schema + + messages = [{"role": "user", "content": prompt}] + payload: dict[str, Any] = { + "model": self.model_name, + "messages": messages, + "stream": False, + } + + for k in self._provider_params: + if k in hints: + payload[k] = hints[k] + + # Strict path: provider-enforced JSON schema + if hints.get("strict", False): + try: + payload["response_format"] = { + "type": "json", + "schema": schema.model_json_schema(), + } + except Exception as e: + # If schema export fails, fall back to local validation + self.logger.debug(f"Strict schema export failed, falling back: {e}") + + url = f"{self._base_url}/api/v2/cortex/inference:complete" + + t0 = time.time() + resp = await self._client.post(url, headers=self._headers(), json=payload) + try: + resp.raise_for_status() + except httpx.HTTPStatusError as e: + self.logger.error(f"Cortex COMPLETE error {e.response.status_code}: {e.response.text}") + raise + t1 = time.time() + + data = resp.json() + msg = (data.get("choices") or [{}])[0].get("message", {}) + raw = msg.get("content") + if raw is None: + cl = msg.get("content_list") or [] + if cl and isinstance(cl[0], dict): + raw = cl[0].get("text") + if raw is None: + raw = msg if msg else data + + # Parse JSON + try: + if isinstance(raw, str): + normalized = normalize_json_output(raw) + parsed = cast(dict[str, Any], json.loads(normalized)) + elif isinstance(raw, dict): + parsed = raw + else: + parsed = json.loads(str(raw)) + except Exception: + try: + normalized = normalize_json_output(str(raw)) + parsed = cast(dict[str, Any], json.loads(normalized)) + except Exception as ex: + self.logger.error(f"Failed to parse structured output: {ex}\nRaw: {raw}") + raise + + # Validate against the schema model + try: + content = schema.model_validate(parsed) + except ValidationError as ve: + self.logger.error( + f"Structured output validation failed:\n{ve.json(indent=2)}\nRaw: {raw}" + ) + raise + + usage_block = data.get("usage") or {} + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=schema.__name__, + input_tokens=usage_block.get("prompt_tokens", 0), + output_tokens=usage_block.get("completion_tokens", 0), + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=schema.__name__, + model=self.id, + duration=(t1 - t0), + usage=UsageInfo( + input_tokens=usage_block.get("prompt_tokens", 0), + output_tokens=usage_block.get("completion_tokens", 0), + extra={}, + ), + ), + ) + + +class CortexEmbedder(BaseEmbedder): + """Embeddings via Snowflake Cortex. + + Endpoint: + POST {BASE}/api/v2/cortex/inference:embed + """ + + supported_arguments = ["dimensions"] + + def __init__(self, *, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + model_name = os.environ["SNOWFLAKE_CORTEX_EMBED_MODEL"] + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._base_url = os.environ["SNOWFLAKE_CORTEX_BASE_URL"].rstrip("/") + self._token = os.environ["SNOWFLAKE_AUTH_TOKEN"] + + self._client = httpx.AsyncClient(timeout=HTTPX_TIMEOUT) + self._tokenizer = CortexEstimatingTokenizer(self.model_name) + self._dims = self._infer_dims(self.model_name) + + @property + @override + def id(self) -> str: + return f"snowflake-cortex/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def dimensions(self) -> int: + return self._dims + + @staticmethod + def _infer_dims(model_name: str) -> int: + n = model_name.lower() + if "e5-base" in n: + return 768 + if "snowflake-arctic-embed-m" in n: + return 768 + if "snowflake-arctic-embed-l" in n: + return 1024 + return 768 + + def _headers(self) -> dict[str, str]: + return { + "Authorization": f"Bearer {self._token}", + "Accept": "application/json", + "Content-Type": "application/json", + } + + @policy( + [ + retry( + exceptions=( + httpx.ReadTimeout, + httpx.ConnectTimeout, + httpx.RemoteProtocolError, + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ), + retry(httpx.HTTPStatusError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + payload: dict[str, Any] = {"model": self.model_name, "text": texts} + if "dimensions" in hints: + payload["dimensions"] = hints["dimensions"] + + url = f"{self._base_url}/api/v2/cortex/inference:embed" + resp = await self._client.post(url, headers=self._headers(), json=payload) + try: + resp.raise_for_status() + except httpx.HTTPStatusError as e: + self.logger.error(f"Cortex EMBED error {e.response.status_code}: {e.response.text}") + raise + + data = resp.json() + + vectors: list[list[float]] = [] + for row in data.get("data", []): + emb = row.get("embedding") + if isinstance(emb, list) and emb and isinstance(emb[0], list): + emb = emb[0] + vectors.append(emb) + + return EmbeddingResult(vectors=vectors) + + @property + @override + def max_tokens(self) -> int: + return 8192 + + +class SnowflakeCortexService(NLPService): + """Parlant adapter for Snowflake Cortex (chat + embeddings). + + Environment Variables: + SNOWFLAKE_CORTEX_BASE_URL: Base account URL (e.g. https://.snowflakecomputing.com) + SNOWFLAKE_AUTH_TOKEN: OAuth/Keypair JWT/PAT token + SNOWFLAKE_CORTEX_CHAT_MODEL: Chat model name + SNOWFLAKE_CORTEX_EMBED_MODEL: Embedding model name + SNOWFLAKE_CORTEX_MAX_TOKENS: Optional max token hint + """ + + @staticmethod + def verify_environment() -> str | None: + missing = [] + if not os.environ.get("SNOWFLAKE_CORTEX_BASE_URL"): + missing.append( + "SNOWFLAKE_CORTEX_BASE_URL (e.g. https://.snowflakecomputing.com)" + ) + if not os.environ.get("SNOWFLAKE_AUTH_TOKEN"): + missing.append("SNOWFLAKE_AUTH_TOKEN (OAuth/Keypair JWT/PAT)") + if not os.environ.get("SNOWFLAKE_CORTEX_CHAT_MODEL"): + missing.append("SNOWFLAKE_CORTEX_CHAT_MODEL") + if not os.environ.get("SNOWFLAKE_CORTEX_EMBED_MODEL"): + missing.append("SNOWFLAKE_CORTEX_EMBED_MODEL") + if missing: + return "Missing Snowflake Cortex settings:\n - " + "\n - ".join(missing) + return None + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self._base_url = os.environ["SNOWFLAKE_CORTEX_BASE_URL"].rstrip("/") + self._token = os.environ["SNOWFLAKE_AUTH_TOKEN"] + self._chat_model = os.environ["SNOWFLAKE_CORTEX_CHAT_MODEL"] + self._embed_model = os.environ["SNOWFLAKE_CORTEX_EMBED_MODEL"] + + self.logger.info( + f"SnowflakeCortexService: chat={self._chat_model} | embed={self._embed_model} @ {self._base_url}" + ) + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> SchematicGenerator[T]: + return CortexSchematicGenerator[t]( # type: ignore[valid-type,misc] + schema=t, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + return CortexEmbedder( + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/together_service.py b/src/parlant/adapters/nlp/together_service.py new file mode 100644 index 0000000..1bef8b9 --- /dev/null +++ b/src/parlant/adapters/nlp/together_service.py @@ -0,0 +1,479 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +from pydantic import ValidationError +from together import AsyncTogether # type: ignore +from together.error import ( # type: ignore + RateLimitError, + Timeout, + APIConnectionError, + APIError, + ServiceUnavailableError, +) +from typing import Any, Callable, Mapping +from typing_extensions import override +import jsonfinder # type: ignore +import os +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.adapters.nlp.hugging_face import HuggingFaceEstimatingTokenizer +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Together API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Together account balance and billing status.\n" + "- Review your API usage limits in Together's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://docs.together.ai/docs/rate-limits" +) + + +class LlamaEstimatingTokenizer(EstimatingTokenizer): + def __init__(self) -> None: + self.encoding = tiktoken.encoding_for_model("gpt-4o-2024-08-06") + + @override + async def estimate_token_count(self, prompt: str) -> int: + tokens = self.encoding.encode(prompt) + return len(tokens) + 36 + + +class TogetherAISchematicGenerator(BaseSchematicGenerator[T]): + supported_hints = ["temperature", "max_tokens", "top_p", "top_k"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncTogether(api_key=os.environ.get("TOGETHER_API_KEY")) + self._estimating_tokenizer = LlamaEstimatingTokenizer() + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def tokenizer(self) -> LlamaEstimatingTokenizer: + return self._estimating_tokenizer + + @property + @override + def max_tokens(self) -> int: + # Default max tokens, can be overridden by specific model classes + return 128 * 1024 + + @policy( + [ + retry( + exceptions=( + RateLimitError, + Timeout, + APIConnectionError, + APIError, + ) + ), + retry(ServiceUnavailableError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Together LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + together_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = await self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={"type": "json_object"}, + **together_api_arguments, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + raw_content = response.choices[0].message.content or "{}" + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens, + output_tokens=response.usage.completion_tokens, + extra={}, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class Llama3_1_8B(TogetherAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class Llama3_1_70B(TogetherAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class Llama3_1_405B(TogetherAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class Llama3_3_70B(TogetherAISchematicGenerator[T]): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="meta-llama/Llama-3.3-70B-Instruct-Turbo", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class TogetherAIEmbedder(BaseEmbedder): + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = AsyncTogether(api_key=os.environ.get("TOGETHER_API_KEY")) + + @policy( + [ + retry( + exceptions=( + RateLimitError, + Timeout, + APIConnectionError, + APIError, + ) + ), + retry(ServiceUnavailableError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + _ = hints + + try: + response = await self._client.embeddings.create( + model=self.model_name, + input=texts, + ) + except RateLimitError: + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + vectors = [data_point.embedding for data_point in response.data] + return EmbeddingResult(vectors=vectors) + + +class M2Bert32K(TogetherAIEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name="togethercomputer/m2-bert-80M-32k-retrieval", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + self._estimating_tokenizer = HuggingFaceEstimatingTokenizer(self.model_name) + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def max_tokens(self) -> int: + return 32 * 1024 + + @property + @override + def tokenizer(self) -> HuggingFaceEstimatingTokenizer: + return self._estimating_tokenizer + + @property + @override + def dimensions(self) -> int: + return 768 + + +class CustomTogetherAISchematicGenerator(TogetherAISchematicGenerator[T]): + """Generic Together AI generator that accepts any model name.""" + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__( + model_name=model_name, + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class CustomTogetherAIEmbedder(TogetherAIEmbedder): + """Generic Together AI embedder that accepts any model name.""" + + def __init__(self, model_name: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name=model_name, logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + self._estimating_tokenizer = HuggingFaceEstimatingTokenizer(model_name) + self._dimensions = int(os.environ.get("TOGETHER_EMBEDDING_DIMENSIONS", "768")) + + @property + @override + def id(self) -> str: + return self.model_name + + @property + @override + def max_tokens(self) -> int: + return int(os.environ.get("TOGETHER_EMBEDDING_MAX_TOKENS", "32768")) + + @property + @override + def tokenizer(self) -> HuggingFaceEstimatingTokenizer: + return self._estimating_tokenizer + + @property + @override + def dimensions(self) -> int: + return self._dimensions + + +class TogetherService(NLPService): + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + required_vars = { + "TOGETHER_API_KEY": "your-together-api-key", + "TOGETHER_MODEL": "meta-llama/Llama-3.3-70B-Instruct-Turbo", + "TOGETHER_EMBEDDING_MODEL": "togethercomputer/m2-bert-80M-32k-retrieval", + } + + missing_vars = [] + for var_name, example_value in required_vars.items(): + if not os.environ.get(var_name): + missing_vars.append(f'export {var_name}="{example_value}"') + + if missing_vars: + return f"""\ +You're using the Together AI NLP service, but the following environment variables are not set: + +{chr(10).join(missing_vars)} + +Please set these environment variables before running Parlant. + +Available models can be found at: https://docs.together.ai/docs/inference-models +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.model_name = os.environ.get( + "TOGETHER_MODEL", "meta-llama/Llama-3.3-70B-Instruct-Turbo" + ) + self.embedding_model = os.environ.get( + "TOGETHER_EMBEDDING_MODEL", "togethercomputer/m2-bert-80M-32k-retrieval" + ) + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self._logger.info(f"Initialized TogetherService with model: {self.model_name}") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _get_specialized_generator_class( + self, + model_name: str, + schema_type: type[T], + ) -> Callable[[Logger], TogetherAISchematicGenerator[T]] | None: + """ + Returns the specialized generator class for known models, or None for custom models. + """ + model_to_class: dict[str, Callable[[Logger], TogetherAISchematicGenerator[T]]] = { + "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo": Llama3_1_8B[schema_type], # type: ignore + "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo": Llama3_1_70B[schema_type], # type: ignore + "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": Llama3_1_405B[schema_type], # type: ignore + "meta-llama/Llama-3.3-70B-Instruct-Turbo": Llama3_3_70B[schema_type], # type: ignore + } + + return model_to_class.get(model_name) + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> TogetherAISchematicGenerator[T]: + specialized_class = self._get_specialized_generator_class(self.model_name, schema_type=t) + + if specialized_class: + self._logger.debug(f"Using specialized generator for model: {self.model_name}") + return specialized_class(self._logger) + else: + self._logger.debug(f"Using custom generator for model: {self.model_name}") + return CustomTogetherAISchematicGenerator[t]( # type: ignore + model_name=self.model_name, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + def _get_specialized_embedder_class( + self, + model_name: str, + ) -> Callable[[Logger, Tracer, Meter, HealthReporter], TogetherAIEmbedder] | None: + """ + Returns the specialized embedder class for known models, or None for custom models. + """ + model_to_class: dict[ + str, Callable[[Logger, Tracer, Meter, HealthReporter], TogetherAIEmbedder] + ] = { + "togethercomputer/m2-bert-80M-32k-retrieval": M2Bert32K, + } + + return model_to_class.get(model_name) + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + specialized_class = self._get_specialized_embedder_class(self.embedding_model) + + if specialized_class: + self._logger.debug(f"Using specialized embedder for model: {self.embedding_model}") + return specialized_class(self._logger, self._tracer, self._meter, self._health_reporter) + else: + self._logger.debug(f"Using custom embedder for model: {self.embedding_model}") + return CustomTogetherAIEmbedder( + model_name=self.embedding_model, + logger=self._logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_moderation_service(self) -> ModerationService: + return NoModeration() diff --git a/src/parlant/adapters/nlp/vertex_service.py b/src/parlant/adapters/nlp/vertex_service.py new file mode 100644 index 0000000..d8cee4b --- /dev/null +++ b/src/parlant/adapters/nlp/vertex_service.py @@ -0,0 +1,923 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Maintainer: Agam Dubey hello.world.agam@gmail.com + +# Moderation service needs to be added +# Usage guidelines - Use gemini-2.5-pro and claude sonnet 4 models for best results +# Set env variables: VERTEX_AI_PROJECT_ID VERTEX_AI_REGION, VERTEX_AI_MODEL + +import os +import time +from typing import Any, Mapping, cast +from typing_extensions import override +from enum import Enum + +import google.auth +import google.api_core.exceptions +import google.genai # type: ignore +import google.genai.types # type: ignore +from google.api_core.exceptions import NotFound, TooManyRequests, ResourceExhausted, ServerError + +from anthropic import ( + AsyncAnthropicVertex, + APIConnectionError, + APIResponseValidationError, + APITimeoutError, + InternalServerError, + RateLimitError, +) # type: ignore + +import jsonfinder # type: ignore +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.moderation import ModerationService, NoModeration +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerator, + FallbackSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.loggers import Logger +from parlant.core.health import HealthReporter + + +class ModelProvider(Enum): + """Enum to identify the model provider.""" + + ANTHROPIC = "anthropic" + GOOGLE = "google" + + +class VertexAIAuthError(Exception): + """Raised when there are authentication issues with Vertex AI.""" + + pass + + +class VertexAIEstimatingTokenizer(EstimatingTokenizer): + """Tokenizer that estimates token count for Vertex AI models.""" + + def __init__(self, client: google.genai.Client, model_name: str): + self.model_name = model_name + self._client = client + if "claude" in model_name.lower(): + self.encoding: tiktoken.Encoding | None = tiktoken.encoding_for_model( + "gpt-4o-2024-08-06" + ) + else: + self.encoding = None + + @override + async def estimate_token_count(self, prompt: str) -> int: + """Estimate token count using tiktoken for Claude, Google API for Gemini.""" + if self.encoding: + tokens = self.encoding.encode(prompt) + return int(len(tokens) * 1.15) # @check - as seen on aws_service for bedrock + else: + model_approximation = { + "text-embedding-004": "gemini-2.5-pro", + }.get(self.model_name, self.model_name) + + result = await self._client.aio.models.count_tokens( + model=model_approximation, + contents=prompt, + ) + return int(result.total_tokens or 0) + + +def get_model_provider(model_name: str) -> ModelProvider: + """Determine the model provider based on model name.""" + if "claude" in model_name.lower(): + return ModelProvider.ANTHROPIC + elif "gemini" in model_name.lower(): + return ModelProvider.GOOGLE + else: + raise ValueError(f"Unknown model provider for model: {model_name}") + + +class VertexAIClaudeSchematicGenerator(BaseSchematicGenerator[T]): + """Schematic generator for Claude models via Vertex AI.""" + + supported_hints = ["temperature", "max_tokens", "top_p", "top_k"] + + def __init__(self, + project_id: str, + region: str, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self.project_id = project_id + self.region = region + + self._client = AsyncAnthropicVertex( + project_id=project_id, + region=region, + ) + + self._genai_client = google.genai.Client(project=project_id, location=region, vertexai=True) + self._tokenizer = VertexAIEstimatingTokenizer(self._genai_client, model_name) + + @property + @override + def id(self) -> str: + return f"vertex-ai/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + # Claude models support 200k tokens + return 200_000 + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + RateLimitError, + APIResponseValidationError, + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ), + retry(InternalServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Vertex LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + anthropic_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + + t_start = time.time() + try: + response = await self._client.messages.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + max_tokens=hints.get("max_tokens", 8192), + **anthropic_api_arguments, + ) + except RateLimitError: + self.logger.error( + "Vertex AI rate limit exceeded. Possible reasons:\n" + "1. Your GCP project may have insufficient quota.\n" + "2. The model may not be enabled in Vertex AI Model Garden.\n" + "3. You might have exceeded the requests-per-minute limit.\n\n" + "Recommended actions:\n" + "- Check your Vertex AI quotas in the GCP Console.\n" + "- Ensure the model is enabled in Vertex AI Model Garden.\n" + "- Review IAM permissions for the service account.\n" + "- Visit: https://console.cloud.google.com/vertex-ai/model-garden", + ) + raise + except Exception as e: + if "403" in str(e) or "permission" in str(e).lower(): + self.logger.error( + f"Permission denied accessing Vertex AI. Ensure:\n" + f"1. ADC is properly configured (run 'gcloud auth application-default login')\n" + f"2. The service account has 'Vertex AI User' role\n" + f"3. The {self.model_name} model is enabled in Vertex AI Model Garden\n" + f"Error: {e}" + ) + raise + + t_end = time.time() + + raw_content = response.content[0].text + + try: + json_content = normalize_json_output(raw_content) + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error( + f"Failed to extract JSON returned by {self.model_name}:\n{raw_content}" + ) + raise + + try: + model_content = self.schema.model_validate(json_object) + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.input_tokens, + output_tokens=response.usage.output_tokens, + ), + ), + ) + except ValidationError: + self.logger.error( + f"JSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class VertexAIGeminiSchematicGenerator(BaseSchematicGenerator[T]): + """Schematic generator for Gemini models""" + + supported_hints = ["temperature", "thinking_config"] + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + project_id: str, + region: str, + model_name: str, + ) -> None: + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self.project_id = project_id + self.region = region + + self._client = google.genai.Client(project=project_id, location=region, vertexai=True) + self._tokenizer = VertexAIEstimatingTokenizer(self._client, model_name) + + @property + @override + def id(self) -> str: + return f"vertex-ai/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + if "flash" in self.model_name.lower(): + return 1024 * 1024 # 1M tokens + else: + return 2 * 1024 * 1024 # 2M tokens + + @policy( + [ + retry( + exceptions=( + NotFound, + TooManyRequests, + ResourceExhausted, + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ), + retry(ServerError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + with self.logger.scope(f"Vertex LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + gemini_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + config = { + "response_mime_type": "application/json", + "response_schema": self.schema.model_json_schema(), + **gemini_api_arguments, + } + + t_start = time.time() + try: + response = await self._client.aio.models.generate_content( + model=self.model_name, + contents=prompt, + config=cast(google.genai.types.GenerateContentConfigOrDict, config), + ) + except TooManyRequests: + self.logger.error( + "Google API rate limit exceeded.\n\n" + "Possible reasons:\n" + "1. Insufficient API credits in your account.\n" + "2. Using a free-tier account with limited request capacity.\n" + "3. Exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Google API account balance and billing status.\n" + "- Review your API usage limits in the Google Cloud Console.\n" + "- Learn more about quotas and limits:\n" + " https://cloud.google.com/docs/quota-and-billing/quotas/quotas-overview" + ) + raise + except Exception as e: + if "403" in str(e) or "permission" in str(e).lower(): + self.logger.error( + f"Permission denied accessing Google Gen AI. Ensure:\n" + f"1. GEMINI_API_KEY is properly configured\n" + f"2. The API key has proper permissions\n" + f"3. The {self.model_name} model is accessible\n" + f"Error: {e}" + ) + raise + + t_end = time.time() + + raw_content = response.text + + try: + json_content = normalize_json_output(raw_content or "{}") + # Fix Gemini's quote issues + json_content = json_content.replace(""", '"').replace(""", '"') + + # Fix double-escaped sequences + for control_char in "utn": + json_content = json_content.replace(f"\\\\{control_char}", f"\\{control_char}") + + json_object = jsonfinder.only_json(json_content)[2] + except Exception: + self.logger.error(f"Failed to extract JSON from {self.model_name}:\n{raw_content}") + raise + + if response.usage_metadata: + self.logger.trace(response.usage_metadata.model_dump_json(indent=2)) + + try: + model_content = self.schema.model_validate(json_object) + + return SchematicGenerationResult( + content=model_content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage_metadata.prompt_token_count or 0, + output_tokens=response.usage_metadata.candidates_token_count or 0, + extra={ + "cached_input_tokens": ( + response.usage_metadata.cached_content_token_count + if response.usage_metadata + else 0 + ) + or 0 + }, + ) + if response.usage_metadata + else UsageInfo(input_tokens=0, output_tokens=0, extra={}), + ), + ) + except ValidationError: + self.logger.error(f"JSON from {self.model_name} doesn't match schema:\n{raw_content}") + raise + + +class VertexClaudeOpus4(VertexAIClaudeSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="claude-opus-4@20250514", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexClaudeSonnet4(VertexAIClaudeSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="claude-sonnet-4@20250514", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexClaudeSonnet35(VertexAIClaudeSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="claude-3-5-sonnet-v2@20241022", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexClaudeHaiku35(VertexAIClaudeSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="claude-3-5-haiku@20241022", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexGemini15Flash(VertexAIGeminiSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="gemini-1.5-flash", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexGemini15Pro(VertexAIGeminiSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="gemini-1.5-pro", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexGemini20Flash(VertexAIGeminiSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="gemini-2.0-flash", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + +class VertexGemini25Flash(VertexAIGeminiSchematicGenerator[T]): + def __init__(self, project_id: str, region: str, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter + ) -> None: + super().__init__( + project_id=project_id, + region=region, + model_name="gemini-2.5-flash", + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + ) + + @override + async def generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + return await super().generate( + prompt, + {"thinking_config": {"thinking_budget": 0}, **hints}, + ) + + +class VertexGemini25Pro(VertexAIGeminiSchematicGenerator[T]): + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + project_id: str, + region: str, + ) -> None: + super().__init__( + logger=logger, + tracer=tracer, + meter=meter, health_reporter=health_reporter, + project_id=project_id, + region=region, + model_name="gemini-2.5-pro", + ) + + +class VertexAIEmbedder(BaseEmbedder): + """Embedder using Google Gen AI text embeddings""" + + supported_hints = ["title", "task_type"] + + def __init__( + self, + logger: Logger, + tracer: Tracer, + meter: Meter, + model_name: str, + health_reporter: HealthReporter, + ): + self.project_id = os.environ.get("VERTEX_AI_PROJECT_ID") + + if not self.project_id: + raise ValueError( + "VERTEX_AI_PROJECT_ID environment variable must be set. " + "Set this to your Google Cloud Project ID." + ) + + super().__init__(logger, tracer, meter, model_name, health_reporter) + + self.region = os.environ.get("VERTEX_AI_REGION", "us-central1") + self._client = google.genai.Client( + project=self.project_id, location=self.region, vertexai=True + ) + self._tokenizer = VertexAIEstimatingTokenizer(self._client, model_name) + + @property + @override + def id(self) -> str: + return f"vertex-ai/{self.model_name}" + + @property + @override + def tokenizer(self) -> EstimatingTokenizer: + return self._tokenizer + + @property + @override + def max_tokens(self) -> int: + return 8192 + + @policy( + [ + retry( + exceptions=( + NotFound, + TooManyRequests, + ResourceExhausted, + ), + max_exceptions=3, + wait_times=(1.0, 2.0, 4.0), + ) + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + gemini_api_arguments = {k: v for k, v in hints.items() if k in self.supported_hints} + if "task_type" not in gemini_api_arguments: + gemini_api_arguments["task_type"] = "RETRIEVAL_DOCUMENT" + + try: + response = await self._client.aio.models.embed_content( # type: ignore + model=self.model_name, + contents=texts, # type: ignore + config=cast(google.genai.types.EmbedContentConfigDict, gemini_api_arguments), + ) + + vectors = [ + data_point.values for data_point in response.embeddings or [] if data_point.values + ] + return EmbeddingResult(vectors=vectors) + + except TooManyRequests: + self.logger.error( + ( + "Google API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Google API account balance and billing status.\n" + "- Review your API usage limits in Google's dashboard.\n" + "- For more details on rate limits and usage tiers, visit:\n" + " https://cloud.google.com/docs/quota-and-billing/quotas/quotas-overview" + ), + ) + raise + except Exception as e: + self.logger.error(f"Error during embedding: {e}") + raise + + +class VertexTextEmbedding004(VertexAIEmbedder): + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + super().__init__(model_name="text-embedding-004", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def dimensions(self) -> int: + return 768 + + +class VertexAIService(NLPService): + """NLP Service for Vertex AI supporting both Claude and Gemini models via appropriate APIs.""" + + CLAUDE_MODELS = { + "claude-opus-4": "claude-opus-4@20250514", + "claude-sonnet-4": "claude-sonnet-4@20250514", + "claude-sonnet-3.5": "claude-3-5-sonnet-v2@20241022", + "claude-haiku-3.5": "claude-3-5-haiku@20241022", + } + + GEMINI_MODELS = { + "gemini-1.5-flash": "gemini-1.5-flash", + "gemini-1.5-pro": "gemini-1.5-pro", + "gemini-2.0-flash": "gemini-2.0-flash", + "gemini-2.5-pro": "gemini-2.5-pro", + "gemini-2.5-flash": "gemini-2.5-flash", + } + + @staticmethod + def verify_environment() -> str | None: + """Returns an error message if the environment is not set up correctly.""" + + required_vars = { + "VERTEX_AI_PROJECT_ID": "your-project-id", + "VERTEX_AI_REGION": "us-central1", + "VERTEX_AI_MODEL": "claude-sonnet-3.5", + } + + missing_vars = [] + for var_name, example_value in required_vars.items(): + if not os.environ.get(var_name): + missing_vars.append(f"export {var_name}={example_value}") + + if missing_vars: + return f"""\ + You're using the VERTEX AI service, but required environment variables are not set. + Please set the following environment variables before running Parlant: + + {chr(10).join(missing_vars)} + """ + + return None + + @staticmethod + def validate_adc() -> str | None: + """Validate that Application Default Credentials are configured.""" + try: + credentials, project = google.auth.default() # type: ignore + if not credentials: + return """\ + No Application Default Credentials found. + Run 'gcloud auth application-default login' for local development. + """ + except Exception as e: + return f"""\ + Failed to load Application Default Credentials: {e} + Run 'gcloud auth application-default login' for local development. + """ + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + self.project_id = os.environ.get("VERTEX_AI_PROJECT_ID", "project_id") + self.region = os.environ.get("VERTEX_AI_REGION", "us-central1") + self.model_name = self._normalize_model_name( + os.environ.get("VERTEX_AI_MODEL", "claude-sonnet-3.5") + ) + + self.logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + + self.logger.info( + f"Initialized VertexAIService with model {self.model_name} " + f"in project {self.project_id}, region {self.project_id}" + ) + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + def _normalize_model_name(self, model_name: str) -> str: + """Normalize model name to full version string.""" + # Check if it's a short name we recognize + if model_name in self.CLAUDE_MODELS: + return self.CLAUDE_MODELS[model_name] + elif model_name in self.GEMINI_MODELS: + return self.GEMINI_MODELS[model_name] + # Otherwise assume it's already a full model name + return model_name + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> SchematicGenerator[T]: + """Get a schematic generator for the specified type.""" + provider = get_model_provider(self.model_name) + + if provider == ModelProvider.ANTHROPIC: + if "opus-4" in self.model_name: + primary = VertexClaudeOpus4[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + fallback = VertexClaudeSonnet4[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + return FallbackSchematicGenerator[t]( # type: ignore + primary, fallback, logger=self.logger + ) + elif "sonnet-4" in self.model_name: + return VertexClaudeSonnet4[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "claude-3-5" in self.model_name: + return VertexClaudeSonnet35[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "haiku" in self.model_name: + return VertexClaudeHaiku35[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + else: + # Default to Sonnet 3.5 + return VertexClaudeSonnet35[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + elif provider == ModelProvider.GOOGLE: + if "1.5-flash" in self.model_name: + return VertexGemini15Flash[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "1.5-pro" in self.model_name: + return VertexGemini15Pro[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "2.0-flash" in self.model_name: + return VertexGemini20Flash[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "2.5-flash" in self.model_name: + return VertexGemini25Flash[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + elif "2.5-pro" in self.model_name: + return VertexGemini25Pro[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + else: + # Default to Gemini 2.5-flash + return VertexGemini25Flash[t]( # type: ignore + project_id=self.project_id, + region=self.region, + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + else: + raise ValueError(f"Unsupported model: {self.model_name}") + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + """Get an embedder for text embeddings using Google Gen AI.""" + return VertexTextEmbedding004( + logger=self.logger, + tracer=self._tracer, + meter=self._meter, + health_reporter=self._health_reporter, + ) + + @override + async def get_moderation_service(self) -> ModerationService: # @Todo - add moderation service + """Get a moderation service.""" + return NoModeration() diff --git a/src/parlant/adapters/nlp/zhipu_service.py b/src/parlant/adapters/nlp/zhipu_service.py new file mode 100644 index 0000000..06b5684 --- /dev/null +++ b/src/parlant/adapters/nlp/zhipu_service.py @@ -0,0 +1,661 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +from itertools import chain +import time +from parlant.core.engines.alpha.guideline_matching.generic.journey.journey_backtrack_node_selection import ( + JourneyBacktrackNodeSelectionSchema, +) +from zhipuai import ZhipuAI # type: ignore +from zhipuai.core._errors import ( # type: ignore + APIConnectionError, + APITimeoutError, + APIReachLimitError, + APIServerFlowExceedError, + APIInternalError, +) +from typing import Any, Mapping +from typing_extensions import override +import json +import jsonfinder # type: ignore +import os + +from pydantic import ValidationError +import tiktoken + +from parlant.adapters.nlp.common import normalize_json_output, record_llm_metrics +from parlant.core.engines.alpha.canned_response_generator import ( + CannedResponseDraftSchema, + CannedResponseSelectionSchema, +) +from parlant.core.engines.alpha.prompt_builder import PromptBuilder +from parlant.core.engines.alpha.tool_calling.single_tool_batch import SingleToolBatchSchema +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.meter import Meter +from parlant.core.nlp.policies import policy, retry +from parlant.core.nlp.tokenization import EstimatingTokenizer +from parlant.core.nlp.service import ( + EmbedderHints, + NLPService, + SchematicGeneratorHints, + StreamingTextGeneratorHints, +) +from parlant.core.nlp.embedding import BaseEmbedder, Embedder, EmbeddingResult +from parlant.core.nlp.generation import ( + T, + BaseSchematicGenerator, + SchematicGenerationResult, + StreamingTextGenerator, +) +from parlant.core.nlp.generation_info import GenerationInfo, UsageInfo +from parlant.core.nlp.moderation import ( + BaseModerationService, + CustomerModerationContext, + ModerationCheck, + ModerationTag, +) +from parlant.core.health import HealthReporter + + +RATE_LIMIT_ERROR_MESSAGE = ( + "Zhipu AI API rate limit exceeded. Possible reasons:\n" + "1. Your account may have insufficient API credits.\n" + "2. You may be using a free-tier account with limited request capacity.\n" + "3. You might have exceeded the requests-per-minute limit for your account.\n\n" + "Recommended actions:\n" + "- Check your Zhipu AI account balance and billing status.\n" + "- Review your API usage limits in Zhipu AI's dashboard.\n" + "- For more details on rate limits and usage, visit:\n" + " https://open.bigmodel.cn/dev/api\n" +) + + +class ZhipuEstimatingTokenizer(EstimatingTokenizer): + """Tokenizer for estimating token count for Zhipu AI models using tiktoken.""" + + def __init__(self, model_name: str) -> None: + """Initialize the tokenizer with a model name. + + Args: + model_name: The name of the Zhipu AI model (e.g., 'glm-4-plus') + """ + self.model_name = model_name + # Use cl100k_base encoding as an approximation for Zhipu AI models + self.encoding = tiktoken.get_encoding("cl100k_base") + + @override + async def estimate_token_count(self, prompt: str) -> int: + """Estimate the number of tokens in the given prompt. + + Args: + prompt: The text to estimate token count for + + Returns: + The estimated number of tokens + """ + tokens = self.encoding.encode(prompt) + return len(tokens) + + +class ZhipuSchematicGenerator(BaseSchematicGenerator[T]): + """Base class for Zhipu AI schematic generators that produce structured JSON output.""" + + supported_zhipu_params = ["temperature", "max_tokens", "top_p"] + supported_hints = supported_zhipu_params + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + tokenizer_model_name: str | None = None, + ) -> None: + """Initialize the Zhipu AI schematic generator. + + Args: + model_name: The name of the Zhipu AI model (e.g., 'glm-4-plus') + logger: Logger instance for logging operations + meter: Meter instance for metrics + tokenizer_model_name: Optional model name for tokenizer (defaults to model_name) + """ + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = ZhipuAI(api_key=os.environ["ZHIPUAI_API_KEY"]) + + self._tokenizer = ZhipuEstimatingTokenizer( + model_name=tokenizer_model_name or self.model_name + ) + + @property + @override + def id(self) -> str: + """Return the model identifier in the format 'zhipu/{model_name}'. + + Returns: + The model identifier string + """ + return f"zhipu/{self.model_name}" + + @property + @override + def tokenizer(self) -> ZhipuEstimatingTokenizer: + """Return the tokenizer instance. + + Returns: + The ZhipuEstimatingTokenizer instance + """ + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + APIReachLimitError, + APIServerFlowExceedError, + ), + ), + retry(APIInternalError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + """Generate structured JSON output using Zhipu AI model. + + Args: + prompt: The prompt string or PromptBuilder instance + hints: Optional parameters for generation (temperature, max_tokens, top_p) + + Returns: + SchematicGenerationResult containing the parsed content and generation info + """ + with self.logger.scope(f"Zhipu LLM Request ({self.schema.__name__})"): + return await self._do_generate(prompt, hints) + + async def _do_generate( + self, + prompt: str | PromptBuilder, + hints: Mapping[str, Any] = {}, + ) -> SchematicGenerationResult[T]: + """Internal method to handle the actual API call and response processing. + + Args: + prompt: The prompt string or PromptBuilder instance + hints: Optional parameters for generation + + Returns: + SchematicGenerationResult containing the parsed content and generation info + """ + # Build prompt if it's a PromptBuilder instance + if isinstance(prompt, PromptBuilder): + prompt = prompt.build() + + # Filter parameters to only include supported ones + zhipu_api_arguments = {k: v for k, v in hints.items() if k in self.supported_zhipu_params} + + # Track response time + t_start = time.time() + + try: + response = self._client.chat.completions.create( + messages=[{"role": "user", "content": prompt}], + model=self.model_name, + response_format={"type": "json_object"}, + **zhipu_api_arguments, + ) + except (APIReachLimitError, APIServerFlowExceedError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + t_end = time.time() + + # Log usage information if available + if hasattr(response, "usage") and response.usage: + self.logger.trace( + f"Token usage - Input: {response.usage.prompt_tokens}, " + f"Output: {response.usage.completion_tokens}, " + f"Total: {response.usage.total_tokens}" + ) + + # Extract raw content from response + raw_content = response.choices[0].message.content or "{}" + + # Parse JSON from response + try: + json_content = json.loads(normalize_json_output(raw_content)) + except json.JSONDecodeError: + self.logger.warning(f"Invalid JSON returned by {self.model_name}:\n{raw_content})") + json_content = jsonfinder.only_json(raw_content)[2] + self.logger.warning("Found JSON content within model response; continuing...") + + # Validate against schema + try: + content = self.schema.model_validate(json_content) + + assert response.usage + + await record_llm_metrics( + self.meter, + self.model_name, + schema_name=self.schema.__name__, + input_tokens=response.usage.prompt_tokens or 0, + output_tokens=response.usage.completion_tokens or 0, + cached_input_tokens=0, + ) + + return SchematicGenerationResult( + content=content, + info=GenerationInfo( + schema_name=self.schema.__name__, + model=self.id, + duration=(t_end - t_start), + usage=UsageInfo( + input_tokens=response.usage.prompt_tokens or 0, + output_tokens=response.usage.completion_tokens or 0, + ), + ), + ) + + except ValidationError as e: + self.logger.error( + f"Error: {e.json(indent=2)}\nJSON content returned by {self.model_name} does not match expected schema:\n{raw_content}" + ) + raise + + +class GLM_4_Plus(ZhipuSchematicGenerator[T]): + """GLM-4-Plus model for high-performance tasks.""" + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + """Initialize GLM-4-Plus model. + + Args: + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(model_name="glm-4-plus", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + """Return the maximum token limit for GLM-4-Plus. + + Returns: + Maximum token count of 128K + """ + return 128 * 1024 + + +class GLM_4_Flash(ZhipuSchematicGenerator[T]): + """GLM-4-Flash model for fast response tasks.""" + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + """Initialize GLM-4-Flash model. + + Args: + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(model_name="glm-4-flash", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + """Return the maximum token limit for GLM-4-Flash. + + Returns: + Maximum token count of 128K + """ + return 128 * 1024 + + +class GLM_4_Air(ZhipuSchematicGenerator[T]): + """GLM-4-Air model for lightweight tasks.""" + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + """Initialize GLM-4-Air model. + + Args: + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(model_name="glm-4-air", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + """Return the maximum token limit for GLM-4-Air. + + Returns: + Maximum token count of 128K + """ + return 128 * 1024 + + +class ZhipuEmbedder(BaseEmbedder): + """Embedder for generating text embeddings using Zhipu AI models.""" + + supported_arguments = ["dimensions"] + + def __init__(self, + model_name: str, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + """Initialize the Zhipu AI embedder. + + Args: + model_name: The name of the Zhipu AI embedding model (e.g., 'embedding-3') + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter, model_name=model_name) + + self._client = ZhipuAI(api_key=os.environ["ZHIPUAI_API_KEY"]) + + self._tokenizer = ZhipuEstimatingTokenizer(model_name=self.model_name) + + @property + @override + def id(self) -> str: + """Return the embedding model identifier in the format 'zhipu/{model_name}'. + + Returns: + The model identifier string + """ + return f"zhipu/{self.model_name}" + + @property + @override + def tokenizer(self) -> ZhipuEstimatingTokenizer: + """Return the tokenizer instance. + + Returns: + The ZhipuEstimatingTokenizer instance + """ + return self._tokenizer + + @policy( + [ + retry( + exceptions=( + APIConnectionError, + APITimeoutError, + APIReachLimitError, + APIServerFlowExceedError, + ), + ), + retry(APIInternalError, max_exceptions=2, wait_times=(1.0, 5.0)), + ] + ) + @override + async def do_embed( + self, + texts: list[str], + hints: Mapping[str, Any] = {}, + ) -> EmbeddingResult: + """Generate embeddings for the given texts using Zhipu AI embedding API. + + Args: + texts: List of text strings to generate embeddings for + hints: Optional parameters for embedding (dimensions) + + Returns: + EmbeddingResult containing the list of embedding vectors + """ + # Filter parameters to only include supported ones + zhipu_api_arguments = {k: v for k, v in hints.items() if k in self.supported_arguments} + + try: + response = self._client.embeddings.create( + model=self.model_name, + input=texts, + **zhipu_api_arguments, + ) + except (APIReachLimitError, APIServerFlowExceedError): + self.logger.error(RATE_LIMIT_ERROR_MESSAGE) + raise + + # Log usage information if available + if hasattr(response, "usage") and response.usage: + self.logger.trace(f"Token usage - Total: {response.usage.total_tokens}") + + # Extract embeddings from response + embeddings = [item.embedding for item in response.data] + + return EmbeddingResult(vectors=embeddings) + + +class Embedding_3(ZhipuEmbedder): + """Embedding-3 model for generating text embeddings.""" + + def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, health_reporter: HealthReporter) -> None: + """Initialize Embedding-3 model. + + Args: + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(model_name="embedding-3", logger=logger, tracer=tracer, meter=meter, health_reporter=health_reporter) + + @property + @override + def max_tokens(self) -> int: + """Return the maximum token limit for Embedding-3. + + Returns: + Maximum token count of 8192 + """ + return 8192 + + @property + @override + def dimensions(self) -> int: + """Return the default embedding dimensions for Embedding-3. + + Returns: + Default embedding dimensions of 2048 + """ + return 2048 + + +class ZhipuModerationService(BaseModerationService): + """Moderation service for detecting inappropriate content using Zhipu AI.""" + + def __init__(self, model_name: str, logger: Logger, meter: Meter, health_reporter: HealthReporter) -> None: + """Initialize the Zhipu AI moderation service. + + Args: + model_name: The name of the Zhipu AI moderation model + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + super().__init__(logger, meter, health_reporter) + + self.model_name = model_name + self._client = ZhipuAI(api_key=os.environ["ZHIPUAI_API_KEY"]) + + self._hist_moderation_request_duration = meter.create_duration_histogram( + name="moderation", + description="Duration of moderation requests in milliseconds", + ) + + @override + async def do_moderate(self, context: CustomerModerationContext) -> ModerationCheck: + """Check content for inappropriate material using Zhipu AI moderation API. + + Args: + context: The moderation context containing the message to check + + Returns: + ModerationCheck object containing flagged status and tags + """ + async with self._hist_moderation_request_duration.measure(): + return await self._do_moderate(context) + + async def _do_moderate(self, context: CustomerModerationContext) -> ModerationCheck: + """Internal method to handle the actual moderation API call. + + Args: + context: The moderation context containing the message to check + + Returns: + ModerationCheck object containing flagged status and tags + """ + + def extract_tags(category: str) -> list[ModerationTag]: + """Map Zhipu AI moderation categories to ModerationTag values. + + Args: + category: The Zhipu AI category name + + Returns: + List of corresponding ModerationTag values + """ + mapping: dict[str, list[ModerationTag]] = { + "sexual": ["sexual"], + "hate": ["hate"], + "harassment": ["harassment"], + "violence": ["violence"], + "self_harm": ["self-harm"], + "self-harm": ["self-harm"], + "illegal": ["illicit"], + "illicit": ["illicit"], + } + + return mapping.get(category.replace("-", "_"), []) + + response = self._client.moderations.create( + model=self.model_name, + input=context.message, + ) + + result = response.results[0] + + return ModerationCheck( + flagged=result.flagged, + tags=list( + set( + chain.from_iterable( + extract_tags(category) + for category, detected in result.categories + if detected + ) + ) + ), + ) + + +class ZhipuService(NLPService): + """Main NLP service class for Zhipu AI integration.""" + + @staticmethod + def verify_environment() -> str | None: + """Verify that the environment is properly configured for Zhipu AI service. + + Returns: + Error message string if environment is not configured correctly, None otherwise + """ + if not os.environ.get("ZHIPUAI_API_KEY"): + return """\ +You're using the Zhipu AI NLP service, but ZHIPUAI_API_KEY is not set. +Please set ZHIPUAI_API_KEY in your environment before running Parlant. + +To obtain an API key: +1. Visit https://open.bigmodel.cn/ +2. Register or log in to your account +3. Create an API key in the console +4. Set the environment variable: export ZHIPUAI_API_KEY=your_api_key_here +""" + + return None + + def __init__(self, + logger: Logger, + tracer: Tracer, + meter: Meter, health_reporter: HealthReporter, + ) -> None: + """Initialize the Zhipu AI service. + + Args: + logger: Logger instance for logging operations + meter: Meter instance for metrics + """ + self._logger = logger + self._tracer = tracer + self._meter = meter + + self._health_reporter = health_reporter + self._logger.info("Initialized ZhipuService") + + @property + @override + def supports_streaming(self) -> bool: + return False + + @override + async def get_streaming_text_generator( + self, hints: StreamingTextGeneratorHints = {} + ) -> StreamingTextGenerator: + raise NotImplementedError("Streaming is not supported. Check supports_streaming first.") + + @override + async def get_schematic_generator( + self, t: type[T], hints: SchematicGeneratorHints = {} + ) -> ZhipuSchematicGenerator[T]: + """Get the appropriate schematic generator for the given schema type. + + Args: + t: The schema type to generate for + + Returns: + A ZhipuSchematicGenerator instance configured for the schema type + """ + return { + SingleToolBatchSchema: GLM_4_Flash[SingleToolBatchSchema], + JourneyBacktrackNodeSelectionSchema: GLM_4_Plus[JourneyBacktrackNodeSelectionSchema], + CannedResponseDraftSchema: GLM_4_Plus[CannedResponseDraftSchema], + CannedResponseSelectionSchema: GLM_4_Plus[CannedResponseSelectionSchema], + }.get(t, GLM_4_Flash[t])(self._logger, self._tracer, self._meter, self._health_reporter) # type: ignore + + @override + async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder: + """Get the embedder instance for generating text embeddings. + + Returns: + An Embedding_3 embedder instance + """ + return Embedding_3(self._logger, self._tracer, self._meter, self._health_reporter) + + @override + async def get_moderation_service(self) -> BaseModerationService: + """Get the moderation service instance for content checking. + + Returns: + A ZhipuModerationService instance + """ + return ZhipuModerationService( + model_name="moderation", + logger=self._logger, + meter=self._meter, + health_reporter=self._health_reporter, + ) diff --git a/src/parlant/adapters/tracing/opentelemetry.py b/src/parlant/adapters/tracing/opentelemetry.py new file mode 100644 index 0000000..1e9690a --- /dev/null +++ b/src/parlant/adapters/tracing/opentelemetry.py @@ -0,0 +1,280 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import contextvars +import os +from contextlib import contextmanager +from types import TracebackType +from typing import Iterator, Mapping +from typing_extensions import override, Self + +from opentelemetry import trace, context +from opentelemetry.sdk.resources import Resource +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( + OTLPSpanExporter as GrpcOTLPSpanExporter, +) +from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( + OTLPSpanExporter as HttpOTLPSpanExporter, +) +from opentelemetry.trace import Status, StatusCode, SpanContext, TraceFlags +from opentelemetry.trace.span import TraceState + +from parlant.core.common import generate_id +from parlant.core.tracer import Tracer, AttributeValue + + +class OpenTelemetryTracer(Tracer): + def __init__(self) -> None: + self._service_name = os.getenv("OTEL_SERVICE_NAME", "parlant") + + self._tracer_provider: TracerProvider + self._span_processor: BatchSpanProcessor + self._span_exporter: GrpcOTLPSpanExporter | HttpOTLPSpanExporter + self._tracer: trace.Tracer + + self._spans = contextvars.ContextVar[str]( + "otel_tracer_spans", + default="", + ) + + self._attributes = contextvars.ContextVar[Mapping[str, AttributeValue]]( + "otel_tracer_attributes", + default={}, + ) + + self._trace_id = contextvars.ContextVar[str]( + "otel_tracer_trace_id", + default="", + ) + + self._current_span = contextvars.ContextVar[trace.Span | None]( + "otel_tracer_current_span", + default=None, + ) + + async def __aenter__(self) -> Self: + resource = Resource.create({"service.name": self._service_name}) + + self._tracer_provider = TracerProvider(resource=resource) + + # Add console exporter for debugging (using BatchSpanProcessor) + console_exporter = ConsoleSpanExporter() + console_processor = BatchSpanProcessor( + span_exporter=console_exporter, + schedule_delay_millis=1000, + ) + self._tracer_provider.add_span_processor(console_processor) + + # Add OTLP exporter if endpoint is configured + endpoint = os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") + if endpoint: + insecure = os.getenv("OTEL_EXPORTER_OTLP_INSECURE", "false").lower() == "true" + protocol = os.getenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc").lower() + + match protocol: + case "http/protobuf": + self._span_exporter = HttpOTLPSpanExporter(endpoint=endpoint) + case "http/json": + raise ValueError( + "http/json protocol is not supported for traces exporter. please use http/protobuf or grpc." + ) + case "grpc": + self._span_exporter = GrpcOTLPSpanExporter( + endpoint=endpoint, + insecure=insecure, + ) + case _: + raise ValueError(f"Unsupported OTLP protocol: {protocol}") + + self._span_processor = BatchSpanProcessor( + span_exporter=self._span_exporter, + schedule_delay_millis=2000, + ) + self._tracer_provider.add_span_processor(self._span_processor) + + trace.set_tracer_provider(self._tracer_provider) + self._tracer = trace.get_tracer(__name__) + + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool: + self._tracer_provider.force_flush() + self._tracer_provider.shutdown() + + return False + + @contextmanager + @override + def span( + self, + span_id: str, + attributes: Mapping[str, AttributeValue] = {}, + ) -> Iterator[None]: + # Use standard OpenTelemetry span creation + current_spans = self._spans.get() + + # Prepare attributes first + current_attributes = self._attributes.get() + new_attributes = {**current_attributes, **attributes} + + if not current_spans: + new_spans = span_id + custom_trace_id = generate_id({"strategy": "uuid4"}) + trace_id_reset_token = self._trace_id.set(custom_trace_id) + + # Convert UUID hex to proper OpenTelemetry format + # Ensure exactly 32 hex chars (128 bits) for trace ID + trace_id_hex = str(custom_trace_id)[:32] + trace_id_int = int(trace_id_hex, 16) + + # Ensure trace ID is non-zero (OpenTelemetry requirement) + if trace_id_int == 0: + trace_id_int = 1 + + # Generate 64-bit span ID (16 hex chars) + span_uuid = generate_id({"strategy": "uuid4"}) + span_id_hex = str(span_uuid)[:16] + span_id_int = int(span_id_hex, 16) + + # Ensure span ID is non-zero (OpenTelemetry requirement) + if span_id_int == 0: + span_id_int = 1 + + span_context = SpanContext( + trace_id=trace_id_int, + span_id=span_id_int, + is_remote=False, + trace_flags=TraceFlags(0x01), + trace_state=TraceState(), + ) + + # For root spans, create a completely isolated context + # We'll create the span with our custom context after setting up the isolated context + isolated_ctx = context.Context() + ctx = isolated_ctx + else: + new_spans = current_spans + f"::{span_id}" + trace_id_reset_token = None + ctx = context.get_current() + + spans_reset_token = self._spans.set(new_spans) + attributes_reset_token = self._attributes.set(new_attributes) + + # Create span with the prepared context + if not current_spans: + # For root spans, we need to manually create a span with our custom context + # Start the span normally first + span = self._tracer.start_span(name=span_id, attributes=new_attributes, context=ctx) + # Then update its context with our custom IDs (this is a workaround) + if hasattr(span, "_context"): + span._context = span_context + else: + # For child spans, create normally + span = self._tracer.start_span(name=span_id, attributes=new_attributes, context=ctx) + + span_token = self._current_span.set(span) + + try: + with trace.use_span(span, end_on_exit=True): + yield + except Exception as e: + span.set_status(Status(StatusCode.ERROR, str(e))) + span.record_exception(e) + raise + finally: + self._spans.reset(spans_reset_token) + self._attributes.reset(attributes_reset_token) + self._current_span.reset(span_token) + if trace_id_reset_token is not None: + self._trace_id.reset(trace_id_reset_token) + + @contextmanager + @override + def attributes( + self, + attributes: Mapping[str, AttributeValue], + ) -> Iterator[None]: + current_attributes = self._attributes.get() + new_attributes = {**current_attributes, **attributes} + + attributes_reset_token = self._attributes.set(new_attributes) + + current_span = self._current_span.get() + if current_span and current_span.is_recording(): + current_span.set_attributes(attributes) + + try: + yield + finally: + self._attributes.reset(attributes_reset_token) + + @property + @override + def trace_id(self) -> str: + if trace_id := self._trace_id.get(): + return trace_id + + return "
" + + @property + @override + def span_id(self) -> str: + if spans := self._spans.get(): + return spans + + return "
" + + @override + def get_attribute( + self, + name: str, + ) -> AttributeValue | None: + attributes = self._attributes.get() + return attributes.get(name, None) + + @override + def set_attribute( + self, + name: str, + value: AttributeValue, + ) -> None: + current_attributes = self._attributes.get() + new_attributes = {**current_attributes, name: value} + self._attributes.set(new_attributes) + + current_span = self._current_span.get() + if current_span and current_span.is_recording(): + current_span.set_attribute(name, value) + + @override + def add_event( + self, + name: str, + attributes: Mapping[str, AttributeValue] = {}, + ) -> None: + current_span = self._current_span.get() + if current_span and current_span.is_recording(): + current_span.add_event(name, attributes) + + @override + def flush(self) -> None: + if hasattr(self, "_tracer_provider") and self._tracer_provider: + self._tracer_provider.force_flush() diff --git a/src/parlant/adapters/vector_db/chroma.py b/src/parlant/adapters/vector_db/chroma.py new file mode 100644 index 0000000..8c29b46 --- /dev/null +++ b/src/parlant/adapters/vector_db/chroma.py @@ -0,0 +1,731 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import json +from pathlib import Path +from typing import Any, Awaitable, Callable, Generic, Mapping, Optional, Sequence, cast +from typing_extensions import override, Self +import chromadb +from chromadb.api.collection_configuration import ( + CreateCollectionConfiguration, + CreateHNSWConfiguration, +) + + +from parlant.core.async_utils import ReaderWriterLock +from parlant.core.common import JSONSerializable +from parlant.core.loggers import Logger +from parlant.core.tracer import Tracer +from parlant.core.nlp.embedding import ( + Embedder, + EmbedderFactory, + EmbeddingCacheProvider, + NullEmbedder, +) +from parlant.core.persistence.common import Where, ensure_is_total +from parlant.core.persistence.vector_database import ( + BaseDocument, + BaseVectorCollection, + DeleteResult, + InsertResult, + SimilarDocumentResult, + UpdateResult, + VectorDatabase, + TDocument, + identity_loader, +) + + +class ChromaDatabase(VectorDatabase): + def __init__( + self, + logger: Logger, + tracer: Tracer, + dir_path: Path, + embedder_factory: EmbedderFactory, + embedding_cache_provider: EmbeddingCacheProvider, + ) -> None: + self._dir_path = dir_path + self._logger = logger + self._tracer = tracer + self._embedder_factory = embedder_factory + + self.chroma_client: chromadb.api.ClientAPI + self._collections: dict[str, ChromaCollection[BaseDocument]] = {} + + self._embedding_cache_provider = embedding_cache_provider + + async def __aenter__(self) -> Self: + self.chroma_client = chromadb.PersistentClient(str(self._dir_path)) + return self + + async def __aexit__( + self, + exc_type: Optional[type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[object], + ) -> None: + pass + + def format_collection_name( + self, + name: str, + embedder_type: type[Embedder], + ) -> str: + return f"{name}_{embedder_type.__name__}" + + # Loads documents from unembedded collection, migrates them if needed, and ensures embedded collection is in sync + async def _load_collection_documents( + self, + embedded_collection: chromadb.Collection, + unembedded_collection: chromadb.Collection, + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> chromadb.Collection: + failed_migrations: list[BaseDocument] = [] + embedder = self._embedder_factory.create_embedder(embedder_type) + + unembedded_docs = unembedded_collection.get()["metadatas"] + indexing_required = False + + if unembedded_docs: + for doc in unembedded_docs: + prospective_doc = cast(BaseDocument, doc) + try: + if loaded_doc := await document_loader(prospective_doc): + if loaded_doc != prospective_doc: + unembedded_collection.update( + ids=[prospective_doc["id"]], + documents=[loaded_doc["content"]], + metadatas=[cast(chromadb.Metadata, loaded_doc)], + embeddings=[0], + ) + indexing_required = True + else: + self._logger.warning(f'Failed to load document "{doc}"') + unembedded_collection.delete(where={"id": prospective_doc["id"]}) + failed_migrations.append(prospective_doc) + + except Exception as e: + self._logger.error(f"Failed to load document '{doc}'. error: {e}.") + failed_migrations.append(prospective_doc) + + # Store failed migrations in a separate collection for debugging + if failed_migrations: + failed_migrations_collection = await self.get_or_create_collection( + "failed_migrations", + BaseDocument, + NullEmbedder, + identity_loader, + ) + + for failed_doc in failed_migrations: + failed_migrations_collection.embedded_collection.add( + ids=[failed_doc["id"]], + documents=[failed_doc["content"]], + metadatas=[cast(chromadb.Metadata, failed_doc)], + embeddings=[0], + ) + + if ( + indexing_required + or unembedded_collection.metadata["version"] != embedded_collection.metadata["version"] + ): + await self._index_collection(embedded_collection, unembedded_collection, embedder) + + return embedded_collection + + # Syncs embedded collection with unembedded collection + async def _index_collection( + self, + collection: chromadb.Collection, + unembedded_collection: chromadb.Collection, + embedder: Embedder, + ) -> None: + if docs := unembedded_collection.get()["metadatas"]: + unembedded_docs_by_id = {doc["id"]: doc for doc in docs} + + # Remove docs from embedded collection that no longer exist in unembedded + # Update embeddings for changed docs + if docs := collection.get()["metadatas"]: + for doc in docs: + if doc["id"] not in unembedded_docs_by_id: + collection.delete(where={"id": cast(str, doc["id"])}) + else: + if doc["checksum"] != unembedded_docs_by_id[doc["id"]]["checksum"]: + embeddings = list( + ( + await embedder.embed( + [cast(str, unembedded_docs_by_id[doc["id"]]["content"])] + ) + ).vectors + ) + + collection.update( + ids=[str(doc["id"])], + documents=[cast(str, unembedded_docs_by_id[doc["id"]]["content"])], + metadatas=unembedded_docs_by_id[doc["id"]], + embeddings=embeddings, + ) + unembedded_docs_by_id.pop(doc["id"]) + + # Add new docs from unembedded to embedded collection + for doc in unembedded_docs_by_id.values(): + collection.add( + ids=[str(doc["id"])], + documents=[cast(str, doc["content"])], + metadatas=[doc], + embeddings=list((await embedder.embed([cast(str, doc["content"])])).vectors), + ) + + collection.metadata.update({"version": unembedded_collection.metadata["version"]}) + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + ) -> ChromaCollection[TDocument]: + if name in self._collections: + raise ValueError(f'Collection "{name}" already exists.') + + embedded_collection = self.chroma_client.create_collection( + name=self.format_collection_name(name, embedder_type), + metadata={"version": 1}, + embedding_function=None, + configuration=CreateCollectionConfiguration( + hnsw=CreateHNSWConfiguration(space="cosine") + ), + ) + + unembedded_collection = self.chroma_client.create_collection( + name=f"{name}_unembedded", + metadata={"version": 1}, + embedding_function=None, + ) + + self._collections[name] = ChromaCollection( + self._logger, + self._tracer, + embedded_collection=embedded_collection, + unembedded_collection=unembedded_collection, + name=name, + schema=schema, + embedder=self._embedder_factory.create_embedder(embedder_type), + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + + return cast(ChromaCollection[TDocument], self._collections[name]) + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> ChromaCollection[TDocument]: + if collection := self._collections.get(name): + return cast(ChromaCollection[TDocument], collection) + + # Find unembedded collection first which acts as the SSOT. + # Check if we have a corresponding embedded collection for the embedder type. + # Whether we find an existing embedded collection or create a new one, + # we reindex and sync it with the unembedded collection to ensure consistency + elif unembedded_collection := next( + ( + col + for col in self.chroma_client.list_collections() + if col.name == f"{name}_unembedded" + ), + None, + ): + embedded_collection = next( + ( + col + for col in self.chroma_client.list_collections() + if col.name == self.format_collection_name(name, embedder_type) + ), + None, + ) or self.chroma_client.create_collection( + name=self.format_collection_name(name, embedder_type), + metadata={"version": 1}, + embedding_function=None, + configuration=CreateCollectionConfiguration( + hnsw=CreateHNSWConfiguration(space="cosine") + ), + ) + + await self._index_collection( + collection=embedded_collection, + unembedded_collection=unembedded_collection, + embedder=self._embedder_factory.create_embedder(embedder_type), + ) + + self._collections[name] = ChromaCollection( + self._logger, + self._tracer, + embedded_collection=await self._load_collection_documents( + embedded_collection=embedded_collection, + unembedded_collection=unembedded_collection, + embedder_type=embedder_type, + document_loader=document_loader, + ), + unembedded_collection=unembedded_collection, + name=name, + schema=schema, + embedder=self._embedder_factory.create_embedder(embedder_type), + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + return cast(ChromaCollection[TDocument], self._collections[name]) + + raise ValueError(f'ChromaDB collection "{name}" not found.') + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> ChromaCollection[TDocument]: + if collection := self._collections.get(name): + return cast(ChromaCollection[TDocument], collection) + + # Get or create unembedded collection for storing raw documents + # Then get or create embedded collection for storing embeddings + # Load and migrate documents from unembedded collection, then reindex embedded collection to ensure it is in sync + unembedded_collection = next( + ( + col + for col in self.chroma_client.list_collections() + if col.name == f"{name}_unembedded" + ), + None, + ) or self.chroma_client.create_collection( + name=f"{name}_unembedded", + metadata={"version": 1}, + embedding_function=None, + ) + + embedded_collection = next( + ( + col + for col in self.chroma_client.list_collections() + if col.name == self.format_collection_name(name, embedder_type) + ), + None, + ) or self.chroma_client.create_collection( + name=self.format_collection_name(name, embedder_type), + metadata={"version": 1}, + configuration=CreateCollectionConfiguration( + hnsw=CreateHNSWConfiguration(space="cosine") + ), + ) + + self._collections[name] = ChromaCollection( + self._logger, + self._tracer, + embedded_collection=await self._load_collection_documents( + embedded_collection=embedded_collection, + unembedded_collection=unembedded_collection, + embedder_type=embedder_type, + document_loader=document_loader, + ), + unembedded_collection=unembedded_collection, + name=name, + schema=schema, + embedder=self._embedder_factory.create_embedder(embedder_type), + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + + return cast(ChromaCollection[TDocument], self._collections[name]) + + @override + async def delete_collection( + self, + name: str, + ) -> None: + if name not in self._collections: + raise ValueError(f'Collection "{name}" not found.') + + self.chroma_client.delete_collection(name=name) + self.chroma_client.delete_collection(name=f"{name}_unembedded") + del self._collections[name] + + @override + async def upsert_metadata( + self, + key: str, + value: JSONSerializable, + ) -> None: + if metadata_collection := next( + (col for col in self.chroma_client.list_collections() if col.name == "metadata"), + None, + ): + pass + else: + metadata_collection = self.chroma_client.create_collection( + name="metadata", + embedding_function=None, + ) + + if metadatas := metadata_collection.get()["metadatas"]: + document = cast(dict[str, JSONSerializable], metadatas[0]) + document[key] = value + + metadata_collection.update( + ids=["__metadata__"], + documents=["__metadata__"], + metadatas=[cast(chromadb.Metadata, document)], + embeddings=[0], + ) + else: + document = {key: value} + + metadata_collection.add( + ids=["__metadata__"], + documents=["__metadata__"], + metadatas=[cast(chromadb.Metadata, document)], + embeddings=[0], + ) + + @override + async def remove_metadata( + self, + key: str, + ) -> None: + if metadata_collection := next( + (col for col in self.chroma_client.list_collections() if col.name == "metadata"), + None, + ): + if metadatas := metadata_collection.get()["metadatas"]: + document = cast(dict[str, JSONSerializable], metadatas[0]) + document.pop(key) + + metadata_collection.update( + ids=["__metadata__"], + documents=["__metadata__"], + metadatas=[cast(chromadb.Metadata, document)], + embeddings=[0], + ) + else: + raise ValueError(f'Metadata with key "{key}" not found.') + else: + raise ValueError("Metadata collection not found.") + + @override + async def read_metadata( + self, + ) -> Mapping[str, JSONSerializable]: + if metadata_collection := next( + (col for col in self.chroma_client.list_collections() if col.name == "metadata"), + None, + ): + if metadatas := metadata_collection.get()["metadatas"]: + return cast(dict[str, JSONSerializable], metadatas[0]) + else: + return {} + else: + return {} + + +class ChromaCollection(Generic[TDocument], BaseVectorCollection[TDocument]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + embedded_collection: chromadb.Collection, + unembedded_collection: chromadb.Collection, + name: str, + schema: type[TDocument], + embedder: Embedder, + embedding_cache_provider: EmbeddingCacheProvider, + version: int, + ) -> None: + super().__init__(tracer) + + self._logger = logger + self._tracer = tracer + self._name = name + self._schema = schema + self._embedder = embedder + self._embedding_cache_provider = embedding_cache_provider + self._version = version + + self._lock = ReaderWriterLock() + self._unembedded_collection = unembedded_collection + self.embedded_collection = embedded_collection + + @override + async def find( + self, + filters: Where, + ) -> Sequence[TDocument]: + async with self._lock.reader_lock: + if metadatas := self.embedded_collection.get( + where=cast(chromadb.Where, filters) or None + )["metadatas"]: + return [cast(TDocument, m) for m in metadatas] + + return [] + + @override + async def find_one( + self, + filters: Where, + ) -> Optional[TDocument]: + async with self._lock.reader_lock: + if metadatas := self.embedded_collection.get( + where=cast(chromadb.Where, filters) or None + )["metadatas"]: + return cast(TDocument, {k: v for k, v in metadatas[0].items()}) + + return None + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[document["content"]], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([document["content"]])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[document["content"]], + vectors=embeddings, + ) + + async with self._lock.writer_lock: + self._version += 1 + + self._unembedded_collection.add( + ids=[document["id"]], + documents=[document["content"]], + metadatas=[cast(chromadb.Metadata, document)], + embeddings=[0], + ) + + self._unembedded_collection.modify( + metadata={**self._unembedded_collection.metadata, **{"version": self._version}} + ) + + self.embedded_collection.add( + ids=[document["id"]], + documents=[document["content"]], + metadatas=[cast(chromadb.Metadata, document)], + embeddings=embeddings, + ) + self.embedded_collection.modify( + metadata={**self.embedded_collection.metadata, **{"version": self._version}} + ) + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + async with self._lock.writer_lock: + if docs := self.embedded_collection.get(where=cast(chromadb.Where, filters) or None)[ + "metadatas" + ]: + doc = docs[0] + + if "content" in params: + content = params["content"] + document = params["content"] + else: + content = str(doc["content"]) + document = str(doc["content"]) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[content], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([content])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[content], + vectors=embeddings, + ) + + updated_document = {**doc, **params} + + self._version += 1 + + self._unembedded_collection.update( + ids=[str(doc["id"])], + documents=[document], + metadatas=[cast(chromadb.Metadata, updated_document)], + embeddings=[0], + ) + self._unembedded_collection.modify( + metadata={**self._unembedded_collection.metadata, **{"version": self._version}} + ) + + self.embedded_collection.update( + ids=[str(doc["id"])], + documents=[document], + metadatas=[cast(chromadb.Metadata, updated_document)], + embeddings=embeddings, # type: ignore + ) + self.embedded_collection.modify( + metadata={**self.embedded_collection.metadata, **{"version": self._version}} + ) + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=cast(TDocument, updated_document), + ) + + elif upsert: + ensure_is_total(params, self._schema) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[params["content"]], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([params["content"]])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[params["content"]], + vectors=embeddings, + ) + + self._version += 1 + + self._unembedded_collection.add( + ids=[params["id"]], + documents=[params["content"]], + metadatas=[cast(chromadb.Metadata, params)], + embeddings=[0], + ) + self._unembedded_collection.modify( + metadata={**self._unembedded_collection.metadata, **{"version": self._version}} + ) + + self.embedded_collection.add( + ids=[params["id"]], + documents=[params["content"]], + metadatas=[cast(chromadb.Metadata, params)], + embeddings=embeddings, + ) + self.embedded_collection.modify( + metadata={**self.embedded_collection.metadata, **{"version": self._version}} + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + async with self._lock.writer_lock: + if docs := self.embedded_collection.get(where=cast(chromadb.Where, filters) or None)[ + "metadatas" + ]: + if len(docs) > 1: + raise ValueError( + f"ChromaCollection delete_one: detected more than one document with filters '{filters}'. Aborting..." + ) + deleted_document = docs[0] + + self._version += 1 + + self._unembedded_collection.delete(where=cast(chromadb.Where, filters) or None) + self._unembedded_collection.modify( + metadata={**self._unembedded_collection.metadata, **{"version": self._version}} + ) + + self.embedded_collection.delete(where=cast(chromadb.Where, filters) or None) + self.embedded_collection.modify( + metadata={**self.embedded_collection.metadata, **{"version": self._version}} + ) + + return DeleteResult( + deleted_count=1, + acknowledged=True, + deleted_document=cast(TDocument, deleted_document), + ) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) + + @override + async def do_find_similar_documents( + self, + filters: Where, + query: str, + k: int, + hints: Mapping[str, Any] = {}, + ) -> Sequence[SimilarDocumentResult[TDocument]]: + async with self._lock.reader_lock: + query_embeddings = list((await self._embedder.embed([query], hints)).vectors) + + docs = self.embedded_collection.query( + where=cast(chromadb.Where, filters) or None, + query_embeddings=query_embeddings, + n_results=k, + ) + + if not docs["metadatas"]: + return [] + + self._logger.trace( + f"Similar documents found\n{json.dumps(docs['metadatas'][0], indent=2)}" + ) + + assert docs["distances"] + return [ + SimilarDocumentResult(document=cast(TDocument, m), distance=d) + for m, d in zip(docs["metadatas"][0], docs["distances"][0]) + ] diff --git a/src/parlant/adapters/vector_db/mongo.py b/src/parlant/adapters/vector_db/mongo.py new file mode 100644 index 0000000..ebd9a27 --- /dev/null +++ b/src/parlant/adapters/vector_db/mongo.py @@ -0,0 +1,596 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Requires MongoDB Atlas with vector search support. +# Atlas builds the index asynchronously after creation. + +from __future__ import annotations + +import asyncio +import json +from typing import Any, Awaitable, Callable, Generic, Mapping, Optional, Sequence, cast + +from pymongo import AsyncMongoClient +from pymongo.asynchronous.collection import AsyncCollection +from pymongo.asynchronous.database import AsyncDatabase +from pymongo.operations import SearchIndexModel +from typing_extensions import Self, override + +from parlant.core.async_utils import ReaderWriterLock +from parlant.core.common import JSONSerializable +from parlant.core.loggers import Logger +from parlant.core.nlp.embedding import ( + Embedder, + EmbedderFactory, + EmbeddingCacheProvider, +) +from parlant.core.persistence.common import Where, ensure_is_total +from parlant.core.persistence.vector_database import ( + BaseDocument, + BaseVectorCollection, + DeleteResult, + InsertResult, + SimilarDocumentResult, + TDocument, + UpdateResult, + VectorDatabase, +) +from parlant.core.tracer import Tracer + +VECTOR_INDEX_NAME = "vector_index" +_METADATA_COLLECTION_NAME = "_vector_metadata" +_INDEX_READY_POLL_INTERVAL = 0.5 +_INDEX_READY_TIMEOUT = 60.0 + + +class MongoVectorDatabase(VectorDatabase): + def __init__( + self, + mongo_client: AsyncMongoClient[Any], + database_name: str, + logger: Logger, + tracer: Tracer, + embedder_factory: EmbedderFactory, + embedding_cache_provider: EmbeddingCacheProvider, + ) -> None: + self._mongo_client = mongo_client + self._database_name = database_name + self._logger = logger + self._tracer = tracer + self._embedder_factory = embedder_factory + self._embedding_cache_provider = embedding_cache_provider + + self._database: AsyncDatabase[Any] = mongo_client[database_name] + self._collections: dict[str, MongoVectorCollection[BaseDocument]] = {} + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: Optional[type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[object], + ) -> None: + self._collections.clear() + + def _format_collection_name( + self, + name: str, + embedder_type: type[Embedder], + ) -> str: + return f"{name}_{embedder_type.__name__}" + + async def _ensure_collection_exists( + self, + collection_name: str, + ) -> None: + """Ensure the MongoDB collection exists by creating it if needed.""" + existing = await self._database.list_collection_names() + if collection_name not in existing: + await self._database.create_collection(collection_name) + + async def _ensure_vector_index( + self, + mongo_collection: AsyncCollection[Any], + embedder: Embedder, + ) -> None: + """Create a vector search index on the collection if it doesn't exist.""" + # Ensure the collection exists in MongoDB before creating a search index + await self._ensure_collection_exists(mongo_collection.name) + + # Check if the index already exists + existing_indexes: list[Mapping[str, Any]] = [] + cursor = await mongo_collection.list_search_indexes() + async for index in cursor: + existing_indexes.append(index) + + for index in existing_indexes: + if index.get("name") == VECTOR_INDEX_NAME: + return + + search_index_model = SearchIndexModel( + definition={ + "fields": [ + { + "type": "vector", + "path": "__embedding__", + "numDimensions": embedder.dimensions, + "similarity": "cosine", + }, + { + "type": "filter", + "path": "id", + }, + { + "type": "filter", + "path": "version", + }, + { + "type": "filter", + "path": "name", + }, + { + "type": "filter", + "path": "checksum", + }, + ] + }, + name=VECTOR_INDEX_NAME, + type="vectorSearch", + ) + + await mongo_collection.create_search_index(search_index_model) + self._logger.info( + f"Created vector search index '{VECTOR_INDEX_NAME}' " + f"on collection '{mongo_collection.name}'" + ) + + # Wait for the index to be ready + await self._wait_for_index_ready(mongo_collection) + + async def _wait_for_index_ready( + self, + mongo_collection: AsyncCollection[Any], + ) -> None: + """Poll until the vector search index is queryable.""" + elapsed = 0.0 + while elapsed < _INDEX_READY_TIMEOUT: + index_cursor = await mongo_collection.list_search_indexes() + async for index in index_cursor: + if index.get("name") == VECTOR_INDEX_NAME and index.get("queryable") is True: + return + await asyncio.sleep(_INDEX_READY_POLL_INTERVAL) + elapsed += _INDEX_READY_POLL_INTERVAL + + self._logger.warning( + f"Vector search index '{VECTOR_INDEX_NAME}' on '{mongo_collection.name}' " + f"did not become ready within {_INDEX_READY_TIMEOUT}s" + ) + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + ) -> MongoVectorCollection[TDocument]: + if name in self._collections: + raise ValueError(f'Collection "{name}" already exists.') + + embedder = self._embedder_factory.create_embedder(embedder_type) + collection_name = self._format_collection_name(name, embedder_type) + + mongo_collection = self._database[collection_name] + await self._ensure_vector_index(mongo_collection, embedder) + + collection = MongoVectorCollection( + logger=self._logger, + tracer=self._tracer, + mongo_collection=mongo_collection, + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + ) + + self._collections[name] = collection # type: ignore[assignment] + return collection # type: ignore[return-value] + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> MongoVectorCollection[TDocument]: + if collection := self._collections.get(name): + return cast(MongoVectorCollection[TDocument], collection) + + embedder = self._embedder_factory.create_embedder(embedder_type) + collection_name = self._format_collection_name(name, embedder_type) + + # Check if the collection exists in MongoDB + existing_collections = await self._database.list_collection_names() + if collection_name not in existing_collections: + raise ValueError(f'Mongo vector collection "{name}" not found.') + + mongo_collection = self._database[collection_name] + await self._ensure_vector_index(mongo_collection, embedder) + + # Run document loader on existing documents for migration + await self._migrate_documents(mongo_collection, embedder, document_loader) + + collection = MongoVectorCollection( + logger=self._logger, + tracer=self._tracer, + mongo_collection=mongo_collection, + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + ) + + self._collections[name] = collection # type: ignore[assignment] + return collection # type: ignore[return-value] + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> MongoVectorCollection[TDocument]: + if collection := self._collections.get(name): + return cast(MongoVectorCollection[TDocument], collection) + + embedder = self._embedder_factory.create_embedder(embedder_type) + collection_name = self._format_collection_name(name, embedder_type) + + mongo_collection = self._database[collection_name] + await self._ensure_vector_index(mongo_collection, embedder) + + # Run document loader on existing documents for migration + await self._migrate_documents(mongo_collection, embedder, document_loader) + + collection = MongoVectorCollection( + logger=self._logger, + tracer=self._tracer, + mongo_collection=mongo_collection, + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + ) + + self._collections[name] = collection # type: ignore[assignment] + return collection # type: ignore[return-value] + + async def _migrate_documents( + self, + mongo_collection: AsyncCollection[Any], + embedder: Embedder, + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> None: + """Run document_loader on all existing documents, updating or removing as needed.""" + cursor = mongo_collection.find({}) + async for raw_doc in cursor: + mongo_id = raw_doc.pop("_id", None) + # Strip embedding from the document before passing to loader + raw_doc.pop("__embedding__", None) + + prospective_doc = cast(BaseDocument, raw_doc) + try: + loaded_doc = await document_loader(prospective_doc) + if loaded_doc: + if loaded_doc != prospective_doc: + # Re-embed if content changed + content = loaded_doc.get("content", "") + embeddings = list((await embedder.embed([str(content)])).vectors) + update_doc = dict(loaded_doc) + update_doc["__embedding__"] = list(embeddings[0]) + await mongo_collection.replace_one( + {"_id": mongo_id}, + update_doc, + ) + else: + self._logger.warning(f'Failed to load document "{prospective_doc}"') + await mongo_collection.delete_one({"_id": mongo_id}) + except Exception as e: + self._logger.error(f"Failed to load document '{prospective_doc}' with error: {e}.") + + @override + async def delete_collection( + self, + name: str, + ) -> None: + if name not in self._collections: + raise ValueError(f'Collection "{name}" not found.') + + collection = self._collections[name] + await collection._mongo_collection.drop() + del self._collections[name] + + @override + async def upsert_metadata( + self, + key: str, + value: JSONSerializable, + ) -> None: + metadata_collection = self._database[_METADATA_COLLECTION_NAME] + await metadata_collection.update_one( + {"_id": "metadata"}, + {"$set": {key: value}}, + upsert=True, + ) + + @override + async def remove_metadata( + self, + key: str, + ) -> None: + metadata_collection = self._database[_METADATA_COLLECTION_NAME] + await metadata_collection.update_one( + {"_id": "metadata"}, + {"$unset": {key: ""}}, + ) + + @override + async def read_metadata( + self, + ) -> Mapping[str, JSONSerializable]: + metadata_collection = self._database[_METADATA_COLLECTION_NAME] + doc = await metadata_collection.find_one({"_id": "metadata"}) + if doc is None: + return {} + + result = dict(doc) + result.pop("_id", None) + return result + + +class MongoVectorCollection(Generic[TDocument], BaseVectorCollection[TDocument]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + mongo_collection: AsyncCollection[Any], + name: str, + schema: type[TDocument], + embedder: Embedder, + embedding_cache_provider: EmbeddingCacheProvider, + ) -> None: + super().__init__(tracer) + + self._logger = logger + self._name = name + self._schema = schema + self._embedder = embedder + self._embedding_cache_provider = embedding_cache_provider + self._mongo_collection = mongo_collection + self._lock = ReaderWriterLock() + + def _strip_internal_fields(self, doc: dict[str, Any]) -> TDocument: + """Remove MongoDB internal fields and embedding from a document.""" + doc.pop("_id", None) + doc.pop("__embedding__", None) + return cast(TDocument, doc) + + async def _get_embedding(self, content: str) -> list[float]: + """Get embedding for content, using cache if available.""" + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[content], + ): + return list(e.vectors[0]) + + embeddings = list((await self._embedder.embed([content])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[content], + vectors=list(embeddings), + ) + return list(embeddings[0]) + + @override + async def find( + self, + filters: Where, + ) -> Sequence[TDocument]: + async with self._lock.reader_lock: + mongo_filter = dict(filters) if filters else {} + + docs: list[TDocument] = [] + async for raw_doc in self._mongo_collection.find(mongo_filter): + docs.append(self._strip_internal_fields(raw_doc)) + + return docs + + @override + async def find_one( + self, + filters: Where, + ) -> Optional[TDocument]: + async with self._lock.reader_lock: + mongo_filter = dict(filters) if filters else {} + + raw_doc = await self._mongo_collection.find_one(mongo_filter) + if raw_doc is None: + return None + + return self._strip_internal_fields(raw_doc) + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + embedding = await self._get_embedding(document["content"]) + + async with self._lock.writer_lock: + mongo_doc = dict(document) + mongo_doc["__embedding__"] = embedding + + await self._mongo_collection.insert_one(mongo_doc) + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + async with self._lock.writer_lock: + mongo_filter = dict(filters) if filters else {} + + existing = await self._mongo_collection.find_one(mongo_filter) + + if existing: + doc = dict(existing) + doc.pop("_id", None) + doc.pop("__embedding__", None) + + content = params.get("content", doc.get("content", "")) + embedding = await self._get_embedding(str(content)) + + updated_doc = {**doc, **params} + updated_doc["__embedding__"] = embedding + + await self._mongo_collection.replace_one( + {"_id": existing["_id"]}, + updated_doc, + ) + + updated_doc.pop("_id", None) + updated_doc.pop("__embedding__", None) + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=cast(TDocument, updated_doc), + ) + + elif upsert: + ensure_is_total(params, self._schema) + + embedding = await self._get_embedding(params["content"]) + + mongo_doc = dict(params) + mongo_doc["__embedding__"] = embedding + + await self._mongo_collection.insert_one(mongo_doc) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + async with self._lock.writer_lock: + mongo_filter = dict(filters) if filters else {} + + existing = await self._mongo_collection.find_one(mongo_filter) + + if existing: + await self._mongo_collection.delete_one({"_id": existing["_id"]}) + + return DeleteResult( + deleted_count=1, + acknowledged=True, + deleted_document=self._strip_internal_fields(existing), + ) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) + + @override + async def do_find_similar_documents( + self, + filters: Where, + query: str, + k: int, + hints: Mapping[str, Any] = {}, + ) -> Sequence[SimilarDocumentResult[TDocument]]: + async with self._lock.reader_lock: + query_embeddings = list((await self._embedder.embed([query], hints)).vectors) + + if not query_embeddings or len(query_embeddings[0]) == 0: + self._logger.warning(f"Empty embedding generated for query: {query}") + return [] + + # Build the $vectorSearch stage + vector_search_stage: dict[str, Any] = { + "$vectorSearch": { + "index": VECTOR_INDEX_NAME, + "path": "__embedding__", + "queryVector": list(query_embeddings[0]), + "numCandidates": max(k * 10, 100), + "limit": k, + } + } + + # Add pre-filter if filters are provided + mongo_filter = dict(filters) if filters else {} + if mongo_filter: + vector_search_stage["$vectorSearch"]["filter"] = mongo_filter + + pipeline: list[dict[str, Any]] = [ + vector_search_stage, + { + "$addFields": { + "search_score": {"$meta": "vectorSearchScore"}, + } + }, + ] + + results: list[SimilarDocumentResult[TDocument]] = [] + agg_cursor = await self._mongo_collection.aggregate(pipeline) + async for raw_doc in agg_cursor: + score = raw_doc.pop("search_score", 0.0) + doc = self._strip_internal_fields(raw_doc) + results.append( + SimilarDocumentResult( + document=doc, + distance=1.0 - float(score), + ) + ) + + self._logger.trace( + f"Similar documents found\n{json.dumps([dict(r.document) for r in results], indent=2)}" + ) + + return results diff --git a/src/parlant/adapters/vector_db/qdrant.py b/src/parlant/adapters/vector_db/qdrant.py new file mode 100644 index 0000000..feea506 --- /dev/null +++ b/src/parlant/adapters/vector_db/qdrant.py @@ -0,0 +1,1392 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import asyncio +import gc +import hashlib +import json +import sys +from pathlib import Path +from typing import Any, Awaitable, Callable, Generic, Mapping, Optional, Sequence, TypeVar, cast +from typing_extensions import override, Self +from qdrant_client import QdrantClient # type: ignore[import-untyped] +from qdrant_client.http import models # type: ignore[import-untyped] +from qdrant_client.http.models import Filter, FieldCondition, Range, MatchValue, MatchAny # type: ignore[import-untyped] +from qdrant_client.http.exceptions import ResponseHandlingException # type: ignore[import-untyped] + + +from parlant.core.async_utils import ReaderWriterLock +from parlant.core.common import JSONSerializable +from parlant.core.loggers import Logger +from parlant.core.nlp.embedding import ( + Embedder, + EmbedderFactory, + EmbeddingCacheProvider, + NullEmbedder, +) +from parlant.core.persistence.common import Where, ensure_is_total +from parlant.core.persistence.vector_database import ( + BaseDocument, + BaseVectorCollection, + DeleteResult, + InsertResult, + SimilarDocumentResult, + UpdateResult, + VectorDatabase, + TDocument, + identity_loader, +) +from parlant.core.tracer import Tracer + + +T = TypeVar("T") + + +async def _retry_on_timeout_async( + operation: Callable[[], Awaitable[T]], + max_retries: int = 3, + base_delay: float = 1.0, + logger: Optional[Logger] = None, +) -> T: + """ + Retry an async operation on timeout errors with exponential backoff. + + Args: + operation: The async operation to retry (callable that returns Awaitable[T]) + max_retries: Maximum number of retry attempts + base_delay: Base delay in seconds for exponential backoff + logger: Optional logger for warning messages + + Returns: + The result of the operation + + Raises: + The last exception if all retries fail + """ + last_exception: Exception | None = None + + for attempt in range(max_retries): + try: + return await operation() + except (ResponseHandlingException, Exception) as e: + # Check if it's a timeout error + error_str = str(e).lower() + is_timeout = ( + "timeout" in error_str + or "read operation timed out" in error_str + or "readtimeout" in error_str + ) + + if is_timeout and attempt < max_retries - 1: + delay = base_delay * (2**attempt) # Exponential backoff: 1s, 2s, 4s + if logger: + logger.warning( + f"Qdrant operation timed out (attempt {attempt + 1}/{max_retries}). " + f"Retrying in {delay}s..." + ) + await asyncio.sleep(delay) + last_exception = e + continue + else: + # Not a timeout or out of retries + raise + + # Should never reach here, but just in case + if last_exception: + raise last_exception + raise RuntimeError("Retry logic failed unexpectedly") + + +def _string_id_to_int(doc_id: str) -> int: + """Convert a string ID to an integer for Qdrant point IDs.""" + # Use hash to convert string to integer + # Take absolute value and use modulo to ensure it fits in int64 range + hash_value = int(hashlib.sha256(doc_id.encode()).hexdigest()[:15], 16) + # Ensure it's within safe int64 range (Qdrant supports int64) + return hash_value % (2**63 - 1) + + +def _extract_field_names_from_where(where: Where, field_names: set[str]) -> None: + """Recursively extract all field names from a Where filter.""" + if not where: + return + + # Handle logical operators + if "$and" in where: + for sub_filter in where["$and"]: + if isinstance(sub_filter, dict): + _extract_field_names_from_where(sub_filter, field_names) + return + + if "$or" in where: + for sub_filter in where["$or"]: + if isinstance(sub_filter, dict): + _extract_field_names_from_where(sub_filter, field_names) + return + + # Handle field conditions + for field_name, field_filter in where.items(): + if isinstance(field_filter, dict): + # This is a field with operators + field_names.add(field_name) + # Recursively check nested filters (for complex nested structures) + for operator, filter_value in field_filter.items(): + if operator in ["$and", "$or"] and isinstance(filter_value, list): + for nested_filter in filter_value: + if isinstance(nested_filter, dict): + _extract_field_names_from_where(nested_filter, field_names) + + +def _convert_where_to_qdrant_filter(where: Where) -> Optional[Filter]: + """Convert a Where filter to a Qdrant Filter.""" + if not where: + return None + + # Handle logical operators + if "$and" in where: + and_conditions: list[Filter] = [] + for sub_filter in where["$and"]: + if isinstance(sub_filter, dict): + qdrant_filter = _convert_where_to_qdrant_filter(sub_filter) + if qdrant_filter: + and_conditions.append(qdrant_filter) + if and_conditions: + return Filter(must=and_conditions) + return None + + if "$or" in where: + or_conditions: list[Filter] = [] + for sub_filter in where["$or"]: + if isinstance(sub_filter, dict): + qdrant_filter = _convert_where_to_qdrant_filter(sub_filter) + if qdrant_filter: + or_conditions.append(qdrant_filter) + if or_conditions: + return Filter(should=or_conditions) + return None + + # Handle field conditions + field_conditions: list[FieldCondition] = [] + for field_name, field_filter in where.items(): + if isinstance(field_filter, dict): + for operator, filter_value in field_filter.items(): + if operator == "$eq": + field_conditions.append( + FieldCondition(key=field_name, match=MatchValue(value=filter_value)) + ) + elif operator == "$ne": + # Qdrant doesn't have $ne, so we use must_not + return Filter( + must_not=[ + FieldCondition(key=field_name, match=MatchValue(value=filter_value)) + ] + ) + elif operator == "$gt": + field_conditions.append( + FieldCondition(key=field_name, range=Range(gt=filter_value)) + ) + elif operator == "$gte": + field_conditions.append( + FieldCondition(key=field_name, range=Range(gte=filter_value)) + ) + elif operator == "$lt": + field_conditions.append( + FieldCondition(key=field_name, range=Range(lt=filter_value)) + ) + elif operator == "$lte": + field_conditions.append( + FieldCondition(key=field_name, range=Range(lte=filter_value)) + ) + elif operator == "$in": + field_conditions.append( + FieldCondition(key=field_name, match=MatchAny(any=list(filter_value))) + ) + elif operator == "$nin": + # Qdrant doesn't have $nin, so we use must_not with MatchAny + return Filter( + must_not=[ + FieldCondition(key=field_name, match=MatchAny(any=list(filter_value))) + ] + ) + + if field_conditions: + return Filter(must=field_conditions) # type: ignore[arg-type] + return None + + +class QdrantDatabase(VectorDatabase): + def __init__( + self, + logger: Logger, + tracer: Tracer, + path: Optional[Path] = None, + url: Optional[str] = None, + api_key: Optional[str] = None, + embedder_factory: Optional[EmbedderFactory] = None, + embedding_cache_provider: Optional[EmbeddingCacheProvider] = None, + ) -> None: + self._path = path + self._url = url + self._api_key = api_key + self._logger = logger + self._tracer = tracer + self._embedder_factory = embedder_factory + + self.qdrant_client: Optional[QdrantClient] = None + self._collections: dict[str, QdrantCollection[BaseDocument]] = {} + + self._embedding_cache_provider = embedding_cache_provider + + async def __aenter__(self) -> Self: + if self._path: + # On Windows, retry if the storage folder is locked (from previous instance) + # This handles cases where a previous instance hasn't fully released file locks + max_retries = 5 if sys.platform == "win32" else 1 + for attempt in range(max_retries): + try: + self.qdrant_client = QdrantClient(path=str(self._path)) + break + except RuntimeError as e: + if "already accessed" in str(e) and attempt < max_retries - 1: + import asyncio + + # Exponential backoff: 0.05s, 0.1s, 0.15s, 0.2s, 0.25s + delay = 0.05 * (attempt + 1) + await asyncio.sleep(delay) + continue + raise + elif self._url: + # Set longer timeout for cloud operations (60 seconds) + # This helps with large batch operations and slow network connections + self.qdrant_client = QdrantClient( + url=self._url, + api_key=self._api_key, + timeout=60, # 60 second timeout for cloud operations + ) + else: + # Default to in-memory for testing + self.qdrant_client = QdrantClient(":memory:") + return self + + async def __aexit__( + self, + exc_type: Optional[type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[object], + ) -> None: + # Close collections first to release any resources + self._collections.clear() + + # Close Qdrant client to release file locks (important on Windows) + if self.qdrant_client is not None: + try: + # Explicitly close the client to release file locks and resources + # This is critical on Windows where file locks can persist + # The close() method releases all file handles and locks + self.qdrant_client.close() + except AttributeError: + # If close() doesn't exist (shouldn't happen, but be safe) + pass + except Exception as e: + # Log but don't fail if close() raises an exception + self._logger.warning(f"Error closing Qdrant client: {e}") + finally: + # Clear the reference and force garbage collection + # This ensures all Python references are released + client = self.qdrant_client + self.qdrant_client = None + del client + # Only force GC on Windows where file locks are more persistent + if sys.platform == "win32": + gc.collect() + # On Windows, file locks may take a moment to be released by the OS + # Even after close(), Windows may need a brief moment to release locks + import asyncio + + await asyncio.sleep(0.05) # Minimal delay for Windows file lock release + + def format_collection_name( + self, + name: str, + embedder_type: type[Embedder], + ) -> str: + return f"{name}_{embedder_type.__name__}" + + def _ensure_payload_index(self, collection_name: str, field_name: str) -> None: + """Ensure a payload index exists for a field.""" + assert self.qdrant_client is not None, "Qdrant client must be initialized" + try: + # Check if index exists + collection_info = self.qdrant_client.get_collection(collection_name) + existing_indexes = collection_info.payload_schema or {} + + # Create index if it doesn't exist + if field_name not in existing_indexes: + self.qdrant_client.create_payload_index( + collection_name=collection_name, + field_name=field_name, + field_schema=models.PayloadSchemaType.KEYWORD, + ) + except Exception: + # Try to create index anyway (might fail if it exists) + try: + self.qdrant_client.create_payload_index( + collection_name=collection_name, + field_name=field_name, + field_schema=models.PayloadSchemaType.KEYWORD, + ) + except Exception: + pass # Index might already exist or creation failed + + # Loads documents from unembedded collection, migrates them if needed, and ensures embedded collection is in sync + async def _load_collection_documents( + self, + embedded_collection_name: str, + unembedded_collection_name: str, + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> str: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + assert self._embedder_factory is not None, "Embedder factory must be provided" + failed_migrations: list[BaseDocument] = [] + embedder = self._embedder_factory.create_embedder(embedder_type) + + # Get all points from unembedded collection + unembedded_points = self.qdrant_client.scroll( + collection_name=unembedded_collection_name, + limit=10000, + with_payload=True, + with_vectors=False, + )[0] + + indexing_required = False + + if unembedded_points: + for point in unembedded_points: + prospective_doc = cast(BaseDocument, point.payload) + try: + if loaded_doc := await document_loader(prospective_doc): + if loaded_doc != prospective_doc: + # Update the unembedded collection + self.qdrant_client.upsert( + collection_name=unembedded_collection_name, + points=[ + models.PointStruct( + id=point.id, + vector=[0], + payload=cast(dict[str, Any], loaded_doc), + ) + ], + ) + indexing_required = True + else: + self._logger.warning(f'Failed to load document "{prospective_doc}"') + self.qdrant_client.delete( + collection_name=unembedded_collection_name, + points_selector=models.PointIdsList( + points=[point.id], + ), + ) + failed_migrations.append(prospective_doc) + + except Exception as e: + self._logger.error(f"Failed to load document '{prospective_doc}'. error: {e}.") + failed_migrations.append(prospective_doc) + + # Store failed migrations in a separate collection for debugging + if failed_migrations: + failed_migrations_collection = await self.get_or_create_collection( + "failed_migrations", + BaseDocument, + NullEmbedder, + identity_loader, + ) + + for failed_doc in failed_migrations: + # Use the collection interface consistently instead of direct Qdrant operations + await failed_migrations_collection.insert_one(failed_doc) + + # Get version from special version point in collections + unembedded_version = await self._get_collection_version(unembedded_collection_name) + embedded_version = await self._get_collection_version(embedded_collection_name) + + if indexing_required or unembedded_version != embedded_version: + await self._index_collection( + embedded_collection_name, unembedded_collection_name, embedder + ) + + return embedded_collection_name + + async def _get_collection_version(self, collection_name: str) -> int: + """Get version from metadata collection.""" + assert self.qdrant_client is not None, "Qdrant client must be initialized" + version_key = f"{collection_name}_version" + try: + metadata = await self.read_metadata() + return cast(int, metadata.get(version_key, 1)) + except Exception: + return 1 + + async def _set_collection_version(self, collection_name: str, version: int) -> None: + """Set version in metadata collection.""" + assert self.qdrant_client is not None, "Qdrant client must be initialized" + version_key = f"{collection_name}_version" + await self.upsert_metadata(version_key, version) + + # Syncs embedded collection with unembedded collection + async def _index_collection( + self, + embedded_collection_name: str, + unembedded_collection_name: str, + embedder: Embedder, + ) -> None: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + # Get all points from unembedded collection + unembedded_points = self.qdrant_client.scroll( + collection_name=unembedded_collection_name, + limit=10000, + with_payload=True, + with_vectors=False, + )[0] + + # Map by document ID (string) from payload, not point ID (integer) + unembedded_docs_by_id = { + cast(str, point.payload["id"]): point + for point in unembedded_points + if point.payload is not None and "id" in point.payload + } + + # Get all points from embedded collection + embedded_points = self.qdrant_client.scroll( + collection_name=embedded_collection_name, + limit=10000, + with_payload=True, + with_vectors=True, + )[0] + + # Map by document ID (string) from payload, not point ID (integer) + embedded_docs_by_id = { + cast(str, point.payload["id"]): point + for point in embedded_points + if point.payload is not None and "id" in point.payload + } + + # Remove docs from embedded collection that no longer exist in unembedded + # Update embeddings for changed docs + for doc_id, embedded_point in embedded_docs_by_id.items(): + if doc_id not in unembedded_docs_by_id: + self.qdrant_client.delete( + collection_name=embedded_collection_name, + points_selector=models.PointIdsList(points=[embedded_point.id]), + ) + else: + unembedded_point = unembedded_docs_by_id[doc_id] + unembedded_doc = unembedded_point.payload + if unembedded_doc is not None and embedded_point.payload is not None: + # Only recompute embeddings if checksum changed + if embedded_point.payload.get("checksum") != unembedded_doc.get("checksum"): + embeddings = list( + (await embedder.embed([cast(str, unembedded_doc["content"])])).vectors + ) + if not embeddings or len(embeddings[0]) == 0: + self._logger.warning( + f"Empty embedding for document {doc_id}, skipping sync" + ) + continue + vector = embeddings[0] + else: + # Use existing vector if checksum hasn't changed + # Cast to list[float] since we're using single vector collections + vector = cast(list[float], embedded_point.vector) + + self.qdrant_client.upsert( + collection_name=embedded_collection_name, + points=[ + models.PointStruct( + id=embedded_point.id, # Keep existing point ID + vector=vector, + payload=unembedded_doc, + ) + ], + ) + unembedded_docs_by_id.pop(doc_id) + + # Add new docs from unembedded to embedded collection + for doc_id, unembedded_point in unembedded_docs_by_id.items(): + doc = unembedded_point.payload + if doc is None: + continue + doc_dict = doc + embeddings = list((await embedder.embed([cast(str, doc_dict["content"])])).vectors) + + if not embeddings or len(embeddings[0]) == 0: + self._logger.warning(f"Empty embedding for document {doc_id}, skipping") + continue + + # Convert string ID to integer for Qdrant + point_id = _string_id_to_int(str(doc_id)) + + self.qdrant_client.upsert( + collection_name=embedded_collection_name, + points=[ + models.PointStruct( + id=point_id, + vector=embeddings[0], + payload=doc_dict, + ) + ], + ) + + # Update version in unembedded collection + unembedded_version = await self._get_collection_version(unembedded_collection_name) + await self._set_collection_version(unembedded_collection_name, unembedded_version) + await self._set_collection_version(embedded_collection_name, unembedded_version) + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + ) -> QdrantCollection[TDocument]: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + assert self._embedder_factory is not None, "Embedder factory must be provided" + assert self._embedding_cache_provider is not None, ( + "Embedding cache provider must be provided" + ) + if name in self._collections: + raise ValueError(f'Collection "{name}" already exists.') + + embedder = self._embedder_factory.create_embedder(embedder_type) + vector_size = embedder.dimensions + + embedded_collection_name = self.format_collection_name(name, embedder_type) + unembedded_collection_name = f"{name}_unembedded" + + # Create embedded collection + self.qdrant_client.create_collection( + collection_name=embedded_collection_name, + vectors_config=models.VectorParams( + size=vector_size, + distance=models.Distance.COSINE, + ), + ) + + # Create unembedded collection (with empty vectors for metadata storage) + self.qdrant_client.create_collection( + collection_name=unembedded_collection_name, + vectors_config=models.VectorParams( + size=1, # Minimal size for unembedded collection + distance=models.Distance.COSINE, + ), + ) + + # Ensure payload indexes exist + self._ensure_payload_index(embedded_collection_name, "id") + self._ensure_payload_index(unembedded_collection_name, "id") + + collection = QdrantCollection( + self._logger, + self._tracer, + qdrant_client=self.qdrant_client, + embedded_collection_name=embedded_collection_name, + unembedded_collection_name=unembedded_collection_name, + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + collection._database = self + self._collections[name] = collection # type: ignore[assignment] + + return collection # type: ignore[return-value] + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> QdrantCollection[TDocument]: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + assert self._embedder_factory is not None, "Embedder factory must be provided" + assert self._embedding_cache_provider is not None, ( + "Embedding cache provider must be provided" + ) + if collection := self._collections.get(name): + return cast(QdrantCollection[TDocument], collection) + + # Find unembedded collection first which acts as the SSOT. + unembedded_collection_name = f"{name}_unembedded" + embedded_collection_name = self.format_collection_name(name, embedder_type) + + # Check if collections exist + collections = self.qdrant_client.get_collections().collections + collection_names = [col.name for col in collections] + + if unembedded_collection_name in collection_names: + if embedded_collection_name not in collection_names: + # Create embedded collection if it doesn't exist + embedder = self._embedder_factory.create_embedder(embedder_type) + self.qdrant_client.create_collection( + collection_name=embedded_collection_name, + vectors_config=models.VectorParams( + size=embedder.dimensions, + distance=models.Distance.COSINE, + ), + ) + # Ensure payload index exists + self._ensure_payload_index(embedded_collection_name, "id") + + await self._index_collection( + embedded_collection_name=embedded_collection_name, + unembedded_collection_name=unembedded_collection_name, + embedder=self._embedder_factory.create_embedder(embedder_type), + ) + + collection = QdrantCollection( + self._logger, + self._tracer, + qdrant_client=self.qdrant_client, + embedded_collection_name=await self._load_collection_documents( + embedded_collection_name=embedded_collection_name, + unembedded_collection_name=unembedded_collection_name, + embedder_type=embedder_type, + document_loader=document_loader, + ), + unembedded_collection_name=unembedded_collection_name, + name=name, + schema=schema, + embedder=self._embedder_factory.create_embedder(embedder_type), + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + collection._database = self + self._collections[name] = collection # type: ignore[assignment] + return collection # type: ignore[return-value] + + raise ValueError(f'Qdrant collection "{name}" not found.') + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> QdrantCollection[TDocument]: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + assert self._embedder_factory is not None, "Embedder factory must be provided" + assert self._embedding_cache_provider is not None, ( + "Embedding cache provider must be provided" + ) + if collection := self._collections.get(name): + return cast(QdrantCollection[TDocument], collection) + + embedder = self._embedder_factory.create_embedder(embedder_type) + vector_size = embedder.dimensions + + embedded_collection_name = self.format_collection_name(name, embedder_type) + unembedded_collection_name = f"{name}_unembedded" + + # Get or create collections + collections = self.qdrant_client.get_collections().collections + collection_names = [col.name for col in collections] + + if unembedded_collection_name not in collection_names: + self.qdrant_client.create_collection( + collection_name=unembedded_collection_name, + vectors_config=models.VectorParams( + size=1, # Minimal size for unembedded collection + distance=models.Distance.COSINE, + ), + ) + if embedded_collection_name not in collection_names: + self.qdrant_client.create_collection( + collection_name=embedded_collection_name, + vectors_config=models.VectorParams( + size=vector_size, + distance=models.Distance.COSINE, + ), + ) + + # Ensure payload indexes exist for both collections + self._ensure_payload_index(unembedded_collection_name, "id") + self._ensure_payload_index(embedded_collection_name, "id") + + collection = QdrantCollection( + self._logger, + self._tracer, + qdrant_client=self.qdrant_client, + embedded_collection_name=await self._load_collection_documents( + embedded_collection_name=embedded_collection_name, + unembedded_collection_name=unembedded_collection_name, + embedder_type=embedder_type, + document_loader=document_loader, + ), + unembedded_collection_name=unembedded_collection_name, + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + version=1, + ) + collection._database = self + self._collections[name] = collection # type: ignore[assignment] + + return collection # type: ignore[return-value] + + @override + async def delete_collection( + self, + name: str, + ) -> None: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + if name not in self._collections: + raise ValueError(f'Collection "{name}" not found.') + + embedded_collection_name = self.format_collection_name( + name, type(self._collections[name]._embedder) + ) + unembedded_collection_name = f"{name}_unembedded" + + self.qdrant_client.delete_collection(collection_name=embedded_collection_name) + self.qdrant_client.delete_collection(collection_name=unembedded_collection_name) + del self._collections[name] + + @override + async def upsert_metadata( + self, + key: str, + value: JSONSerializable, + ) -> None: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + metadata_collection_name = "metadata" + + # Check if metadata collection exists + collections = self.qdrant_client.get_collections().collections + collection_names = [col.name for col in collections] + + if metadata_collection_name not in collection_names: + self.qdrant_client.create_collection( + collection_name=metadata_collection_name, + vectors_config=models.VectorParams( + size=1, + distance=models.Distance.COSINE, + ), + ) + + # Get existing metadata + points = self.qdrant_client.scroll( + collection_name=metadata_collection_name, + limit=1, + with_payload=True, + with_vectors=False, + )[0] + + if points: + document = cast(dict[str, JSONSerializable], points[0].payload) + document[key] = value + + self.qdrant_client.upsert( + collection_name=metadata_collection_name, + points=[ + models.PointStruct( + id=points[0].id, + vector=[0], + payload=cast(dict[str, Any], document), + ) + ], + ) + else: + document = {key: value} + + metadata_point_id = _string_id_to_int("__metadata__") + self.qdrant_client.upsert( + collection_name=metadata_collection_name, + points=[ + models.PointStruct( + id=metadata_point_id, + vector=[0], + payload=cast(dict[str, Any], document), + ) + ], + ) + + @override + async def remove_metadata( + self, + key: str, + ) -> None: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + metadata_collection_name = "metadata" + + collections = self.qdrant_client.get_collections().collections + collection_names = [col.name for col in collections] + + if metadata_collection_name in collection_names: + points = self.qdrant_client.scroll( + collection_name=metadata_collection_name, + limit=1, + with_payload=True, + with_vectors=False, + )[0] + + if points: + document = cast(dict[str, JSONSerializable], points[0].payload) + document.pop(key) + + self.qdrant_client.upsert( + collection_name=metadata_collection_name, + points=[ + models.PointStruct( + id=points[0].id, + vector=[0], + payload=cast(dict[str, Any], document), + ) + ], + ) + else: + raise ValueError(f'Metadata with key "{key}" not found.') + else: + raise ValueError("Metadata collection not found.") + + @override + async def read_metadata( + self, + ) -> Mapping[str, JSONSerializable]: + assert self.qdrant_client is not None, "Qdrant client must be initialized" + metadata_collection_name = "metadata" + + collections = self.qdrant_client.get_collections().collections + collection_names = [col.name for col in collections] + + if metadata_collection_name in collection_names: + points = self.qdrant_client.scroll( + collection_name=metadata_collection_name, + limit=1, + with_payload=True, + with_vectors=False, + )[0] + + if points: + return cast(dict[str, JSONSerializable], points[0].payload) + else: + return {} + else: + return {} + + +class QdrantCollection(Generic[TDocument], BaseVectorCollection[TDocument]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + qdrant_client: QdrantClient, + embedded_collection_name: str, + unembedded_collection_name: str, + name: str, + schema: type[TDocument], + embedder: Embedder, + embedding_cache_provider: EmbeddingCacheProvider, + version: int, + ) -> None: + super().__init__(tracer) + + self._logger = logger + self._tracer = tracer + self._name = name + self._schema = schema + self._embedder = embedder + self._embedding_cache_provider = embedding_cache_provider + self._version = version + + self._lock = ReaderWriterLock() + self._unembedded_collection_name = unembedded_collection_name + self.embedded_collection_name = embedded_collection_name + self.qdrant_client = qdrant_client + self._database: Optional[QdrantDatabase] = ( + None # Reference to parent database for version methods + ) + + @override + async def find( + self, + filters: Where, + ) -> Sequence[TDocument]: + async with self._lock.reader_lock: + # Ensure indexes exist for all fields used in filtering + if filters and self._database: + field_names: set[str] = set() + _extract_field_names_from_where(filters, field_names) + for field_name in field_names: + self._database._ensure_payload_index(self.embedded_collection_name, field_name) + + qdrant_filter = _convert_where_to_qdrant_filter(filters) + + try: + points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + scroll_filter=qdrant_filter, + limit=10000, + with_payload=True, + with_vectors=False, + )[0] + except Exception: + # If filter fails due to missing index, scroll all and filter in memory + if qdrant_filter: + all_points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + limit=10000, + with_payload=True, + with_vectors=False, + )[0] + # Filter in memory + from parlant.core.persistence.common import matches_filters + + points = [ + p + for p in all_points + if p.payload is not None and matches_filters(filters, p.payload) + ] + else: + points = [] + + return [cast(TDocument, point.payload) for point in points] + + @override + async def find_one( + self, + filters: Where, + ) -> Optional[TDocument]: + async with self._lock.reader_lock: + # Ensure indexes exist for all fields used in filtering + if filters and self._database: + field_names: set[str] = set() + _extract_field_names_from_where(filters, field_names) + for field_name in field_names: + self._database._ensure_payload_index(self.embedded_collection_name, field_name) + + qdrant_filter = _convert_where_to_qdrant_filter(filters) + + try: + points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + scroll_filter=qdrant_filter, + limit=1, + with_payload=True, + with_vectors=False, + )[0] + except Exception: + # If filter fails due to missing index, scroll all and filter in memory + if qdrant_filter: + all_points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + limit=10000, + with_payload=True, + with_vectors=False, + )[0] + # Filter in memory + from parlant.core.persistence.common import matches_filters + + points = [ + p + for p in all_points + if p.payload is not None and matches_filters(filters, p.payload) + ][:1] + else: + points = [] + + if points: + return cast(TDocument, points[0].payload) + + return None + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[document["content"]], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([document["content"]])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[document["content"]], + vectors=embeddings, + ) + + if not embeddings or len(embeddings[0]) == 0: + raise ValueError( + f"Empty embedding generated for document content: {document['content'][:50]}..." + ) + + async with self._lock.writer_lock: + self._version += 1 + + # Convert string ID to integer for Qdrant + point_id = _string_id_to_int(str(document["id"])) + + # Insert into unembedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self._unembedded_collection_name, + points=[ + models.PointStruct( + id=point_id, + vector=[0], + payload=cast(dict[str, Any], document), + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Insert into embedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self.embedded_collection_name, + points=[ + models.PointStruct( + id=point_id, + vector=embeddings[0], + payload=cast(dict[str, Any], document), + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Update version in both collections + if self._database: + await self._database._set_collection_version( + self._unembedded_collection_name, self._version + ) + await self._database._set_collection_version( + self.embedded_collection_name, self._version + ) + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + async with self._lock.writer_lock: + # Ensure indexes exist for all fields used in filtering + if filters and self._database: + field_names: set[str] = set() + _extract_field_names_from_where(filters, field_names) + for field_name in field_names: + self._database._ensure_payload_index(self.embedded_collection_name, field_name) + + qdrant_filter = _convert_where_to_qdrant_filter(filters) + + points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + scroll_filter=qdrant_filter, + limit=1, + with_payload=True, + with_vectors=True, + )[0] + + if points: + point = points[0] + doc = cast(dict[str, Any], point.payload) + + if "content" in params: + content = params["content"] + else: + content = str(doc["content"]) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[content], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([content])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[content], + vectors=embeddings, + ) + + if not embeddings or len(embeddings[0]) == 0: + raise ValueError(f"Empty embedding generated for content: {content[:50]}...") + + updated_document = {**doc, **params} + + self._version += 1 + + # Update unembedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self._unembedded_collection_name, + points=[ + models.PointStruct( + id=point.id, # point.id is already an integer + vector=[0], + payload=updated_document, + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Update embedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self.embedded_collection_name, + points=[ + models.PointStruct( + id=point.id, # point.id is already an integer + vector=embeddings[0], + payload=updated_document, + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Update version in both collections + if self._database: + await self._database._set_collection_version( + self._unembedded_collection_name, self._version + ) + await self._database._set_collection_version( + self.embedded_collection_name, self._version + ) + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=cast(TDocument, updated_document), + ) + + elif upsert: + ensure_is_total(params, self._schema) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[params["content"]], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([params["content"]])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[params["content"]], + vectors=embeddings, + ) + + if not embeddings or len(embeddings[0]) == 0: + raise ValueError( + f"Empty embedding generated for content: {params['content'][:50] if 'content' in params else 'N/A'}..." + ) + + self._version += 1 + + # Convert string ID to integer for Qdrant + point_id = _string_id_to_int(str(params["id"])) + + # Insert into unembedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self._unembedded_collection_name, + points=[ + models.PointStruct( + id=point_id, + vector=[0], + payload=cast(dict[str, Any], params), + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Insert into embedded collection with retry on timeout + await _retry_on_timeout_async( + lambda: asyncio.to_thread( + self.qdrant_client.upsert, + collection_name=self.embedded_collection_name, + points=[ + models.PointStruct( + id=point_id, + vector=embeddings[0], + payload=cast(dict[str, Any], params), + ) + ], + ), + max_retries=3, + logger=self._logger, + ) + + # Update version in both collections + if self._database: + await self._database._set_collection_version( + self._unembedded_collection_name, self._version + ) + await self._database._set_collection_version( + self.embedded_collection_name, self._version + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + async with self._lock.writer_lock: + # Ensure indexes exist for all fields used in filtering + if filters and self._database: + field_names: set[str] = set() + _extract_field_names_from_where(filters, field_names) + for field_name in field_names: + self._database._ensure_payload_index(self.embedded_collection_name, field_name) + + qdrant_filter = _convert_where_to_qdrant_filter(filters) + + points = self.qdrant_client.scroll( + collection_name=self.embedded_collection_name, + scroll_filter=qdrant_filter, + limit=2, # Check for more than one + with_payload=True, + with_vectors=False, + )[0] + + if len(points) > 1: + raise ValueError( + f"QdrantCollection delete_one: detected more than one document with filters '{filters}'. Aborting..." + ) + + if points: + deleted_document = cast(TDocument, points[0].payload) + point_id = points[0].id + + self._version += 1 + + # Delete from unembedded collection + self.qdrant_client.delete( + collection_name=self._unembedded_collection_name, + points_selector=models.PointIdsList(points=[point_id]), + ) + + # Delete from embedded collection + self.qdrant_client.delete( + collection_name=self.embedded_collection_name, + points_selector=models.PointIdsList(points=[point_id]), + ) + + # Update version in both collections + if self._database: + await self._database._set_collection_version( + self._unembedded_collection_name, self._version + ) + await self._database._set_collection_version( + self.embedded_collection_name, self._version + ) + + return DeleteResult( + deleted_count=1, + acknowledged=True, + deleted_document=deleted_document, + ) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) + + @override + async def do_find_similar_documents( + self, + filters: Where, + query: str, + k: int, + hints: Mapping[str, Any] = {}, + ) -> Sequence[SimilarDocumentResult[TDocument]]: + async with self._lock.reader_lock: + # Ensure indexes exist for all fields used in filtering + if filters and self._database: + field_names: set[str] = set() + _extract_field_names_from_where(filters, field_names) + for field_name in field_names: + self._database._ensure_payload_index(self.embedded_collection_name, field_name) + + query_embeddings = list((await self._embedder.embed([query], hints)).vectors) + qdrant_filter = _convert_where_to_qdrant_filter(filters) + + if not query_embeddings or len(query_embeddings[0]) == 0: + self._logger.warning(f"Empty embedding generated for query: {query}") + return [] + + search_results = self.qdrant_client.query_points( + collection_name=self.embedded_collection_name, + query=list(query_embeddings[0]), + query_filter=qdrant_filter, + limit=k, + ).points + + if not search_results: + return [] + + self._logger.trace( + f"Similar documents found\n{json.dumps([r.payload for r in search_results], indent=2)}" + ) + + return [ + SimilarDocumentResult( + document=cast(TDocument, result.payload), + distance=1.0 - result.score, # Convert similarity to distance + ) + for result in search_results + ] diff --git a/src/parlant/adapters/vector_db/transient.py b/src/parlant/adapters/vector_db/transient.py new file mode 100644 index 0000000..c786395 --- /dev/null +++ b/src/parlant/adapters/vector_db/transient.py @@ -0,0 +1,407 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License") +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ruff: noqa + +from __future__ import annotations +import asyncio +import json +from typing import Any, Awaitable, Callable, Generic, Mapping, Optional, Sequence, cast +import numpy as np +from typing_extensions import override + +import logging + +from parlant.core.tracer import Tracer + +orig_basicConfig = logging.basicConfig +orig_getLogger = logging.getLogger + + +# nano_vectordb overrides logging's basicConfig and stuff... :S +# So we need to protect it for a minute while importing +def _null_basicConfig(*args: Any, **kwargs: Any) -> None: + pass + + +class _NullLogger: + def info(self, *args: Any, **kwargs: Any) -> None: + pass + + def debug(self, *args: Any, **kwargs: Any) -> None: + pass + + +def _null_getLogger(*args: Any, **kwargs: Any) -> object: + return _NullLogger() + + +logging.basicConfig = _null_basicConfig # type: ignore +logging.getLogger = _null_getLogger # type: ignore + +import nano_vectordb # type: ignore + +logging.basicConfig = orig_basicConfig +logging.getLogger = orig_getLogger +# Back to business + +from parlant.core.common import JSONSerializable +from parlant.core.nlp.embedding import ( + Embedder, + EmbedderFactory, + EmbeddingCache, + EmbeddingCacheProvider, +) +from parlant.core.loggers import Logger +from parlant.core.persistence.common import ensure_is_total, matches_filters, Where +from parlant.core.persistence.vector_database import ( + BaseDocument, + BaseVectorCollection, + DeleteResult, + InsertResult, + SimilarDocumentResult, + UpdateResult, + VectorDatabase, + TDocument, +) + + +class TransientVectorDatabase(VectorDatabase): + def __init__( + self, + logger: Logger, + tracer: Tracer, + embedder_factory: EmbedderFactory, + embedding_cache_provider: EmbeddingCacheProvider, + ) -> None: + self._logger = logger + self._tracer = tracer + self._embedder_factory = embedder_factory + self._embedding_cache_provider = embedding_cache_provider + + self._databases: dict[str, nano_vectordb.NanoVectorDB] = {} + self._collections: dict[str, TransientVectorCollection[BaseDocument]] = {} + self._metadata: dict[str, JSONSerializable] = {} + + @override + async def create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + ) -> TransientVectorCollection[TDocument]: + if name in self._collections: + raise ValueError(f'Collection "{name}" already exists.') + + embedder = self._embedder_factory.create_embedder(embedder_type) + + self._databases[name] = nano_vectordb.NanoVectorDB(embedder.dimensions) + + self._collections[name] = TransientVectorCollection( + self._logger, + self._tracer, + nano_db=self._databases[name], + name=name, + schema=schema, + embedder=embedder, + embedding_cache_provider=self._embedding_cache_provider, + ) + + return cast(TransientVectorCollection[TDocument], self._collections[name]) + + @override + async def get_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> TransientVectorCollection[TDocument]: + if collection := self._collections.get(name): + return cast(TransientVectorCollection[TDocument], collection) + + raise ValueError(f'Transient collection "{name}" not found.') + + @override + async def get_or_create_collection( + self, + name: str, + schema: type[TDocument], + embedder_type: type[Embedder], + document_loader: Callable[[BaseDocument], Awaitable[Optional[TDocument]]], + ) -> TransientVectorCollection[TDocument]: + if collection := self._collections.get(name): + assert schema == collection._schema + return cast(TransientVectorCollection[TDocument], collection) + + embedder = self._embedder_factory.create_embedder(embedder_type) + + self._databases[name] = nano_vectordb.NanoVectorDB(embedder.dimensions) + + self._collections[name] = TransientVectorCollection( + self._logger, + self._tracer, + nano_db=self._databases[name], + name=name, + schema=schema, + embedder=self._embedder_factory.create_embedder(embedder_type), + embedding_cache_provider=self._embedding_cache_provider, + ) + + return cast(TransientVectorCollection[TDocument], self._collections[name]) + + @override + async def delete_collection( + self, + name: str, + ) -> None: + if name not in self._collections: + raise ValueError(f'Collection "{name}" not found.') + del self._databases[name] + del self._collections[name] + + @override + async def upsert_metadata( + self, + key: str, + value: JSONSerializable, + ) -> None: + self._metadata[key] = value + + @override + async def remove_metadata( + self, + key: str, + ) -> None: + self._metadata.pop(key) + + @override + async def read_metadata( + self, + ) -> Mapping[str, JSONSerializable]: + return self._metadata + + +class TransientVectorCollection(Generic[TDocument], BaseVectorCollection[TDocument]): + def __init__( + self, + logger: Logger, + tracer: Tracer, + nano_db: nano_vectordb.NanoVectorDB, + name: str, + schema: type[TDocument], + embedder: Embedder, + embedding_cache_provider: EmbeddingCacheProvider, + ) -> None: + self._logger = logger + self._tracer = tracer + self._name = name + self._schema = schema + self._embedder = embedder + self._embedding_cache_provider = embedding_cache_provider + + self._lock = asyncio.Lock() + self._nano_db = nano_db + self._documents: list[TDocument] = [] + + @staticmethod + def _build_filter_lambda( + filters: Where, + ) -> nano_vectordb.dbs.ConditionLambda: + def filter_lambda(candidate: Mapping[str, Any]) -> bool: + return matches_filters(filters, candidate) + + return filter_lambda + + @override + async def find( + self, + filters: Where, + ) -> Sequence[TDocument]: + result = [] + for doc in filter( + lambda d: matches_filters(filters, d), + self._documents, + ): + result.append(doc) + + return result + + @override + async def find_one( + self, + filters: Where, + ) -> Optional[TDocument]: + for doc in self._documents: + if matches_filters(filters, doc): + return doc + + return None + + @override + async def insert_one( + self, + document: TDocument, + ) -> InsertResult: + ensure_is_total(document, self._schema) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[document["content"]], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([document["content"]])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[document["content"]], + vectors=embeddings, + ) + + vector = np.array(embeddings[0], dtype=np.float32) + + data = {**document, "__id__": document["id"], "__vector__": vector} + + async with self._lock: + self._nano_db.upsert([data]) + self._documents.append(document) + + return InsertResult(acknowledged=True) + + @override + async def update_one( + self, + filters: Where, + params: TDocument, + upsert: bool = False, + ) -> UpdateResult[TDocument]: + async with self._lock: + for i, doc in enumerate(self._documents): + if matches_filters(filters, doc): + if "content" in params: + content = params["content"] + else: + content = str(doc["content"]) + + if e := await self._embedding_cache_provider().get( + embedder_type=type(self._embedder), + texts=[content], + ): + embeddings = list(e.vectors) + else: + embeddings = list((await self._embedder.embed([content])).vectors) + await self._embedding_cache_provider().set( + embedder_type=type(self._embedder), + texts=[content], + vectors=embeddings, + ) + + vector = np.array(embeddings[0], dtype=np.float32) + data = {**params, "__id__": doc["id"], "__vector__": vector} + + self._nano_db.upsert([data]) + self._documents[i] = cast(TDocument, {**self._documents[i], **params}) + + return UpdateResult( + acknowledged=True, + matched_count=1, + modified_count=1, + updated_document=self._documents[i], + ) + + if upsert: + ensure_is_total(params, self._schema) + await self.insert_one(params) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=params, + ) + + return UpdateResult( + acknowledged=True, + matched_count=0, + modified_count=0, + updated_document=None, + ) + + @override + async def delete_one( + self, + filters: Where, + ) -> DeleteResult[TDocument]: + for i, d in enumerate(self._documents): + if matches_filters(filters, d): + document = self._documents.pop(i) + + self._nano_db.delete([d["id"]]) + + return DeleteResult(deleted_count=1, acknowledged=True, deleted_document=document) + + return DeleteResult( + acknowledged=True, + deleted_count=0, + deleted_document=None, + ) + + @staticmethod + def _distance_from_similarity(similarity: float) -> float: + return 1 - similarity + + async def do_find_similar_documents( + self, + filters: Where, + query: str, + k: int, + hints: Mapping[str, Any] = {}, + ) -> Sequence[SimilarDocumentResult[TDocument]]: + if not self._documents: + return [] + + query_embeddings = list((await self._embedder.embed([query], hints)).vectors) + vector = np.array(query_embeddings[0], dtype=np.float32) + + keys_to_exclude = {"__id__", "__metrics__"} + + if await self.find(filters) == []: + return [] + + query_result = self._nano_db.query( + query=vector, + top_k=len(self._documents), + filter_lambda=self._build_filter_lambda(filters), + ) + + docs_and_similarities = [ + ( + {key: value for key, value in d.items() if key not in keys_to_exclude}, + float(d["__metrics__"]), + ) + for d in query_result + ] + + self._logger.trace( + f"Similar documents found\n{json.dumps(docs_and_similarities[0], indent=2)}" + ) + + results = [ + SimilarDocumentResult( + document=cast(TDocument, d), + distance=self._distance_from_similarity(sim), + ) + for d, sim in docs_and_similarities + ] + + return results diff --git a/src/parlant/api/agents.py b/src/parlant/api/agents.py new file mode 100644 index 0000000..911f19c --- /dev/null +++ b/src/parlant/api/agents.py @@ -0,0 +1,480 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from fastapi import APIRouter, Path, Request, status +from pydantic import Field +from typing import Annotated, Sequence, TypeAlias + +from parlant.api.authorization import AuthorizationPolicy, Operation +from parlant.api.common import ( + CompositionModeDTO, + ExampleJson, + MessageOutputModeDTO, + apigen_config, + composition_mode_dto_to_composition_mode, + composition_mode_to_composition_mode_dto, + example_json_content, + message_output_mode_dto_to_message_output_mode, + message_output_mode_to_message_output_mode_dto, +) +from parlant.core.app_modules.agents import AgentTagUpdateParamsModel +from parlant.core.agents import AgentId +from parlant.core.application import Application +from parlant.core.common import DefaultBaseModel +from parlant.core.tags import TagId + +API_GROUP = "agents" + +AgentIdPath: TypeAlias = Annotated[ + AgentId, + Path( + description="Unique identifier for the agent", + examples=["IUCGT-lvpS"], + min_length=1, + ), +] + +AgentNameField: TypeAlias = Annotated[ + str, + Field( + description="The display name of the agent, mainly for management purposes", + examples=["Haxon", "Alfred J. Quack"], + min_length=1, + max_length=100, + ), +] + +AgentDescriptionField: TypeAlias = Annotated[ + str, + Field( + description="Detailed description of the agent's purpose and capabilities", + examples=["Technical Support Assistant"], + ), +] + +AgentMaxEngineIterationsField: TypeAlias = Annotated[ + int, + Field( + description="Maximum number of processing iterations the agent can perform per request", + ge=1, + examples=[1, 3], + ), +] + +AgentTagsField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs associated with the agent", + examples=[["tag1", "tag2"]], + ), +] + +AgentTagUpdateAddField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs to add to the agent", + examples=[["tag1", "tag2"]], + ), +] + +AgentTagUpdateRemoveField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs to remove from the agent", + examples=[["tag1", "tag2"]], + ), +] +agent_example: ExampleJson = { + "id": "IUCGT-lvpS", + "name": "Haxon", + "description": "Technical Support Assistant", + "creation_utc": "2024-03-24T12:00:00Z", + "max_engine_iterations": 3, + "composition_mode": "fluid", + "message_output_mode": "block", + "tags": ["tag1", "tag2"], +} + + +class AgentDTO( + DefaultBaseModel, + json_schema_extra={"example": agent_example}, +): + """ + An agent is a specialized AI personality crafted for a specific service role. + + Agents form the basic unit of conversational customization: all behavioral configurations + are made at the agent level. + + Use this model for representing complete agent information in API responses. + """ + + id: AgentIdPath + name: AgentNameField + description: AgentDescriptionField | None = None + max_engine_iterations: AgentMaxEngineIterationsField = 1 + composition_mode: CompositionModeDTO + message_output_mode: MessageOutputModeDTO + tags: AgentTagsField = [] + + +agent_creation_params_example: ExampleJson = { + "name": "Haxon", + "description": "Technical Support Assistant", + "max_engine_iterations": 3, + "composition_mode": "fluid", + "message_output_mode": "block", + "tags": ["tag1", "tag2"], +} + + +class AgentCreationParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": agent_creation_params_example}, +): + """ + Parameters for creating a new agent. + + Optional fields: + - `id`: Custom identifier for the agent. If not provided, an ID will be automatically generated. + Custom IDs can be any string format and are useful for maintaining consistent identifiers + across deployments or integrations. + - `description`: Detailed explanation of the agent's purpose + - `max_engine_iterations`: Processing limit per request + - `composition_mode`: How the agent composes responses + - `message_output_mode`: How the agent outputs messages (block or streaming) + - `tags`: List of tag IDs to associate with the agent + + Note: Agents must be created via the API before they can be used. + """ + + name: AgentNameField + id: AgentIdPath | None = None + description: AgentDescriptionField | None = None + max_engine_iterations: AgentMaxEngineIterationsField | None = None + composition_mode: CompositionModeDTO | None = None + message_output_mode: MessageOutputModeDTO | None = None + tags: AgentTagsField | None = None + + +agent_update_params_example: ExampleJson = { + "name": "Haxon", + "description": "Technical Support Assistant", + "max_engine_iterations": 3, + "composition_mode": "fluid", + "message_output_mode": "block", +} + + +tags_update_params_example: ExampleJson = { + "add": [ + "t9a8g703f4", + "tag_456abc", + ], + "remove": [ + "tag_789def", + "tag_012ghi", + ], +} + + +class AgentTagUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": tags_update_params_example}, +): + """ + Parameters for updating an existing agent's tags. + """ + + add: AgentTagUpdateAddField | None = None + remove: AgentTagUpdateRemoveField | None = None + + +class AgentUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": agent_update_params_example}, +): + """ + Parameters for updating an existing agent. + + All fields are optional. only provided fields will be updated. + The agent's ID and creation timestamp cannot be modified. + """ + + name: AgentNameField | None = None + description: AgentDescriptionField | None = None + max_engine_iterations: AgentMaxEngineIterationsField | None = None + composition_mode: CompositionModeDTO | None = None + message_output_mode: MessageOutputModeDTO | None = None + tags: AgentTagUpdateParamsDTO | None = None + + +def create_router( + policy: AuthorizationPolicy, + app: Application, +) -> APIRouter: + router = APIRouter() + + @router.post( + "", + status_code=status.HTTP_201_CREATED, + operation_id="create_agent", + response_model=AgentDTO, + responses={ + status.HTTP_201_CREATED: { + "description": "Agent successfully created. Returns the complete agent object including generated ID.", + "content": example_json_content(agent_example), + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Validation error in request parameters" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="create"), + ) + async def create_agent( + request: Request, + params: AgentCreationParamsDTO, + ) -> AgentDTO: + """ + Creates a new agent in the system. + + The agent will be initialized with the provided name and optional settings. + A unique identifier will be automatically generated unless a custom ID is provided. + + Default behaviors: + - `name` defaults to `"Unnamed Agent"` if not provided + - `id` is auto-generated if not provided + - `description` defaults to `None` + - `max_engine_iterations` defaults to `None` (uses system default) + """ + await policy.authorize( + request=request, + operation=Operation.CREATE_AGENT, + ) + + agent = await app.agents.create( + name=params and params.name or "Unnamed Agent", + description=params and params.description or None, + max_engine_iterations=params and params.max_engine_iterations or None, + composition_mode=composition_mode_dto_to_composition_mode(params.composition_mode) + if params and params.composition_mode + else None, + message_output_mode=message_output_mode_dto_to_message_output_mode( + params.message_output_mode + ) + if params and params.message_output_mode + else None, + tags=params.tags, + id=params.id if params else None, + ) + + return AgentDTO( + id=agent.id, + name=agent.name, + description=agent.description, + creation_utc=agent.creation_utc, + max_engine_iterations=agent.max_engine_iterations, + composition_mode=composition_mode_to_composition_mode_dto(agent.composition_mode), + message_output_mode=message_output_mode_to_message_output_mode_dto( + agent.message_output_mode + ), + tags=agent.tags, + ) + + @router.get( + "", + operation_id="list_agents", + response_model=Sequence[AgentDTO], + responses={ + status.HTTP_200_OK: { + "description": "List of all agents in the system", + "content": example_json_content([agent_example]), + } + }, + **apigen_config(group_name=API_GROUP, method_name="list"), + ) + async def list_agents(request: Request) -> Sequence[AgentDTO]: + """ + Retrieves a list of all agents in the system. + + Returns an empty list if no agents exist. + Agents are returned in no guaranteed order. + """ + await policy.authorize( + request=request, + operation=Operation.LIST_AGENTS, + ) + + agents = await app.agents.find() + + return [ + AgentDTO( + id=a.id, + name=a.name, + description=a.description, + creation_utc=a.creation_utc, + max_engine_iterations=a.max_engine_iterations, + composition_mode=composition_mode_to_composition_mode_dto(a.composition_mode), + message_output_mode=message_output_mode_to_message_output_mode_dto( + a.message_output_mode + ), + tags=a.tags, + ) + for a in agents + ] + + @router.get( + "/{agent_id}", + operation_id="read_agent", + response_model=AgentDTO, + responses={ + status.HTTP_200_OK: { + "description": "Agent details successfully retrieved. Returns the complete agent object.", + "content": example_json_content(agent_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "Agent not found. the specified `agent_id` does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="retrieve"), + ) + async def read_agent( + request: Request, + agent_id: AgentIdPath, + ) -> AgentDTO: + """ + Retrieves details of a specific agent by ID. + """ + await policy.authorize( + request=request, + operation=Operation.READ_AGENT, + ) + + agent = await app.agents.read(agent_id=agent_id) + + if await policy.check_permission(request, Operation.READ_AGENT_DESCRIPTION): + description = agent.description + else: + description = None + + return AgentDTO( + id=agent.id, + name=agent.name, + description=description, + creation_utc=agent.creation_utc, + max_engine_iterations=agent.max_engine_iterations, + composition_mode=composition_mode_to_composition_mode_dto(agent.composition_mode), + message_output_mode=message_output_mode_to_message_output_mode_dto( + agent.message_output_mode + ), + tags=agent.tags, + ) + + @router.patch( + "/{agent_id}", + operation_id="update_agent", + response_model=AgentDTO, + responses={ + status.HTTP_200_OK: { + "description": "Agent successfully updated. Returns the updated agent.", + "content": example_json_content(agent_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "Agent not found. the specified `agent_id` does not exist" + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Validation error in update parameters" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="update"), + ) + async def update_agent( + request: Request, + agent_id: AgentIdPath, + params: AgentUpdateParamsDTO, + ) -> AgentDTO: + """ + Updates an existing agent's attributes. + + Only the provided attributes will be updated; others will remain unchanged. + The agent's ID and creation timestamp cannot be modified. + """ + await policy.authorize( + request=request, + operation=Operation.UPDATE_AGENT, + ) + + agent = await app.agents.update( + agent_id=agent_id, + name=params.name, + description=params.description, + max_engine_iterations=params.max_engine_iterations, + composition_mode=composition_mode_dto_to_composition_mode(params.composition_mode) + if params.composition_mode + else None, + message_output_mode=message_output_mode_dto_to_message_output_mode( + params.message_output_mode + ) + if params.message_output_mode + else None, + tags=AgentTagUpdateParamsModel(add=params.tags.add, remove=params.tags.remove) + if params.tags + else None, + ) + + return AgentDTO( + id=agent.id, + name=agent.name, + description=agent.description, + creation_utc=agent.creation_utc, + max_engine_iterations=agent.max_engine_iterations, + composition_mode=composition_mode_to_composition_mode_dto(agent.composition_mode), + message_output_mode=message_output_mode_to_message_output_mode_dto( + agent.message_output_mode + ), + tags=agent.tags, + ) + + @router.delete( + "/{agent_id}", + operation_id="delete_agent", + status_code=status.HTTP_204_NO_CONTENT, + responses={ + status.HTTP_204_NO_CONTENT: { + "description": "Agent successfully deleted. No content returned." + }, + status.HTTP_404_NOT_FOUND: { + "description": "Agent not found. The specified `agent_id` does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="delete"), + ) + async def delete_agent( + request: Request, + agent_id: AgentIdPath, + ) -> None: + """ + Deletes an agent from the agent. + + Deleting a non-existent agent will return 404. + No content will be returned from a successful deletion. + """ + await policy.authorize( + request=request, + operation=Operation.DELETE_AGENT, + ) + + await app.agents.delete(agent_id=agent_id) + + return router diff --git a/src/parlant/api/app.py b/src/parlant/api/app.py new file mode 100644 index 0000000..4dbfcde --- /dev/null +++ b/src/parlant/api/app.py @@ -0,0 +1,380 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +from contextvars import ContextVar +import os +import traceback +from typing import Any, Awaitable, Callable, Mapping, TypeAlias + +import mimetypes + +from fastapi import APIRouter, FastAPI, HTTPException, Request, Response, status +from fastapi.responses import RedirectResponse +from fastapi.routing import APIRoute +from fastapi.staticfiles import StaticFiles +from starlette.types import Receive, Scope, Send +from starlette.routing import Match + + +from lagom import Container + +from parlant.adapters.loggers.websocket import WebSocketLogger +from parlant.api.health import configure_healthz +from parlant.core.health import HealthReporter +from parlant.api import agents, capabilities +from parlant.api import evaluations +from parlant.api import journeys +from parlant.api import relationships +from parlant.api import sessions +from parlant.api import glossary +from parlant.api import guidelines +from parlant.api import context_variables as variables +from parlant.api import services +from parlant.api import tags +from parlant.api import customers +from parlant.api import logs +from parlant.api import canned_responses +from parlant.api.authorization import ( + AuthorizationException, + AuthorizationPolicy, + Operation, + RateLimitExceededException, +) +from parlant.core.version import VERSION +from parlant.core.meter import Meter +from parlant.core.tracer import Tracer +from parlant.core.common import ItemNotFoundError, generate_id +from parlant.core.loggers import Logger +from parlant.core.application import Application + + +mimetypes.add_type("text/javascript", ".js") +mimetypes.add_type("image/svg+xml", ".svg") + + +ASGIApplication: TypeAlias = Callable[ + [ + Scope, + Receive, + Send, + ], + Awaitable[None], +] + + +class AppWrapper: + def __init__(self, app: FastAPI) -> None: + self.app = app + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """FastAPI's built-in exception handling doesn't catch BaseExceptions + such as asyncio.CancelledError. This causes the server process to terminate + with an ugly traceback. This wrapper addresses that by specifically allowing + asyncio.CancelledError to gracefully exit. + """ + try: + return await self.app(scope, receive, send) + except asyncio.CancelledError: + pass + + +RECORDED_FLAG = "_otel_metrics_recorded" + + +def _resolve_operation_id(request: Request) -> str | None: + route = request.scope.get("route") + if isinstance(route, APIRoute): + return route.operation_id + + # If scope['route'] not set (404/early errors/etc.), try to match manually + for r in getattr(request.app.router, "routes", []): + if isinstance(r, APIRoute) and r.matches(request.scope)[0] == Match.FULL: + return r.operation_id + return None + + +async def create_api_app( + container: Container, + configure: Callable[[FastAPI], Awaitable[FastAPI | None]] | None = None, + contextvar_propagation: Mapping[ContextVar[Any], Any] = {}, +) -> ASGIApplication: + logger = container[Logger] + websocket_logger = container[WebSocketLogger] + tracer = container[Tracer] + authorization_policy = container[AuthorizationPolicy] + application = container[Application] + + meter = container[Meter] + _hist_http_request_duration = meter.create_duration_histogram( + name="httpreq", + description="HTTP Request Duration", + ) + + configure_healthz(container) + health_reporter = container[HealthReporter] + + api_app = FastAPI( + title="Parlant API", + description="API documentation for the Parlant server.", + version=VERSION, + ) + + api_app = await authorization_policy.configure_app(api_app) + + @api_app.middleware("http") + async def propagate_contextvars_into_request_task( + request: Request, + call_next: Callable[[Request], Awaitable[Response]], + ) -> Response: + for var, value in contextvar_propagation.items(): + var.set(value) + return await call_next(request) + + @api_app.middleware("http") + async def handle_cancellation( + request: Request, + call_next: Callable[[Request], Awaitable[Response]], + ) -> Response: + try: + return await call_next(request) + except asyncio.CancelledError: + return Response(status_code=status.HTTP_503_SERVICE_UNAVAILABLE) + + @api_app.middleware("http") + async def add_trace_id( + request: Request, + call_next: Callable[[Request], Awaitable[Response]], + ) -> Response: + if ( + request.url.path.startswith("/docs") + or request.url.path.startswith("/redoc") + or request.url.path.startswith("/openapi.json") + ): + await authorization_policy.authorize( + request=request, + operation=Operation.ACCESS_API_DOCS, + ) + return await call_next(request) + + if request.url.path.startswith("/chat/"): + await authorization_policy.authorize( + request=request, + operation=Operation.ACCESS_INTEGRATED_UI, + ) + + return await call_next(request) + + operation_id = _resolve_operation_id(request) + + if operation_id is None: + return await call_next(request) + + request_id = generate_id() + with tracer.span( + "http.request", + { + "http.request.id": request_id, + "http.request.operation": operation_id, + "http.request.method": request.method, + **request.path_params, + }, + ): + async with _hist_http_request_duration.measure( + { + "http.request.operation": operation_id, + "http.request.method": request.method, + }, + ): + return await call_next(request) + + @api_app.exception_handler(RateLimitExceededException) + async def rate_limit_exceeded_handler( + request: Request, exc: RateLimitExceededException + ) -> HTTPException: + logger.trace(f"Rate limit exceeded: {exc}") + + raise HTTPException( + status_code=status.HTTP_429_TOO_MANY_REQUESTS, + detail=str(exc), + ) + + @api_app.exception_handler(AuthorizationException) + async def authorization_error_handler( + request: Request, exc: AuthorizationException + ) -> HTTPException: + logger.trace(f"Authorization error: {exc}") + + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=str(exc), + ) + + @api_app.exception_handler(ItemNotFoundError) + async def item_not_found_error_handler( + request: Request, exc: ItemNotFoundError + ) -> HTTPException: + logger.info(str(exc)) + + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=str(exc), + ) + + @api_app.exception_handler(Exception) + async def server_error_handler(request: Request, exc: ItemNotFoundError) -> HTTPException: + logger.error(str(exc)) + logger.error(str(traceback.format_exception(exc))) + + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=str(exc), + ) + + static_dir = os.path.join(os.path.dirname(__file__), "chat/dist") + api_app.mount("/chat", StaticFiles(directory=static_dir, html=True), name="static") + + @api_app.get("/", include_in_schema=False) + async def root() -> Response: + return RedirectResponse("/chat") + + @api_app.get("/healthz") + async def health_check() -> dict[str, Any]: + return health_reporter.snapshot() + + agent_router = APIRouter(prefix="/agents") + + api_app.include_router( + router=agents.create_router( + policy=authorization_policy, + app=application, + ), + prefix="/agents", + ) + + api_app.include_router( + router=agent_router, + ) + + api_app.include_router( + prefix="/sessions", + router=sessions.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/services", + router=services.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/tags", + router=tags.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/terms", + router=glossary.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/customers", + router=customers.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/canned_responses", + router=canned_responses.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/context-variables", + router=variables.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/guidelines", + router=guidelines.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/relationships", + router=relationships.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/journeys", + router=journeys.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/evaluations", + router=evaluations.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + prefix="/capabilities", + router=capabilities.create_router( + authorization_policy=authorization_policy, + app=application, + ), + ) + + api_app.include_router( + router=logs.create_router( + websocket_logger, + ) + ) + + # Call configure_api hook if provided + if configure: + if new_app := await configure(api_app): + api_app = new_app + + # Store FastAPI app in container for access via Server.api property + container[FastAPI] = api_app + + return AppWrapper(api_app) diff --git a/src/parlant/api/authorization.py b/src/parlant/api/authorization.py new file mode 100644 index 0000000..c6014b2 --- /dev/null +++ b/src/parlant/api/authorization.py @@ -0,0 +1,331 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from abc import ABC, abstractmethod +from enum import Enum +from typing import Awaitable, Callable + +from typing_extensions import override +from fastapi import FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware + +from limits.storage import MemoryStorage +from limits.strategies import ( + MovingWindowRateLimiter, + FixedWindowRateLimiter, + SlidingWindowCounterRateLimiter, +) +from limits import RateLimitItem, RateLimitItemPerMinute + + +class Operation(Enum): + ACCESS_INTEGRATED_UI = "access_integrated_ui" + ACCESS_API_DOCS = "access_api_docs" + + CREATE_AGENT = "create_agent" + READ_AGENT = "read_agent" + READ_AGENT_DESCRIPTION = "read_agent_description" + LIST_AGENTS = "list_agents" + UPDATE_AGENT = "update_agent" + DELETE_AGENT = "delete_agent" + + CREATE_CANNED_RESPONSE = "create_canned_response" + READ_CANNED_RESPONSE = "read_canned_response" + LIST_CANNED_RESPONSES = "list_canned_responses" + UPDATE_CANNED_RESPONSE = "update_canned_response" + DELETE_CANNED_RESPONSE = "delete_canned_response" + + CREATE_CAPABILITY = "create_capability" + READ_CAPABILITY = "read_capability" + LIST_CAPABILITIES = "list_capabilities" + UPDATE_CAPABILITY = "update_capability" + DELETE_CAPABILITY = "delete_capability" + + CREATE_CONTEXT_VARIABLE = "create_context_variable" + READ_CONTEXT_VARIABLE = "read_context_variable" + LIST_CONTEXT_VARIABLES = "list_context_variables" + UPDATE_CONTEXT_VARIABLE = "update_context_variable" + DELETE_CONTEXT_VARIABLE = "delete_context_variable" + DELETE_CONTEXT_VARIABLES = "delete_context_variables" + READ_CONTEXT_VARIABLE_VALUE = "read_context_variable_value" + UPDATE_CONTEXT_VARIABLE_VALUE = "update_context_variable_value" + DELETE_CONTEXT_VARIABLE_VALUE = "delete_context_variable_value" + + CREATE_CUSTOMER = "create_customer" + READ_CUSTOMER = "read_customer" + LIST_CUSTOMERS = "list_customers" + UPDATE_CUSTOMER = "update_customer" + DELETE_CUSTOMER = "delete_customer" + + CREATE_EVALUATION = "create_evaluation" + READ_EVALUATION = "read_evaluation" + + CREATE_TERM = "create_term" + READ_TERM = "read_term" + LIST_TERMS = "list_terms" + UPDATE_TERM = "update_term" + DELETE_TERM = "delete_term" + + CREATE_GUIDELINE = "create_guideline" + READ_GUIDELINE = "read_guideline" + LIST_GUIDELINES = "list_guidelines" + UPDATE_GUIDELINE = "update_guideline" + DELETE_GUIDELINE = "delete_guideline" + + CREATE_JOURNEY = "create_journey" + READ_JOURNEY = "read_journey" + LIST_JOURNEYS = "list_journeys" + UPDATE_JOURNEY = "update_journey" + DELETE_JOURNEY = "delete_journey" + + CREATE_RELATIONSHIP = "create_relationship" + READ_RELATIONSHIP = "read_relationship" + LIST_RELATIONSHIPS = "list_relationships" + DELETE_RELATIONSHIP = "delete_relationship" + + UPDATE_SERVICE = "update_service" + READ_SERVICE = "read_service" + LIST_SERVICES = "list_services" + DELETE_SERVICE = "delete_service" + + CREATE_GUEST_SESSION = "create_guest_session" + CREATE_CUSTOMER_SESSION = "create_customer_session" + READ_SESSION = "read_session" + LIST_SESSIONS = "list_sessions" + UPDATE_SESSION = "update_session" + DELETE_SESSION = "delete_session" + DELETE_SESSIONS = "delete_sessions" + CREATE_CUSTOMER_EVENT = "create_customer_event" + CREATE_AGENT_EVENT = "create_agent_event" + CREATE_HUMAN_AGENT_EVENT = "create_human_agent_event" + CREATE_HUMAN_AGENT_ON_BEHALF_OF_AI_AGENT_EVENT = ( + "create_human_agent_on_behalf_of_ai_agent_event" + ) + OVERRIDE_CUSTOMER_PARTICIPANT = "override_customer_participant" + CREATE_STATUS_EVENT = "create_status_event" + CREATE_CUSTOM_EVENT = "create_custom_event" + LIST_EVENTS = "list_events" + READ_EVENT = "read_event" + DELETE_EVENTS = "delete_events" + UPDATE_EVENT = "update_event" + + CREATE_TAG = "create_tag" + READ_TAG = "read_tag" + LIST_TAGS = "list_tags" + UPDATE_TAG = "update_tag" + DELETE_TAG = "delete_tag" + + +class AuthorizationException(Exception): + def __init__( + self, + request: Request, + operation: Operation | None, + message_prefix: str = "Authorization failed", + ) -> None: + super().__init__( + f"{message_prefix}: OPERATION={operation.value if operation else 'GENERIC'}, HEADERS={request.headers}" + ) + + self.request = request + self.operation = operation + + +class RateLimitExceededException(AuthorizationException): + def __init__(self, request: Request, operation: Operation | None) -> None: + super().__init__( + request=request, + operation=operation, + message_prefix="Rate limit exceeded", + ) + + +class AuthorizationPolicy(ABC): + async def configure_app(self, app: FastAPI) -> FastAPI: + return app + + @abstractmethod + async def check_permission(self, request: Request, operation: Operation) -> bool: ... + + @abstractmethod + async def check_rate_limit(self, request: Request, operation: Operation) -> bool: ... + + async def authorize(self, request: Request, operation: Operation) -> None: + if not await self.check_permission(request, operation): + raise AuthorizationException(request, operation) + + if not await self.check_rate_limit(request, operation): + raise RateLimitExceededException(request, operation) + + @property + @abstractmethod + def name(self) -> str: ... + + +class DevelopmentAuthorizationPolicy(AuthorizationPolicy): + async def configure_app(self, app: FastAPI) -> FastAPI: + # Allow all origins in development + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + return app + + @override + async def check_rate_limit(self, request: Request, operation: Operation) -> bool: + # In development, we do not enforce rate limits + return True + + @override + async def check_permission(self, request: Request, operation: Operation) -> bool: + # In development, we allow all actions + return True + + @property + @override + def name(self) -> str: + return "development" + + +class RateLimiter(ABC): + @abstractmethod + async def check( + self, + request: Request, + operation: Operation, + ) -> bool: ... + + +class ProductionAuthorizationPolicy(AuthorizationPolicy): + def __init__(self) -> None: + # This can be modified externally to install specific limiters + # for specific API operations. + self.specific_limiters: dict[ + Operation, + Callable[[Request, Operation], Awaitable[bool]], + ] = {} + + # It is also possible to change or override the default limiter + # for this instance from outside this class (or in subclasses). + self.default_limiter: RateLimiter = BasicRateLimiter( + rate_limit_item_per_operation={ + # Some reasonable defaults... + Operation.READ_AGENT: RateLimitItemPerMinute(30), + Operation.CREATE_GUEST_SESSION: RateLimitItemPerMinute(10), + Operation.READ_SESSION: RateLimitItemPerMinute(30), + Operation.LIST_EVENTS: RateLimitItemPerMinute(240), + Operation.CREATE_CUSTOMER_EVENT: RateLimitItemPerMinute(30), + Operation.CREATE_STATUS_EVENT: RateLimitItemPerMinute(60), + } + ) + + async def configure_app(self, app: FastAPI) -> FastAPI: + # By default, allow all origins in production as well. + # This can be customized in subclasses. + # It's recommended to override this method to set more restrictive CORS policies + # for your production environment, e.g., by specifying only the origins (site URLs) + # from which your application can be accessed safely (e.g., https://your-site.com). + + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + return app + + @property + @override + def name(self) -> str: + return "production" + + @override + async def check_permission(self, request: Request, operation: Operation) -> bool: + if operation in [ + Operation.READ_AGENT, + Operation.CREATE_GUEST_SESSION, + Operation.READ_SESSION, + Operation.LIST_EVENTS, + Operation.CREATE_CUSTOMER_EVENT, + ]: + return True + else: + return False + + @override + async def check_rate_limit(self, request: Request, operation: Operation) -> bool: + if specific_limiter := self.specific_limiters.get(operation): + return await specific_limiter(request, operation) + return await self.default_limiter.check(request, operation) + + +class BasicRateLimiter(RateLimiter): + def __init__( + self, + rate_limit_item_per_operation: dict[Operation, RateLimitItem], + storage: MemoryStorage | None = None, + limiter_type: type[ + MovingWindowRateLimiter | FixedWindowRateLimiter | SlidingWindowCounterRateLimiter + ] = MovingWindowRateLimiter, + ) -> None: + self.rate_limit_item_per_operation = rate_limit_item_per_operation + self._limiter = limiter_type(storage or MemoryStorage()) + self._default_rate_limit_item = RateLimitItemPerMinute(100) + + async def check( + self, + request: Request, + operation: Operation, + ) -> bool: + if item := self.rate_limit_item_per_operation.get(operation): + return self._limiter.hit(item, self._build_key(request, operation)) + + return self._limiter.hit(self._default_rate_limit_item, self._build_key(request, None)) + + def _build_key( + self, + request: Request, + operation: Operation | None, + ) -> str: + ip = self._get_client_ip(request) + + if not ip: + raise AuthorizationException( + request=request, + operation=operation, + message_prefix="Authorization failed: No client IP found", + ) + + return f"IP={ip}--OP={operation.value if operation else 'GENERIC'}" + + @staticmethod + def _get_client_ip(request: Request) -> str | None: + headers = request.headers + + if xff := headers.get("x-forwarded-for"): + return xff.split(",")[0].strip() + + if xri := headers.get("x-real-ip"): + return xri.strip() + + if cf := headers.get("cf-connecting-ip"): + return cf.strip() + + return request.client.host if request.client else None diff --git a/src/parlant/api/canned_responses.py b/src/parlant/api/canned_responses.py new file mode 100644 index 0000000..d397580 --- /dev/null +++ b/src/parlant/api/canned_responses.py @@ -0,0 +1,542 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import datetime +from typing import Annotated, Sequence, TypeAlias +import dateutil +from fastapi import APIRouter, HTTPException, Query, Request, status +from pydantic import Field + +from parlant.api.authorization import AuthorizationPolicy, Operation +from parlant.core.app_modules.canned_responses import ( + CannedResponseTagUpdateParamsModel, + CannedResponseMetadataUpdateParamsModel, +) +from parlant.core.application import Application +from parlant.core.common import DefaultBaseModel +from parlant.core.canned_responses import ( + CannedResponseId, + CannedResponseField, +) +from parlant.core.tags import TagId +from parlant.api.common import ExampleJson, JSONSerializableDTO, apigen_config, example_json_content + + +API_GROUP = "canned_responses" + + +CannedResponseFieldNameField: TypeAlias = Annotated[ + str, + Field( + description="The name of the canned response field.", + examples=["username", "location"], + min_length=1, + ), +] + +CannedResponseFieldDescriptionField: TypeAlias = Annotated[ + str, + Field( + description="A description of the canned response field.", + examples=["User's name", "Geographical location"], + min_length=0, + ), +] + +CannedResponseFieldExampleField: TypeAlias = Annotated[ + str, + Field( + description="An example value for the canned response field.", + examples=["Alice", "New York"], + min_length=0, + ), +] + +canned_response_field_example: ExampleJson = { + "description": "An example value for the canned response field.", + "examples": ["Alice", "New York"], + "min_length": 1, +} + + +class CannedResponseFieldDTO( + DefaultBaseModel, + json_schema_extra={"example": canned_response_field_example}, +): + name: CannedResponseFieldNameField + description: CannedResponseFieldDescriptionField + examples: list[CannedResponseFieldExampleField] + + +CannedResponseFieldSequenceField: TypeAlias = Annotated[ + Sequence[CannedResponseFieldDTO], + Field( + description="A sequence of canned response fields associated with the canned response.", + examples=[ + [{"name": "username", "description": "User's name", "examples": ["Alice", "Bob"]}] + ], + ), +] + +TagIdField: TypeAlias = Annotated[ + TagId, + Field( + description="Unique identifier for the tag", + examples=["t9a8g703f4"], + ), +] + +TagIdSequenceField: TypeAlias = Annotated[ + Sequence[TagIdField], + Field( + description="Collection of tag IDs associated with the canned response.", + examples=[["tag123", "tag456"], []], + ), +] + +CannedResponseSignalSequenceField: TypeAlias = Annotated[ + Sequence[str], + Field( + description="A sequence of signals associated with the canned response, to help with filtering and matching.", + examples=[ + ["What is your name?", "Where are you located?", "Let me know if I can help you."], + ], + ), +] + +CannedResponseFieldDependenciesField: TypeAlias = Annotated[ + Sequence[str], + Field( + description="A sequence of field names that must be available in context for this response to be considered.", + examples=[ + ["order", "customer"], + ], + ), +] + +CannedResponseMetadataField: TypeAlias = Annotated[ + dict[str, JSONSerializableDTO], + Field( + description="Additional metadata associated with the canned response.", + examples=[{"category": "greeting", "priority": 1}], + ), +] + +CannedResponseMetadataUnsetField: TypeAlias = Annotated[ + Sequence[str], + Field( + description="Metadata keys to remove from the canned response", + examples=[["old_key", "deprecated_field"]], + ), +] + +CannedResponseIdField: TypeAlias = Annotated[ + CannedResponseId, + Field( + description="Unique identifier for the tag", + examples=["t9a8g703f4"], + ), +] + +CannedResponseCreationUTCField: TypeAlias = Annotated[ + datetime, + Field( + description="UTC timestamp of when the canned response was created", + examples=[dateutil.parser.parse("2024-03-24T12:00:00Z")], + ), +] + +CannedResponseValueField: TypeAlias = Annotated[ + str, + Field( + description="The textual content of the canned response.", + examples=["Your account balance is {balance}", "the answer is {answer}"], + min_length=1, + ), +] + +canned_response_example: ExampleJson = { + "id": "frag123", + "creation_utc": "2024-03-24T12:00:00Z", + "value": "Your account balance is {balance}", + "fields": [{"name": "balance", "description": "Account's balance", "examples": [9000]}], + "tags": ["private", "office"], + "signals": ["What is your balance?", "How much money do I have?"], + "metadata": {"category": "account", "priority": 1}, + "field_dependencies": ["account"], +} + + +class CannedResponseDTO( + DefaultBaseModel, + json_schema_extra={"example": canned_response_example}, +): + id: CannedResponseIdField + creation_utc: CannedResponseCreationUTCField + value: CannedResponseValueField + fields: CannedResponseFieldSequenceField + tags: TagIdSequenceField + signals: CannedResponseSignalSequenceField + metadata: CannedResponseMetadataField + field_dependencies: CannedResponseFieldDependenciesField = [] + + +canned_response_creation_params_example: ExampleJson = { + "value": "Your account balance is {balance}", + "fields": [ + { + "name": "balance", + "description": "Account's balance", + "examples": ["9000"], + } + ], + "metadata": {"category": "account", "priority": 1}, + "field_dependencies": ["account"], +} + + +class CannedResponseCreationParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": canned_response_creation_params_example}, +): + """Parameters for creating a new canned response.""" + + value: CannedResponseValueField + fields: CannedResponseFieldSequenceField + tags: TagIdSequenceField | None = None + signals: CannedResponseSignalSequenceField | None = None + metadata: CannedResponseMetadataField | None = None + field_dependencies: CannedResponseFieldDependenciesField | None = None + + +CannedResponseTagUpdateAddField: TypeAlias = Annotated[ + Sequence[TagIdField], + Field( + description="Optional collection of tag ids to add to the canned response's tags", + ), +] + +CannedResponseTagUpdateRemoveField: TypeAlias = Annotated[ + Sequence[TagIdField], + Field( + description="Optional collection of tag ids to remove from the canned response's tags", + ), +] + +tags_update_params_example: ExampleJson = { + "add": [ + "t9a8g703f4", + "tag_456abc", + ], + "remove": [ + "tag_789def", + "tag_012ghi", + ], +} + + +class CannedResponseTagUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": tags_update_params_example}, +): + """ + Parameters for updating a canned response's tags. + + Allows adding new tags to and removing existing tags from a canned response. + Both operations can be performed in a single request. + """ + + add: CannedResponseTagUpdateAddField | None = None + remove: CannedResponseTagUpdateRemoveField | None = None + + +canned_response_metadata_update_params_example: ExampleJson = { + "set": { + "category": "account", + "priority": 2, + "version": "1.1", + }, + "unset": ["old_category", "deprecated_field"], +} + + +class CannedResponseMetadataUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": canned_response_metadata_update_params_example}, +): + """Parameters for updating the metadata of a canned response.""" + + set: CannedResponseMetadataField | None = None + unset: CannedResponseMetadataUnsetField | None = None + + +canned_response_update_params_example: ExampleJson = { + "value": "Your updated balance is {balance}", + "fields": [ + { + "name": "balance", + "description": "Updated account balance", + "examples": ["10000"], + }, + ], + "metadata": { + "set": { + "category": "account", + "priority": 2, + }, + "unset": ["old_field"], + }, +} + + +class CannedResponseUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": canned_response_update_params_example}, +): + """Parameters for updating an existing canned response.""" + + value: CannedResponseValueField | None = None + fields: CannedResponseFieldSequenceField | None = None + tags: CannedResponseTagUpdateParamsDTO | None = None + metadata: CannedResponseMetadataUpdateParamsDTO | None = None + + +def _dto_to_canned_response_field(dto: CannedResponseFieldDTO) -> CannedResponseField: + return CannedResponseField( + name=dto.name, + description=dto.description, + examples=dto.examples, + ) + + +def _canned_response_field_to_dto( + canned_response_field: CannedResponseField, +) -> CannedResponseFieldDTO: + return CannedResponseFieldDTO( + name=canned_response_field.name, + description=canned_response_field.description, + examples=canned_response_field.examples, + ) + + +TagsQuery: TypeAlias = Annotated[ + Sequence[TagId], + Query(description="Filter canned responses by tags", examples=["tag1", "tag2"]), +] + + +def create_router( + authorization_policy: AuthorizationPolicy, + app: Application, +) -> APIRouter: + router = APIRouter() + + @router.post( + "", + operation_id="create_canned_response", + status_code=status.HTTP_201_CREATED, + response_model=CannedResponseDTO, + responses={ + status.HTTP_201_CREATED: { + "description": "CannedResponse successfully created.", + "content": example_json_content(canned_response_example), + }, + }, + **apigen_config(group_name=API_GROUP, method_name="create"), + ) + async def create_canned_response( + request: Request, + params: CannedResponseCreationParamsDTO, + ) -> CannedResponseDTO: + await authorization_policy.authorize(request, Operation.CREATE_CANNED_RESPONSE) + + canrep = await app.canned_responses.create( + value=params.value, + fields=[_dto_to_canned_response_field(s) for s in params.fields], + tags=params.tags or None, + signals=params.signals or None, + metadata=params.metadata or {}, + field_dependencies=params.field_dependencies or None, + ) + + return CannedResponseDTO( + id=canrep.id, + creation_utc=canrep.creation_utc, + value=canrep.value, + fields=[_canned_response_field_to_dto(s) for s in canrep.fields], + tags=canrep.tags, + signals=canrep.signals, + metadata=canrep.metadata, + field_dependencies=canrep.field_dependencies, + ) + + @router.get( + "/{canned_response_id}", + operation_id="read_canned_response", + response_model=CannedResponseDTO, + responses={ + status.HTTP_200_OK: { + "description": "Canned response details successfully retrieved. Returns the CannedResponse object.", + "content": example_json_content(canned_response_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "Canned response not found. The specified canned_response_id does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="retrieve"), + ) + async def read_canned_response( + request: Request, + canned_response_id: CannedResponseIdField, + ) -> CannedResponseDTO: + """Retrieves details of a specific canned response by ID.""" + await authorization_policy.authorize(request, Operation.READ_CANNED_RESPONSE) + + canrep = await app.canned_responses.read(canned_response_id=canned_response_id) + + return CannedResponseDTO( + id=canrep.id, + creation_utc=canrep.creation_utc, + value=canrep.value, + fields=[_canned_response_field_to_dto(s) for s in canrep.fields], + tags=canrep.tags, + signals=canrep.signals, + metadata=canrep.metadata, + field_dependencies=canrep.field_dependencies, + ) + + @router.get( + "", + operation_id="list_canned_responses", + response_model=Sequence[CannedResponseDTO], + responses={ + status.HTTP_200_OK: { + "description": "List of all canned responses in the system", + "content": example_json_content([canned_response_example]), + } + }, + **apigen_config(group_name=API_GROUP, method_name="list"), + ) + async def list_canned_responses( + request: Request, tags: TagsQuery = [] + ) -> Sequence[CannedResponseDTO]: + """Lists all canned responses, optionally filtered by tags.""" + await authorization_policy.authorize(request, Operation.LIST_CANNED_RESPONSES) + + canreps = await app.canned_responses.find(tags=tags) + + return [ + CannedResponseDTO( + id=f.id, + creation_utc=f.creation_utc, + value=f.value, + fields=[_canned_response_field_to_dto(s) for s in f.fields], + tags=f.tags, + signals=f.signals, + metadata=f.metadata, + field_dependencies=f.field_dependencies, + ) + for f in canreps + ] + + @router.patch( + "/{canned_response_id}", + operation_id="update_canned_response", + response_model=CannedResponseDTO, + responses={ + status.HTTP_200_OK: { + "description": "Canned response successfully updated. Returns the updated CannedResponse object.", + "content": example_json_content(canned_response_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "CannedResponse not found. The specified canned_response_id does not exist" + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Validation error in update parameters" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="update"), + ) + async def update_canned_response( + request: Request, + canned_response_id: CannedResponseIdField, + params: CannedResponseUpdateParamsDTO, + ) -> CannedResponseDTO: + """ + Updates an existing canned response's attributes. + + Only provided attributes will be updated; others remain unchanged. + The canned response's ID and creation timestamp cannot be modified. + Extra metadata and tags can be added or removed independently. + """ + await authorization_policy.authorize(request, Operation.UPDATE_CANNED_RESPONSE) + + if params.fields and not params.value: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, + detail="CannedResponse fields cannot be updated without providing a new value.", + ) + + metadata_params = None + if params.metadata: + metadata_params = CannedResponseMetadataUpdateParamsModel( + set=params.metadata.set, + unset=params.metadata.unset, + ) + + canrep = await app.canned_responses.update( + canned_response_id=canned_response_id, + value=params.value, + fields=( + [_dto_to_canned_response_field(s) for s in params.fields] if params.fields else [] + ), + tags=CannedResponseTagUpdateParamsModel(add=params.tags.add, remove=params.tags.remove) + if params.tags + else None, + metadata=metadata_params, + ) + + return CannedResponseDTO( + id=canrep.id, + creation_utc=canrep.creation_utc, + value=canrep.value, + fields=[_canned_response_field_to_dto(s) for s in canrep.fields], + tags=canrep.tags, + signals=canrep.signals, + metadata=canrep.metadata, + field_dependencies=canrep.field_dependencies, + ) + + @router.delete( + "/{canned_response_id}", + operation_id="delete_canned_response", + status_code=status.HTTP_204_NO_CONTENT, + responses={ + status.HTTP_204_NO_CONTENT: { + "description": "CannedResponse successfully deleted. No content returned." + }, + status.HTTP_404_NOT_FOUND: { + "description": "CannedResponse not found. The specified canned_response_id does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="delete"), + ) + async def delete_canned_response( + request: Request, canned_response_id: CannedResponseIdField + ) -> None: + await authorization_policy.authorize(request, Operation.DELETE_CANNED_RESPONSE) + + await app.canned_responses.delete(canned_response_id) + + return router diff --git a/src/parlant/api/capabilities.py b/src/parlant/api/capabilities.py new file mode 100644 index 0000000..42b36ce --- /dev/null +++ b/src/parlant/api/capabilities.py @@ -0,0 +1,370 @@ +# Copyright 2026 Emcie Co Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from fastapi import APIRouter, Path, Query, Request, status +from pydantic import Field +from typing import Annotated, Sequence, TypeAlias + +from parlant.api.authorization import AuthorizationPolicy, Operation +from parlant.core.app_modules.capabilities import CapabilityTagUpdateParamsModel +from parlant.core.application import Application +from parlant.core.common import DefaultBaseModel +from parlant.api.common import ExampleJson, apigen_config, example_json_content +from parlant.core.capabilities import CapabilityId +from parlant.core.tags import TagId + +API_GROUP = "capabilities" + +CapabilityIdPath: TypeAlias = Annotated[ + CapabilityId, + Path( + description="Unique identifier for the capability", + examples=["cap_123abc"], + min_length=1, + ), +] + +CapabilityTitleField: TypeAlias = Annotated[ + str, + Field( + description="The title of the capability", + examples=["Reset password", "Replace phone"], + min_length=1, + max_length=100, + ), +] + +CapabilityDescriptionField: TypeAlias = Annotated[ + str, + Field( + description="Detailed description of the capability's purpose", + examples=["Provide a weather update"], + ), +] + +CapabilitySignalsField: TypeAlias = Annotated[ + Sequence[str], + Field( + description="Example signals that this capability can handle", + examples=[["I thought I remembered my password", "My phone just broke"]], + ), +] + +CapabilityTagsField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs associated with the capability", + examples=[["tag1", "tag2"]], + ), +] + +capability_example: ExampleJson = { + "id": "cap_123abc", + "title": "Provide Replacement Phone", + "description": "Provide a replacement phone when a customer needs repair for their phone.", + "signals": ["My phone is broken", "I need a replacement while my phone is being repaired"], + "tags": ["tag1", "tag2"], +} + + +class CapabilityDTO( + DefaultBaseModel, + json_schema_extra={"example": capability_example}, +): + """ + A capability represents a functional feature or skill of the agent. + """ + + id: CapabilityIdPath + title: CapabilityTitleField + description: CapabilityDescriptionField + signals: CapabilitySignalsField + tags: CapabilityTagsField = [] + + +class CapabilityCreationParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": capability_example}, +): + """ + Parameters for creating a new capability. + """ + + title: CapabilityTitleField + description: CapabilityDescriptionField + signals: CapabilitySignalsField + tags: CapabilityTagsField | None = None + + +CapabilityTagUpdateAddField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs to add to the capability", + examples=[["tag1", "tag2"]], + ), +] + +CapabilityTagUpdateRemoveField: TypeAlias = Annotated[ + list[TagId], + Field( + description="List of tag IDs to remove from the capability", + examples=[["tag1", "tag2"]], + ), +] + +capability_tag_update_params_example: ExampleJson = { + "add": ["tag1", "tag2"], + "remove": ["tag3"], +} + + +class CapabilityTagUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": capability_tag_update_params_example}, +): + """ + Parameters for updating an existing capability's tags. + """ + + add: CapabilityTagUpdateAddField | None = None + remove: CapabilityTagUpdateRemoveField | None = None + + +class CapabilityUpdateParamsDTO( + DefaultBaseModel, + json_schema_extra={"example": capability_example}, +): + """ + Parameters for updating an existing capability. + All fields are optional. Only provided fields will be updated. + """ + + title: CapabilityTitleField | None = None + description: CapabilityDescriptionField | None = None + signals: CapabilitySignalsField | None = None + tags: CapabilityTagUpdateParamsDTO | None = None + + +TagIdQuery: TypeAlias = Annotated[ + TagId | None, + Query( + description="The tag ID to filter capabilities by", + examples=["tag:123"], + ), +] + + +def create_router( + authorization_policy: AuthorizationPolicy, + app: Application, +) -> APIRouter: + router = APIRouter() + + @router.post( + "", + status_code=status.HTTP_201_CREATED, + operation_id="create_capability", + response_model=CapabilityDTO, + responses={ + status.HTTP_201_CREATED: { + "description": "Capability successfully created. Returns the complete capability object including generated ID.", + "content": example_json_content(capability_example), + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Validation error in request parameters" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="create"), + ) + async def create_capability( + request: Request, + params: CapabilityCreationParamsDTO, + ) -> CapabilityDTO: + """ + Creates a new capability in the system. + + The capability will be initialized with the provided title, description, signals, and optional tags. + A unique identifier will be automatically generated. + + Default behaviors: + - `signals` defaults to an empty list if not provided + """ + await authorization_policy.authorize(request, Operation.CREATE_CAPABILITY) + + capability = await app.capabilities.create( + params.title, params.description, params.signals, params.tags + ) + + return CapabilityDTO( + id=capability.id, + title=capability.title, + description=capability.description, + signals=capability.signals, + tags=capability.tags, + ) + + @router.get( + "", + operation_id="list_capabilities", + response_model=Sequence[CapabilityDTO], + responses={ + status.HTTP_200_OK: { + "description": "List of all capabilities in the system", + "content": example_json_content([capability_example]), + } + }, + **apigen_config(group_name=API_GROUP, method_name="list"), + ) + async def list_capabilities( + request: Request, + tag_id: TagIdQuery = None, + ) -> Sequence[CapabilityDTO]: + """ + Retrieves a list of all capabilities in the system. + + Returns an empty list if no capabilities exist. + Capabilities are returned in no guaranteed order. + """ + await authorization_policy.authorize(request, Operation.LIST_CAPABILITIES) + + capabilities = await app.capabilities.find(tag_id) + + return [ + CapabilityDTO( + id=capability.id, + title=capability.title, + description=capability.description, + signals=capability.signals, + tags=capability.tags, + ) + for capability in capabilities + ] + + @router.get( + "/{capability_id}", + operation_id="read_capability", + response_model=CapabilityDTO, + responses={ + status.HTTP_200_OK: { + "description": "Capability details successfully retrieved. Returns the complete capability object.", + "content": example_json_content(capability_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "Capability not found. The specified `capability_id` does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="retrieve"), + ) + async def read_capability( + request: Request, + capability_id: CapabilityIdPath, + ) -> CapabilityDTO: + """ + Retrieves details of a specific capability by ID. + + Returns the complete capability object. + """ + await authorization_policy.authorize(request, Operation.READ_CAPABILITY) + + capability = await app.capabilities.read(capability_id=capability_id) + + return CapabilityDTO( + id=capability.id, + title=capability.title, + description=capability.description, + signals=capability.signals, + tags=capability.tags, + ) + + @router.patch( + "/{capability_id}", + operation_id="update_capability", + response_model=CapabilityDTO, + responses={ + status.HTTP_200_OK: { + "description": "Capability successfully updated. Returns the updated capability.", + "content": example_json_content(capability_example), + }, + status.HTTP_404_NOT_FOUND: { + "description": "Capability not found. The specified `capability_id` does not exist" + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Validation error in update parameters" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="update"), + ) + async def update_capability( + request: Request, + capability_id: CapabilityIdPath, + params: CapabilityUpdateParamsDTO, + ) -> CapabilityDTO: + """ + Updates an existing capability's attributes. + + Only the provided attributes will be updated; others will remain unchanged. + The capability's ID and creation timestamp cannot be modified. + """ + await authorization_policy.authorize(request, Operation.UPDATE_CAPABILITY) + + capability = await app.capabilities.update( + capability_id, + title=params.title, + description=params.description, + signals=params.signals, + tags=CapabilityTagUpdateParamsModel( + add=params.tags.add, + remove=params.tags.remove, + ) + if params.tags + else None, + ) + + return CapabilityDTO( + id=capability.id, + title=capability.title, + description=capability.description, + signals=capability.signals, + tags=capability.tags, + ) + + @router.delete( + "/{capability_id}", + operation_id="delete_capability", + status_code=status.HTTP_204_NO_CONTENT, + responses={ + status.HTTP_204_NO_CONTENT: { + "description": "Capability successfully deleted. No content returned." + }, + status.HTTP_404_NOT_FOUND: { + "description": "Capability not found. The specified `capability_id` does not exist" + }, + }, + **apigen_config(group_name=API_GROUP, method_name="delete"), + ) + async def delete_capability( + request: Request, + capability_id: CapabilityIdPath, + ) -> None: + """ + Deletes a capability from the system. + + Deleting a non-existent capability will return 404. + No content will be returned from a successful deletion. + """ + await authorization_policy.authorize(request, Operation.DELETE_CAPABILITY) + + await app.capabilities.delete(capability_id=capability_id) + + return router diff --git a/src/parlant/api/chat/.gitignore b/src/parlant/api/chat/.gitignore new file mode 100644 index 0000000..251ce6d --- /dev/null +++ b/src/parlant/api/chat/.gitignore @@ -0,0 +1,23 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/parlant/api/chat/.prettierrc b/src/parlant/api/chat/.prettierrc new file mode 100644 index 0000000..e7a8128 --- /dev/null +++ b/src/parlant/api/chat/.prettierrc @@ -0,0 +1,11 @@ +{ + "singleQuote": true, + "tabWidth": 2, + "semi": true, + "bracketSameLine": true, + "arrowParens": "always", + "bracketSpacing": false, + "jsxSingleQuote": true, + "printWidth": 250, + "useTabs": true +} \ No newline at end of file diff --git a/src/parlant/api/chat/.vite/deps_temp_0491001f/package.json b/src/parlant/api/chat/.vite/deps_temp_0491001f/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/src/parlant/api/chat/.vite/deps_temp_0491001f/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/src/parlant/api/chat/components.json b/src/parlant/api/chat/components.json new file mode 100644 index 0000000..d5b6312 --- /dev/null +++ b/src/parlant/api/chat/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} \ No newline at end of file diff --git a/src/parlant/api/chat/dist/app-logo.svg b/src/parlant/api/chat/dist/app-logo.svg new file mode 100644 index 0000000..fa26858 --- /dev/null +++ b/src/parlant/api/chat/dist/app-logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/assets/index-CrGGfMHl.js b/src/parlant/api/chat/dist/assets/index-CrGGfMHl.js new file mode 100644 index 0000000..d8c64e3 --- /dev/null +++ b/src/parlant/api/chat/dist/assets/index-CrGGfMHl.js @@ -0,0 +1,101 @@ +function DM(t,e){for(var n=0;nr[i]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}})();function _s(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var lg={exports:{}},wu={},ug={exports:{}},Et={};var nv;function LM(){if(nv)return Et;nv=1;var t=Symbol.for("react.element"),e=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.provider"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),f=Symbol.for("react.lazy"),p=Symbol.iterator;function m(U){return U===null||typeof U!="object"?null:(U=p&&U[p]||U["@@iterator"],typeof U=="function"?U:null)}var g={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},x=Object.assign,v={};function S(U,Q,R){this.props=U,this.context=Q,this.refs=v,this.updater=R||g}S.prototype.isReactComponent={},S.prototype.setState=function(U,Q){if(typeof U!="object"&&typeof U!="function"&&U!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,U,Q,"setState")},S.prototype.forceUpdate=function(U){this.updater.enqueueForceUpdate(this,U,"forceUpdate")};function C(){}C.prototype=S.prototype;function A(U,Q,R){this.props=U,this.context=Q,this.refs=v,this.updater=R||g}var k=A.prototype=new C;k.constructor=A,x(k,S.prototype),k.isPureReactComponent=!0;var M=Array.isArray,F=Object.prototype.hasOwnProperty,I={current:null},D={key:!0,ref:!0,__self:!0,__source:!0};function G(U,Q,R){var oe,pe={},ue=null,J=null;if(Q!=null)for(oe in Q.ref!==void 0&&(J=Q.ref),Q.key!==void 0&&(ue=""+Q.key),Q)F.call(Q,oe)&&!D.hasOwnProperty(oe)&&(pe[oe]=Q[oe]);var he=arguments.length-2;if(he===1)pe.children=R;else if(1>>1,Q=j[U];if(0>>1;Ui(pe,O))uei(J,pe)?(j[U]=J,j[ue]=O,U=ue):(j[U]=pe,j[oe]=O,U=oe);else if(uei(J,O))j[U]=J,j[ue]=O,U=ue;else break e}}return W}function i(j,W){var O=j.sortIndex-W.sortIndex;return O!==0?O:j.id-W.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;t.unstable_now=function(){return s.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],d=[],f=1,p=null,m=3,g=!1,x=!1,v=!1,S=typeof setTimeout=="function"?setTimeout:null,C=typeof clearTimeout=="function"?clearTimeout:null,A=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function k(j){for(var W=n(d);W!==null;){if(W.callback===null)r(d);else if(W.startTime<=j)r(d),W.sortIndex=W.expirationTime,e(c,W);else break;W=n(d)}}function M(j){if(v=!1,k(j),!x)if(n(c)!==null)x=!0,ae(F);else{var W=n(d);W!==null&&de(M,W.startTime-j)}}function F(j,W){x=!1,v&&(v=!1,C(G),G=-1),g=!0;var O=m;try{for(k(W),p=n(c);p!==null&&(!(p.expirationTime>W)||j&&!Y());){var U=p.callback;if(typeof U=="function"){p.callback=null,m=p.priorityLevel;var Q=U(p.expirationTime<=W);W=t.unstable_now(),typeof Q=="function"?p.callback=Q:p===n(c)&&r(c),k(W)}else r(c);p=n(c)}if(p!==null)var R=!0;else{var oe=n(d);oe!==null&&de(M,oe.startTime-W),R=!1}return R}finally{p=null,m=O,g=!1}}var I=!1,D=null,G=-1,X=5,P=-1;function Y(){return!(t.unstable_now()-Pj||125U?(j.sortIndex=O,e(d,j),n(c)===null&&j===n(d)&&(v?(C(G),G=-1):v=!0,de(M,O-U))):(j.sortIndex=Q,e(c,j),x||g||(x=!0,ae(F))),j},t.unstable_shouldYield=Y,t.unstable_wrapCallback=function(j){var W=m;return function(){var O=m;m=W;try{return j.apply(this,arguments)}finally{m=O}}}})(fg)),fg}var av;function UM(){return av||(av=1,dg.exports=BM()),dg.exports}var lv;function HM(){if(lv)return Cr;lv=1;var t=Dh(),e=UM();function n(a){for(var u="https://reactjs.org/docs/error-decoder.html?invariant="+a,h=1;h"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),c=Object.prototype.hasOwnProperty,d=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f={},p={};function m(a){return c.call(p,a)?!0:c.call(f,a)?!1:d.test(a)?p[a]=!0:(f[a]=!0,!1)}function g(a,u,h,b){if(h!==null&&h.type===0)return!1;switch(typeof u){case"function":case"symbol":return!0;case"boolean":return b?!1:h!==null?!h.acceptsBooleans:(a=a.toLowerCase().slice(0,5),a!=="data-"&&a!=="aria-");default:return!1}}function x(a,u,h,b){if(u===null||typeof u>"u"||g(a,u,h,b))return!0;if(b)return!1;if(h!==null)switch(h.type){case 3:return!u;case 4:return u===!1;case 5:return isNaN(u);case 6:return isNaN(u)||1>u}return!1}function v(a,u,h,b,y,_,N){this.acceptsBooleans=u===2||u===3||u===4,this.attributeName=b,this.attributeNamespace=y,this.mustUseProperty=h,this.propertyName=a,this.type=u,this.sanitizeURL=_,this.removeEmptyString=N}var S={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){S[a]=new v(a,0,!1,a,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var u=a[0];S[u]=new v(u,1,!1,a[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(a){S[a]=new v(a,2,!1,a.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){S[a]=new v(a,2,!1,a,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(a){S[a]=new v(a,3,!1,a.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(a){S[a]=new v(a,3,!0,a,null,!1,!1)}),["capture","download"].forEach(function(a){S[a]=new v(a,4,!1,a,null,!1,!1)}),["cols","rows","size","span"].forEach(function(a){S[a]=new v(a,6,!1,a,null,!1,!1)}),["rowSpan","start"].forEach(function(a){S[a]=new v(a,5,!1,a.toLowerCase(),null,!1,!1)});var C=/[\-:]([a-z])/g;function A(a){return a[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(a){var u=a.replace(C,A);S[u]=new v(u,1,!1,a,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var u=a.replace(C,A);S[u]=new v(u,1,!1,a,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(a){var u=a.replace(C,A);S[u]=new v(u,1,!1,a,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(a){S[a]=new v(a,1,!1,a.toLowerCase(),null,!1,!1)}),S.xlinkHref=new v("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(a){S[a]=new v(a,1,!1,a.toLowerCase(),null,!0,!0)});function k(a,u,h,b){var y=S.hasOwnProperty(u)?S[u]:null;(y!==null?y.type!==0:b||!(2H||y[N]!==_[H]){var K=` +`+y[N].replace(" at new "," at ");return a.displayName&&K.includes("")&&(K=K.replace("",a.displayName)),K}while(1<=N&&0<=H);break}}}finally{R=!1,Error.prepareStackTrace=h}return(a=a?a.displayName||a.name:"")?Q(a):""}function pe(a){switch(a.tag){case 5:return Q(a.type);case 16:return Q("Lazy");case 13:return Q("Suspense");case 19:return Q("SuspenseList");case 0:case 2:case 15:return a=oe(a.type,!1),a;case 11:return a=oe(a.type.render,!1),a;case 1:return a=oe(a.type,!0),a;default:return""}}function ue(a){if(a==null)return null;if(typeof a=="function")return a.displayName||a.name||null;if(typeof a=="string")return a;switch(a){case D:return"Fragment";case I:return"Portal";case X:return"Profiler";case G:return"StrictMode";case ie:return"Suspense";case Z:return"SuspenseList"}if(typeof a=="object")switch(a.$$typeof){case Y:return(a.displayName||"Context")+".Consumer";case P:return(a._context.displayName||"Context")+".Provider";case z:var u=a.render;return a=a.displayName,a||(a=u.displayName||u.name||"",a=a!==""?"ForwardRef("+a+")":"ForwardRef"),a;case ee:return u=a.displayName||null,u!==null?u:ue(a.type)||"Memo";case ae:u=a._payload,a=a._init;try{return ue(a(u))}catch{}}return null}function J(a){var u=a.type;switch(a.tag){case 24:return"Cache";case 9:return(u.displayName||"Context")+".Consumer";case 10:return(u._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return a=u.render,a=a.displayName||a.name||"",u.displayName||(a!==""?"ForwardRef("+a+")":"ForwardRef");case 7:return"Fragment";case 5:return u;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ue(u);case 8:return u===G?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof u=="function")return u.displayName||u.name||null;if(typeof u=="string")return u}return null}function he(a){switch(typeof a){case"boolean":case"number":case"string":case"undefined":return a;case"object":return a;default:return""}}function _e(a){var u=a.type;return(a=a.nodeName)&&a.toLowerCase()==="input"&&(u==="checkbox"||u==="radio")}function ke(a){var u=_e(a)?"checked":"value",h=Object.getOwnPropertyDescriptor(a.constructor.prototype,u),b=""+a[u];if(!a.hasOwnProperty(u)&&typeof h<"u"&&typeof h.get=="function"&&typeof h.set=="function"){var y=h.get,_=h.set;return Object.defineProperty(a,u,{configurable:!0,get:function(){return y.call(this)},set:function(N){b=""+N,_.call(this,N)}}),Object.defineProperty(a,u,{enumerable:h.enumerable}),{getValue:function(){return b},setValue:function(N){b=""+N},stopTracking:function(){a._valueTracker=null,delete a[u]}}}}function Ve(a){a._valueTracker||(a._valueTracker=ke(a))}function ot(a){if(!a)return!1;var u=a._valueTracker;if(!u)return!0;var h=u.getValue(),b="";return a&&(b=_e(a)?a.checked?"true":"false":a.value),a=b,a!==h?(u.setValue(a),!0):!1}function qe(a){if(a=a||(typeof document<"u"?document:void 0),typeof a>"u")return null;try{return a.activeElement||a.body}catch{return a.body}}function kt(a,u){var h=u.checked;return O({},u,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:h??a._wrapperState.initialChecked})}function fn(a,u){var h=u.defaultValue==null?"":u.defaultValue,b=u.checked!=null?u.checked:u.defaultChecked;h=he(u.value!=null?u.value:h),a._wrapperState={initialChecked:b,initialValue:h,controlled:u.type==="checkbox"||u.type==="radio"?u.checked!=null:u.value!=null}}function nt(a,u){u=u.checked,u!=null&&k(a,"checked",u,!1)}function Yt(a,u){nt(a,u);var h=he(u.value),b=u.type;if(h!=null)b==="number"?(h===0&&a.value===""||a.value!=h)&&(a.value=""+h):a.value!==""+h&&(a.value=""+h);else if(b==="submit"||b==="reset"){a.removeAttribute("value");return}u.hasOwnProperty("value")?Pn(a,u.type,h):u.hasOwnProperty("defaultValue")&&Pn(a,u.type,he(u.defaultValue)),u.checked==null&&u.defaultChecked!=null&&(a.defaultChecked=!!u.defaultChecked)}function Ct(a,u,h){if(u.hasOwnProperty("value")||u.hasOwnProperty("defaultValue")){var b=u.type;if(!(b!=="submit"&&b!=="reset"||u.value!==void 0&&u.value!==null))return;u=""+a._wrapperState.initialValue,h||u===a.value||(a.value=u),a.defaultValue=u}h=a.name,h!==""&&(a.name=""),a.defaultChecked=!!a._wrapperState.initialChecked,h!==""&&(a.name=h)}function Pn(a,u,h){(u!=="number"||qe(a.ownerDocument)!==a)&&(h==null?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+h&&(a.defaultValue=""+h))}var Fn=Array.isArray;function on(a,u,h,b){if(a=a.options,u){u={};for(var y=0;y"+u.valueOf().toString()+"",u=Qe.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;u.firstChild;)a.appendChild(u.firstChild)}});function rt(a,u){if(u){var h=a.firstChild;if(h&&h===a.lastChild&&h.nodeType===3){h.nodeValue=u;return}}a.textContent=u}var an={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Zn=["Webkit","ms","Moz","O"];Object.keys(an).forEach(function(a){Zn.forEach(function(u){u=u+a.charAt(0).toUpperCase()+a.substring(1),an[u]=an[a]})});function Re(a,u,h){return u==null||typeof u=="boolean"||u===""?"":h||typeof u!="number"||u===0||an.hasOwnProperty(a)&&an[a]?(""+u).trim():u+"px"}function Me(a,u){a=a.style;for(var h in u)if(u.hasOwnProperty(h)){var b=h.indexOf("--")===0,y=Re(h,u[h],b);h==="float"&&(h="cssFloat"),b?a.setProperty(h,y):a[h]=y}}var Ge=O({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Ke(a,u){if(u){if(Ge[a]&&(u.children!=null||u.dangerouslySetInnerHTML!=null))throw Error(n(137,a));if(u.dangerouslySetInnerHTML!=null){if(u.children!=null)throw Error(n(60));if(typeof u.dangerouslySetInnerHTML!="object"||!("__html"in u.dangerouslySetInnerHTML))throw Error(n(61))}if(u.style!=null&&typeof u.style!="object")throw Error(n(62))}}function bt(a,u){if(a.indexOf("-")===-1)return typeof u.is=="string";switch(a){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var vt=null;function jt(a){return a=a.target||a.srcElement||window,a.correspondingUseElement&&(a=a.correspondingUseElement),a.nodeType===3?a.parentNode:a}var fr=null,Dt=null,$t=null;function qt(a){if(a=au(a)){if(typeof fr!="function")throw Error(n(280));var u=a.stateNode;u&&(u=fd(u),fr(a.stateNode,a.type,u))}}function V(a){Dt?$t?$t.push(a):$t=[a]:Dt=a}function te(){if(Dt){var a=Dt,u=$t;if($t=Dt=null,qt(a),u)for(a=0;a>>=0,a===0?32:31-(Ii(a)/pa|0)|0}var pr=64,xo=4194304;function Rs(a){switch(a&-a){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return a&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return a&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return a}}function vo(a,u){var h=a.pendingLanes;if(h===0)return 0;var b=0,y=a.suspendedLanes,_=a.pingedLanes,N=h&268435455;if(N!==0){var H=N&~y;H!==0?b=Rs(H):(_&=N,_!==0&&(b=Rs(_)))}else N=h&~y,N!==0?b=Rs(N):_!==0&&(b=Rs(_));if(b===0)return 0;if(u!==0&&u!==b&&(u&y)===0&&(y=b&-b,_=u&-u,y>=_||y===16&&(_&4194240)!==0))return u;if((b&4)!==0&&(b|=h&16),u=a.entangledLanes,u!==0)for(a=a.entanglements,u&=b;0h;h++)u.push(a);return u}function Os(a,u,h){a.pendingLanes|=u,u!==536870912&&(a.suspendedLanes=0,a.pingedLanes=0),a=a.eventTimes,u=31-pn(u),a[u]=h}function Yr(a,u){var h=a.pendingLanes&~u;a.pendingLanes=u,a.suspendedLanes=0,a.pingedLanes=0,a.expiredLanes&=u,a.mutableReadLanes&=u,a.entangledLanes&=u,u=a.entanglements;var b=a.eventTimes;for(a=a.expirationTimes;0=Zl),q1=" ",X1=!1;function Q1(a,u){switch(a){case"keyup":return NO.indexOf(u.keyCode)!==-1;case"keydown":return u.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Z1(a){return a=a.detail,typeof a=="object"&&"data"in a?a.data:null}var ba=!1;function IO(a,u){switch(a){case"compositionend":return Z1(u);case"keypress":return u.which!==32?null:(X1=!0,q1);case"textInput":return a=u.data,a===q1&&X1?null:a;default:return null}}function OO(a,u){if(ba)return a==="compositionend"||!jp&&Q1(a,u)?(a=$1(),td=Pp=Ds=null,ba=!1,a):null;switch(a){case"paste":return null;case"keypress":if(!(u.ctrlKey||u.altKey||u.metaKey)||u.ctrlKey&&u.altKey){if(u.char&&1=u)return{node:h,offset:u-a};a=b}e:{for(;h;){if(h.nextSibling){h=h.nextSibling;break e}h=h.parentNode}h=void 0}h=sy(h)}}function ay(a,u){return a&&u?a===u?!0:a&&a.nodeType===3?!1:u&&u.nodeType===3?ay(a,u.parentNode):"contains"in a?a.contains(u):a.compareDocumentPosition?!!(a.compareDocumentPosition(u)&16):!1:!1}function ly(){for(var a=window,u=qe();u instanceof a.HTMLIFrameElement;){try{var h=typeof u.contentWindow.location.href=="string"}catch{h=!1}if(h)a=u.contentWindow;else break;u=qe(a.document)}return u}function Vp(a){var u=a&&a.nodeName&&a.nodeName.toLowerCase();return u&&(u==="input"&&(a.type==="text"||a.type==="search"||a.type==="tel"||a.type==="url"||a.type==="password")||u==="textarea"||a.contentEditable==="true")}function zO(a){var u=ly(),h=a.focusedElem,b=a.selectionRange;if(u!==h&&h&&h.ownerDocument&&ay(h.ownerDocument.documentElement,h)){if(b!==null&&Vp(h)){if(u=b.start,a=b.end,a===void 0&&(a=u),"selectionStart"in h)h.selectionStart=u,h.selectionEnd=Math.min(a,h.value.length);else if(a=(u=h.ownerDocument||document)&&u.defaultView||window,a.getSelection){a=a.getSelection();var y=h.textContent.length,_=Math.min(b.start,y);b=b.end===void 0?_:Math.min(b.end,y),!a.extend&&_>b&&(y=b,b=_,_=y),y=oy(h,_);var N=oy(h,b);y&&N&&(a.rangeCount!==1||a.anchorNode!==y.node||a.anchorOffset!==y.offset||a.focusNode!==N.node||a.focusOffset!==N.offset)&&(u=u.createRange(),u.setStart(y.node,y.offset),a.removeAllRanges(),_>b?(a.addRange(u),a.extend(N.node,N.offset)):(u.setEnd(N.node,N.offset),a.addRange(u)))}}for(u=[],a=h;a=a.parentNode;)a.nodeType===1&&u.push({element:a,left:a.scrollLeft,top:a.scrollTop});for(typeof h.focus=="function"&&h.focus(),h=0;h=document.documentMode,Ea=null,Gp=null,nu=null,Kp=!1;function uy(a,u,h){var b=h.window===h?h.document:h.nodeType===9?h:h.ownerDocument;Kp||Ea==null||Ea!==qe(b)||(b=Ea,"selectionStart"in b&&Vp(b)?b={start:b.selectionStart,end:b.selectionEnd}:(b=(b.ownerDocument&&b.ownerDocument.defaultView||window).getSelection(),b={anchorNode:b.anchorNode,anchorOffset:b.anchorOffset,focusNode:b.focusNode,focusOffset:b.focusOffset}),nu&&tu(nu,b)||(nu=b,b=ud(Gp,"onSelect"),0Ta||(a.current=sm[Ta],sm[Ta]=null,Ta--)}function Qt(a,u){Ta++,sm[Ta]=a.current,a.current=u}var Bs={},Jn=Fs(Bs),vr=Fs(!1),_o=Bs;function Sa(a,u){var h=a.type.contextTypes;if(!h)return Bs;var b=a.stateNode;if(b&&b.__reactInternalMemoizedUnmaskedChildContext===u)return b.__reactInternalMemoizedMaskedChildContext;var y={},_;for(_ in h)y[_]=u[_];return b&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=u,a.__reactInternalMemoizedMaskedChildContext=y),y}function wr(a){return a=a.childContextTypes,a!=null}function hd(){nn(vr),nn(Jn)}function Sy(a,u,h){if(Jn.current!==Bs)throw Error(n(168));Qt(Jn,u),Qt(vr,h)}function _y(a,u,h){var b=a.stateNode;if(u=u.childContextTypes,typeof b.getChildContext!="function")return h;b=b.getChildContext();for(var y in b)if(!(y in u))throw Error(n(108,J(a)||"Unknown",y));return O({},h,b)}function pd(a){return a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||Bs,_o=Jn.current,Qt(Jn,a),Qt(vr,vr.current),!0}function Cy(a,u,h){var b=a.stateNode;if(!b)throw Error(n(169));h?(a=_y(a,u,_o),b.__reactInternalMemoizedMergedChildContext=a,nn(vr),nn(Jn),Qt(Jn,a)):nn(vr),Qt(vr,h)}var rs=null,md=!1,om=!1;function Ay(a){rs===null?rs=[a]:rs.push(a)}function JO(a){md=!0,Ay(a)}function Us(){if(!om&&rs!==null){om=!0;var a=0,u=It;try{var h=rs;for(It=1;a>=N,y-=N,is=1<<32-pn(u)+y|h<st?(zn=Je,Je=null):zn=Je.sibling;var Mt=ge(ne,Je,se[st],Ae);if(Mt===null){Je===null&&(Je=zn);break}a&&Je&&Mt.alternate===null&&u(ne,Je),q=_(Mt,q,st),Ze===null?We=Mt:Ze.sibling=Mt,Ze=Mt,Je=zn}if(st===se.length)return h(ne,Je),ln&&Ao(ne,st),We;if(Je===null){for(;stst?(zn=Je,Je=null):zn=Je.sibling;var Ys=ge(ne,Je,Mt.value,Ae);if(Ys===null){Je===null&&(Je=zn);break}a&&Je&&Ys.alternate===null&&u(ne,Je),q=_(Ys,q,st),Ze===null?We=Ys:Ze.sibling=Ys,Ze=Ys,Je=zn}if(Mt.done)return h(ne,Je),ln&&Ao(ne,st),We;if(Je===null){for(;!Mt.done;st++,Mt=se.next())Mt=xe(ne,Mt.value,Ae),Mt!==null&&(q=_(Mt,q,st),Ze===null?We=Mt:Ze.sibling=Mt,Ze=Mt);return ln&&Ao(ne,st),We}for(Je=b(ne,Je);!Mt.done;st++,Mt=se.next())Mt=Le(Je,ne,st,Mt.value,Ae),Mt!==null&&(a&&Mt.alternate!==null&&Je.delete(Mt.key===null?st:Mt.key),q=_(Mt,q,st),Ze===null?We=Mt:Ze.sibling=Mt,Ze=Mt);return a&&Je.forEach(function(MM){return u(ne,MM)}),ln&&Ao(ne,st),We}function Tn(ne,q,se,Ae){if(typeof se=="object"&&se!==null&&se.type===D&&se.key===null&&(se=se.props.children),typeof se=="object"&&se!==null){switch(se.$$typeof){case F:e:{for(var We=se.key,Ze=q;Ze!==null;){if(Ze.key===We){if(We=se.type,We===D){if(Ze.tag===7){h(ne,Ze.sibling),q=y(Ze,se.props.children),q.return=ne,ne=q;break e}}else if(Ze.elementType===We||typeof We=="object"&&We!==null&&We.$$typeof===ae&&My(We)===Ze.type){h(ne,Ze.sibling),q=y(Ze,se.props),q.ref=lu(ne,Ze,se),q.return=ne,ne=q;break e}h(ne,Ze);break}else u(ne,Ze);Ze=Ze.sibling}se.type===D?(q=Lo(se.props.children,ne.mode,Ae,se.key),q.return=ne,ne=q):(Ae=$d(se.type,se.key,se.props,null,ne.mode,Ae),Ae.ref=lu(ne,q,se),Ae.return=ne,ne=Ae)}return N(ne);case I:e:{for(Ze=se.key;q!==null;){if(q.key===Ze)if(q.tag===4&&q.stateNode.containerInfo===se.containerInfo&&q.stateNode.implementation===se.implementation){h(ne,q.sibling),q=y(q,se.children||[]),q.return=ne,ne=q;break e}else{h(ne,q);break}else u(ne,q);q=q.sibling}q=rg(se,ne.mode,Ae),q.return=ne,ne=q}return N(ne);case ae:return Ze=se._init,Tn(ne,q,Ze(se._payload),Ae)}if(Fn(se))return ze(ne,q,se,Ae);if(W(se))return $e(ne,q,se,Ae);yd(ne,se)}return typeof se=="string"&&se!==""||typeof se=="number"?(se=""+se,q!==null&&q.tag===6?(h(ne,q.sibling),q=y(q,se),q.return=ne,ne=q):(h(ne,q),q=ng(se,ne.mode,Ae),q.return=ne,ne=q),N(ne)):h(ne,q)}return Tn}var ka=Dy(!0),Ly=Dy(!1),xd=Fs(null),vd=null,Na=null,fm=null;function hm(){fm=Na=vd=null}function pm(a){var u=xd.current;nn(xd),a._currentValue=u}function mm(a,u,h){for(;a!==null;){var b=a.alternate;if((a.childLanes&u)!==u?(a.childLanes|=u,b!==null&&(b.childLanes|=u)):b!==null&&(b.childLanes&u)!==u&&(b.childLanes|=u),a===h)break;a=a.return}}function Ra(a,u){vd=a,fm=Na=null,a=a.dependencies,a!==null&&a.firstContext!==null&&((a.lanes&u)!==0&&(Tr=!0),a.firstContext=null)}function Qr(a){var u=a._currentValue;if(fm!==a)if(a={context:a,memoizedValue:u,next:null},Na===null){if(vd===null)throw Error(n(308));Na=a,vd.dependencies={lanes:0,firstContext:a}}else Na=Na.next=a;return u}var ko=null;function gm(a){ko===null?ko=[a]:ko.push(a)}function Py(a,u,h,b){var y=u.interleaved;return y===null?(h.next=h,gm(u)):(h.next=y.next,y.next=h),u.interleaved=h,os(a,b)}function os(a,u){a.lanes|=u;var h=a.alternate;for(h!==null&&(h.lanes|=u),h=a,a=a.return;a!==null;)a.childLanes|=u,h=a.alternate,h!==null&&(h.childLanes|=u),h=a,a=a.return;return h.tag===3?h.stateNode:null}var Hs=!1;function bm(a){a.updateQueue={baseState:a.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Fy(a,u){a=a.updateQueue,u.updateQueue===a&&(u.updateQueue={baseState:a.baseState,firstBaseUpdate:a.firstBaseUpdate,lastBaseUpdate:a.lastBaseUpdate,shared:a.shared,effects:a.effects})}function as(a,u){return{eventTime:a,lane:u,tag:0,payload:null,callback:null,next:null}}function zs(a,u,h){var b=a.updateQueue;if(b===null)return null;if(b=b.shared,(Ot&2)!==0){var y=b.pending;return y===null?u.next=u:(u.next=y.next,y.next=u),b.pending=u,os(a,h)}return y=b.interleaved,y===null?(u.next=u,gm(b)):(u.next=y.next,y.next=u),b.interleaved=u,os(a,h)}function wd(a,u,h){if(u=u.updateQueue,u!==null&&(u=u.shared,(h&4194240)!==0)){var b=u.lanes;b&=a.pendingLanes,h|=b,u.lanes=h,Vl(a,h)}}function By(a,u){var h=a.updateQueue,b=a.alternate;if(b!==null&&(b=b.updateQueue,h===b)){var y=null,_=null;if(h=h.firstBaseUpdate,h!==null){do{var N={eventTime:h.eventTime,lane:h.lane,tag:h.tag,payload:h.payload,callback:h.callback,next:null};_===null?y=_=N:_=_.next=N,h=h.next}while(h!==null);_===null?y=_=u:_=_.next=u}else y=_=u;h={baseState:b.baseState,firstBaseUpdate:y,lastBaseUpdate:_,shared:b.shared,effects:b.effects},a.updateQueue=h;return}a=h.lastBaseUpdate,a===null?h.firstBaseUpdate=u:a.next=u,h.lastBaseUpdate=u}function Td(a,u,h,b){var y=a.updateQueue;Hs=!1;var _=y.firstBaseUpdate,N=y.lastBaseUpdate,H=y.shared.pending;if(H!==null){y.shared.pending=null;var K=H,le=K.next;K.next=null,N===null?_=le:N.next=le,N=K;var Ee=a.alternate;Ee!==null&&(Ee=Ee.updateQueue,H=Ee.lastBaseUpdate,H!==N&&(H===null?Ee.firstBaseUpdate=le:H.next=le,Ee.lastBaseUpdate=K))}if(_!==null){var xe=y.baseState;N=0,Ee=le=K=null,H=_;do{var ge=H.lane,Le=H.eventTime;if((b&ge)===ge){Ee!==null&&(Ee=Ee.next={eventTime:Le,lane:0,tag:H.tag,payload:H.payload,callback:H.callback,next:null});e:{var ze=a,$e=H;switch(ge=u,Le=h,$e.tag){case 1:if(ze=$e.payload,typeof ze=="function"){xe=ze.call(Le,xe,ge);break e}xe=ze;break e;case 3:ze.flags=ze.flags&-65537|128;case 0:if(ze=$e.payload,ge=typeof ze=="function"?ze.call(Le,xe,ge):ze,ge==null)break e;xe=O({},xe,ge);break e;case 2:Hs=!0}}H.callback!==null&&H.lane!==0&&(a.flags|=64,ge=y.effects,ge===null?y.effects=[H]:ge.push(H))}else Le={eventTime:Le,lane:ge,tag:H.tag,payload:H.payload,callback:H.callback,next:null},Ee===null?(le=Ee=Le,K=xe):Ee=Ee.next=Le,N|=ge;if(H=H.next,H===null){if(H=y.shared.pending,H===null)break;ge=H,H=ge.next,ge.next=null,y.lastBaseUpdate=ge,y.shared.pending=null}}while(!0);if(Ee===null&&(K=xe),y.baseState=K,y.firstBaseUpdate=le,y.lastBaseUpdate=Ee,u=y.shared.interleaved,u!==null){y=u;do N|=y.lane,y=y.next;while(y!==u)}else _===null&&(y.shared.lanes=0);Io|=N,a.lanes=N,a.memoizedState=xe}}function Uy(a,u,h){if(a=u.effects,u.effects=null,a!==null)for(u=0;uh?h:4,a(!0);var b=wm.transition;wm.transition={};try{a(!1),u()}finally{It=h,wm.transition=b}}function ix(){return Zr().memoizedState}function rM(a,u,h){var b=Vs(a);if(h={lane:b,action:h,hasEagerState:!1,eagerState:null,next:null},sx(a))ox(u,h);else if(h=Py(a,u,h,b),h!==null){var y=gr();mi(h,a,b,y),ax(h,u,b)}}function iM(a,u,h){var b=Vs(a),y={lane:b,action:h,hasEagerState:!1,eagerState:null,next:null};if(sx(a))ox(u,y);else{var _=a.alternate;if(a.lanes===0&&(_===null||_.lanes===0)&&(_=u.lastRenderedReducer,_!==null))try{var N=u.lastRenderedState,H=_(N,h);if(y.hasEagerState=!0,y.eagerState=H,ci(H,N)){var K=u.interleaved;K===null?(y.next=y,gm(u)):(y.next=K.next,K.next=y),u.interleaved=y;return}}catch{}h=Py(a,u,y,b),h!==null&&(y=gr(),mi(h,a,b,y),ax(h,u,b))}}function sx(a){var u=a.alternate;return a===gn||u!==null&&u===gn}function ox(a,u){fu=Cd=!0;var h=a.pending;h===null?u.next=u:(u.next=h.next,h.next=u),a.pending=u}function ax(a,u,h){if((h&4194240)!==0){var b=u.lanes;b&=a.pendingLanes,h|=b,u.lanes=h,Vl(a,h)}}var Nd={readContext:Qr,useCallback:er,useContext:er,useEffect:er,useImperativeHandle:er,useInsertionEffect:er,useLayoutEffect:er,useMemo:er,useReducer:er,useRef:er,useState:er,useDebugValue:er,useDeferredValue:er,useTransition:er,useMutableSource:er,useSyncExternalStore:er,useId:er,unstable_isNewReconciler:!1},sM={readContext:Qr,useCallback:function(a,u){return Li().memoizedState=[a,u===void 0?null:u],a},useContext:Qr,useEffect:Xy,useImperativeHandle:function(a,u,h){return h=h!=null?h.concat([a]):null,Ad(4194308,4,Jy.bind(null,u,a),h)},useLayoutEffect:function(a,u){return Ad(4194308,4,a,u)},useInsertionEffect:function(a,u){return Ad(4,2,a,u)},useMemo:function(a,u){var h=Li();return u=u===void 0?null:u,a=a(),h.memoizedState=[a,u],a},useReducer:function(a,u,h){var b=Li();return u=h!==void 0?h(u):u,b.memoizedState=b.baseState=u,a={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:a,lastRenderedState:u},b.queue=a,a=a.dispatch=rM.bind(null,gn,a),[b.memoizedState,a]},useRef:function(a){var u=Li();return a={current:a},u.memoizedState=a},useState:Yy,useDebugValue:Nm,useDeferredValue:function(a){return Li().memoizedState=a},useTransition:function(){var a=Yy(!1),u=a[0];return a=nM.bind(null,a[1]),Li().memoizedState=a,[u,a]},useMutableSource:function(){},useSyncExternalStore:function(a,u,h){var b=gn,y=Li();if(ln){if(h===void 0)throw Error(n(407));h=h()}else{if(h=u(),Hn===null)throw Error(n(349));(Ro&30)!==0||$y(b,u,h)}y.memoizedState=h;var _={value:h,getSnapshot:u};return y.queue=_,Xy(Vy.bind(null,b,_,a),[a]),b.flags|=2048,mu(9,Wy.bind(null,b,_,h,u),void 0,null),h},useId:function(){var a=Li(),u=Hn.identifierPrefix;if(ln){var h=ss,b=is;h=(b&~(1<<32-pn(b)-1)).toString(32)+h,u=":"+u+"R"+h,h=hu++,0<\/script>",a=a.removeChild(a.firstChild)):typeof b.is=="string"?a=N.createElement(h,{is:b.is}):(a=N.createElement(h),h==="select"&&(N=a,b.multiple?N.multiple=!0:b.size&&(N.size=b.size))):a=N.createElementNS(a,h),a[Mi]=u,a[ou]=b,Ax(a,u,!1,!1),u.stateNode=a;e:{switch(N=bt(h,b),h){case"dialog":tn("cancel",a),tn("close",a),y=b;break;case"iframe":case"object":case"embed":tn("load",a),y=b;break;case"video":case"audio":for(y=0;yLa&&(u.flags|=128,b=!0,gu(_,!1),u.lanes=4194304)}else{if(!b)if(a=Sd(N),a!==null){if(u.flags|=128,b=!0,h=a.updateQueue,h!==null&&(u.updateQueue=h,u.flags|=4),gu(_,!0),_.tail===null&&_.tailMode==="hidden"&&!N.alternate&&!ln)return tr(u),null}else 2*hn()-_.renderingStartTime>La&&h!==1073741824&&(u.flags|=128,b=!0,gu(_,!1),u.lanes=4194304);_.isBackwards?(N.sibling=u.child,u.child=N):(h=_.last,h!==null?h.sibling=N:u.child=N,_.last=N)}return _.tail!==null?(u=_.tail,_.rendering=u,_.tail=u.sibling,_.renderingStartTime=hn(),u.sibling=null,h=mn.current,Qt(mn,b?h&1|2:h&1),u):(tr(u),null);case 22:case 23:return Jm(),b=u.memoizedState!==null,a!==null&&a.memoizedState!==null!==b&&(u.flags|=8192),b&&(u.mode&1)!==0?(Fr&1073741824)!==0&&(tr(u),u.subtreeFlags&6&&(u.flags|=8192)):tr(u),null;case 24:return null;case 25:return null}throw Error(n(156,u.tag))}function hM(a,u){switch(lm(u),u.tag){case 1:return wr(u.type)&&hd(),a=u.flags,a&65536?(u.flags=a&-65537|128,u):null;case 3:return Ia(),nn(vr),nn(Jn),vm(),a=u.flags,(a&65536)!==0&&(a&128)===0?(u.flags=a&-65537|128,u):null;case 5:return ym(u),null;case 13:if(nn(mn),a=u.memoizedState,a!==null&&a.dehydrated!==null){if(u.alternate===null)throw Error(n(340));Aa()}return a=u.flags,a&65536?(u.flags=a&-65537|128,u):null;case 19:return nn(mn),null;case 4:return Ia(),null;case 10:return pm(u.type._context),null;case 22:case 23:return Jm(),null;case 24:return null;default:return null}}var Md=!1,nr=!1,pM=typeof WeakSet=="function"?WeakSet:Set,Ue=null;function Ma(a,u){var h=a.ref;if(h!==null)if(typeof h=="function")try{h(null)}catch(b){yn(a,u,b)}else h.current=null}function zm(a,u,h){try{h()}catch(b){yn(a,u,b)}}var Rx=!1;function mM(a,u){if(Jp=Jc,a=ly(),Vp(a)){if("selectionStart"in a)var h={start:a.selectionStart,end:a.selectionEnd};else e:{h=(h=a.ownerDocument)&&h.defaultView||window;var b=h.getSelection&&h.getSelection();if(b&&b.rangeCount!==0){h=b.anchorNode;var y=b.anchorOffset,_=b.focusNode;b=b.focusOffset;try{h.nodeType,_.nodeType}catch{h=null;break e}var N=0,H=-1,K=-1,le=0,Ee=0,xe=a,ge=null;t:for(;;){for(var Le;xe!==h||y!==0&&xe.nodeType!==3||(H=N+y),xe!==_||b!==0&&xe.nodeType!==3||(K=N+b),xe.nodeType===3&&(N+=xe.nodeValue.length),(Le=xe.firstChild)!==null;)ge=xe,xe=Le;for(;;){if(xe===a)break t;if(ge===h&&++le===y&&(H=N),ge===_&&++Ee===b&&(K=N),(Le=xe.nextSibling)!==null)break;xe=ge,ge=xe.parentNode}xe=Le}h=H===-1||K===-1?null:{start:H,end:K}}else h=null}h=h||{start:0,end:0}}else h=null;for(em={focusedElem:a,selectionRange:h},Jc=!1,Ue=u;Ue!==null;)if(u=Ue,a=u.child,(u.subtreeFlags&1028)!==0&&a!==null)a.return=u,Ue=a;else for(;Ue!==null;){u=Ue;try{var ze=u.alternate;if((u.flags&1024)!==0)switch(u.tag){case 0:case 11:case 15:break;case 1:if(ze!==null){var $e=ze.memoizedProps,Tn=ze.memoizedState,ne=u.stateNode,q=ne.getSnapshotBeforeUpdate(u.elementType===u.type?$e:fi(u.type,$e),Tn);ne.__reactInternalSnapshotBeforeUpdate=q}break;case 3:var se=u.stateNode.containerInfo;se.nodeType===1?se.textContent="":se.nodeType===9&&se.documentElement&&se.removeChild(se.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(n(163))}}catch(Ae){yn(u,u.return,Ae)}if(a=u.sibling,a!==null){a.return=u.return,Ue=a;break}Ue=u.return}return ze=Rx,Rx=!1,ze}function bu(a,u,h){var b=u.updateQueue;if(b=b!==null?b.lastEffect:null,b!==null){var y=b=b.next;do{if((y.tag&a)===a){var _=y.destroy;y.destroy=void 0,_!==void 0&&zm(u,h,_)}y=y.next}while(y!==b)}}function Dd(a,u){if(u=u.updateQueue,u=u!==null?u.lastEffect:null,u!==null){var h=u=u.next;do{if((h.tag&a)===a){var b=h.create;h.destroy=b()}h=h.next}while(h!==u)}}function jm(a){var u=a.ref;if(u!==null){var h=a.stateNode;a.tag,a=h,typeof u=="function"?u(a):u.current=a}}function Ix(a){var u=a.alternate;u!==null&&(a.alternate=null,Ix(u)),a.child=null,a.deletions=null,a.sibling=null,a.tag===5&&(u=a.stateNode,u!==null&&(delete u[Mi],delete u[ou],delete u[im],delete u[QO],delete u[ZO])),a.stateNode=null,a.return=null,a.dependencies=null,a.memoizedProps=null,a.memoizedState=null,a.pendingProps=null,a.stateNode=null,a.updateQueue=null}function Ox(a){return a.tag===5||a.tag===3||a.tag===4}function Mx(a){e:for(;;){for(;a.sibling===null;){if(a.return===null||Ox(a.return))return null;a=a.return}for(a.sibling.return=a.return,a=a.sibling;a.tag!==5&&a.tag!==6&&a.tag!==18;){if(a.flags&2||a.child===null||a.tag===4)continue e;a.child.return=a,a=a.child}if(!(a.flags&2))return a.stateNode}}function $m(a,u,h){var b=a.tag;if(b===5||b===6)a=a.stateNode,u?h.nodeType===8?h.parentNode.insertBefore(a,u):h.insertBefore(a,u):(h.nodeType===8?(u=h.parentNode,u.insertBefore(a,h)):(u=h,u.appendChild(a)),h=h._reactRootContainer,h!=null||u.onclick!==null||(u.onclick=dd));else if(b!==4&&(a=a.child,a!==null))for($m(a,u,h),a=a.sibling;a!==null;)$m(a,u,h),a=a.sibling}function Wm(a,u,h){var b=a.tag;if(b===5||b===6)a=a.stateNode,u?h.insertBefore(a,u):h.appendChild(a);else if(b!==4&&(a=a.child,a!==null))for(Wm(a,u,h),a=a.sibling;a!==null;)Wm(a,u,h),a=a.sibling}var Vn=null,hi=!1;function js(a,u,h){for(h=h.child;h!==null;)Dx(a,u,h),h=h.sibling}function Dx(a,u,h){if(Tt&&typeof Tt.onCommitFiberUnmount=="function")try{Tt.onCommitFiberUnmount(mt,h)}catch{}switch(h.tag){case 5:nr||Ma(h,u);case 6:var b=Vn,y=hi;Vn=null,js(a,u,h),Vn=b,hi=y,Vn!==null&&(hi?(a=Vn,h=h.stateNode,a.nodeType===8?a.parentNode.removeChild(h):a.removeChild(h)):Vn.removeChild(h.stateNode));break;case 18:Vn!==null&&(hi?(a=Vn,h=h.stateNode,a.nodeType===8?rm(a.parentNode,h):a.nodeType===1&&rm(a,h),ql(a)):rm(Vn,h.stateNode));break;case 4:b=Vn,y=hi,Vn=h.stateNode.containerInfo,hi=!0,js(a,u,h),Vn=b,hi=y;break;case 0:case 11:case 14:case 15:if(!nr&&(b=h.updateQueue,b!==null&&(b=b.lastEffect,b!==null))){y=b=b.next;do{var _=y,N=_.destroy;_=_.tag,N!==void 0&&((_&2)!==0||(_&4)!==0)&&zm(h,u,N),y=y.next}while(y!==b)}js(a,u,h);break;case 1:if(!nr&&(Ma(h,u),b=h.stateNode,typeof b.componentWillUnmount=="function"))try{b.props=h.memoizedProps,b.state=h.memoizedState,b.componentWillUnmount()}catch(H){yn(h,u,H)}js(a,u,h);break;case 21:js(a,u,h);break;case 22:h.mode&1?(nr=(b=nr)||h.memoizedState!==null,js(a,u,h),nr=b):js(a,u,h);break;default:js(a,u,h)}}function Lx(a){var u=a.updateQueue;if(u!==null){a.updateQueue=null;var h=a.stateNode;h===null&&(h=a.stateNode=new pM),u.forEach(function(b){var y=SM.bind(null,a,b);h.has(b)||(h.add(b),b.then(y,y))})}}function pi(a,u){var h=u.deletions;if(h!==null)for(var b=0;by&&(y=N),b&=~_}if(b=y,b=hn()-b,b=(120>b?120:480>b?480:1080>b?1080:1920>b?1920:3e3>b?3e3:4320>b?4320:1960*bM(b/1960))-b,10a?16:a,Ws===null)var b=!1;else{if(a=Ws,Ws=null,Ud=0,(Ot&6)!==0)throw Error(n(331));var y=Ot;for(Ot|=4,Ue=a.current;Ue!==null;){var _=Ue,N=_.child;if((Ue.flags&16)!==0){var H=_.deletions;if(H!==null){for(var K=0;Khn()-Km?Mo(a,0):Gm|=h),_r(a,u)}function Yx(a,u){u===0&&((a.mode&1)===0?u=1:(u=xo,xo<<=1,(xo&130023424)===0&&(xo=4194304)));var h=gr();a=os(a,u),a!==null&&(Os(a,u,h),_r(a,h))}function TM(a){var u=a.memoizedState,h=0;u!==null&&(h=u.retryLane),Yx(a,h)}function SM(a,u){var h=0;switch(a.tag){case 13:var b=a.stateNode,y=a.memoizedState;y!==null&&(h=y.retryLane);break;case 19:b=a.stateNode;break;default:throw Error(n(314))}b!==null&&b.delete(u),Yx(a,h)}var qx;qx=function(a,u,h){if(a!==null)if(a.memoizedProps!==u.pendingProps||vr.current)Tr=!0;else{if((a.lanes&h)===0&&(u.flags&128)===0)return Tr=!1,dM(a,u,h);Tr=(a.flags&131072)!==0}else Tr=!1,ln&&(u.flags&1048576)!==0&&ky(u,bd,u.index);switch(u.lanes=0,u.tag){case 2:var b=u.type;Od(a,u),a=u.pendingProps;var y=Sa(u,Jn.current);Ra(u,h),y=Sm(null,u,b,a,y,h);var _=_m();return u.flags|=1,typeof y=="object"&&y!==null&&typeof y.render=="function"&&y.$$typeof===void 0?(u.tag=1,u.memoizedState=null,u.updateQueue=null,wr(b)?(_=!0,pd(u)):_=!1,u.memoizedState=y.state!==null&&y.state!==void 0?y.state:null,bm(u),y.updater=Rd,u.stateNode=y,y._reactInternals=u,Im(u,b,a,h),u=Lm(null,u,b,!0,_,h)):(u.tag=0,ln&&_&&am(u),mr(null,u,y,h),u=u.child),u;case 16:b=u.elementType;e:{switch(Od(a,u),a=u.pendingProps,y=b._init,b=y(b._payload),u.type=b,y=u.tag=CM(b),a=fi(b,a),y){case 0:u=Dm(null,u,b,a,h);break e;case 1:u=vx(null,u,b,a,h);break e;case 11:u=gx(null,u,b,a,h);break e;case 14:u=bx(null,u,b,fi(b.type,a),h);break e}throw Error(n(306,b,""))}return u;case 0:return b=u.type,y=u.pendingProps,y=u.elementType===b?y:fi(b,y),Dm(a,u,b,y,h);case 1:return b=u.type,y=u.pendingProps,y=u.elementType===b?y:fi(b,y),vx(a,u,b,y,h);case 3:e:{if(wx(u),a===null)throw Error(n(387));b=u.pendingProps,_=u.memoizedState,y=_.element,Fy(a,u),Td(u,b,null,h);var N=u.memoizedState;if(b=N.element,_.isDehydrated)if(_={element:b,isDehydrated:!1,cache:N.cache,pendingSuspenseBoundaries:N.pendingSuspenseBoundaries,transitions:N.transitions},u.updateQueue.baseState=_,u.memoizedState=_,u.flags&256){y=Oa(Error(n(423)),u),u=Tx(a,u,b,h,y);break e}else if(b!==y){y=Oa(Error(n(424)),u),u=Tx(a,u,b,h,y);break e}else for(Pr=Ps(u.stateNode.containerInfo.firstChild),Lr=u,ln=!0,di=null,h=Ly(u,null,b,h),u.child=h;h;)h.flags=h.flags&-3|4096,h=h.sibling;else{if(Aa(),b===y){u=ls(a,u,h);break e}mr(a,u,b,h)}u=u.child}return u;case 5:return Hy(u),a===null&&cm(u),b=u.type,y=u.pendingProps,_=a!==null?a.memoizedProps:null,N=y.children,tm(b,y)?N=null:_!==null&&tm(b,_)&&(u.flags|=32),xx(a,u),mr(a,u,N,h),u.child;case 6:return a===null&&cm(u),null;case 13:return Sx(a,u,h);case 4:return Em(u,u.stateNode.containerInfo),b=u.pendingProps,a===null?u.child=ka(u,null,b,h):mr(a,u,b,h),u.child;case 11:return b=u.type,y=u.pendingProps,y=u.elementType===b?y:fi(b,y),gx(a,u,b,y,h);case 7:return mr(a,u,u.pendingProps,h),u.child;case 8:return mr(a,u,u.pendingProps.children,h),u.child;case 12:return mr(a,u,u.pendingProps.children,h),u.child;case 10:e:{if(b=u.type._context,y=u.pendingProps,_=u.memoizedProps,N=y.value,Qt(xd,b._currentValue),b._currentValue=N,_!==null)if(ci(_.value,N)){if(_.children===y.children&&!vr.current){u=ls(a,u,h);break e}}else for(_=u.child,_!==null&&(_.return=u);_!==null;){var H=_.dependencies;if(H!==null){N=_.child;for(var K=H.firstContext;K!==null;){if(K.context===b){if(_.tag===1){K=as(-1,h&-h),K.tag=2;var le=_.updateQueue;if(le!==null){le=le.shared;var Ee=le.pending;Ee===null?K.next=K:(K.next=Ee.next,Ee.next=K),le.pending=K}}_.lanes|=h,K=_.alternate,K!==null&&(K.lanes|=h),mm(_.return,h,u),H.lanes|=h;break}K=K.next}}else if(_.tag===10)N=_.type===u.type?null:_.child;else if(_.tag===18){if(N=_.return,N===null)throw Error(n(341));N.lanes|=h,H=N.alternate,H!==null&&(H.lanes|=h),mm(N,h,u),N=_.sibling}else N=_.child;if(N!==null)N.return=_;else for(N=_;N!==null;){if(N===u){N=null;break}if(_=N.sibling,_!==null){_.return=N.return,N=_;break}N=N.return}_=N}mr(a,u,y.children,h),u=u.child}return u;case 9:return y=u.type,b=u.pendingProps.children,Ra(u,h),y=Qr(y),b=b(y),u.flags|=1,mr(a,u,b,h),u.child;case 14:return b=u.type,y=fi(b,u.pendingProps),y=fi(b.type,y),bx(a,u,b,y,h);case 15:return Ex(a,u,u.type,u.pendingProps,h);case 17:return b=u.type,y=u.pendingProps,y=u.elementType===b?y:fi(b,y),Od(a,u),u.tag=1,wr(b)?(a=!0,pd(u)):a=!1,Ra(u,h),ux(u,b,y),Im(u,b,y,h),Lm(null,u,b,!0,a,h);case 19:return Cx(a,u,h);case 22:return yx(a,u,h)}throw Error(n(156,u.tag))};function Xx(a,u){return Kc(a,u)}function _M(a,u,h,b){this.tag=a,this.key=h,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=u,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=b,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function ei(a,u,h,b){return new _M(a,u,h,b)}function tg(a){return a=a.prototype,!(!a||!a.isReactComponent)}function CM(a){if(typeof a=="function")return tg(a)?1:0;if(a!=null){if(a=a.$$typeof,a===z)return 11;if(a===ee)return 14}return 2}function Ks(a,u){var h=a.alternate;return h===null?(h=ei(a.tag,u,a.key,a.mode),h.elementType=a.elementType,h.type=a.type,h.stateNode=a.stateNode,h.alternate=a,a.alternate=h):(h.pendingProps=u,h.type=a.type,h.flags=0,h.subtreeFlags=0,h.deletions=null),h.flags=a.flags&14680064,h.childLanes=a.childLanes,h.lanes=a.lanes,h.child=a.child,h.memoizedProps=a.memoizedProps,h.memoizedState=a.memoizedState,h.updateQueue=a.updateQueue,u=a.dependencies,h.dependencies=u===null?null:{lanes:u.lanes,firstContext:u.firstContext},h.sibling=a.sibling,h.index=a.index,h.ref=a.ref,h}function $d(a,u,h,b,y,_){var N=2;if(b=a,typeof a=="function")tg(a)&&(N=1);else if(typeof a=="string")N=5;else e:switch(a){case D:return Lo(h.children,y,_,u);case G:N=8,y|=8;break;case X:return a=ei(12,h,u,y|2),a.elementType=X,a.lanes=_,a;case ie:return a=ei(13,h,u,y),a.elementType=ie,a.lanes=_,a;case Z:return a=ei(19,h,u,y),a.elementType=Z,a.lanes=_,a;case de:return Wd(h,y,_,u);default:if(typeof a=="object"&&a!==null)switch(a.$$typeof){case P:N=10;break e;case Y:N=9;break e;case z:N=11;break e;case ee:N=14;break e;case ae:N=16,b=null;break e}throw Error(n(130,a==null?a:typeof a,""))}return u=ei(N,h,u,y),u.elementType=a,u.type=b,u.lanes=_,u}function Lo(a,u,h,b){return a=ei(7,a,b,u),a.lanes=h,a}function Wd(a,u,h,b){return a=ei(22,a,b,u),a.elementType=de,a.lanes=h,a.stateNode={isHidden:!1},a}function ng(a,u,h){return a=ei(6,a,null,u),a.lanes=h,a}function rg(a,u,h){return u=ei(4,a.children!==null?a.children:[],a.key,u),u.lanes=h,u.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation},u}function AM(a,u,h,b,y){this.tag=u,this.containerInfo=a,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Is(0),this.expirationTimes=Is(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Is(0),this.identifierPrefix=b,this.onRecoverableError=y,this.mutableSourceEagerHydrationData=null}function ig(a,u,h,b,y,_,N,H,K){return a=new AM(a,u,h,H,K),u===1?(u=1,_===!0&&(u|=8)):u=0,_=ei(3,null,null,u),a.current=_,_.stateNode=a,_.memoizedState={element:b,isDehydrated:h,cache:null,transitions:null,pendingSuspenseBoundaries:null},bm(_),a}function kM(a,u,h){var b=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),cg.exports=HM(),cg.exports}var cv;function zM(){if(cv)return Qd;cv=1;var t=ZS();return Qd.createRoot=t.createRoot,Qd.hydrateRoot=t.hydrateRoot,Qd}var jM=zM();const $M=()=>{const e=window.location.pathname.split("/").filter(Boolean);return e.length>0&&!["chat","docs","api","healthz"].includes(e[0])?"/"+e[0]:""},lo=$M(),Zb=async(t,e={})=>{try{const n=await fetch(t,e);if(!n.ok)throw new Error(`HTTP error! Status: ${n.status}`);return e.method==="PATCH"||e.method==="DELETE"?void 0:await n.json()}catch(n){throw console.error("Fetch error:",n),n}},dv=async(t,e)=>Zb(`${lo}/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),WM=async(t,e)=>Zb(`${lo}/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),JS=async t=>Zb(`${lo}/${t}`,{method:"DELETE"});var Ac=ZS();const e_=_s(Ac);var VM=t=>{switch(t){case"success":return YM;case"info":return XM;case"warning":return qM;case"error":return QM;default:return null}},GM=Array(12).fill(0),KM=({visible:t,className:e})=>we.createElement("div",{className:["sonner-loading-wrapper",e].filter(Boolean).join(" "),"data-visible":t},we.createElement("div",{className:"sonner-spinner"},GM.map((n,r)=>we.createElement("div",{className:"sonner-loading-bar",key:`spinner-bar-${r}`})))),YM=we.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},we.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",clipRule:"evenodd"})),qM=we.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",height:"20",width:"20"},we.createElement("path",{fillRule:"evenodd",d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",clipRule:"evenodd"})),XM=we.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},we.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",clipRule:"evenodd"})),QM=we.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},we.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",clipRule:"evenodd"})),ZM=we.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"},we.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),we.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"})),JM=()=>{let[t,e]=we.useState(document.hidden);return we.useEffect(()=>{let n=()=>{e(document.hidden)};return document.addEventListener("visibilitychange",n),()=>window.removeEventListener("visibilitychange",n)},[]),t},C0=1,eD=class{constructor(){this.subscribe=t=>(this.subscribers.push(t),()=>{let e=this.subscribers.indexOf(t);this.subscribers.splice(e,1)}),this.publish=t=>{this.subscribers.forEach(e=>e(t))},this.addToast=t=>{this.publish(t),this.toasts=[...this.toasts,t]},this.create=t=>{var e;let{message:n,...r}=t,i=typeof t?.id=="number"||((e=t.id)==null?void 0:e.length)>0?t.id:C0++,s=this.toasts.find(l=>l.id===i),o=t.dismissible===void 0?!0:t.dismissible;return this.dismissedToasts.has(i)&&this.dismissedToasts.delete(i),s?this.toasts=this.toasts.map(l=>l.id===i?(this.publish({...l,...t,id:i,title:n}),{...l,...t,id:i,dismissible:o,title:n}):l):this.addToast({title:n,...r,dismissible:o,id:i}),i},this.dismiss=t=>(this.dismissedToasts.add(t),t||this.toasts.forEach(e=>{this.subscribers.forEach(n=>n({id:e.id,dismiss:!0}))}),this.subscribers.forEach(e=>e({id:t,dismiss:!0})),t),this.message=(t,e)=>this.create({...e,message:t}),this.error=(t,e)=>this.create({...e,message:t,type:"error"}),this.success=(t,e)=>this.create({...e,type:"success",message:t}),this.info=(t,e)=>this.create({...e,type:"info",message:t}),this.warning=(t,e)=>this.create({...e,type:"warning",message:t}),this.loading=(t,e)=>this.create({...e,type:"loading",message:t}),this.promise=(t,e)=>{if(!e)return;let n;e.loading!==void 0&&(n=this.create({...e,promise:t,type:"loading",message:e.loading,description:typeof e.description!="function"?e.description:void 0}));let r=t instanceof Promise?t:t(),i=n!==void 0,s,o=r.then(async c=>{if(s=["resolve",c],we.isValidElement(c))i=!1,this.create({id:n,type:"default",message:c});else if(nD(c)&&!c.ok){i=!1;let d=typeof e.error=="function"?await e.error(`HTTP error! status: ${c.status}`):e.error,f=typeof e.description=="function"?await e.description(`HTTP error! status: ${c.status}`):e.description;this.create({id:n,type:"error",message:d,description:f})}else if(e.success!==void 0){i=!1;let d=typeof e.success=="function"?await e.success(c):e.success,f=typeof e.description=="function"?await e.description(c):e.description;this.create({id:n,type:"success",message:d,description:f})}}).catch(async c=>{if(s=["reject",c],e.error!==void 0){i=!1;let d=typeof e.error=="function"?await e.error(c):e.error,f=typeof e.description=="function"?await e.description(c):e.description;this.create({id:n,type:"error",message:d,description:f})}}).finally(()=>{var c;i&&(this.dismiss(n),n=void 0),(c=e.finally)==null||c.call(e)}),l=()=>new Promise((c,d)=>o.then(()=>s[0]==="reject"?d(s[1]):c(s[1])).catch(d));return typeof n!="string"&&typeof n!="number"?{unwrap:l}:Object.assign(n,{unwrap:l})},this.custom=(t,e)=>{let n=e?.id||C0++;return this.create({jsx:t(n),id:n,...e}),n},this.getActiveToasts=()=>this.toasts.filter(t=>!this.dismissedToasts.has(t.id)),this.subscribers=[],this.toasts=[],this.dismissedToasts=new Set}},Rr=new eD,tD=(t,e)=>{let n=e?.id||C0++;return Rr.addToast({title:t,...e,id:n}),n},nD=t=>t&&typeof t=="object"&&"ok"in t&&typeof t.ok=="boolean"&&"status"in t&&typeof t.status=="number",rD=tD,iD=()=>Rr.toasts,sD=()=>Rr.getActiveToasts(),Ir=Object.assign(rD,{success:Rr.success,info:Rr.info,warning:Rr.warning,error:Rr.error,custom:Rr.custom,message:Rr.message,promise:Rr.promise,dismiss:Rr.dismiss,loading:Rr.loading},{getHistory:iD,getToasts:sD});function oD(t,{insertAt:e}={}){if(typeof document>"u")return;let n=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",e==="top"&&n.firstChild?n.insertBefore(r,n.firstChild):n.appendChild(r),r.styleSheet?r.styleSheet.cssText=t:r.appendChild(document.createTextNode(t))}oD(`:where(html[dir="ltr"]),:where([data-sonner-toaster][dir="ltr"]){--toast-icon-margin-start: -3px;--toast-icon-margin-end: 4px;--toast-svg-margin-start: -1px;--toast-svg-margin-end: 0px;--toast-button-margin-start: auto;--toast-button-margin-end: 0;--toast-close-button-start: 0;--toast-close-button-end: unset;--toast-close-button-transform: translate(-35%, -35%)}:where(html[dir="rtl"]),:where([data-sonner-toaster][dir="rtl"]){--toast-icon-margin-start: 4px;--toast-icon-margin-end: -3px;--toast-svg-margin-start: 0px;--toast-svg-margin-end: -1px;--toast-button-margin-start: 0;--toast-button-margin-end: auto;--toast-close-button-start: unset;--toast-close-button-end: 0;--toast-close-button-transform: translate(35%, -35%)}:where([data-sonner-toaster]){position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1: hsl(0, 0%, 99%);--gray2: hsl(0, 0%, 97.3%);--gray3: hsl(0, 0%, 95.1%);--gray4: hsl(0, 0%, 93%);--gray5: hsl(0, 0%, 90.9%);--gray6: hsl(0, 0%, 88.7%);--gray7: hsl(0, 0%, 85.8%);--gray8: hsl(0, 0%, 78%);--gray9: hsl(0, 0%, 56.1%);--gray10: hsl(0, 0%, 52.3%);--gray11: hsl(0, 0%, 43.5%);--gray12: hsl(0, 0%, 9%);--border-radius: 8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:none;z-index:999999999;transition:transform .4s ease}:where([data-sonner-toaster][data-lifted="true"]){transform:translateY(-10px)}@media (hover: none) and (pointer: coarse){:where([data-sonner-toaster][data-lifted="true"]){transform:none}}:where([data-sonner-toaster][data-x-position="right"]){right:var(--offset-right)}:where([data-sonner-toaster][data-x-position="left"]){left:var(--offset-left)}:where([data-sonner-toaster][data-x-position="center"]){left:50%;transform:translate(-50%)}:where([data-sonner-toaster][data-y-position="top"]){top:var(--offset-top)}:where([data-sonner-toaster][data-y-position="bottom"]){bottom:var(--offset-bottom)}:where([data-sonner-toast]){--y: translateY(100%);--lift-amount: calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);filter:blur(0);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:none;overflow-wrap:anywhere}:where([data-sonner-toast][data-styled="true"]){padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px #0000001a;width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}:where([data-sonner-toast]:focus-visible){box-shadow:0 4px 12px #0000001a,0 0 0 2px #0003}:where([data-sonner-toast][data-y-position="top"]){top:0;--y: translateY(-100%);--lift: 1;--lift-amount: calc(1 * var(--gap))}:where([data-sonner-toast][data-y-position="bottom"]){bottom:0;--y: translateY(100%);--lift: -1;--lift-amount: calc(var(--lift) * var(--gap))}:where([data-sonner-toast]) :where([data-description]){font-weight:400;line-height:1.4;color:inherit}:where([data-sonner-toast]) :where([data-title]){font-weight:500;line-height:1.5;color:inherit}:where([data-sonner-toast]) :where([data-icon]){display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}:where([data-sonner-toast][data-promise="true"]) :where([data-icon])>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}:where([data-sonner-toast]) :where([data-icon])>*{flex-shrink:0}:where([data-sonner-toast]) :where([data-icon]) svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}:where([data-sonner-toast]) :where([data-content]){display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;cursor:pointer;outline:none;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}:where([data-sonner-toast]) :where([data-button]):focus-visible{box-shadow:0 0 0 2px #0006}:where([data-sonner-toast]) :where([data-button]):first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}:where([data-sonner-toast]) :where([data-cancel]){color:var(--normal-text);background:rgba(0,0,0,.08)}:where([data-sonner-toast][data-theme="dark"]) :where([data-cancel]){background:rgba(255,255,255,.3)}:where([data-sonner-toast]) :where([data-close-button]){position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast] [data-close-button]{background:var(--gray1)}:where([data-sonner-toast]) :where([data-close-button]):focus-visible{box-shadow:0 4px 12px #0000001a,0 0 0 2px #0003}:where([data-sonner-toast]) :where([data-disabled="true"]){cursor:not-allowed}:where([data-sonner-toast]):hover :where([data-close-button]):hover{background:var(--gray2);border-color:var(--gray5)}:where([data-sonner-toast][data-swiping="true"]):before{content:"";position:absolute;left:-50%;right:-50%;height:100%;z-index:-1}:where([data-sonner-toast][data-y-position="top"][data-swiping="true"]):before{bottom:50%;transform:scaleY(3) translateY(50%)}:where([data-sonner-toast][data-y-position="bottom"][data-swiping="true"]):before{top:50%;transform:scaleY(3) translateY(-50%)}:where([data-sonner-toast][data-swiping="false"][data-removed="true"]):before{content:"";position:absolute;inset:0;transform:scaleY(2)}:where([data-sonner-toast]):after{content:"";position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}:where([data-sonner-toast][data-mounted="true"]){--y: translateY(0);opacity:1}:where([data-sonner-toast][data-expanded="false"][data-front="false"]){--scale: var(--toasts-before) * .05 + 1;--y: translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}:where([data-sonner-toast])>*{transition:opacity .4s}:where([data-sonner-toast][data-expanded="false"][data-front="false"][data-styled="true"])>*{opacity:0}:where([data-sonner-toast][data-visible="false"]){opacity:0;pointer-events:none}:where([data-sonner-toast][data-mounted="true"][data-expanded="true"]){--y: translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}:where([data-sonner-toast][data-removed="true"][data-front="true"][data-swipe-out="false"]){--y: translateY(calc(var(--lift) * -100%));opacity:0}:where([data-sonner-toast][data-removed="true"][data-front="false"][data-swipe-out="false"][data-expanded="true"]){--y: translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}:where([data-sonner-toast][data-removed="true"][data-front="false"][data-swipe-out="false"][data-expanded="false"]){--y: translateY(40%);opacity:0;transition:transform .5s,opacity .2s}:where([data-sonner-toast][data-removed="true"][data-front="false"]):before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y, 0px)) translate(var(--swipe-amount-x, 0px));transition:none}[data-sonner-toast][data-swiped=true]{user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{0%{transform:var(--y) translate(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translate(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{0%{transform:var(--y) translate(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translate(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{0%{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{0%{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width: 600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-theme=light]{--normal-bg: #fff;--normal-border: var(--gray4);--normal-text: var(--gray12);--success-bg: hsl(143, 85%, 96%);--success-border: hsl(145, 92%, 91%);--success-text: hsl(140, 100%, 27%);--info-bg: hsl(208, 100%, 97%);--info-border: hsl(221, 91%, 91%);--info-text: hsl(210, 92%, 45%);--warning-bg: hsl(49, 100%, 97%);--warning-border: hsl(49, 91%, 91%);--warning-text: hsl(31, 92%, 45%);--error-bg: hsl(359, 100%, 97%);--error-border: hsl(359, 100%, 94%);--error-text: hsl(360, 100%, 45%)}[data-sonner-toaster][data-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg: #000;--normal-border: hsl(0, 0%, 20%);--normal-text: var(--gray1)}[data-sonner-toaster][data-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg: #fff;--normal-border: var(--gray3);--normal-text: var(--gray12)}[data-sonner-toaster][data-theme=dark]{--normal-bg: #000;--normal-bg-hover: hsl(0, 0%, 12%);--normal-border: hsl(0, 0%, 20%);--normal-border-hover: hsl(0, 0%, 25%);--normal-text: var(--gray1);--success-bg: hsl(150, 100%, 6%);--success-border: hsl(147, 100%, 12%);--success-text: hsl(150, 86%, 65%);--info-bg: hsl(215, 100%, 6%);--info-border: hsl(223, 100%, 12%);--info-text: hsl(216, 87%, 65%);--warning-bg: hsl(64, 100%, 6%);--warning-border: hsl(60, 100%, 12%);--warning-text: hsl(46, 87%, 65%);--error-bg: hsl(358, 76%, 10%);--error-border: hsl(357, 89%, 16%);--error-text: hsl(358, 100%, 81%)}[data-sonner-toaster][data-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success],[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info],[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning],[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error],[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size: 16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:nth-child(1){animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}to{opacity:.15}}@media (prefers-reduced-motion){[data-sonner-toast],[data-sonner-toast]>*,.sonner-loading-bar{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)} +`);function Zd(t){return t.label!==void 0}var aD=3,lD="32px",uD="16px",fv=4e3,cD=356,dD=14,fD=20,hD=200;function gi(...t){return t.filter(Boolean).join(" ")}function pD(t){let[e,n]=t.split("-"),r=[];return e&&r.push(e),n&&r.push(n),r}var mD=t=>{var e,n,r,i,s,o,l,c,d,f,p;let{invert:m,toast:g,unstyled:x,interacting:v,setHeights:S,visibleToasts:C,heights:A,index:k,toasts:M,expanded:F,removeToast:I,defaultRichColors:D,closeButton:G,style:X,cancelButtonStyle:P,actionButtonStyle:Y,className:z="",descriptionClassName:ie="",duration:Z,position:ee,gap:ae,loadingIcon:de,expandByDefault:j,classNames:W,icons:O,closeButtonAriaLabel:U="Close toast",pauseWhenPageIsHidden:Q}=t,[R,oe]=we.useState(null),[pe,ue]=we.useState(null),[J,he]=we.useState(!1),[_e,ke]=we.useState(!1),[Ve,ot]=we.useState(!1),[qe,kt]=we.useState(!1),[fn,nt]=we.useState(!1),[Yt,Ct]=we.useState(0),[Pn,Fn]=we.useState(0),on=we.useRef(g.duration||Z||fv),dr=we.useRef(null),Mn=we.useRef(null),Qn=k===0,li=k+1<=C,ce=g.type,ye=g.dismissible!==!1,Qe=g.className||"",ut=g.descriptionClassName||"",rt=we.useMemo(()=>A.findIndex(te=>te.toastId===g.id)||0,[A,g.id]),an=we.useMemo(()=>{var te;return(te=g.closeButton)!=null?te:G},[g.closeButton,G]),Zn=we.useMemo(()=>g.duration||Z||fv,[g.duration,Z]),Re=we.useRef(0),Me=we.useRef(0),Ge=we.useRef(0),Ke=we.useRef(null),[bt,vt]=ee.split("-"),jt=we.useMemo(()=>A.reduce((te,me,De)=>De>=rt?te:te+me.height,0),[A,rt]),fr=JM(),Dt=g.invert||m,$t=ce==="loading";Me.current=we.useMemo(()=>rt*ae+jt,[rt,jt]),we.useEffect(()=>{on.current=Zn},[Zn]),we.useEffect(()=>{he(!0)},[]),we.useEffect(()=>{let te=Mn.current;if(te){let me=te.getBoundingClientRect().height;return Fn(me),S(De=>[{toastId:g.id,height:me,position:g.position},...De]),()=>S(De=>De.filter(wt=>wt.toastId!==g.id))}},[S,g.id]),we.useLayoutEffect(()=>{if(!J)return;let te=Mn.current,me=te.style.height;te.style.height="auto";let De=te.getBoundingClientRect().height;te.style.height=me,Fn(De),S(wt=>wt.find(_t=>_t.toastId===g.id)?wt.map(_t=>_t.toastId===g.id?{..._t,height:De}:_t):[{toastId:g.id,height:De,position:g.position},...wt])},[J,g.title,g.description,S,g.id]);let qt=we.useCallback(()=>{ke(!0),Ct(Me.current),S(te=>te.filter(me=>me.toastId!==g.id)),setTimeout(()=>{I(g)},hD)},[g,I,S,Me]);we.useEffect(()=>{if(g.promise&&ce==="loading"||g.duration===1/0||g.type==="loading")return;let te;return F||v||Q&&fr?(()=>{if(Ge.current{var me;(me=g.onAutoClose)==null||me.call(g,g),qt()},on.current)),()=>clearTimeout(te)},[F,v,g,ce,Q,fr,qt]),we.useEffect(()=>{g.delete&&qt()},[qt,g.delete]);function V(){var te,me,De;return O!=null&&O.loading?we.createElement("div",{className:gi(W?.loader,(te=g?.classNames)==null?void 0:te.loader,"sonner-loader"),"data-visible":ce==="loading"},O.loading):de?we.createElement("div",{className:gi(W?.loader,(me=g?.classNames)==null?void 0:me.loader,"sonner-loader"),"data-visible":ce==="loading"},de):we.createElement(KM,{className:gi(W?.loader,(De=g?.classNames)==null?void 0:De.loader),visible:ce==="loading"})}return we.createElement("li",{tabIndex:0,ref:Mn,className:gi(z,Qe,W?.toast,(e=g?.classNames)==null?void 0:e.toast,W?.default,W?.[ce],(n=g?.classNames)==null?void 0:n[ce]),"data-sonner-toast":"","data-rich-colors":(r=g.richColors)!=null?r:D,"data-styled":!(g.jsx||g.unstyled||x),"data-mounted":J,"data-promise":!!g.promise,"data-swiped":fn,"data-removed":_e,"data-visible":li,"data-y-position":bt,"data-x-position":vt,"data-index":k,"data-front":Qn,"data-swiping":Ve,"data-dismissible":ye,"data-type":ce,"data-invert":Dt,"data-swipe-out":qe,"data-swipe-direction":pe,"data-expanded":!!(F||j&&J),style:{"--index":k,"--toasts-before":k,"--z-index":M.length-k,"--offset":`${_e?Yt:Me.current}px`,"--initial-height":j?"auto":`${Pn}px`,...X,...g.style},onDragEnd:()=>{ot(!1),oe(null),Ke.current=null},onPointerDown:te=>{$t||!ye||(dr.current=new Date,Ct(Me.current),te.target.setPointerCapture(te.pointerId),te.target.tagName!=="BUTTON"&&(ot(!0),Ke.current={x:te.clientX,y:te.clientY}))},onPointerUp:()=>{var te,me,De,wt;if(qe||!ye)return;Ke.current=null;let _t=Number(((te=Mn.current)==null?void 0:te.style.getPropertyValue("--swipe-amount-x").replace("px",""))||0),Oe=Number(((me=Mn.current)==null?void 0:me.style.getPropertyValue("--swipe-amount-y").replace("px",""))||0),Ie=new Date().getTime()-((De=dr.current)==null?void 0:De.getTime()),He=R==="x"?_t:Oe,Bt=Math.abs(He)/Ie;if(Math.abs(He)>=fD||Bt>.11){Ct(Me.current),(wt=g.onDismiss)==null||wt.call(g,g),ue(R==="x"?_t>0?"right":"left":Oe>0?"down":"up"),qt(),kt(!0),nt(!1);return}ot(!1),oe(null)},onPointerMove:te=>{var me,De,wt,_t;if(!Ke.current||!ye||((me=window.getSelection())==null?void 0:me.toString().length)>0)return;let Oe=te.clientY-Ke.current.y,Ie=te.clientX-Ke.current.x,He=(De=t.swipeDirections)!=null?De:pD(ee);!R&&(Math.abs(Ie)>1||Math.abs(Oe)>1)&&oe(Math.abs(Ie)>Math.abs(Oe)?"x":"y");let Bt={x:0,y:0};R==="y"?(He.includes("top")||He.includes("bottom"))&&(He.includes("top")&&Oe<0||He.includes("bottom")&&Oe>0)&&(Bt.y=Oe):R==="x"&&(He.includes("left")||He.includes("right"))&&(He.includes("left")&&Ie<0||He.includes("right")&&Ie>0)&&(Bt.x=Ie),(Math.abs(Bt.x)>0||Math.abs(Bt.y)>0)&&nt(!0),(wt=Mn.current)==null||wt.style.setProperty("--swipe-amount-x",`${Bt.x}px`),(_t=Mn.current)==null||_t.style.setProperty("--swipe-amount-y",`${Bt.y}px`)}},an&&!g.jsx?we.createElement("button",{"aria-label":U,"data-disabled":$t,"data-close-button":!0,onClick:$t||!ye?()=>{}:()=>{var te;qt(),(te=g.onDismiss)==null||te.call(g,g)},className:gi(W?.closeButton,(i=g?.classNames)==null?void 0:i.closeButton)},(s=O?.close)!=null?s:ZM):null,g.jsx||T.isValidElement(g.title)?g.jsx?g.jsx:typeof g.title=="function"?g.title():g.title:we.createElement(we.Fragment,null,ce||g.icon||g.promise?we.createElement("div",{"data-icon":"",className:gi(W?.icon,(o=g?.classNames)==null?void 0:o.icon)},g.promise||g.type==="loading"&&!g.icon?g.icon||V():null,g.type!=="loading"?g.icon||O?.[ce]||VM(ce):null):null,we.createElement("div",{"data-content":"",className:gi(W?.content,(l=g?.classNames)==null?void 0:l.content)},we.createElement("div",{"data-title":"",className:gi(W?.title,(c=g?.classNames)==null?void 0:c.title)},typeof g.title=="function"?g.title():g.title),g.description?we.createElement("div",{"data-description":"",className:gi(ie,ut,W?.description,(d=g?.classNames)==null?void 0:d.description)},typeof g.description=="function"?g.description():g.description):null),T.isValidElement(g.cancel)?g.cancel:g.cancel&&Zd(g.cancel)?we.createElement("button",{"data-button":!0,"data-cancel":!0,style:g.cancelButtonStyle||P,onClick:te=>{var me,De;Zd(g.cancel)&&ye&&((De=(me=g.cancel).onClick)==null||De.call(me,te),qt())},className:gi(W?.cancelButton,(f=g?.classNames)==null?void 0:f.cancelButton)},g.cancel.label):null,T.isValidElement(g.action)?g.action:g.action&&Zd(g.action)?we.createElement("button",{"data-button":!0,"data-action":!0,style:g.actionButtonStyle||Y,onClick:te=>{var me,De;Zd(g.action)&&((De=(me=g.action).onClick)==null||De.call(me,te),!te.defaultPrevented&&qt())},className:gi(W?.actionButton,(p=g?.classNames)==null?void 0:p.actionButton)},g.action.label):null))};function hv(){if(typeof window>"u"||typeof document>"u")return"ltr";let t=document.documentElement.getAttribute("dir");return t==="auto"||!t?window.getComputedStyle(document.documentElement).direction:t}function gD(t,e){let n={};return[t,e].forEach((r,i)=>{let s=i===1,o=s?"--mobile-offset":"--offset",l=s?uD:lD;function c(d){["top","right","bottom","left"].forEach(f=>{n[`${o}-${f}`]=typeof d=="number"?`${d}px`:d})}typeof r=="number"||typeof r=="string"?c(r):typeof r=="object"?["top","right","bottom","left"].forEach(d=>{r[d]===void 0?n[`${o}-${d}`]=l:n[`${o}-${d}`]=typeof r[d]=="number"?`${r[d]}px`:r[d]}):c(l)}),n}var bD=T.forwardRef(function(t,e){let{invert:n,position:r="bottom-right",hotkey:i=["altKey","KeyT"],expand:s,closeButton:o,className:l,offset:c,mobileOffset:d,theme:f="light",richColors:p,duration:m,style:g,visibleToasts:x=aD,toastOptions:v,dir:S=hv(),gap:C=dD,loadingIcon:A,icons:k,containerAriaLabel:M="Notifications",pauseWhenPageIsHidden:F}=t,[I,D]=we.useState([]),G=we.useMemo(()=>Array.from(new Set([r].concat(I.filter(Q=>Q.position).map(Q=>Q.position)))),[I,r]),[X,P]=we.useState([]),[Y,z]=we.useState(!1),[ie,Z]=we.useState(!1),[ee,ae]=we.useState(f!=="system"?f:typeof window<"u"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),de=we.useRef(null),j=i.join("+").replace(/Key/g,"").replace(/Digit/g,""),W=we.useRef(null),O=we.useRef(!1),U=we.useCallback(Q=>{D(R=>{var oe;return(oe=R.find(pe=>pe.id===Q.id))!=null&&oe.delete||Rr.dismiss(Q.id),R.filter(({id:pe})=>pe!==Q.id)})},[]);return we.useEffect(()=>Rr.subscribe(Q=>{if(Q.dismiss){D(R=>R.map(oe=>oe.id===Q.id?{...oe,delete:!0}:oe));return}setTimeout(()=>{e_.flushSync(()=>{D(R=>{let oe=R.findIndex(pe=>pe.id===Q.id);return oe!==-1?[...R.slice(0,oe),{...R[oe],...Q},...R.slice(oe+1)]:[Q,...R]})})})}),[]),we.useEffect(()=>{if(f!=="system"){ae(f);return}if(f==="system"&&(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?ae("dark"):ae("light")),typeof window>"u")return;let Q=window.matchMedia("(prefers-color-scheme: dark)");try{Q.addEventListener("change",({matches:R})=>{ae(R?"dark":"light")})}catch{Q.addListener(({matches:oe})=>{try{ae(oe?"dark":"light")}catch(pe){console.error(pe)}})}},[f]),we.useEffect(()=>{I.length<=1&&z(!1)},[I]),we.useEffect(()=>{let Q=R=>{var oe,pe;i.every(ue=>R[ue]||R.code===ue)&&(z(!0),(oe=de.current)==null||oe.focus()),R.code==="Escape"&&(document.activeElement===de.current||(pe=de.current)!=null&&pe.contains(document.activeElement))&&z(!1)};return document.addEventListener("keydown",Q),()=>document.removeEventListener("keydown",Q)},[i]),we.useEffect(()=>{if(de.current)return()=>{W.current&&(W.current.focus({preventScroll:!0}),W.current=null,O.current=!1)}},[de.current]),we.createElement("section",{ref:e,"aria-label":`${M} ${j}`,tabIndex:-1,"aria-live":"polite","aria-relevant":"additions text","aria-atomic":"false",suppressHydrationWarning:!0},G.map((Q,R)=>{var oe;let[pe,ue]=Q.split("-");return I.length?we.createElement("ol",{key:Q,dir:S==="auto"?hv():S,tabIndex:-1,ref:de,className:l,"data-sonner-toaster":!0,"data-theme":ee,"data-y-position":pe,"data-lifted":Y&&I.length>1&&!s,"data-x-position":ue,style:{"--front-toast-height":`${((oe=X[0])==null?void 0:oe.height)||0}px`,"--width":`${cD}px`,"--gap":`${C}px`,...g,...gD(c,d)},onBlur:J=>{O.current&&!J.currentTarget.contains(J.relatedTarget)&&(O.current=!1,W.current&&(W.current.focus({preventScroll:!0}),W.current=null))},onFocus:J=>{J.target instanceof HTMLElement&&J.target.dataset.dismissible==="false"||O.current||(O.current=!0,W.current=J.relatedTarget)},onMouseEnter:()=>z(!0),onMouseMove:()=>z(!0),onMouseLeave:()=>{ie||z(!1)},onDragEnd:()=>z(!1),onPointerDown:J=>{J.target instanceof HTMLElement&&J.target.dataset.dismissible==="false"||Z(!0)},onPointerUp:()=>Z(!1)},I.filter(J=>!J.position&&R===0||J.position===Q).map((J,he)=>{var _e,ke;return we.createElement(mD,{key:J.id,icons:k,index:he,toast:J,defaultRichColors:p,duration:(_e=v?.duration)!=null?_e:m,className:v?.className,descriptionClassName:v?.descriptionClassName,invert:n,visibleToasts:x,closeButton:(ke=v?.closeButton)!=null?ke:o,interacting:ie,position:Q,style:v?.style,unstyled:v?.unstyled,classNames:v?.classNames,cancelButtonStyle:v?.cancelButtonStyle,actionButtonStyle:v?.actionButtonStyle,removeToast:U,toasts:I.filter(Ve=>Ve.position==J.position),heights:X.filter(Ve=>Ve.position==J.position),setHeights:P,expandByDefault:s,gap:C,loadingIcon:A,expanded:Y,pauseWhenPageIsHidden:F,swipeDirections:t.swipeDirections})})):null}))});const pv=20,Jd=404,mv="Error: Gateway Timeout";function hg(t,e,n=[],r=!1,i=!0,s=!0){const[o,l]=T.useState(null),[c,d]=T.useState(!1),[f,p]=T.useState(null),[m,g]=T.useState(!1),x="",v=T.useRef(null);T.useEffect(()=>{if(f&&f.message!==mv)throw new Error(`Failed to fetch "${t}"`)},[f,t]);const S=()=>w.jsxs("div",{children:[w.jsx("div",{children:"Something went wrong"}),w.jsx("div",{role:"button",onClick:()=>g(M=>!M),className:"underline cursor-pointer",children:"Click to retry"})]}),C=()=>g(M=>!M);T.useEffect(()=>{r&&f?.message===mv&&(g(M=>!M),f.message="")},[r,f]);const A=T.useCallback((M="")=>{const F=new AbortController;v.current=F;const{signal:I}=F;setTimeout(()=>d(!0),0),p(null),fetch(`${lo}/${t}${M||x}`,{signal:I}).then(async G=>{if(!G.ok)throw G.status===Jd?{code:Jd,message:G.statusText}:new Error(`Error: ${G.statusText}`);const X=await G.json();l(X)}).catch(G=>{s&&G.code!==pv?p({message:G.message}):G.code!==pv&&G.code!==Jd&&r&&A(),G.code===Jd&&Ir.error("resource not found. please try to refresh the page")}).finally(()=>s&&d(!1))},[t,m,...n]);return T.useEffect(()=>{if(i)return A(),()=>{v.current?.abort()}},[A,i]),{data:o,loading:c,error:f,refetch:C,ErrorTemplate:f&&S,abortFetch:()=>{v.current?.abort()}}}function t_(t){var e,n,r="";if(typeof t=="string"||typeof t=="number")r+=t;else if(typeof t=="object")if(Array.isArray(t)){var i=t.length;for(e=0;e{const e=xD(t),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=t;return{getClassGroupId:o=>{const l=o.split(Jb);return l[0]===""&&l.length!==1&&l.shift(),n_(l,e)||yD(o)},getConflictingClassGroupIds:(o,l)=>{const c=n[o]||[];return l&&r[o]?[...c,...r[o]]:c}}},n_=(t,e)=>{if(t.length===0)return e.classGroupId;const n=t[0],r=e.nextPart.get(n),i=r?n_(t.slice(1),r):void 0;if(i)return i;if(e.validators.length===0)return;const s=t.join(Jb);return e.validators.find(({validator:o})=>o(s))?.classGroupId},gv=/^\[(.+)\]$/,yD=t=>{if(gv.test(t)){const e=gv.exec(t)[1],n=e?.substring(0,e.indexOf(":"));if(n)return"arbitrary.."+n}},xD=t=>{const{theme:e,prefix:n}=t,r={nextPart:new Map,validators:[]};return wD(Object.entries(t.classGroups),n).forEach(([s,o])=>{A0(o,r,s,e)}),r},A0=(t,e,n,r)=>{t.forEach(i=>{if(typeof i=="string"){const s=i===""?e:bv(e,i);s.classGroupId=n;return}if(typeof i=="function"){if(vD(i)){A0(i(r),e,n,r);return}e.validators.push({validator:i,classGroupId:n});return}Object.entries(i).forEach(([s,o])=>{A0(o,bv(e,s),n,r)})})},bv=(t,e)=>{let n=t;return e.split(Jb).forEach(r=>{n.nextPart.has(r)||n.nextPart.set(r,{nextPart:new Map,validators:[]}),n=n.nextPart.get(r)}),n},vD=t=>t.isThemeGetter,wD=(t,e)=>e?t.map(([n,r])=>{const i=r.map(s=>typeof s=="string"?e+s:typeof s=="object"?Object.fromEntries(Object.entries(s).map(([o,l])=>[e+o,l])):s);return[n,i]}):t,TD=t=>{if(t<1)return{get:()=>{},set:()=>{}};let e=0,n=new Map,r=new Map;const i=(s,o)=>{n.set(s,o),e++,e>t&&(e=0,r=n,n=new Map)};return{get(s){let o=n.get(s);if(o!==void 0)return o;if((o=r.get(s))!==void 0)return i(s,o),o},set(s,o){n.has(s)?n.set(s,o):i(s,o)}}},r_="!",SD=t=>{const{separator:e,experimentalParseClassName:n}=t,r=e.length===1,i=e[0],s=e.length,o=l=>{const c=[];let d=0,f=0,p;for(let S=0;Sf?p-f:void 0;return{modifiers:c,hasImportantModifier:g,baseClassName:x,maybePostfixModifierPosition:v}};return n?l=>n({className:l,parseClassName:o}):o},_D=t=>{if(t.length<=1)return t;const e=[];let n=[];return t.forEach(r=>{r[0]==="["?(e.push(...n.sort(),r),n=[]):n.push(r)}),e.push(...n.sort()),e},CD=t=>({cache:TD(t.cacheSize),parseClassName:SD(t),...ED(t)}),AD=/\s+/,kD=(t,e)=>{const{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i}=e,s=[],o=t.trim().split(AD);let l="";for(let c=o.length-1;c>=0;c-=1){const d=o[c],{modifiers:f,hasImportantModifier:p,baseClassName:m,maybePostfixModifierPosition:g}=n(d);let x=!!g,v=r(x?m.substring(0,g):m);if(!v){if(!x){l=d+(l.length>0?" "+l:l);continue}if(v=r(m),!v){l=d+(l.length>0?" "+l:l);continue}x=!1}const S=_D(f).join(":"),C=p?S+r_:S,A=C+v;if(s.includes(A))continue;s.push(A);const k=i(v,x);for(let M=0;M0?" "+l:l)}return l};function On(){let t=0,e,n,r="";for(;t{if(typeof t=="string")return t;let e,n="";for(let r=0;rp(f),t());return n=CD(d),r=n.cache.get,i=n.cache.set,s=l,l(c)}function l(c){const d=r(c);if(d)return d;const f=kD(c,n);return i(c,f),f}return function(){return s(On.apply(null,arguments))}}const rn=t=>{const e=n=>n[t]||[];return e.isThemeGetter=!0,e},s_=/^\[(?:([a-z-]+):)?(.+)\]$/i,RD=/^\d+\/\d+$/,ID=new Set(["px","full","screen"]),OD=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,MD=/\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$/,DD=/^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/,LD=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,PD=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,cs=t=>nl(t)||ID.has(t)||RD.test(t),qs=t=>kl(t,"length",WD),nl=t=>!!t&&!Number.isNaN(Number(t)),pg=t=>kl(t,"number",nl),Tu=t=>!!t&&Number.isInteger(Number(t)),FD=t=>t.endsWith("%")&&nl(t.slice(0,-1)),ht=t=>s_.test(t),Xs=t=>OD.test(t),BD=new Set(["length","size","percentage"]),UD=t=>kl(t,BD,o_),HD=t=>kl(t,"position",o_),zD=new Set(["image","url"]),jD=t=>kl(t,zD,GD),$D=t=>kl(t,"",VD),Su=()=>!0,kl=(t,e,n)=>{const r=s_.exec(t);return r?r[1]?typeof e=="string"?r[1]===e:e.has(r[1]):n(r[2]):!1},WD=t=>MD.test(t)&&!DD.test(t),o_=()=>!1,VD=t=>LD.test(t),GD=t=>PD.test(t),KD=()=>{const t=rn("colors"),e=rn("spacing"),n=rn("blur"),r=rn("brightness"),i=rn("borderColor"),s=rn("borderRadius"),o=rn("borderSpacing"),l=rn("borderWidth"),c=rn("contrast"),d=rn("grayscale"),f=rn("hueRotate"),p=rn("invert"),m=rn("gap"),g=rn("gradientColorStops"),x=rn("gradientColorStopPositions"),v=rn("inset"),S=rn("margin"),C=rn("opacity"),A=rn("padding"),k=rn("saturate"),M=rn("scale"),F=rn("sepia"),I=rn("skew"),D=rn("space"),G=rn("translate"),X=()=>["auto","contain","none"],P=()=>["auto","hidden","clip","visible","scroll"],Y=()=>["auto",ht,e],z=()=>[ht,e],ie=()=>["",cs,qs],Z=()=>["auto",nl,ht],ee=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],ae=()=>["solid","dashed","dotted","double","none"],de=()=>["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"],W=()=>["","0",ht],O=()=>["auto","avoid","all","avoid-page","page","left","right","column"],U=()=>[nl,ht];return{cacheSize:500,separator:":",theme:{colors:[Su],spacing:[cs,qs],blur:["none","",Xs,ht],brightness:U(),borderColor:[t],borderRadius:["none","","full",Xs,ht],borderSpacing:z(),borderWidth:ie(),contrast:U(),grayscale:W(),hueRotate:U(),invert:W(),gap:z(),gradientColorStops:[t],gradientColorStopPositions:[FD,qs],inset:Y(),margin:Y(),opacity:U(),padding:z(),saturate:U(),scale:U(),sepia:W(),skew:U(),space:z(),translate:z()},classGroups:{aspect:[{aspect:["auto","square","video",ht]}],container:["container"],columns:[{columns:[Xs]}],"break-after":[{"break-after":O()}],"break-before":[{"break-before":O()}],"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:[...ee(),ht]}],overflow:[{overflow:P()}],"overflow-x":[{"overflow-x":P()}],"overflow-y":[{"overflow-y":P()}],overscroll:[{overscroll:X()}],"overscroll-x":[{"overscroll-x":X()}],"overscroll-y":[{"overscroll-y":X()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[v]}],"inset-x":[{"inset-x":[v]}],"inset-y":[{"inset-y":[v]}],start:[{start:[v]}],end:[{end:[v]}],top:[{top:[v]}],right:[{right:[v]}],bottom:[{bottom:[v]}],left:[{left:[v]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Tu,ht]}],basis:[{basis:Y()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",ht]}],grow:[{grow:W()}],shrink:[{shrink:W()}],order:[{order:["first","last","none",Tu,ht]}],"grid-cols":[{"grid-cols":[Su]}],"col-start-end":[{col:["auto",{span:["full",Tu,ht]},ht]}],"col-start":[{"col-start":Z()}],"col-end":[{"col-end":Z()}],"grid-rows":[{"grid-rows":[Su]}],"row-start-end":[{row:["auto",{span:[Tu,ht]},ht]}],"row-start":[{"row-start":Z()}],"row-end":[{"row-end":Z()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",ht]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",ht]}],gap:[{gap:[m]}],"gap-x":[{"gap-x":[m]}],"gap-y":[{"gap-y":[m]}],"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:[A]}],px:[{px:[A]}],py:[{py:[A]}],ps:[{ps:[A]}],pe:[{pe:[A]}],pt:[{pt:[A]}],pr:[{pr:[A]}],pb:[{pb:[A]}],pl:[{pl:[A]}],m:[{m:[S]}],mx:[{mx:[S]}],my:[{my:[S]}],ms:[{ms:[S]}],me:[{me:[S]}],mt:[{mt:[S]}],mr:[{mr:[S]}],mb:[{mb:[S]}],ml:[{ml:[S]}],"space-x":[{"space-x":[D]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[D]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",ht,e]}],"min-w":[{"min-w":[ht,e,"min","max","fit"]}],"max-w":[{"max-w":[ht,e,"none","full","min","max","fit","prose",{screen:[Xs]},Xs]}],h:[{h:[ht,e,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[ht,e,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[ht,e,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[ht,e,"auto","min","max","fit"]}],"font-size":[{text:["base",Xs,qs]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",pg]}],"font-family":[{font:[Su]}],"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",ht]}],"line-clamp":[{"line-clamp":["none",nl,pg]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",cs,ht]}],"list-image":[{"list-image":["none",ht]}],"list-style-type":[{list:["none","disc","decimal",ht]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[t]}],"placeholder-opacity":[{"placeholder-opacity":[C]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[t]}],"text-opacity":[{"text-opacity":[C]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...ae(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",cs,qs]}],"underline-offset":[{"underline-offset":["auto",cs,ht]}],"text-decoration-color":[{decoration:[t]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:z()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",ht]}],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",ht]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[C]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...ee(),HD]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",UD]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},jD]}],"bg-color":[{bg:[t]}],"gradient-from-pos":[{from:[x]}],"gradient-via-pos":[{via:[x]}],"gradient-to-pos":[{to:[x]}],"gradient-from":[{from:[g]}],"gradient-via":[{via:[g]}],"gradient-to":[{to:[g]}],rounded:[{rounded:[s]}],"rounded-s":[{"rounded-s":[s]}],"rounded-e":[{"rounded-e":[s]}],"rounded-t":[{"rounded-t":[s]}],"rounded-r":[{"rounded-r":[s]}],"rounded-b":[{"rounded-b":[s]}],"rounded-l":[{"rounded-l":[s]}],"rounded-ss":[{"rounded-ss":[s]}],"rounded-se":[{"rounded-se":[s]}],"rounded-ee":[{"rounded-ee":[s]}],"rounded-es":[{"rounded-es":[s]}],"rounded-tl":[{"rounded-tl":[s]}],"rounded-tr":[{"rounded-tr":[s]}],"rounded-br":[{"rounded-br":[s]}],"rounded-bl":[{"rounded-bl":[s]}],"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":[C]}],"border-style":[{border:[...ae(),"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":[C]}],"divide-style":[{divide:ae()}],"border-color":[{border:[i]}],"border-color-x":[{"border-x":[i]}],"border-color-y":[{"border-y":[i]}],"border-color-s":[{"border-s":[i]}],"border-color-e":[{"border-e":[i]}],"border-color-t":[{"border-t":[i]}],"border-color-r":[{"border-r":[i]}],"border-color-b":[{"border-b":[i]}],"border-color-l":[{"border-l":[i]}],"divide-color":[{divide:[i]}],"outline-style":[{outline:["",...ae()]}],"outline-offset":[{"outline-offset":[cs,ht]}],"outline-w":[{outline:[cs,qs]}],"outline-color":[{outline:[t]}],"ring-w":[{ring:ie()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[t]}],"ring-opacity":[{"ring-opacity":[C]}],"ring-offset-w":[{"ring-offset":[cs,qs]}],"ring-offset-color":[{"ring-offset":[t]}],shadow:[{shadow:["","inner","none",Xs,$D]}],"shadow-color":[{shadow:[Su]}],opacity:[{opacity:[C]}],"mix-blend":[{"mix-blend":[...de(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":de()}],filter:[{filter:["","none"]}],blur:[{blur:[n]}],brightness:[{brightness:[r]}],contrast:[{contrast:[c]}],"drop-shadow":[{"drop-shadow":["","none",Xs,ht]}],grayscale:[{grayscale:[d]}],"hue-rotate":[{"hue-rotate":[f]}],invert:[{invert:[p]}],saturate:[{saturate:[k]}],sepia:[{sepia:[F]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[n]}],"backdrop-brightness":[{"backdrop-brightness":[r]}],"backdrop-contrast":[{"backdrop-contrast":[c]}],"backdrop-grayscale":[{"backdrop-grayscale":[d]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[f]}],"backdrop-invert":[{"backdrop-invert":[p]}],"backdrop-opacity":[{"backdrop-opacity":[C]}],"backdrop-saturate":[{"backdrop-saturate":[k]}],"backdrop-sepia":[{"backdrop-sepia":[F]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[o]}],"border-spacing-x":[{"border-spacing-x":[o]}],"border-spacing-y":[{"border-spacing-y":[o]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",ht]}],duration:[{duration:U()}],ease:[{ease:["linear","in","out","in-out",ht]}],delay:[{delay:U()}],animate:[{animate:["none","spin","ping","pulse","bounce",ht]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[M]}],"scale-x":[{"scale-x":[M]}],"scale-y":[{"scale-y":[M]}],rotate:[{rotate:[Tu,ht]}],"translate-x":[{"translate-x":[G]}],"translate-y":[{"translate-y":[G]}],"skew-x":[{"skew-x":[I]}],"skew-y":[{"skew-y":[I]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",ht]}],accent:[{accent:["auto",t]}],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",ht]}],"caret-color":[{caret:[t]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":z()}],"scroll-mx":[{"scroll-mx":z()}],"scroll-my":[{"scroll-my":z()}],"scroll-ms":[{"scroll-ms":z()}],"scroll-me":[{"scroll-me":z()}],"scroll-mt":[{"scroll-mt":z()}],"scroll-mr":[{"scroll-mr":z()}],"scroll-mb":[{"scroll-mb":z()}],"scroll-ml":[{"scroll-ml":z()}],"scroll-p":[{"scroll-p":z()}],"scroll-px":[{"scroll-px":z()}],"scroll-py":[{"scroll-py":z()}],"scroll-ps":[{"scroll-ps":z()}],"scroll-pe":[{"scroll-pe":z()}],"scroll-pt":[{"scroll-pt":z()}],"scroll-pr":[{"scroll-pr":z()}],"scroll-pb":[{"scroll-pb":z()}],"scroll-pl":[{"scroll-pl":z()}],"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",ht]}],fill:[{fill:[t,"none"]}],"stroke-w":[{stroke:[cs,qs,pg]}],stroke:[{stroke:[t,"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"]}}},Xe=ND(KD),qf=new BroadcastChannel("active_tabs"),eE=Date.now()+"-"+Math.random();console.log("broadcasting...");qf.postMessage({type:"opened",timestamp:Date.now(),id:eE});window.addEventListener("beforeunload",()=>{qf.postMessage({tabId:eE,type:"closed"}),sessionStorage.setItem("active_tabs",JSON.stringify([])),qf.close()});qf.onmessage=t=>{const e=JSON.parse(sessionStorage.getItem("active_tabs")||"[]");if(t.data.type==="opened"&&t.data.id!==eE)sessionStorage.setItem("active_tabs",JSON.stringify([...e,t.data.id]));else if(t.data.type==="closed"){console.log("closedddd");const n=e.filter(r=>r!==t.data.tabId);sessionStorage.setItem("active_tabs",JSON.stringify(n))}console.log("Message from another tab:",t.data,t)};const YD=()=>JSON.parse(sessionStorage.getItem("active_tabs")||"[]").length;function Rt(...t){return Xe(Al(t))}const Ev=(t,e)=>t?new Date(t).toLocaleDateString()===new Date(e).toLocaleDateString():!1,hl=(t,e)=>{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(t).then(()=>Ir.info(t?.length<100?`Copied text: ${t}`:"Text copied")).catch(()=>{Xf(t,e)}):Xf(t,e)},Xf=(t,e)=>{const n=document.createElement("textarea");n.value=t,(e||document.body).appendChild(n),n.style.position="fixed",n.select();try{document.execCommand("copy")?Ir.info(t?.length<100?`Copied text: ${t}`:"Text copied"):console.error("Fallback: Copy command failed.")}catch(r){console.error("Fallback: Unable to copy",r)}finally{(e||document.body).removeChild(n)}},qD=(t,e,n={})=>{try{const{headers:r=[],delimiter:i=",",includeHeaders:s=!0,dateFormat:o="iso"}=n;if(!t||t.length===0)throw new Error("No data to export");const l=r.length>0?r:Object.keys(t[0]),c=x=>{const v=String(x||"");return v.includes(i)||v.includes('"')||v.includes(` +`)?`"${v.replace(/"/g,'""')}"`:v},d=x=>x instanceof Date?o==="readable"?x.toLocaleString():x.toISOString():x,f=[];s&&f.push(l.map(x=>c(x)).join(i)),t.forEach(x=>{const v=l.map(S=>{const C=x[S];return c(d(C))});f.push(v.join(i))});const p=f.join(` +`),m=new Blob([p],{type:"text/csv;charset=utf-8;"}),g=document.createElement("a");if(g.download!==void 0){const x=URL.createObjectURL(m);return g.setAttribute("href",x),g.setAttribute("download",e),g.style.visibility="hidden",document.body.appendChild(g),g.click(),document.body.removeChild(g),URL.revokeObjectURL(x),!0}return!1}catch(r){throw console.error("CSV export failed:",r),r}};function Lh(t,e,n){return new Promise((r,i)=>{const s=indexedDB.open(t,1);s.onupgradeneeded=()=>{const o=s.result;if(!o.objectStoreNames.contains(e)){const l=o.createObjectStore(e,{autoIncrement:!0});n&&l.createIndex(n.name,n.keyPath,{unique:!1})}},s.onsuccess=()=>r(s.result),s.onerror=()=>i(s.error)})}const XD=async(t,e,n,r,i="update",s)=>{const c=(await Lh(t,e,s)).transaction(e,"readwrite").objectStore(e);if(i==="multiple"){const d=c.get(n);d.onsuccess=()=>{let f=d.result;Array.isArray(f)||(f=f!==void 0?[f]:[]),f.push(r);const p=c.put(f,n);p.onsuccess=()=>{console.log("Item appended in IndexedDB")},p.onerror=()=>{console.error("Error appending item in IndexedDB")}},d.onerror=()=>{console.error("Error getting item for multiple mode in IndexedDB")}}else{const d=c.put(r,n);d.onerror=()=>{console.error("Error updating item in IndexedDB")}}},QD=async(t,e,n)=>{const o=(await Lh(t,e)).transaction(e,"readwrite").objectStore(e).delete(n);o.onerror=()=>{console.error("Error deleting item in IndexedDB")}},ZD=async(t,e,n,r)=>{try{const o=(await Lh(t,e,r)).transaction(e,"readonly").objectStore(e);return await new Promise((c,d)=>{const f=o.get(n);f.onsuccess=()=>c(f.result),f.onerror=()=>d(f.error)})}catch(i){return console.error("Error opening IndexedDB:",i),null}},a_=async(t,e,n,r,i,s)=>{try{const d=(await Lh(t,e,i)).transaction(e,"readonly").objectStore(e).index(n),f=await new Promise((p,m)=>{const g=d.getAll(r);g.onsuccess=()=>p(g.result),g.onerror=()=>m(g.error)});return s?f.reduce((p,m)=>(p[m.traceId]=m.flagValue,p),{}):f}catch(o){return console.error("Error opening IndexedDB:",o),null}},sc=T.forwardRef(({className:t,type:e,...n},r)=>w.jsx("input",{type:e,className:Rt("flex h-10 w-full rounded-md border border-[#eeeeee] bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",t),ref:r,...n}));sc.displayName="Input";function je(t,e,{checkForDefaultPrevented:n=!0}={}){return function(i){if(t?.(i),n===!1||!i.defaultPrevented)return e?.(i)}}function yv(t,e){if(typeof t=="function")return t(e);t!=null&&(t.current=e)}function Ph(...t){return e=>{let n=!1;const r=t.map(i=>{const s=yv(i,e);return!n&&typeof s=="function"&&(n=!0),s});if(n)return()=>{for(let i=0;i{const{children:o,...l}=s,c=T.useMemo(()=>l,Object.values(l));return w.jsx(n.Provider,{value:c,children:o})};r.displayName=t+"Provider";function i(s){const o=T.useContext(n);if(o)return o;if(e!==void 0)return e;throw new Error(`\`${s}\` must be used within \`${t}\``)}return[r,i]}function Cs(t,e=[]){let n=[];function r(s,o){const l=T.createContext(o),c=n.length;n=[...n,o];const d=p=>{const{scope:m,children:g,...x}=p,v=m?.[t]?.[c]||l,S=T.useMemo(()=>x,Object.values(x));return w.jsx(v.Provider,{value:S,children:g})};d.displayName=s+"Provider";function f(p,m){const g=m?.[t]?.[c]||l,x=T.useContext(g);if(x)return x;if(o!==void 0)return o;throw new Error(`\`${p}\` must be used within \`${s}\``)}return[d,f]}const i=()=>{const s=n.map(o=>T.createContext(o));return function(l){const c=l?.[t]||s;return T.useMemo(()=>({[`__scope${t}`]:{...l,[t]:c}}),[l,c])}};return i.scopeName=t,[r,eL(i,...e)]}function eL(...t){const e=t[0];if(t.length===1)return e;const n=()=>{const r=t.map(i=>({useScope:i(),scopeName:i.scopeName}));return function(s){const o=r.reduce((l,{useScope:c,scopeName:d})=>{const p=c(s)[`__scope${d}`];return{...l,...p}},{});return T.useMemo(()=>({[`__scope${e.scopeName}`]:o}),[o])}};return n.scopeName=e.scopeName,n}function Go(t){const e=nL(t),n=T.forwardRef((r,i)=>{const{children:s,...o}=r,l=T.Children.toArray(s),c=l.find(iL);if(c){const d=c.props.children,f=l.map(p=>p===c?T.Children.count(d)>1?T.Children.only(null):T.isValidElement(d)?d.props.children:null:p);return w.jsx(e,{...o,ref:i,children:T.isValidElement(d)?T.cloneElement(d,void 0,f):null})}return w.jsx(e,{...o,ref:i,children:s})});return n.displayName=`${t}.Slot`,n}var tL=Go("Slot");function nL(t){const e=T.forwardRef((n,r)=>{const{children:i,...s}=n;if(T.isValidElement(i)){const o=oL(i),l=sL(s,i.props);return i.type!==T.Fragment&&(l.ref=r?Ph(r,o):o),T.cloneElement(i,l)}return T.Children.count(i)>1?T.Children.only(null):null});return e.displayName=`${t}.SlotClone`,e}var l_=Symbol("radix.slottable");function rL(t){const e=({children:n})=>w.jsx(w.Fragment,{children:n});return e.displayName=`${t}.Slottable`,e.__radixId=l_,e}function iL(t){return T.isValidElement(t)&&typeof t.type=="function"&&"__radixId"in t.type&&t.type.__radixId===l_}function sL(t,e){const n={...e};for(const r in e){const i=t[r],s=e[r];/^on[A-Z]/.test(r)?i&&s?n[r]=(...l)=>{const c=s(...l);return i(...l),c}:i&&(n[r]=i):r==="style"?n[r]={...i,...s}:r==="className"&&(n[r]=[i,s].filter(Boolean).join(" "))}return{...t,...n}}function oL(t){let e=Object.getOwnPropertyDescriptor(t.props,"ref")?.get,n=e&&"isReactWarning"in e&&e.isReactWarning;return n?t.ref:(e=Object.getOwnPropertyDescriptor(t,"ref")?.get,n=e&&"isReactWarning"in e&&e.isReactWarning,n?t.props.ref:t.props.ref||t.ref)}var aL=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],xt=aL.reduce((t,e)=>{const n=Go(`Primitive.${e}`),r=T.forwardRef((i,s)=>{const{asChild:o,...l}=i,c=o?n:e;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),w.jsx(c,{...l,ref:s})});return r.displayName=`Primitive.${e}`,{...t,[e]:r}},{});function u_(t,e){t&&Ac.flushSync(()=>t.dispatchEvent(e))}function Yi(t){const e=T.useRef(t);return T.useEffect(()=>{e.current=t}),T.useMemo(()=>(...n)=>e.current?.(...n),[])}function lL(t,e=globalThis?.document){const n=Yi(t);T.useEffect(()=>{const r=i=>{i.key==="Escape"&&n(i)};return e.addEventListener("keydown",r,{capture:!0}),()=>e.removeEventListener("keydown",r,{capture:!0})},[n,e])}var uL="DismissableLayer",k0="dismissableLayer.update",cL="dismissableLayer.pointerDownOutside",dL="dismissableLayer.focusOutside",xv,c_=T.createContext({layers:new Set,layersWithOutsidePointerEventsDisabled:new Set,branches:new Set}),kc=T.forwardRef((t,e)=>{const{disableOutsidePointerEvents:n=!1,onEscapeKeyDown:r,onPointerDownOutside:i,onFocusOutside:s,onInteractOutside:o,onDismiss:l,...c}=t,d=T.useContext(c_),[f,p]=T.useState(null),m=f?.ownerDocument??globalThis?.document,[,g]=T.useState({}),x=Pt(e,D=>p(D)),v=Array.from(d.layers),[S]=[...d.layersWithOutsidePointerEventsDisabled].slice(-1),C=v.indexOf(S),A=f?v.indexOf(f):-1,k=d.layersWithOutsidePointerEventsDisabled.size>0,M=A>=C,F=pL(D=>{const G=D.target,X=[...d.branches].some(P=>P.contains(G));!M||X||(i?.(D),o?.(D),D.defaultPrevented||l?.())},m),I=mL(D=>{const G=D.target;[...d.branches].some(P=>P.contains(G))||(s?.(D),o?.(D),D.defaultPrevented||l?.())},m);return lL(D=>{A===d.layers.size-1&&(r?.(D),!D.defaultPrevented&&l&&(D.preventDefault(),l()))},m),T.useEffect(()=>{if(f)return n&&(d.layersWithOutsidePointerEventsDisabled.size===0&&(xv=m.body.style.pointerEvents,m.body.style.pointerEvents="none"),d.layersWithOutsidePointerEventsDisabled.add(f)),d.layers.add(f),vv(),()=>{n&&d.layersWithOutsidePointerEventsDisabled.size===1&&(m.body.style.pointerEvents=xv)}},[f,m,n,d]),T.useEffect(()=>()=>{f&&(d.layers.delete(f),d.layersWithOutsidePointerEventsDisabled.delete(f),vv())},[f,d]),T.useEffect(()=>{const D=()=>g({});return document.addEventListener(k0,D),()=>document.removeEventListener(k0,D)},[]),w.jsx(xt.div,{...c,ref:x,style:{pointerEvents:k?M?"auto":"none":void 0,...t.style},onFocusCapture:je(t.onFocusCapture,I.onFocusCapture),onBlurCapture:je(t.onBlurCapture,I.onBlurCapture),onPointerDownCapture:je(t.onPointerDownCapture,F.onPointerDownCapture)})});kc.displayName=uL;var fL="DismissableLayerBranch",hL=T.forwardRef((t,e)=>{const n=T.useContext(c_),r=T.useRef(null),i=Pt(e,r);return T.useEffect(()=>{const s=r.current;if(s)return n.branches.add(s),()=>{n.branches.delete(s)}},[n.branches]),w.jsx(xt.div,{...t,ref:i})});hL.displayName=fL;function pL(t,e=globalThis?.document){const n=Yi(t),r=T.useRef(!1),i=T.useRef(()=>{});return T.useEffect(()=>{const s=l=>{if(l.target&&!r.current){let c=function(){d_(cL,n,d,{discrete:!0})};const d={originalEvent:l};l.pointerType==="touch"?(e.removeEventListener("click",i.current),i.current=c,e.addEventListener("click",i.current,{once:!0})):c()}else e.removeEventListener("click",i.current);r.current=!1},o=window.setTimeout(()=>{e.addEventListener("pointerdown",s)},0);return()=>{window.clearTimeout(o),e.removeEventListener("pointerdown",s),e.removeEventListener("click",i.current)}},[e,n]),{onPointerDownCapture:()=>r.current=!0}}function mL(t,e=globalThis?.document){const n=Yi(t),r=T.useRef(!1);return T.useEffect(()=>{const i=s=>{s.target&&!r.current&&d_(dL,n,{originalEvent:s},{discrete:!1})};return e.addEventListener("focusin",i),()=>e.removeEventListener("focusin",i)},[e,n]),{onFocusCapture:()=>r.current=!0,onBlurCapture:()=>r.current=!1}}function vv(){const t=new CustomEvent(k0);document.dispatchEvent(t)}function d_(t,e,n,{discrete:r}){const i=n.originalEvent.target,s=new CustomEvent(t,{bubbles:!1,cancelable:!0,detail:n});e&&i.addEventListener(t,e,{once:!0}),r?u_(i,s):i.dispatchEvent(s)}var lr=globalThis?.document?T.useLayoutEffect:()=>{},gL=Qb[" useId ".trim().toString()]||(()=>{}),bL=0;function Gi(t){const[e,n]=T.useState(gL());return lr(()=>{n(r=>r??String(bL++))},[t]),e?`radix-${e}`:""}const EL=["top","right","bottom","left"],uo=Math.min,$r=Math.max,Qf=Math.round,ef=Math.floor,Ki=t=>({x:t,y:t}),yL={left:"right",right:"left",bottom:"top",top:"bottom"},xL={start:"end",end:"start"};function N0(t,e,n){return $r(t,uo(e,n))}function ys(t,e){return typeof t=="function"?t(e):t}function xs(t){return t.split("-")[0]}function Nl(t){return t.split("-")[1]}function tE(t){return t==="x"?"y":"x"}function nE(t){return t==="y"?"height":"width"}const vL=new Set(["top","bottom"]);function Vi(t){return vL.has(xs(t))?"y":"x"}function rE(t){return tE(Vi(t))}function wL(t,e,n){n===void 0&&(n=!1);const r=Nl(t),i=rE(t),s=nE(i);let o=i==="x"?r===(n?"end":"start")?"right":"left":r==="start"?"bottom":"top";return e.reference[s]>e.floating[s]&&(o=Zf(o)),[o,Zf(o)]}function TL(t){const e=Zf(t);return[R0(t),e,R0(e)]}function R0(t){return t.replace(/start|end/g,e=>xL[e])}const wv=["left","right"],Tv=["right","left"],SL=["top","bottom"],_L=["bottom","top"];function CL(t,e,n){switch(t){case"top":case"bottom":return n?e?Tv:wv:e?wv:Tv;case"left":case"right":return e?SL:_L;default:return[]}}function AL(t,e,n,r){const i=Nl(t);let s=CL(xs(t),n==="start",r);return i&&(s=s.map(o=>o+"-"+i),e&&(s=s.concat(s.map(R0)))),s}function Zf(t){return t.replace(/left|right|bottom|top/g,e=>yL[e])}function kL(t){return{top:0,right:0,bottom:0,left:0,...t}}function f_(t){return typeof t!="number"?kL(t):{top:t,right:t,bottom:t,left:t}}function Jf(t){const{x:e,y:n,width:r,height:i}=t;return{width:r,height:i,top:n,left:e,right:e+r,bottom:n+i,x:e,y:n}}function Sv(t,e,n){let{reference:r,floating:i}=t;const s=Vi(e),o=rE(e),l=nE(o),c=xs(e),d=s==="y",f=r.x+r.width/2-i.width/2,p=r.y+r.height/2-i.height/2,m=r[l]/2-i[l]/2;let g;switch(c){case"top":g={x:f,y:r.y-i.height};break;case"bottom":g={x:f,y:r.y+r.height};break;case"right":g={x:r.x+r.width,y:p};break;case"left":g={x:r.x-i.width,y:p};break;default:g={x:r.x,y:r.y}}switch(Nl(e)){case"start":g[o]-=m*(n&&d?-1:1);break;case"end":g[o]+=m*(n&&d?-1:1);break}return g}const NL=async(t,e,n)=>{const{placement:r="bottom",strategy:i="absolute",middleware:s=[],platform:o}=n,l=s.filter(Boolean),c=await(o.isRTL==null?void 0:o.isRTL(e));let d=await o.getElementRects({reference:t,floating:e,strategy:i}),{x:f,y:p}=Sv(d,r,c),m=r,g={},x=0;for(let v=0;v({name:"arrow",options:t,async fn(e){const{x:n,y:r,placement:i,rects:s,platform:o,elements:l,middlewareData:c}=e,{element:d,padding:f=0}=ys(t,e)||{};if(d==null)return{};const p=f_(f),m={x:n,y:r},g=rE(i),x=nE(g),v=await o.getDimensions(d),S=g==="y",C=S?"top":"left",A=S?"bottom":"right",k=S?"clientHeight":"clientWidth",M=s.reference[x]+s.reference[g]-m[g]-s.floating[x],F=m[g]-s.reference[g],I=await(o.getOffsetParent==null?void 0:o.getOffsetParent(d));let D=I?I[k]:0;(!D||!await(o.isElement==null?void 0:o.isElement(I)))&&(D=l.floating[k]||s.floating[x]);const G=M/2-F/2,X=D/2-v[x]/2-1,P=uo(p[C],X),Y=uo(p[A],X),z=P,ie=D-v[x]-Y,Z=D/2-v[x]/2+G,ee=N0(z,Z,ie),ae=!c.arrow&&Nl(i)!=null&&Z!==ee&&s.reference[x]/2-(ZZ<=0)){var Y,z;const Z=(((Y=s.flip)==null?void 0:Y.index)||0)+1,ee=D[Z];if(ee&&(!(p==="alignment"?A!==Vi(ee):!1)||P.every(j=>j.overflows[0]>0&&Vi(j.placement)===A)))return{data:{index:Z,overflows:P},reset:{placement:ee}};let ae=(z=P.filter(de=>de.overflows[0]<=0).sort((de,j)=>de.overflows[1]-j.overflows[1])[0])==null?void 0:z.placement;if(!ae)switch(g){case"bestFit":{var ie;const de=(ie=P.filter(j=>{if(I){const W=Vi(j.placement);return W===A||W==="y"}return!0}).map(j=>[j.placement,j.overflows.filter(W=>W>0).reduce((W,O)=>W+O,0)]).sort((j,W)=>j[1]-W[1])[0])==null?void 0:ie[0];de&&(ae=de);break}case"initialPlacement":ae=l;break}if(i!==ae)return{reset:{placement:ae}}}return{}}}};function _v(t,e){return{top:t.top-e.height,right:t.right-e.width,bottom:t.bottom-e.height,left:t.left-e.width}}function Cv(t){return EL.some(e=>t[e]>=0)}const OL=function(t){return t===void 0&&(t={}),{name:"hide",options:t,async fn(e){const{rects:n}=e,{strategy:r="referenceHidden",...i}=ys(t,e);switch(r){case"referenceHidden":{const s=await oc(e,{...i,elementContext:"reference"}),o=_v(s,n.reference);return{data:{referenceHiddenOffsets:o,referenceHidden:Cv(o)}}}case"escaped":{const s=await oc(e,{...i,altBoundary:!0}),o=_v(s,n.floating);return{data:{escapedOffsets:o,escaped:Cv(o)}}}default:return{}}}}},h_=new Set(["left","top"]);async function ML(t,e){const{placement:n,platform:r,elements:i}=t,s=await(r.isRTL==null?void 0:r.isRTL(i.floating)),o=xs(n),l=Nl(n),c=Vi(n)==="y",d=h_.has(o)?-1:1,f=s&&c?-1:1,p=ys(e,t);let{mainAxis:m,crossAxis:g,alignmentAxis:x}=typeof p=="number"?{mainAxis:p,crossAxis:0,alignmentAxis:null}:{mainAxis:p.mainAxis||0,crossAxis:p.crossAxis||0,alignmentAxis:p.alignmentAxis};return l&&typeof x=="number"&&(g=l==="end"?x*-1:x),c?{x:g*f,y:m*d}:{x:m*d,y:g*f}}const DL=function(t){return t===void 0&&(t=0),{name:"offset",options:t,async fn(e){var n,r;const{x:i,y:s,placement:o,middlewareData:l}=e,c=await ML(e,t);return o===((n=l.offset)==null?void 0:n.placement)&&(r=l.arrow)!=null&&r.alignmentOffset?{}:{x:i+c.x,y:s+c.y,data:{...c,placement:o}}}}},LL=function(t){return t===void 0&&(t={}),{name:"shift",options:t,async fn(e){const{x:n,y:r,placement:i}=e,{mainAxis:s=!0,crossAxis:o=!1,limiter:l={fn:S=>{let{x:C,y:A}=S;return{x:C,y:A}}},...c}=ys(t,e),d={x:n,y:r},f=await oc(e,c),p=Vi(xs(i)),m=tE(p);let g=d[m],x=d[p];if(s){const S=m==="y"?"top":"left",C=m==="y"?"bottom":"right",A=g+f[S],k=g-f[C];g=N0(A,g,k)}if(o){const S=p==="y"?"top":"left",C=p==="y"?"bottom":"right",A=x+f[S],k=x-f[C];x=N0(A,x,k)}const v=l.fn({...e,[m]:g,[p]:x});return{...v,data:{x:v.x-n,y:v.y-r,enabled:{[m]:s,[p]:o}}}}}},PL=function(t){return t===void 0&&(t={}),{options:t,fn(e){const{x:n,y:r,placement:i,rects:s,middlewareData:o}=e,{offset:l=0,mainAxis:c=!0,crossAxis:d=!0}=ys(t,e),f={x:n,y:r},p=Vi(i),m=tE(p);let g=f[m],x=f[p];const v=ys(l,e),S=typeof v=="number"?{mainAxis:v,crossAxis:0}:{mainAxis:0,crossAxis:0,...v};if(c){const k=m==="y"?"height":"width",M=s.reference[m]-s.floating[k]+S.mainAxis,F=s.reference[m]+s.reference[k]-S.mainAxis;gF&&(g=F)}if(d){var C,A;const k=m==="y"?"width":"height",M=h_.has(xs(i)),F=s.reference[p]-s.floating[k]+(M&&((C=o.offset)==null?void 0:C[p])||0)+(M?0:S.crossAxis),I=s.reference[p]+s.reference[k]+(M?0:((A=o.offset)==null?void 0:A[p])||0)-(M?S.crossAxis:0);xI&&(x=I)}return{[m]:g,[p]:x}}}},FL=function(t){return t===void 0&&(t={}),{name:"size",options:t,async fn(e){var n,r;const{placement:i,rects:s,platform:o,elements:l}=e,{apply:c=()=>{},...d}=ys(t,e),f=await oc(e,d),p=xs(i),m=Nl(i),g=Vi(i)==="y",{width:x,height:v}=s.floating;let S,C;p==="top"||p==="bottom"?(S=p,C=m===(await(o.isRTL==null?void 0:o.isRTL(l.floating))?"start":"end")?"left":"right"):(C=p,S=m==="end"?"top":"bottom");const A=v-f.top-f.bottom,k=x-f.left-f.right,M=uo(v-f[S],A),F=uo(x-f[C],k),I=!e.middlewareData.shift;let D=M,G=F;if((n=e.middlewareData.shift)!=null&&n.enabled.x&&(G=k),(r=e.middlewareData.shift)!=null&&r.enabled.y&&(D=A),I&&!m){const P=$r(f.left,0),Y=$r(f.right,0),z=$r(f.top,0),ie=$r(f.bottom,0);g?G=x-2*(P!==0||Y!==0?P+Y:$r(f.left,f.right)):D=v-2*(z!==0||ie!==0?z+ie:$r(f.top,f.bottom))}await c({...e,availableWidth:G,availableHeight:D});const X=await o.getDimensions(l.floating);return x!==X.width||v!==X.height?{reset:{rects:!0}}:{}}}};function Fh(){return typeof window<"u"}function Rl(t){return p_(t)?(t.nodeName||"").toLowerCase():"#document"}function Vr(t){var e;return(t==null||(e=t.ownerDocument)==null?void 0:e.defaultView)||window}function Qi(t){var e;return(e=(p_(t)?t.ownerDocument:t.document)||window.document)==null?void 0:e.documentElement}function p_(t){return Fh()?t instanceof Node||t instanceof Vr(t).Node:!1}function Ti(t){return Fh()?t instanceof Element||t instanceof Vr(t).Element:!1}function qi(t){return Fh()?t instanceof HTMLElement||t instanceof Vr(t).HTMLElement:!1}function Av(t){return!Fh()||typeof ShadowRoot>"u"?!1:t instanceof ShadowRoot||t instanceof Vr(t).ShadowRoot}const BL=new Set(["inline","contents"]);function Nc(t){const{overflow:e,overflowX:n,overflowY:r,display:i}=Si(t);return/auto|scroll|overlay|hidden|clip/.test(e+r+n)&&!BL.has(i)}const UL=new Set(["table","td","th"]);function HL(t){return UL.has(Rl(t))}const zL=[":popover-open",":modal"];function Bh(t){return zL.some(e=>{try{return t.matches(e)}catch{return!1}})}const jL=["transform","translate","scale","rotate","perspective"],$L=["transform","translate","scale","rotate","perspective","filter"],WL=["paint","layout","strict","content"];function iE(t){const e=sE(),n=Ti(t)?Si(t):t;return jL.some(r=>n[r]?n[r]!=="none":!1)||(n.containerType?n.containerType!=="normal":!1)||!e&&(n.backdropFilter?n.backdropFilter!=="none":!1)||!e&&(n.filter?n.filter!=="none":!1)||$L.some(r=>(n.willChange||"").includes(r))||WL.some(r=>(n.contain||"").includes(r))}function VL(t){let e=co(t);for(;qi(e)&&!pl(e);){if(iE(e))return e;if(Bh(e))return null;e=co(e)}return null}function sE(){return typeof CSS>"u"||!CSS.supports?!1:CSS.supports("-webkit-backdrop-filter","none")}const GL=new Set(["html","body","#document"]);function pl(t){return GL.has(Rl(t))}function Si(t){return Vr(t).getComputedStyle(t)}function Uh(t){return Ti(t)?{scrollLeft:t.scrollLeft,scrollTop:t.scrollTop}:{scrollLeft:t.scrollX,scrollTop:t.scrollY}}function co(t){if(Rl(t)==="html")return t;const e=t.assignedSlot||t.parentNode||Av(t)&&t.host||Qi(t);return Av(e)?e.host:e}function m_(t){const e=co(t);return pl(e)?t.ownerDocument?t.ownerDocument.body:t.body:qi(e)&&Nc(e)?e:m_(e)}function ac(t,e,n){var r;e===void 0&&(e=[]),n===void 0&&(n=!0);const i=m_(t),s=i===((r=t.ownerDocument)==null?void 0:r.body),o=Vr(i);if(s){const l=I0(o);return e.concat(o,o.visualViewport||[],Nc(i)?i:[],l&&n?ac(l):[])}return e.concat(i,ac(i,[],n))}function I0(t){return t.parent&&Object.getPrototypeOf(t.parent)?t.frameElement:null}function g_(t){const e=Si(t);let n=parseFloat(e.width)||0,r=parseFloat(e.height)||0;const i=qi(t),s=i?t.offsetWidth:n,o=i?t.offsetHeight:r,l=Qf(n)!==s||Qf(r)!==o;return l&&(n=s,r=o),{width:n,height:r,$:l}}function oE(t){return Ti(t)?t:t.contextElement}function rl(t){const e=oE(t);if(!qi(e))return Ki(1);const n=e.getBoundingClientRect(),{width:r,height:i,$:s}=g_(e);let o=(s?Qf(n.width):n.width)/r,l=(s?Qf(n.height):n.height)/i;return(!o||!Number.isFinite(o))&&(o=1),(!l||!Number.isFinite(l))&&(l=1),{x:o,y:l}}const KL=Ki(0);function b_(t){const e=Vr(t);return!sE()||!e.visualViewport?KL:{x:e.visualViewport.offsetLeft,y:e.visualViewport.offsetTop}}function YL(t,e,n){return e===void 0&&(e=!1),!n||e&&n!==Vr(t)?!1:e}function Ko(t,e,n,r){e===void 0&&(e=!1),n===void 0&&(n=!1);const i=t.getBoundingClientRect(),s=oE(t);let o=Ki(1);e&&(r?Ti(r)&&(o=rl(r)):o=rl(t));const l=YL(s,n,r)?b_(s):Ki(0);let c=(i.left+l.x)/o.x,d=(i.top+l.y)/o.y,f=i.width/o.x,p=i.height/o.y;if(s){const m=Vr(s),g=r&&Ti(r)?Vr(r):r;let x=m,v=I0(x);for(;v&&r&&g!==x;){const S=rl(v),C=v.getBoundingClientRect(),A=Si(v),k=C.left+(v.clientLeft+parseFloat(A.paddingLeft))*S.x,M=C.top+(v.clientTop+parseFloat(A.paddingTop))*S.y;c*=S.x,d*=S.y,f*=S.x,p*=S.y,c+=k,d+=M,x=Vr(v),v=I0(x)}}return Jf({width:f,height:p,x:c,y:d})}function aE(t,e){const n=Uh(t).scrollLeft;return e?e.left+n:Ko(Qi(t)).left+n}function E_(t,e,n){n===void 0&&(n=!1);const r=t.getBoundingClientRect(),i=r.left+e.scrollLeft-(n?0:aE(t,r)),s=r.top+e.scrollTop;return{x:i,y:s}}function qL(t){let{elements:e,rect:n,offsetParent:r,strategy:i}=t;const s=i==="fixed",o=Qi(r),l=e?Bh(e.floating):!1;if(r===o||l&&s)return n;let c={scrollLeft:0,scrollTop:0},d=Ki(1);const f=Ki(0),p=qi(r);if((p||!p&&!s)&&((Rl(r)!=="body"||Nc(o))&&(c=Uh(r)),qi(r))){const g=Ko(r);d=rl(r),f.x=g.x+r.clientLeft,f.y=g.y+r.clientTop}const m=o&&!p&&!s?E_(o,c,!0):Ki(0);return{width:n.width*d.x,height:n.height*d.y,x:n.x*d.x-c.scrollLeft*d.x+f.x+m.x,y:n.y*d.y-c.scrollTop*d.y+f.y+m.y}}function XL(t){return Array.from(t.getClientRects())}function QL(t){const e=Qi(t),n=Uh(t),r=t.ownerDocument.body,i=$r(e.scrollWidth,e.clientWidth,r.scrollWidth,r.clientWidth),s=$r(e.scrollHeight,e.clientHeight,r.scrollHeight,r.clientHeight);let o=-n.scrollLeft+aE(t);const l=-n.scrollTop;return Si(r).direction==="rtl"&&(o+=$r(e.clientWidth,r.clientWidth)-i),{width:i,height:s,x:o,y:l}}function ZL(t,e){const n=Vr(t),r=Qi(t),i=n.visualViewport;let s=r.clientWidth,o=r.clientHeight,l=0,c=0;if(i){s=i.width,o=i.height;const d=sE();(!d||d&&e==="fixed")&&(l=i.offsetLeft,c=i.offsetTop)}return{width:s,height:o,x:l,y:c}}const JL=new Set(["absolute","fixed"]);function eP(t,e){const n=Ko(t,!0,e==="fixed"),r=n.top+t.clientTop,i=n.left+t.clientLeft,s=qi(t)?rl(t):Ki(1),o=t.clientWidth*s.x,l=t.clientHeight*s.y,c=i*s.x,d=r*s.y;return{width:o,height:l,x:c,y:d}}function kv(t,e,n){let r;if(e==="viewport")r=ZL(t,n);else if(e==="document")r=QL(Qi(t));else if(Ti(e))r=eP(e,n);else{const i=b_(t);r={x:e.x-i.x,y:e.y-i.y,width:e.width,height:e.height}}return Jf(r)}function y_(t,e){const n=co(t);return n===e||!Ti(n)||pl(n)?!1:Si(n).position==="fixed"||y_(n,e)}function tP(t,e){const n=e.get(t);if(n)return n;let r=ac(t,[],!1).filter(l=>Ti(l)&&Rl(l)!=="body"),i=null;const s=Si(t).position==="fixed";let o=s?co(t):t;for(;Ti(o)&&!pl(o);){const l=Si(o),c=iE(o);!c&&l.position==="fixed"&&(i=null),(s?!c&&!i:!c&&l.position==="static"&&!!i&&JL.has(i.position)||Nc(o)&&!c&&y_(t,o))?r=r.filter(f=>f!==o):i=l,o=co(o)}return e.set(t,r),r}function nP(t){let{element:e,boundary:n,rootBoundary:r,strategy:i}=t;const o=[...n==="clippingAncestors"?Bh(e)?[]:tP(e,this._c):[].concat(n),r],l=o[0],c=o.reduce((d,f)=>{const p=kv(e,f,i);return d.top=$r(p.top,d.top),d.right=uo(p.right,d.right),d.bottom=uo(p.bottom,d.bottom),d.left=$r(p.left,d.left),d},kv(e,l,i));return{width:c.right-c.left,height:c.bottom-c.top,x:c.left,y:c.top}}function rP(t){const{width:e,height:n}=g_(t);return{width:e,height:n}}function iP(t,e,n){const r=qi(e),i=Qi(e),s=n==="fixed",o=Ko(t,!0,s,e);let l={scrollLeft:0,scrollTop:0};const c=Ki(0);function d(){c.x=aE(i)}if(r||!r&&!s)if((Rl(e)!=="body"||Nc(i))&&(l=Uh(e)),r){const g=Ko(e,!0,s,e);c.x=g.x+e.clientLeft,c.y=g.y+e.clientTop}else i&&d();s&&!r&&i&&d();const f=i&&!r&&!s?E_(i,l):Ki(0),p=o.left+l.scrollLeft-c.x-f.x,m=o.top+l.scrollTop-c.y-f.y;return{x:p,y:m,width:o.width,height:o.height}}function mg(t){return Si(t).position==="static"}function Nv(t,e){if(!qi(t)||Si(t).position==="fixed")return null;if(e)return e(t);let n=t.offsetParent;return Qi(t)===n&&(n=n.ownerDocument.body),n}function x_(t,e){const n=Vr(t);if(Bh(t))return n;if(!qi(t)){let i=co(t);for(;i&&!pl(i);){if(Ti(i)&&!mg(i))return i;i=co(i)}return n}let r=Nv(t,e);for(;r&&HL(r)&&mg(r);)r=Nv(r,e);return r&&pl(r)&&mg(r)&&!iE(r)?n:r||VL(t)||n}const sP=async function(t){const e=this.getOffsetParent||x_,n=this.getDimensions,r=await n(t.floating);return{reference:iP(t.reference,await e(t.floating),t.strategy),floating:{x:0,y:0,width:r.width,height:r.height}}};function oP(t){return Si(t).direction==="rtl"}const aP={convertOffsetParentRelativeRectToViewportRelativeRect:qL,getDocumentElement:Qi,getClippingRect:nP,getOffsetParent:x_,getElementRects:sP,getClientRects:XL,getDimensions:rP,getScale:rl,isElement:Ti,isRTL:oP};function v_(t,e){return t.x===e.x&&t.y===e.y&&t.width===e.width&&t.height===e.height}function lP(t,e){let n=null,r;const i=Qi(t);function s(){var l;clearTimeout(r),(l=n)==null||l.disconnect(),n=null}function o(l,c){l===void 0&&(l=!1),c===void 0&&(c=1),s();const d=t.getBoundingClientRect(),{left:f,top:p,width:m,height:g}=d;if(l||e(),!m||!g)return;const x=ef(p),v=ef(i.clientWidth-(f+m)),S=ef(i.clientHeight-(p+g)),C=ef(f),k={rootMargin:-x+"px "+-v+"px "+-S+"px "+-C+"px",threshold:$r(0,uo(1,c))||1};let M=!0;function F(I){const D=I[0].intersectionRatio;if(D!==c){if(!M)return o();D?o(!1,D):r=setTimeout(()=>{o(!1,1e-7)},1e3)}D===1&&!v_(d,t.getBoundingClientRect())&&o(),M=!1}try{n=new IntersectionObserver(F,{...k,root:i.ownerDocument})}catch{n=new IntersectionObserver(F,k)}n.observe(t)}return o(!0),s}function uP(t,e,n,r){r===void 0&&(r={});const{ancestorScroll:i=!0,ancestorResize:s=!0,elementResize:o=typeof ResizeObserver=="function",layoutShift:l=typeof IntersectionObserver=="function",animationFrame:c=!1}=r,d=oE(t),f=i||s?[...d?ac(d):[],...ac(e)]:[];f.forEach(C=>{i&&C.addEventListener("scroll",n,{passive:!0}),s&&C.addEventListener("resize",n)});const p=d&&l?lP(d,n):null;let m=-1,g=null;o&&(g=new ResizeObserver(C=>{let[A]=C;A&&A.target===d&&g&&(g.unobserve(e),cancelAnimationFrame(m),m=requestAnimationFrame(()=>{var k;(k=g)==null||k.observe(e)})),n()}),d&&!c&&g.observe(d),g.observe(e));let x,v=c?Ko(t):null;c&&S();function S(){const C=Ko(t);v&&!v_(v,C)&&n(),v=C,x=requestAnimationFrame(S)}return n(),()=>{var C;f.forEach(A=>{i&&A.removeEventListener("scroll",n),s&&A.removeEventListener("resize",n)}),p?.(),(C=g)==null||C.disconnect(),g=null,c&&cancelAnimationFrame(x)}}const cP=DL,dP=LL,fP=IL,hP=FL,pP=OL,Rv=RL,mP=PL,gP=(t,e,n)=>{const r=new Map,i={platform:aP,...n},s={...i.platform,_c:r};return NL(t,e,{...i,platform:s})};var bP=typeof document<"u",EP=function(){},Lf=bP?T.useLayoutEffect:EP;function eh(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(typeof t=="function"&&t.toString()===e.toString())return!0;let n,r,i;if(t&&e&&typeof t=="object"){if(Array.isArray(t)){if(n=t.length,n!==e.length)return!1;for(r=n;r--!==0;)if(!eh(t[r],e[r]))return!1;return!0}if(i=Object.keys(t),n=i.length,n!==Object.keys(e).length)return!1;for(r=n;r--!==0;)if(!{}.hasOwnProperty.call(e,i[r]))return!1;for(r=n;r--!==0;){const s=i[r];if(!(s==="_owner"&&t.$$typeof)&&!eh(t[s],e[s]))return!1}return!0}return t!==t&&e!==e}function w_(t){return typeof window>"u"?1:(t.ownerDocument.defaultView||window).devicePixelRatio||1}function Iv(t,e){const n=w_(t);return Math.round(e*n)/n}function gg(t){const e=T.useRef(t);return Lf(()=>{e.current=t}),e}function yP(t){t===void 0&&(t={});const{placement:e="bottom",strategy:n="absolute",middleware:r=[],platform:i,elements:{reference:s,floating:o}={},transform:l=!0,whileElementsMounted:c,open:d}=t,[f,p]=T.useState({x:0,y:0,strategy:n,placement:e,middlewareData:{},isPositioned:!1}),[m,g]=T.useState(r);eh(m,r)||g(r);const[x,v]=T.useState(null),[S,C]=T.useState(null),A=T.useCallback(j=>{j!==I.current&&(I.current=j,v(j))},[]),k=T.useCallback(j=>{j!==D.current&&(D.current=j,C(j))},[]),M=s||x,F=o||S,I=T.useRef(null),D=T.useRef(null),G=T.useRef(f),X=c!=null,P=gg(c),Y=gg(i),z=gg(d),ie=T.useCallback(()=>{if(!I.current||!D.current)return;const j={placement:e,strategy:n,middleware:m};Y.current&&(j.platform=Y.current),gP(I.current,D.current,j).then(W=>{const O={...W,isPositioned:z.current!==!1};Z.current&&!eh(G.current,O)&&(G.current=O,Ac.flushSync(()=>{p(O)}))})},[m,e,n,Y,z]);Lf(()=>{d===!1&&G.current.isPositioned&&(G.current.isPositioned=!1,p(j=>({...j,isPositioned:!1})))},[d]);const Z=T.useRef(!1);Lf(()=>(Z.current=!0,()=>{Z.current=!1}),[]),Lf(()=>{if(M&&(I.current=M),F&&(D.current=F),M&&F){if(P.current)return P.current(M,F,ie);ie()}},[M,F,ie,P,X]);const ee=T.useMemo(()=>({reference:I,floating:D,setReference:A,setFloating:k}),[A,k]),ae=T.useMemo(()=>({reference:M,floating:F}),[M,F]),de=T.useMemo(()=>{const j={position:n,left:0,top:0};if(!ae.floating)return j;const W=Iv(ae.floating,f.x),O=Iv(ae.floating,f.y);return l?{...j,transform:"translate("+W+"px, "+O+"px)",...w_(ae.floating)>=1.5&&{willChange:"transform"}}:{position:n,left:W,top:O}},[n,l,ae.floating,f.x,f.y]);return T.useMemo(()=>({...f,update:ie,refs:ee,elements:ae,floatingStyles:de}),[f,ie,ee,ae,de])}const xP=t=>{function e(n){return{}.hasOwnProperty.call(n,"current")}return{name:"arrow",options:t,fn(n){const{element:r,padding:i}=typeof t=="function"?t(n):t;return r&&e(r)?r.current!=null?Rv({element:r.current,padding:i}).fn(n):{}:r?Rv({element:r,padding:i}).fn(n):{}}}},vP=(t,e)=>({...cP(t),options:[t,e]}),wP=(t,e)=>({...dP(t),options:[t,e]}),TP=(t,e)=>({...mP(t),options:[t,e]}),SP=(t,e)=>({...fP(t),options:[t,e]}),_P=(t,e)=>({...hP(t),options:[t,e]}),CP=(t,e)=>({...pP(t),options:[t,e]}),AP=(t,e)=>({...xP(t),options:[t,e]});var kP="Arrow",T_=T.forwardRef((t,e)=>{const{children:n,width:r=10,height:i=5,...s}=t;return w.jsx(xt.svg,{...s,ref:e,width:r,height:i,viewBox:"0 0 30 10",preserveAspectRatio:"none",children:t.asChild?n:w.jsx("polygon",{points:"0,0 30,0 15,10"})})});T_.displayName=kP;var NP=T_;function S_(t){const[e,n]=T.useState(void 0);return lr(()=>{if(t){n({width:t.offsetWidth,height:t.offsetHeight});const r=new ResizeObserver(i=>{if(!Array.isArray(i)||!i.length)return;const s=i[0];let o,l;if("borderBoxSize"in s){const c=s.borderBoxSize,d=Array.isArray(c)?c[0]:c;o=d.inlineSize,l=d.blockSize}else o=t.offsetWidth,l=t.offsetHeight;n({width:o,height:l})});return r.observe(t,{box:"border-box"}),()=>r.unobserve(t)}else n(void 0)},[t]),e}var lE="Popper",[__,Il]=Cs(lE),[RP,C_]=__(lE),A_=t=>{const{__scopePopper:e,children:n}=t,[r,i]=T.useState(null);return w.jsx(RP,{scope:e,anchor:r,onAnchorChange:i,children:n})};A_.displayName=lE;var k_="PopperAnchor",N_=T.forwardRef((t,e)=>{const{__scopePopper:n,virtualRef:r,...i}=t,s=C_(k_,n),o=T.useRef(null),l=Pt(e,o);return T.useEffect(()=>{s.onAnchorChange(r?.current||o.current)}),r?null:w.jsx(xt.div,{...i,ref:l})});N_.displayName=k_;var uE="PopperContent",[IP,OP]=__(uE),R_=T.forwardRef((t,e)=>{const{__scopePopper:n,side:r="bottom",sideOffset:i=0,align:s="center",alignOffset:o=0,arrowPadding:l=0,avoidCollisions:c=!0,collisionBoundary:d=[],collisionPadding:f=0,sticky:p="partial",hideWhenDetached:m=!1,updatePositionStrategy:g="optimized",onPlaced:x,...v}=t,S=C_(uE,n),[C,A]=T.useState(null),k=Pt(e,J=>A(J)),[M,F]=T.useState(null),I=S_(M),D=I?.width??0,G=I?.height??0,X=r+(s!=="center"?"-"+s:""),P=typeof f=="number"?f:{top:0,right:0,bottom:0,left:0,...f},Y=Array.isArray(d)?d:[d],z=Y.length>0,ie={padding:P,boundary:Y.filter(DP),altBoundary:z},{refs:Z,floatingStyles:ee,placement:ae,isPositioned:de,middlewareData:j}=yP({strategy:"fixed",placement:X,whileElementsMounted:(...J)=>uP(...J,{animationFrame:g==="always"}),elements:{reference:S.anchor},middleware:[vP({mainAxis:i+G,alignmentAxis:o}),c&&wP({mainAxis:!0,crossAxis:!1,limiter:p==="partial"?TP():void 0,...ie}),c&&SP({...ie}),_P({...ie,apply:({elements:J,rects:he,availableWidth:_e,availableHeight:ke})=>{const{width:Ve,height:ot}=he.reference,qe=J.floating.style;qe.setProperty("--radix-popper-available-width",`${_e}px`),qe.setProperty("--radix-popper-available-height",`${ke}px`),qe.setProperty("--radix-popper-anchor-width",`${Ve}px`),qe.setProperty("--radix-popper-anchor-height",`${ot}px`)}}),M&&AP({element:M,padding:l}),LP({arrowWidth:D,arrowHeight:G}),m&&CP({strategy:"referenceHidden",...ie})]}),[W,O]=M_(ae),U=Yi(x);lr(()=>{de&&U?.()},[de,U]);const Q=j.arrow?.x,R=j.arrow?.y,oe=j.arrow?.centerOffset!==0,[pe,ue]=T.useState();return lr(()=>{C&&ue(window.getComputedStyle(C).zIndex)},[C]),w.jsx("div",{ref:Z.setFloating,"data-radix-popper-content-wrapper":"",style:{...ee,transform:de?ee.transform:"translate(0, -200%)",minWidth:"max-content",zIndex:pe,"--radix-popper-transform-origin":[j.transformOrigin?.x,j.transformOrigin?.y].join(" "),...j.hide?.referenceHidden&&{visibility:"hidden",pointerEvents:"none"}},dir:t.dir,children:w.jsx(IP,{scope:n,placedSide:W,onArrowChange:F,arrowX:Q,arrowY:R,shouldHideArrow:oe,children:w.jsx(xt.div,{"data-side":W,"data-align":O,...v,ref:k,style:{...v.style,animation:de?void 0:"none"}})})})});R_.displayName=uE;var I_="PopperArrow",MP={top:"bottom",right:"left",bottom:"top",left:"right"},O_=T.forwardRef(function(e,n){const{__scopePopper:r,...i}=e,s=OP(I_,r),o=MP[s.placedSide];return w.jsx("span",{ref:s.onArrowChange,style:{position:"absolute",left:s.arrowX,top:s.arrowY,[o]:0,transformOrigin:{top:"",right:"0 0",bottom:"center 0",left:"100% 0"}[s.placedSide],transform:{top:"translateY(100%)",right:"translateY(50%) rotate(90deg) translateX(-50%)",bottom:"rotate(180deg)",left:"translateY(50%) rotate(-90deg) translateX(50%)"}[s.placedSide],visibility:s.shouldHideArrow?"hidden":void 0},children:w.jsx(NP,{...i,ref:n,style:{...i.style,display:"block"}})})});O_.displayName=I_;function DP(t){return t!==null}var LP=t=>({name:"transformOrigin",options:t,fn(e){const{placement:n,rects:r,middlewareData:i}=e,o=i.arrow?.centerOffset!==0,l=o?0:t.arrowWidth,c=o?0:t.arrowHeight,[d,f]=M_(n),p={start:"0%",center:"50%",end:"100%"}[f],m=(i.arrow?.x??0)+l/2,g=(i.arrow?.y??0)+c/2;let x="",v="";return d==="bottom"?(x=o?p:`${m}px`,v=`${-c}px`):d==="top"?(x=o?p:`${m}px`,v=`${r.floating.height+c}px`):d==="right"?(x=`${-c}px`,v=o?p:`${g}px`):d==="left"&&(x=`${r.floating.width+c}px`,v=o?p:`${g}px`),{data:{x,y:v}}}});function M_(t){const[e,n="center"]=t.split("-");return[e,n]}var cE=A_,dE=N_,fE=R_,hE=O_,PP="Portal",Hh=T.forwardRef((t,e)=>{const{container:n,...r}=t,[i,s]=T.useState(!1);lr(()=>s(!0),[]);const o=n||i&&globalThis?.document?.body;return o?e_.createPortal(w.jsx(xt.div,{...r,ref:e}),o):null});Hh.displayName=PP;function FP(t,e){return T.useReducer((n,r)=>e[n][r]??n,t)}var Zi=t=>{const{present:e,children:n}=t,r=BP(e),i=typeof n=="function"?n({present:r.isPresent}):T.Children.only(n),s=Pt(r.ref,UP(i));return typeof n=="function"||r.isPresent?T.cloneElement(i,{ref:s}):null};Zi.displayName="Presence";function BP(t){const[e,n]=T.useState(),r=T.useRef(null),i=T.useRef(t),s=T.useRef("none"),o=t?"mounted":"unmounted",[l,c]=FP(o,{mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}});return T.useEffect(()=>{const d=tf(r.current);s.current=l==="mounted"?d:"none"},[l]),lr(()=>{const d=r.current,f=i.current;if(f!==t){const m=s.current,g=tf(d);t?c("MOUNT"):g==="none"||d?.display==="none"?c("UNMOUNT"):c(f&&m!==g?"ANIMATION_OUT":"UNMOUNT"),i.current=t}},[t,c]),lr(()=>{if(e){let d;const f=e.ownerDocument.defaultView??window,p=g=>{const v=tf(r.current).includes(g.animationName);if(g.target===e&&v&&(c("ANIMATION_END"),!i.current)){const S=e.style.animationFillMode;e.style.animationFillMode="forwards",d=f.setTimeout(()=>{e.style.animationFillMode==="forwards"&&(e.style.animationFillMode=S)})}},m=g=>{g.target===e&&(s.current=tf(r.current))};return e.addEventListener("animationstart",m),e.addEventListener("animationcancel",p),e.addEventListener("animationend",p),()=>{f.clearTimeout(d),e.removeEventListener("animationstart",m),e.removeEventListener("animationcancel",p),e.removeEventListener("animationend",p)}}else c("ANIMATION_END")},[e,c]),{isPresent:["mounted","unmountSuspended"].includes(l),ref:T.useCallback(d=>{r.current=d?getComputedStyle(d):null,n(d)},[])}}function tf(t){return t?.animationName||"none"}function UP(t){let e=Object.getOwnPropertyDescriptor(t.props,"ref")?.get,n=e&&"isReactWarning"in e&&e.isReactWarning;return n?t.ref:(e=Object.getOwnPropertyDescriptor(t,"ref")?.get,n=e&&"isReactWarning"in e&&e.isReactWarning,n?t.props.ref:t.props.ref||t.ref)}var HP=Qb[" useInsertionEffect ".trim().toString()]||lr;function Yo({prop:t,defaultProp:e,onChange:n=()=>{},caller:r}){const[i,s,o]=zP({defaultProp:e,onChange:n}),l=t!==void 0,c=l?t:i;{const f=T.useRef(t!==void 0);T.useEffect(()=>{const p=f.current;p!==l&&console.warn(`${r} is changing from ${p?"controlled":"uncontrolled"} to ${l?"controlled":"uncontrolled"}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`),f.current=l},[l,r])}const d=T.useCallback(f=>{if(l){const p=jP(f)?f(t):f;p!==t&&o.current?.(p)}else s(f)},[l,t,s,o]);return[c,d]}function zP({defaultProp:t,onChange:e}){const[n,r]=T.useState(t),i=T.useRef(n),s=T.useRef(e);return HP(()=>{s.current=e},[e]),T.useEffect(()=>{i.current!==n&&(s.current?.(n),i.current=n)},[n,i]),[n,r,s]}function jP(t){return typeof t=="function"}var D_=Object.freeze({position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal"}),$P="VisuallyHidden",L_=T.forwardRef((t,e)=>w.jsx(xt.span,{...t,ref:e,style:{...D_,...t.style}}));L_.displayName=$P;var WP=L_,[zh]=Cs("Tooltip",[Il]),jh=Il(),P_="TooltipProvider",VP=700,O0="tooltip.open",[GP,pE]=zh(P_),F_=t=>{const{__scopeTooltip:e,delayDuration:n=VP,skipDelayDuration:r=300,disableHoverableContent:i=!1,children:s}=t,o=T.useRef(!0),l=T.useRef(!1),c=T.useRef(0);return T.useEffect(()=>{const d=c.current;return()=>window.clearTimeout(d)},[]),w.jsx(GP,{scope:e,isOpenDelayedRef:o,delayDuration:n,onOpen:T.useCallback(()=>{window.clearTimeout(c.current),o.current=!1},[]),onClose:T.useCallback(()=>{window.clearTimeout(c.current),c.current=window.setTimeout(()=>o.current=!0,r)},[r]),isPointerInTransitRef:l,onPointerInTransitChange:T.useCallback(d=>{l.current=d},[]),disableHoverableContent:i,children:s})};F_.displayName=P_;var lc="Tooltip",[KP,$h]=zh(lc),B_=t=>{const{__scopeTooltip:e,children:n,open:r,defaultOpen:i,onOpenChange:s,disableHoverableContent:o,delayDuration:l}=t,c=pE(lc,t.__scopeTooltip),d=jh(e),[f,p]=T.useState(null),m=Gi(),g=T.useRef(0),x=o??c.disableHoverableContent,v=l??c.delayDuration,S=T.useRef(!1),[C,A]=Yo({prop:r,defaultProp:i??!1,onChange:D=>{D?(c.onOpen(),document.dispatchEvent(new CustomEvent(O0))):c.onClose(),s?.(D)},caller:lc}),k=T.useMemo(()=>C?S.current?"delayed-open":"instant-open":"closed",[C]),M=T.useCallback(()=>{window.clearTimeout(g.current),g.current=0,S.current=!1,A(!0)},[A]),F=T.useCallback(()=>{window.clearTimeout(g.current),g.current=0,A(!1)},[A]),I=T.useCallback(()=>{window.clearTimeout(g.current),g.current=window.setTimeout(()=>{S.current=!0,A(!0),g.current=0},v)},[v,A]);return T.useEffect(()=>()=>{g.current&&(window.clearTimeout(g.current),g.current=0)},[]),w.jsx(cE,{...d,children:w.jsx(KP,{scope:e,contentId:m,open:C,stateAttribute:k,trigger:f,onTriggerChange:p,onTriggerEnter:T.useCallback(()=>{c.isOpenDelayedRef.current?I():M()},[c.isOpenDelayedRef,I,M]),onTriggerLeave:T.useCallback(()=>{x?F():(window.clearTimeout(g.current),g.current=0)},[F,x]),onOpen:M,onClose:F,disableHoverableContent:x,children:n})})};B_.displayName=lc;var M0="TooltipTrigger",U_=T.forwardRef((t,e)=>{const{__scopeTooltip:n,...r}=t,i=$h(M0,n),s=pE(M0,n),o=jh(n),l=T.useRef(null),c=Pt(e,l,i.onTriggerChange),d=T.useRef(!1),f=T.useRef(!1),p=T.useCallback(()=>d.current=!1,[]);return T.useEffect(()=>()=>document.removeEventListener("pointerup",p),[p]),w.jsx(dE,{asChild:!0,...o,children:w.jsx(xt.button,{"aria-describedby":i.open?i.contentId:void 0,"data-state":i.stateAttribute,...r,ref:c,onPointerMove:je(t.onPointerMove,m=>{m.pointerType!=="touch"&&!f.current&&!s.isPointerInTransitRef.current&&(i.onTriggerEnter(),f.current=!0)}),onPointerLeave:je(t.onPointerLeave,()=>{i.onTriggerLeave(),f.current=!1}),onPointerDown:je(t.onPointerDown,()=>{i.open&&i.onClose(),d.current=!0,document.addEventListener("pointerup",p,{once:!0})}),onFocus:je(t.onFocus,()=>{d.current||i.onOpen()}),onBlur:je(t.onBlur,i.onClose),onClick:je(t.onClick,i.onClose)})})});U_.displayName=M0;var YP="TooltipPortal",[FX,qP]=zh(YP,{forceMount:void 0}),ml="TooltipContent",H_=T.forwardRef((t,e)=>{const n=qP(ml,t.__scopeTooltip),{forceMount:r=n.forceMount,side:i="top",...s}=t,o=$h(ml,t.__scopeTooltip);return w.jsx(Zi,{present:r||o.open,children:o.disableHoverableContent?w.jsx(z_,{side:i,...s,ref:e}):w.jsx(XP,{side:i,...s,ref:e})})}),XP=T.forwardRef((t,e)=>{const n=$h(ml,t.__scopeTooltip),r=pE(ml,t.__scopeTooltip),i=T.useRef(null),s=Pt(e,i),[o,l]=T.useState(null),{trigger:c,onClose:d}=n,f=i.current,{onPointerInTransitChange:p}=r,m=T.useCallback(()=>{l(null),p(!1)},[p]),g=T.useCallback((x,v)=>{const S=x.currentTarget,C={x:x.clientX,y:x.clientY},A=t3(C,S.getBoundingClientRect()),k=n3(C,A),M=r3(v.getBoundingClientRect()),F=s3([...k,...M]);l(F),p(!0)},[p]);return T.useEffect(()=>()=>m(),[m]),T.useEffect(()=>{if(c&&f){const x=S=>g(S,f),v=S=>g(S,c);return c.addEventListener("pointerleave",x),f.addEventListener("pointerleave",v),()=>{c.removeEventListener("pointerleave",x),f.removeEventListener("pointerleave",v)}}},[c,f,g,m]),T.useEffect(()=>{if(o){const x=v=>{const S=v.target,C={x:v.clientX,y:v.clientY},A=c?.contains(S)||f?.contains(S),k=!i3(C,o);A?m():k&&(m(),d())};return document.addEventListener("pointermove",x),()=>document.removeEventListener("pointermove",x)}},[c,f,o,d,m]),w.jsx(z_,{...t,ref:s})}),[QP,ZP]=zh(lc,{isInside:!1}),JP=rL("TooltipContent"),z_=T.forwardRef((t,e)=>{const{__scopeTooltip:n,children:r,"aria-label":i,onEscapeKeyDown:s,onPointerDownOutside:o,...l}=t,c=$h(ml,n),d=jh(n),{onClose:f}=c;return T.useEffect(()=>(document.addEventListener(O0,f),()=>document.removeEventListener(O0,f)),[f]),T.useEffect(()=>{if(c.trigger){const p=m=>{m.target?.contains(c.trigger)&&f()};return window.addEventListener("scroll",p,{capture:!0}),()=>window.removeEventListener("scroll",p,{capture:!0})}},[c.trigger,f]),w.jsx(kc,{asChild:!0,disableOutsidePointerEvents:!1,onEscapeKeyDown:s,onPointerDownOutside:o,onFocusOutside:p=>p.preventDefault(),onDismiss:f,children:w.jsxs(fE,{"data-state":c.stateAttribute,...d,...l,ref:e,style:{...l.style,"--radix-tooltip-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-tooltip-content-available-width":"var(--radix-popper-available-width)","--radix-tooltip-content-available-height":"var(--radix-popper-available-height)","--radix-tooltip-trigger-width":"var(--radix-popper-anchor-width)","--radix-tooltip-trigger-height":"var(--radix-popper-anchor-height)"},children:[w.jsx(JP,{children:r}),w.jsx(QP,{scope:n,isInside:!0,children:w.jsx(WP,{id:c.contentId,role:"tooltip",children:i||r})})]})})});H_.displayName=ml;var j_="TooltipArrow",e3=T.forwardRef((t,e)=>{const{__scopeTooltip:n,...r}=t,i=jh(n);return ZP(j_,n).isInside?null:w.jsx(hE,{...i,...r,ref:e})});e3.displayName=j_;function t3(t,e){const n=Math.abs(e.top-t.y),r=Math.abs(e.bottom-t.y),i=Math.abs(e.right-t.x),s=Math.abs(e.left-t.x);switch(Math.min(n,r,i,s)){case s:return"left";case i:return"right";case n:return"top";case r:return"bottom";default:throw new Error("unreachable")}}function n3(t,e,n=5){const r=[];switch(e){case"top":r.push({x:t.x-n,y:t.y+n},{x:t.x+n,y:t.y+n});break;case"bottom":r.push({x:t.x-n,y:t.y-n},{x:t.x+n,y:t.y-n});break;case"left":r.push({x:t.x+n,y:t.y-n},{x:t.x+n,y:t.y+n});break;case"right":r.push({x:t.x-n,y:t.y-n},{x:t.x-n,y:t.y+n});break}return r}function r3(t){const{top:e,right:n,bottom:r,left:i}=t;return[{x:i,y:e},{x:n,y:e},{x:n,y:r},{x:i,y:r}]}function i3(t,e){const{x:n,y:r}=t;let i=!1;for(let s=0,o=e.length-1;sr!=m>r&&n<(p-d)*(r-f)/(m-f)+d&&(i=!i)}return i}function s3(t){const e=t.slice();return e.sort((n,r)=>n.xr.x?1:n.yr.y?1:0),o3(e)}function o3(t){if(t.length<=1)return t.slice();const e=[];for(let r=0;r=2;){const s=e[e.length-1],o=e[e.length-2];if((s.x-o.x)*(i.y-o.y)>=(s.y-o.y)*(i.x-o.x))e.pop();else break}e.push(i)}e.pop();const n=[];for(let r=t.length-1;r>=0;r--){const i=t[r];for(;n.length>=2;){const s=n[n.length-1],o=n[n.length-2];if((s.x-o.x)*(i.y-o.y)>=(s.y-o.y)*(i.x-o.x))n.pop();else break}n.push(i)}return n.pop(),e.length===1&&n.length===1&&e[0].x===n[0].x&&e[0].y===n[0].y?e:e.concat(n)}var a3=F_,l3=B_,u3=U_,$_=H_;const c3=a3,d3=l3,f3=u3,W_=T.forwardRef(({className:t,sideOffset:e=4,...n},r)=>w.jsx($_,{ref:r,sideOffset:e,className:Rt("z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",t),...n}));W_.displayName=$_.displayName;function Xn({children:t,value:e,className:n,style:r={},side:i="bottom",align:s="center",delayDuration:o=0}){return w.jsx(c3,{children:w.jsxs(d3,{delayDuration:o,children:[w.jsx(f3,{asChild:!0,children:t}),w.jsx(W_,{side:i,align:s,style:{boxShadow:"none",...r},className:Xe("left-[34px] h-[32px] text-[13px] font-normal font-inter rounded-[20px] border border-[#EBECF0] border-solid bg-white p-[5px_16px_7px_16px]",n),children:w.jsx("div",{children:e})})]})})}const Ov=t=>typeof t=="boolean"?`${t}`:t===0?"0":t,Mv=Al,V_=(t,e)=>n=>{var r;if(e?.variants==null)return Mv(t,n?.class,n?.className);const{variants:i,defaultVariants:s}=e,o=Object.keys(i).map(d=>{const f=n?.[d],p=s?.[d];if(f===null)return null;const m=Ov(f)||Ov(p);return i[d][m]}),l=n&&Object.entries(n).reduce((d,f)=>{let[p,m]=f;return m===void 0||(d[p]=m),d},{}),c=e==null||(r=e.compoundVariants)===null||r===void 0?void 0:r.reduce((d,f)=>{let{class:p,className:m,...g}=f;return Object.entries(g).every(x=>{let[v,S]=x;return Array.isArray(S)?S.includes({...s,...l}[v]):{...s,...l}[v]===S})?[...d,p,m]:d},[]);return Mv(t,o,c,n?.class,n?.className)},h3=V_("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground data-[selected=true]:bg-accent",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}}),An=T.forwardRef(({className:t,variant:e,size:n,asChild:r=!1,...i},s)=>{const o=r?tL:"button";return w.jsx(o,{className:Rt(h3({variant:e,size:n,className:t})),ref:s,...i})});An.displayName="Button";function mE(t){const e=t+"CollectionProvider",[n,r]=Cs(e),[i,s]=n(e,{collectionRef:{current:null},itemMap:new Map}),o=v=>{const{scope:S,children:C}=v,A=we.useRef(null),k=we.useRef(new Map).current;return w.jsx(i,{scope:S,itemMap:k,collectionRef:A,children:C})};o.displayName=e;const l=t+"CollectionSlot",c=Go(l),d=we.forwardRef((v,S)=>{const{scope:C,children:A}=v,k=s(l,C),M=Pt(S,k.collectionRef);return w.jsx(c,{ref:M,children:A})});d.displayName=l;const f=t+"CollectionItemSlot",p="data-radix-collection-item",m=Go(f),g=we.forwardRef((v,S)=>{const{scope:C,children:A,...k}=v,M=we.useRef(null),F=Pt(S,M),I=s(f,C);return we.useEffect(()=>(I.itemMap.set(M,{ref:M,...k}),()=>{I.itemMap.delete(M)})),w.jsx(m,{[p]:"",ref:F,children:A})});g.displayName=f;function x(v){const S=s(t+"CollectionConsumer",v);return we.useCallback(()=>{const A=S.collectionRef.current;if(!A)return[];const k=Array.from(A.querySelectorAll(`[${p}]`));return Array.from(S.itemMap.values()).sort((I,D)=>k.indexOf(I.ref.current)-k.indexOf(D.ref.current))},[S.collectionRef,S.itemMap])}return[{Provider:o,Slot:d,ItemSlot:g},x,r]}var p3=T.createContext(void 0);function gE(t){const e=T.useContext(p3);return t||e||"ltr"}var bg=0;function bE(){T.useEffect(()=>{const t=document.querySelectorAll("[data-radix-focus-guard]");return document.body.insertAdjacentElement("afterbegin",t[0]??Dv()),document.body.insertAdjacentElement("beforeend",t[1]??Dv()),bg++,()=>{bg===1&&document.querySelectorAll("[data-radix-focus-guard]").forEach(e=>e.remove()),bg--}},[])}function Dv(){const t=document.createElement("span");return t.setAttribute("data-radix-focus-guard",""),t.tabIndex=0,t.style.outline="none",t.style.opacity="0",t.style.position="fixed",t.style.pointerEvents="none",t}var Eg="focusScope.autoFocusOnMount",yg="focusScope.autoFocusOnUnmount",Lv={bubbles:!1,cancelable:!0},m3="FocusScope",Wh=T.forwardRef((t,e)=>{const{loop:n=!1,trapped:r=!1,onMountAutoFocus:i,onUnmountAutoFocus:s,...o}=t,[l,c]=T.useState(null),d=Yi(i),f=Yi(s),p=T.useRef(null),m=Pt(e,v=>c(v)),g=T.useRef({paused:!1,pause(){this.paused=!0},resume(){this.paused=!1}}).current;T.useEffect(()=>{if(r){let v=function(k){if(g.paused||!l)return;const M=k.target;l.contains(M)?p.current=M:Zs(p.current,{select:!0})},S=function(k){if(g.paused||!l)return;const M=k.relatedTarget;M!==null&&(l.contains(M)||Zs(p.current,{select:!0}))},C=function(k){if(document.activeElement===document.body)for(const F of k)F.removedNodes.length>0&&Zs(l)};document.addEventListener("focusin",v),document.addEventListener("focusout",S);const A=new MutationObserver(C);return l&&A.observe(l,{childList:!0,subtree:!0}),()=>{document.removeEventListener("focusin",v),document.removeEventListener("focusout",S),A.disconnect()}}},[r,l,g.paused]),T.useEffect(()=>{if(l){Fv.add(g);const v=document.activeElement;if(!l.contains(v)){const C=new CustomEvent(Eg,Lv);l.addEventListener(Eg,d),l.dispatchEvent(C),C.defaultPrevented||(g3(v3(G_(l)),{select:!0}),document.activeElement===v&&Zs(l))}return()=>{l.removeEventListener(Eg,d),setTimeout(()=>{const C=new CustomEvent(yg,Lv);l.addEventListener(yg,f),l.dispatchEvent(C),C.defaultPrevented||Zs(v??document.body,{select:!0}),l.removeEventListener(yg,f),Fv.remove(g)},0)}}},[l,d,f,g]);const x=T.useCallback(v=>{if(!n&&!r||g.paused)return;const S=v.key==="Tab"&&!v.altKey&&!v.ctrlKey&&!v.metaKey,C=document.activeElement;if(S&&C){const A=v.currentTarget,[k,M]=b3(A);k&&M?!v.shiftKey&&C===M?(v.preventDefault(),n&&Zs(k,{select:!0})):v.shiftKey&&C===k&&(v.preventDefault(),n&&Zs(M,{select:!0})):C===A&&v.preventDefault()}},[n,r,g.paused]);return w.jsx(xt.div,{tabIndex:-1,...o,ref:m,onKeyDown:x})});Wh.displayName=m3;function g3(t,{select:e=!1}={}){const n=document.activeElement;for(const r of t)if(Zs(r,{select:e}),document.activeElement!==n)return}function b3(t){const e=G_(t),n=Pv(e,t),r=Pv(e.reverse(),t);return[n,r]}function G_(t){const e=[],n=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT,{acceptNode:r=>{const i=r.tagName==="INPUT"&&r.type==="hidden";return r.disabled||r.hidden||i?NodeFilter.FILTER_SKIP:r.tabIndex>=0?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;n.nextNode();)e.push(n.currentNode);return e}function Pv(t,e){for(const n of t)if(!E3(n,{upTo:e}))return n}function E3(t,{upTo:e}){if(getComputedStyle(t).visibility==="hidden")return!0;for(;t;){if(e!==void 0&&t===e)return!1;if(getComputedStyle(t).display==="none")return!0;t=t.parentElement}return!1}function y3(t){return t instanceof HTMLInputElement&&"select"in t}function Zs(t,{select:e=!1}={}){if(t&&t.focus){const n=document.activeElement;t.focus({preventScroll:!0}),t!==n&&y3(t)&&e&&t.select()}}var Fv=x3();function x3(){let t=[];return{add(e){const n=t[0];e!==n&&n?.pause(),t=Bv(t,e),t.unshift(e)},remove(e){t=Bv(t,e),t[0]?.resume()}}}function Bv(t,e){const n=[...t],r=n.indexOf(e);return r!==-1&&n.splice(r,1),n}function v3(t){return t.filter(e=>e.tagName!=="A")}var xg="rovingFocusGroup.onEntryFocus",w3={bubbles:!1,cancelable:!0},Rc="RovingFocusGroup",[D0,K_,T3]=mE(Rc),[S3,Y_]=Cs(Rc,[T3]),[_3,C3]=S3(Rc),q_=T.forwardRef((t,e)=>w.jsx(D0.Provider,{scope:t.__scopeRovingFocusGroup,children:w.jsx(D0.Slot,{scope:t.__scopeRovingFocusGroup,children:w.jsx(A3,{...t,ref:e})})}));q_.displayName=Rc;var A3=T.forwardRef((t,e)=>{const{__scopeRovingFocusGroup:n,orientation:r,loop:i=!1,dir:s,currentTabStopId:o,defaultCurrentTabStopId:l,onCurrentTabStopIdChange:c,onEntryFocus:d,preventScrollOnEntryFocus:f=!1,...p}=t,m=T.useRef(null),g=Pt(e,m),x=gE(s),[v,S]=Yo({prop:o,defaultProp:l??null,onChange:c,caller:Rc}),[C,A]=T.useState(!1),k=Yi(d),M=K_(n),F=T.useRef(!1),[I,D]=T.useState(0);return T.useEffect(()=>{const G=m.current;if(G)return G.addEventListener(xg,k),()=>G.removeEventListener(xg,k)},[k]),w.jsx(_3,{scope:n,orientation:r,dir:x,loop:i,currentTabStopId:v,onItemFocus:T.useCallback(G=>S(G),[S]),onItemShiftTab:T.useCallback(()=>A(!0),[]),onFocusableItemAdd:T.useCallback(()=>D(G=>G+1),[]),onFocusableItemRemove:T.useCallback(()=>D(G=>G-1),[]),children:w.jsx(xt.div,{tabIndex:C||I===0?-1:0,"data-orientation":r,...p,ref:g,style:{outline:"none",...t.style},onMouseDown:je(t.onMouseDown,()=>{F.current=!0}),onFocus:je(t.onFocus,G=>{const X=!F.current;if(G.target===G.currentTarget&&X&&!C){const P=new CustomEvent(xg,w3);if(G.currentTarget.dispatchEvent(P),!P.defaultPrevented){const Y=M().filter(ae=>ae.focusable),z=Y.find(ae=>ae.active),ie=Y.find(ae=>ae.id===v),ee=[z,ie,...Y].filter(Boolean).map(ae=>ae.ref.current);Z_(ee,f)}}F.current=!1}),onBlur:je(t.onBlur,()=>A(!1))})})}),X_="RovingFocusGroupItem",Q_=T.forwardRef((t,e)=>{const{__scopeRovingFocusGroup:n,focusable:r=!0,active:i=!1,tabStopId:s,children:o,...l}=t,c=Gi(),d=s||c,f=C3(X_,n),p=f.currentTabStopId===d,m=K_(n),{onFocusableItemAdd:g,onFocusableItemRemove:x,currentTabStopId:v}=f;return T.useEffect(()=>{if(r)return g(),()=>x()},[r,g,x]),w.jsx(D0.ItemSlot,{scope:n,id:d,focusable:r,active:i,children:w.jsx(xt.span,{tabIndex:p?0:-1,"data-orientation":f.orientation,...l,ref:e,onMouseDown:je(t.onMouseDown,S=>{r?f.onItemFocus(d):S.preventDefault()}),onFocus:je(t.onFocus,()=>f.onItemFocus(d)),onKeyDown:je(t.onKeyDown,S=>{if(S.key==="Tab"&&S.shiftKey){f.onItemShiftTab();return}if(S.target!==S.currentTarget)return;const C=R3(S,f.orientation,f.dir);if(C!==void 0){if(S.metaKey||S.ctrlKey||S.altKey||S.shiftKey)return;S.preventDefault();let k=m().filter(M=>M.focusable).map(M=>M.ref.current);if(C==="last")k.reverse();else if(C==="prev"||C==="next"){C==="prev"&&k.reverse();const M=k.indexOf(S.currentTarget);k=f.loop?I3(k,M+1):k.slice(M+1)}setTimeout(()=>Z_(k))}}),children:typeof o=="function"?o({isCurrentTabStop:p,hasTabStop:v!=null}):o})})});Q_.displayName=X_;var k3={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function N3(t,e){return e!=="rtl"?t:t==="ArrowLeft"?"ArrowRight":t==="ArrowRight"?"ArrowLeft":t}function R3(t,e,n){const r=N3(t.key,n);if(!(e==="vertical"&&["ArrowLeft","ArrowRight"].includes(r))&&!(e==="horizontal"&&["ArrowUp","ArrowDown"].includes(r)))return k3[r]}function Z_(t,e=!1){const n=document.activeElement;for(const r of t)if(r===n||(r.focus({preventScroll:e}),document.activeElement!==n))return}function I3(t,e){return t.map((n,r)=>t[(e+r)%t.length])}var O3=q_,M3=Q_,D3=function(t){if(typeof document>"u")return null;var e=Array.isArray(t)?t[0]:t;return e.ownerDocument.body},Fa=new WeakMap,nf=new WeakMap,rf={},vg=0,J_=function(t){return t&&(t.host||J_(t.parentNode))},L3=function(t,e){return e.map(function(n){if(t.contains(n))return n;var r=J_(n);return r&&t.contains(r)?r:(console.error("aria-hidden",n,"in not contained inside",t,". Doing nothing"),null)}).filter(function(n){return!!n})},P3=function(t,e,n,r){var i=L3(e,Array.isArray(t)?t:[t]);rf[n]||(rf[n]=new WeakMap);var s=rf[n],o=[],l=new Set,c=new Set(i),d=function(p){!p||l.has(p)||(l.add(p),d(p.parentNode))};i.forEach(d);var f=function(p){!p||c.has(p)||Array.prototype.forEach.call(p.children,function(m){if(l.has(m))f(m);else try{var g=m.getAttribute(r),x=g!==null&&g!=="false",v=(Fa.get(m)||0)+1,S=(s.get(m)||0)+1;Fa.set(m,v),s.set(m,S),o.push(m),v===1&&x&&nf.set(m,!0),S===1&&m.setAttribute(n,"true"),x||m.setAttribute(r,"true")}catch(C){console.error("aria-hidden: cannot operate on ",m,C)}})};return f(e),l.clear(),vg++,function(){o.forEach(function(p){var m=Fa.get(p)-1,g=s.get(p)-1;Fa.set(p,m),s.set(p,g),m||(nf.has(p)||p.removeAttribute(r),nf.delete(p)),g||p.removeAttribute(n)}),vg--,vg||(Fa=new WeakMap,Fa=new WeakMap,nf=new WeakMap,rf={})}},EE=function(t,e,n){n===void 0&&(n="data-aria-hidden");var r=Array.from(Array.isArray(t)?t:[t]),i=D3(t);return i?(r.push.apply(r,Array.from(i.querySelectorAll("[aria-live], script"))),P3(r,i,n,"aria-hidden")):function(){return null}},ji=function(){return ji=Object.assign||function(e){for(var n,r=1,i=arguments.length;r"u")return J3;var e=e6(t),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:e[0],top:e[1],right:e[2],gap:Math.max(0,r-n+e[2]-e[0])}},n6=rC(),il="data-scroll-locked",r6=function(t,e,n,r){var i=t.left,s=t.top,o=t.right,l=t.gap;return n===void 0&&(n="margin"),` + .`.concat(B3,` { + overflow: hidden `).concat(r,`; + padding-right: `).concat(l,"px ").concat(r,`; + } + body[`).concat(il,`] { + overflow: hidden `).concat(r,`; + overscroll-behavior: contain; + `).concat([e&&"position: relative ".concat(r,";"),n==="margin"&&` + padding-left: `.concat(i,`px; + padding-top: `).concat(s,`px; + padding-right: `).concat(o,`px; + margin-left:0; + margin-top:0; + margin-right: `).concat(l,"px ").concat(r,`; + `),n==="padding"&&"padding-right: ".concat(l,"px ").concat(r,";")].filter(Boolean).join(""),` + } + + .`).concat(Pf,` { + right: `).concat(l,"px ").concat(r,`; + } + + .`).concat(Ff,` { + margin-right: `).concat(l,"px ").concat(r,`; + } + + .`).concat(Pf," .").concat(Pf,` { + right: 0 `).concat(r,`; + } + + .`).concat(Ff," .").concat(Ff,` { + margin-right: 0 `).concat(r,`; + } + + body[`).concat(il,`] { + `).concat(U3,": ").concat(l,`px; + } +`)},Hv=function(){var t=parseInt(document.body.getAttribute(il)||"0",10);return isFinite(t)?t:0},i6=function(){T.useEffect(function(){return document.body.setAttribute(il,(Hv()+1).toString()),function(){var t=Hv()-1;t<=0?document.body.removeAttribute(il):document.body.setAttribute(il,t.toString())}},[])},s6=function(t){var e=t.noRelative,n=t.noImportant,r=t.gapMode,i=r===void 0?"margin":r;i6();var s=T.useMemo(function(){return t6(i)},[i]);return T.createElement(n6,{styles:r6(s,!e,i,n?"":"!important")})},L0=!1;if(typeof window<"u")try{var sf=Object.defineProperty({},"passive",{get:function(){return L0=!0,!0}});window.addEventListener("test",sf,sf),window.removeEventListener("test",sf,sf)}catch{L0=!1}var Ba=L0?{passive:!1}:!1,o6=function(t){return t.tagName==="TEXTAREA"},iC=function(t,e){if(!(t instanceof Element))return!1;var n=window.getComputedStyle(t);return n[e]!=="hidden"&&!(n.overflowY===n.overflowX&&!o6(t)&&n[e]==="visible")},a6=function(t){return iC(t,"overflowY")},l6=function(t){return iC(t,"overflowX")},zv=function(t,e){var n=e.ownerDocument,r=e;do{typeof ShadowRoot<"u"&&r instanceof ShadowRoot&&(r=r.host);var i=sC(t,r);if(i){var s=oC(t,r),o=s[1],l=s[2];if(o>l)return!0}r=r.parentNode}while(r&&r!==n.body);return!1},u6=function(t){var e=t.scrollTop,n=t.scrollHeight,r=t.clientHeight;return[e,n,r]},c6=function(t){var e=t.scrollLeft,n=t.scrollWidth,r=t.clientWidth;return[e,n,r]},sC=function(t,e){return t==="v"?a6(e):l6(e)},oC=function(t,e){return t==="v"?u6(e):c6(e)},d6=function(t,e){return t==="h"&&e==="rtl"?-1:1},f6=function(t,e,n,r,i){var s=d6(t,window.getComputedStyle(e).direction),o=s*r,l=n.target,c=e.contains(l),d=!1,f=o>0,p=0,m=0;do{if(!l)break;var g=oC(t,l),x=g[0],v=g[1],S=g[2],C=v-S-s*x;(x||C)&&sC(t,l)&&(p+=C,m+=x);var A=l.parentNode;l=A&&A.nodeType===Node.DOCUMENT_FRAGMENT_NODE?A.host:A}while(!c&&l!==document.body||c&&(e.contains(l)||e===l));return(f&&Math.abs(p)<1||!f&&Math.abs(m)<1)&&(d=!0),d},of=function(t){return"changedTouches"in t?[t.changedTouches[0].clientX,t.changedTouches[0].clientY]:[0,0]},jv=function(t){return[t.deltaX,t.deltaY]},$v=function(t){return t&&"current"in t?t.current:t},h6=function(t,e){return t[0]===e[0]&&t[1]===e[1]},p6=function(t){return` + .block-interactivity-`.concat(t,` {pointer-events: none;} + .allow-interactivity-`).concat(t,` {pointer-events: all;} +`)},m6=0,Ua=[];function g6(t){var e=T.useRef([]),n=T.useRef([0,0]),r=T.useRef(),i=T.useState(m6++)[0],s=T.useState(rC)[0],o=T.useRef(t);T.useEffect(function(){o.current=t},[t]),T.useEffect(function(){if(t.inert){document.body.classList.add("block-interactivity-".concat(i));var v=F3([t.lockRef.current],(t.shards||[]).map($v),!0).filter(Boolean);return v.forEach(function(S){return S.classList.add("allow-interactivity-".concat(i))}),function(){document.body.classList.remove("block-interactivity-".concat(i)),v.forEach(function(S){return S.classList.remove("allow-interactivity-".concat(i))})}}},[t.inert,t.lockRef.current,t.shards]);var l=T.useCallback(function(v,S){if("touches"in v&&v.touches.length===2||v.type==="wheel"&&v.ctrlKey)return!o.current.allowPinchZoom;var C=of(v),A=n.current,k="deltaX"in v?v.deltaX:A[0]-C[0],M="deltaY"in v?v.deltaY:A[1]-C[1],F,I=v.target,D=Math.abs(k)>Math.abs(M)?"h":"v";if("touches"in v&&D==="h"&&I.type==="range")return!1;var G=zv(D,I);if(!G)return!0;if(G?F=D:(F=D==="v"?"h":"v",G=zv(D,I)),!G)return!1;if(!r.current&&"changedTouches"in v&&(k||M)&&(r.current=F),!F)return!0;var X=r.current||F;return f6(X,S,v,X==="h"?k:M)},[]),c=T.useCallback(function(v){var S=v;if(!(!Ua.length||Ua[Ua.length-1]!==s)){var C="deltaY"in S?jv(S):of(S),A=e.current.filter(function(F){return F.name===S.type&&(F.target===S.target||S.target===F.shadowParent)&&h6(F.delta,C)})[0];if(A&&A.should){S.cancelable&&S.preventDefault();return}if(!A){var k=(o.current.shards||[]).map($v).filter(Boolean).filter(function(F){return F.contains(S.target)}),M=k.length>0?l(S,k[0]):!o.current.noIsolation;M&&S.cancelable&&S.preventDefault()}}},[]),d=T.useCallback(function(v,S,C,A){var k={name:v,delta:S,target:C,should:A,shadowParent:b6(C)};e.current.push(k),setTimeout(function(){e.current=e.current.filter(function(M){return M!==k})},1)},[]),f=T.useCallback(function(v){n.current=of(v),r.current=void 0},[]),p=T.useCallback(function(v){d(v.type,jv(v),v.target,l(v,t.lockRef.current))},[]),m=T.useCallback(function(v){d(v.type,of(v),v.target,l(v,t.lockRef.current))},[]);T.useEffect(function(){return Ua.push(s),t.setCallbacks({onScrollCapture:p,onWheelCapture:p,onTouchMoveCapture:m}),document.addEventListener("wheel",c,Ba),document.addEventListener("touchmove",c,Ba),document.addEventListener("touchstart",f,Ba),function(){Ua=Ua.filter(function(v){return v!==s}),document.removeEventListener("wheel",c,Ba),document.removeEventListener("touchmove",c,Ba),document.removeEventListener("touchstart",f,Ba)}},[]);var g=t.removeScrollBar,x=t.inert;return T.createElement(T.Fragment,null,x?T.createElement(s,{styles:p6(i)}):null,g?T.createElement(s6,{noRelative:t.noRelative,gapMode:t.gapMode}):null)}function b6(t){for(var e=null;t!==null;)t instanceof ShadowRoot&&(e=t.host,t=t.host),t=t.parentNode;return e}const E6=G3(nC,g6);var Gh=T.forwardRef(function(t,e){return T.createElement(Vh,ji({},t,{ref:e,sideCar:E6}))});Gh.classNames=Vh.classNames;var P0=["Enter"," "],y6=["ArrowDown","PageUp","Home"],aC=["ArrowUp","PageDown","End"],x6=[...y6,...aC],v6={ltr:[...P0,"ArrowRight"],rtl:[...P0,"ArrowLeft"]},w6={ltr:["ArrowLeft"],rtl:["ArrowRight"]},Ic="Menu",[uc,T6,S6]=mE(Ic),[ia,lC]=Cs(Ic,[S6,Il,Y_]),Kh=Il(),uC=Y_(),[_6,sa]=ia(Ic),[C6,Oc]=ia(Ic),cC=t=>{const{__scopeMenu:e,open:n=!1,children:r,dir:i,onOpenChange:s,modal:o=!0}=t,l=Kh(e),[c,d]=T.useState(null),f=T.useRef(!1),p=Yi(s),m=gE(i);return T.useEffect(()=>{const g=()=>{f.current=!0,document.addEventListener("pointerdown",x,{capture:!0,once:!0}),document.addEventListener("pointermove",x,{capture:!0,once:!0})},x=()=>f.current=!1;return document.addEventListener("keydown",g,{capture:!0}),()=>{document.removeEventListener("keydown",g,{capture:!0}),document.removeEventListener("pointerdown",x,{capture:!0}),document.removeEventListener("pointermove",x,{capture:!0})}},[]),w.jsx(cE,{...l,children:w.jsx(_6,{scope:e,open:n,onOpenChange:p,content:c,onContentChange:d,children:w.jsx(C6,{scope:e,onClose:T.useCallback(()=>p(!1),[p]),isUsingKeyboardRef:f,dir:m,modal:o,children:r})})})};cC.displayName=Ic;var A6="MenuAnchor",yE=T.forwardRef((t,e)=>{const{__scopeMenu:n,...r}=t,i=Kh(n);return w.jsx(dE,{...i,...r,ref:e})});yE.displayName=A6;var xE="MenuPortal",[k6,dC]=ia(xE,{forceMount:void 0}),fC=t=>{const{__scopeMenu:e,forceMount:n,children:r,container:i}=t,s=sa(xE,e);return w.jsx(k6,{scope:e,forceMount:n,children:w.jsx(Zi,{present:n||s.open,children:w.jsx(Hh,{asChild:!0,container:i,children:r})})})};fC.displayName=xE;var ri="MenuContent",[N6,vE]=ia(ri),hC=T.forwardRef((t,e)=>{const n=dC(ri,t.__scopeMenu),{forceMount:r=n.forceMount,...i}=t,s=sa(ri,t.__scopeMenu),o=Oc(ri,t.__scopeMenu);return w.jsx(uc.Provider,{scope:t.__scopeMenu,children:w.jsx(Zi,{present:r||s.open,children:w.jsx(uc.Slot,{scope:t.__scopeMenu,children:o.modal?w.jsx(R6,{...i,ref:e}):w.jsx(I6,{...i,ref:e})})})})}),R6=T.forwardRef((t,e)=>{const n=sa(ri,t.__scopeMenu),r=T.useRef(null),i=Pt(e,r);return T.useEffect(()=>{const s=r.current;if(s)return EE(s)},[]),w.jsx(wE,{...t,ref:i,trapFocus:n.open,disableOutsidePointerEvents:n.open,disableOutsideScroll:!0,onFocusOutside:je(t.onFocusOutside,s=>s.preventDefault(),{checkForDefaultPrevented:!1}),onDismiss:()=>n.onOpenChange(!1)})}),I6=T.forwardRef((t,e)=>{const n=sa(ri,t.__scopeMenu);return w.jsx(wE,{...t,ref:e,trapFocus:!1,disableOutsidePointerEvents:!1,disableOutsideScroll:!1,onDismiss:()=>n.onOpenChange(!1)})}),O6=Go("MenuContent.ScrollLock"),wE=T.forwardRef((t,e)=>{const{__scopeMenu:n,loop:r=!1,trapFocus:i,onOpenAutoFocus:s,onCloseAutoFocus:o,disableOutsidePointerEvents:l,onEntryFocus:c,onEscapeKeyDown:d,onPointerDownOutside:f,onFocusOutside:p,onInteractOutside:m,onDismiss:g,disableOutsideScroll:x,...v}=t,S=sa(ri,n),C=Oc(ri,n),A=Kh(n),k=uC(n),M=T6(n),[F,I]=T.useState(null),D=T.useRef(null),G=Pt(e,D,S.onContentChange),X=T.useRef(0),P=T.useRef(""),Y=T.useRef(0),z=T.useRef(null),ie=T.useRef("right"),Z=T.useRef(0),ee=x?Gh:T.Fragment,ae=x?{as:O6,allowPinchZoom:!0}:void 0,de=W=>{const O=P.current+W,U=M().filter(J=>!J.disabled),Q=document.activeElement,R=U.find(J=>J.ref.current===Q)?.textValue,oe=U.map(J=>J.textValue),pe=W6(oe,O,R),ue=U.find(J=>J.textValue===pe)?.ref.current;(function J(he){P.current=he,window.clearTimeout(X.current),he!==""&&(X.current=window.setTimeout(()=>J(""),1e3))})(O),ue&&setTimeout(()=>ue.focus())};T.useEffect(()=>()=>window.clearTimeout(X.current),[]),bE();const j=T.useCallback(W=>ie.current===z.current?.side&&G6(W,z.current?.area),[]);return w.jsx(N6,{scope:n,searchRef:P,onItemEnter:T.useCallback(W=>{j(W)&&W.preventDefault()},[j]),onItemLeave:T.useCallback(W=>{j(W)||(D.current?.focus(),I(null))},[j]),onTriggerLeave:T.useCallback(W=>{j(W)&&W.preventDefault()},[j]),pointerGraceTimerRef:Y,onPointerGraceIntentChange:T.useCallback(W=>{z.current=W},[]),children:w.jsx(ee,{...ae,children:w.jsx(Wh,{asChild:!0,trapped:i,onMountAutoFocus:je(s,W=>{W.preventDefault(),D.current?.focus({preventScroll:!0})}),onUnmountAutoFocus:o,children:w.jsx(kc,{asChild:!0,disableOutsidePointerEvents:l,onEscapeKeyDown:d,onPointerDownOutside:f,onFocusOutside:p,onInteractOutside:m,onDismiss:g,children:w.jsx(O3,{asChild:!0,...k,dir:C.dir,orientation:"vertical",loop:r,currentTabStopId:F,onCurrentTabStopIdChange:I,onEntryFocus:je(c,W=>{C.isUsingKeyboardRef.current||W.preventDefault()}),preventScrollOnEntryFocus:!0,children:w.jsx(fE,{role:"menu","aria-orientation":"vertical","data-state":NC(S.open),"data-radix-menu-content":"",dir:C.dir,...A,...v,ref:G,style:{outline:"none",...v.style},onKeyDown:je(v.onKeyDown,W=>{const U=W.target.closest("[data-radix-menu-content]")===W.currentTarget,Q=W.ctrlKey||W.altKey||W.metaKey,R=W.key.length===1;U&&(W.key==="Tab"&&W.preventDefault(),!Q&&R&&de(W.key));const oe=D.current;if(W.target!==oe||!x6.includes(W.key))return;W.preventDefault();const ue=M().filter(J=>!J.disabled).map(J=>J.ref.current);aC.includes(W.key)&&ue.reverse(),j6(ue)}),onBlur:je(t.onBlur,W=>{W.currentTarget.contains(W.target)||(window.clearTimeout(X.current),P.current="")}),onPointerMove:je(t.onPointerMove,cc(W=>{const O=W.target,U=Z.current!==W.clientX;if(W.currentTarget.contains(O)&&U){const Q=W.clientX>Z.current?"right":"left";ie.current=Q,Z.current=W.clientX}}))})})})})})})});hC.displayName=ri;var M6="MenuGroup",TE=T.forwardRef((t,e)=>{const{__scopeMenu:n,...r}=t;return w.jsx(xt.div,{role:"group",...r,ref:e})});TE.displayName=M6;var D6="MenuLabel",pC=T.forwardRef((t,e)=>{const{__scopeMenu:n,...r}=t;return w.jsx(xt.div,{...r,ref:e})});pC.displayName=D6;var th="MenuItem",Wv="menu.itemSelect",Yh=T.forwardRef((t,e)=>{const{disabled:n=!1,onSelect:r,...i}=t,s=T.useRef(null),o=Oc(th,t.__scopeMenu),l=vE(th,t.__scopeMenu),c=Pt(e,s),d=T.useRef(!1),f=()=>{const p=s.current;if(!n&&p){const m=new CustomEvent(Wv,{bubbles:!0,cancelable:!0});p.addEventListener(Wv,g=>r?.(g),{once:!0}),u_(p,m),m.defaultPrevented?d.current=!1:o.onClose()}};return w.jsx(mC,{...i,ref:c,disabled:n,onClick:je(t.onClick,f),onPointerDown:p=>{t.onPointerDown?.(p),d.current=!0},onPointerUp:je(t.onPointerUp,p=>{d.current||p.currentTarget?.click()}),onKeyDown:je(t.onKeyDown,p=>{const m=l.searchRef.current!=="";n||m&&p.key===" "||P0.includes(p.key)&&(p.currentTarget.click(),p.preventDefault())})})});Yh.displayName=th;var mC=T.forwardRef((t,e)=>{const{__scopeMenu:n,disabled:r=!1,textValue:i,...s}=t,o=vE(th,n),l=uC(n),c=T.useRef(null),d=Pt(e,c),[f,p]=T.useState(!1),[m,g]=T.useState("");return T.useEffect(()=>{const x=c.current;x&&g((x.textContent??"").trim())},[s.children]),w.jsx(uc.ItemSlot,{scope:n,disabled:r,textValue:i??m,children:w.jsx(M3,{asChild:!0,...l,focusable:!r,children:w.jsx(xt.div,{role:"menuitem","data-highlighted":f?"":void 0,"aria-disabled":r||void 0,"data-disabled":r?"":void 0,...s,ref:d,onPointerMove:je(t.onPointerMove,cc(x=>{r?o.onItemLeave(x):(o.onItemEnter(x),x.defaultPrevented||x.currentTarget.focus({preventScroll:!0}))})),onPointerLeave:je(t.onPointerLeave,cc(x=>o.onItemLeave(x))),onFocus:je(t.onFocus,()=>p(!0)),onBlur:je(t.onBlur,()=>p(!1))})})})}),L6="MenuCheckboxItem",gC=T.forwardRef((t,e)=>{const{checked:n=!1,onCheckedChange:r,...i}=t;return w.jsx(vC,{scope:t.__scopeMenu,checked:n,children:w.jsx(Yh,{role:"menuitemcheckbox","aria-checked":nh(n)?"mixed":n,...i,ref:e,"data-state":_E(n),onSelect:je(i.onSelect,()=>r?.(nh(n)?!0:!n),{checkForDefaultPrevented:!1})})})});gC.displayName=L6;var bC="MenuRadioGroup",[P6,F6]=ia(bC,{value:void 0,onValueChange:()=>{}}),EC=T.forwardRef((t,e)=>{const{value:n,onValueChange:r,...i}=t,s=Yi(r);return w.jsx(P6,{scope:t.__scopeMenu,value:n,onValueChange:s,children:w.jsx(TE,{...i,ref:e})})});EC.displayName=bC;var yC="MenuRadioItem",xC=T.forwardRef((t,e)=>{const{value:n,...r}=t,i=F6(yC,t.__scopeMenu),s=n===i.value;return w.jsx(vC,{scope:t.__scopeMenu,checked:s,children:w.jsx(Yh,{role:"menuitemradio","aria-checked":s,...r,ref:e,"data-state":_E(s),onSelect:je(r.onSelect,()=>i.onValueChange?.(n),{checkForDefaultPrevented:!1})})})});xC.displayName=yC;var SE="MenuItemIndicator",[vC,B6]=ia(SE,{checked:!1}),wC=T.forwardRef((t,e)=>{const{__scopeMenu:n,forceMount:r,...i}=t,s=B6(SE,n);return w.jsx(Zi,{present:r||nh(s.checked)||s.checked===!0,children:w.jsx(xt.span,{...i,ref:e,"data-state":_E(s.checked)})})});wC.displayName=SE;var U6="MenuSeparator",TC=T.forwardRef((t,e)=>{const{__scopeMenu:n,...r}=t;return w.jsx(xt.div,{role:"separator","aria-orientation":"horizontal",...r,ref:e})});TC.displayName=U6;var H6="MenuArrow",SC=T.forwardRef((t,e)=>{const{__scopeMenu:n,...r}=t,i=Kh(n);return w.jsx(hE,{...i,...r,ref:e})});SC.displayName=H6;var z6="MenuSub",[BX,_C]=ia(z6),Fu="MenuSubTrigger",CC=T.forwardRef((t,e)=>{const n=sa(Fu,t.__scopeMenu),r=Oc(Fu,t.__scopeMenu),i=_C(Fu,t.__scopeMenu),s=vE(Fu,t.__scopeMenu),o=T.useRef(null),{pointerGraceTimerRef:l,onPointerGraceIntentChange:c}=s,d={__scopeMenu:t.__scopeMenu},f=T.useCallback(()=>{o.current&&window.clearTimeout(o.current),o.current=null},[]);return T.useEffect(()=>f,[f]),T.useEffect(()=>{const p=l.current;return()=>{window.clearTimeout(p),c(null)}},[l,c]),w.jsx(yE,{asChild:!0,...d,children:w.jsx(mC,{id:i.triggerId,"aria-haspopup":"menu","aria-expanded":n.open,"aria-controls":i.contentId,"data-state":NC(n.open),...t,ref:Ph(e,i.onTriggerChange),onClick:p=>{t.onClick?.(p),!(t.disabled||p.defaultPrevented)&&(p.currentTarget.focus(),n.open||n.onOpenChange(!0))},onPointerMove:je(t.onPointerMove,cc(p=>{s.onItemEnter(p),!p.defaultPrevented&&!t.disabled&&!n.open&&!o.current&&(s.onPointerGraceIntentChange(null),o.current=window.setTimeout(()=>{n.onOpenChange(!0),f()},100))})),onPointerLeave:je(t.onPointerLeave,cc(p=>{f();const m=n.content?.getBoundingClientRect();if(m){const g=n.content?.dataset.side,x=g==="right",v=x?-5:5,S=m[x?"left":"right"],C=m[x?"right":"left"];s.onPointerGraceIntentChange({area:[{x:p.clientX+v,y:p.clientY},{x:S,y:m.top},{x:C,y:m.top},{x:C,y:m.bottom},{x:S,y:m.bottom}],side:g}),window.clearTimeout(l.current),l.current=window.setTimeout(()=>s.onPointerGraceIntentChange(null),300)}else{if(s.onTriggerLeave(p),p.defaultPrevented)return;s.onPointerGraceIntentChange(null)}})),onKeyDown:je(t.onKeyDown,p=>{const m=s.searchRef.current!=="";t.disabled||m&&p.key===" "||v6[r.dir].includes(p.key)&&(n.onOpenChange(!0),n.content?.focus(),p.preventDefault())})})})});CC.displayName=Fu;var AC="MenuSubContent",kC=T.forwardRef((t,e)=>{const n=dC(ri,t.__scopeMenu),{forceMount:r=n.forceMount,...i}=t,s=sa(ri,t.__scopeMenu),o=Oc(ri,t.__scopeMenu),l=_C(AC,t.__scopeMenu),c=T.useRef(null),d=Pt(e,c);return w.jsx(uc.Provider,{scope:t.__scopeMenu,children:w.jsx(Zi,{present:r||s.open,children:w.jsx(uc.Slot,{scope:t.__scopeMenu,children:w.jsx(wE,{id:l.contentId,"aria-labelledby":l.triggerId,...i,ref:d,align:"start",side:o.dir==="rtl"?"left":"right",disableOutsidePointerEvents:!1,disableOutsideScroll:!1,trapFocus:!1,onOpenAutoFocus:f=>{o.isUsingKeyboardRef.current&&c.current?.focus(),f.preventDefault()},onCloseAutoFocus:f=>f.preventDefault(),onFocusOutside:je(t.onFocusOutside,f=>{f.target!==l.trigger&&s.onOpenChange(!1)}),onEscapeKeyDown:je(t.onEscapeKeyDown,f=>{o.onClose(),f.preventDefault()}),onKeyDown:je(t.onKeyDown,f=>{const p=f.currentTarget.contains(f.target),m=w6[o.dir].includes(f.key);p&&m&&(s.onOpenChange(!1),l.trigger?.focus(),f.preventDefault())})})})})})});kC.displayName=AC;function NC(t){return t?"open":"closed"}function nh(t){return t==="indeterminate"}function _E(t){return nh(t)?"indeterminate":t?"checked":"unchecked"}function j6(t){const e=document.activeElement;for(const n of t)if(n===e||(n.focus(),document.activeElement!==e))return}function $6(t,e){return t.map((n,r)=>t[(e+r)%t.length])}function W6(t,e,n){const i=e.length>1&&Array.from(e).every(d=>d===e[0])?e[0]:e,s=n?t.indexOf(n):-1;let o=$6(t,Math.max(s,0));i.length===1&&(o=o.filter(d=>d!==n));const c=o.find(d=>d.toLowerCase().startsWith(i.toLowerCase()));return c!==n?c:void 0}function V6(t,e){const{x:n,y:r}=t;let i=!1;for(let s=0,o=e.length-1;sr!=m>r&&n<(p-d)*(r-f)/(m-f)+d&&(i=!i)}return i}function G6(t,e){if(!e)return!1;const n={x:t.clientX,y:t.clientY};return V6(n,e)}function cc(t){return e=>e.pointerType==="mouse"?t(e):void 0}var K6=cC,Y6=yE,q6=fC,X6=hC,Q6=TE,Z6=pC,J6=Yh,e4=gC,t4=EC,n4=xC,r4=wC,i4=TC,s4=SC,o4=CC,a4=kC,qh="DropdownMenu",[l4]=Cs(qh,[lC]),xr=lC(),[u4,RC]=l4(qh),IC=t=>{const{__scopeDropdownMenu:e,children:n,dir:r,open:i,defaultOpen:s,onOpenChange:o,modal:l=!0}=t,c=xr(e),d=T.useRef(null),[f,p]=Yo({prop:i,defaultProp:s??!1,onChange:o,caller:qh});return w.jsx(u4,{scope:e,triggerId:Gi(),triggerRef:d,contentId:Gi(),open:f,onOpenChange:p,onOpenToggle:T.useCallback(()=>p(m=>!m),[p]),modal:l,children:w.jsx(K6,{...c,open:f,onOpenChange:p,dir:r,modal:l,children:n})})};IC.displayName=qh;var OC="DropdownMenuTrigger",MC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,disabled:r=!1,...i}=t,s=RC(OC,n),o=xr(n);return w.jsx(Y6,{asChild:!0,...o,children:w.jsx(xt.button,{type:"button",id:s.triggerId,"aria-haspopup":"menu","aria-expanded":s.open,"aria-controls":s.open?s.contentId:void 0,"data-state":s.open?"open":"closed","data-disabled":r?"":void 0,disabled:r,...i,ref:Ph(e,s.triggerRef),onPointerDown:je(t.onPointerDown,l=>{!r&&l.button===0&&l.ctrlKey===!1&&(s.onOpenToggle(),s.open||l.preventDefault())}),onKeyDown:je(t.onKeyDown,l=>{r||(["Enter"," "].includes(l.key)&&s.onOpenToggle(),l.key==="ArrowDown"&&s.onOpenChange(!0),["Enter"," ","ArrowDown"].includes(l.key)&&l.preventDefault())})})})});MC.displayName=OC;var c4="DropdownMenuPortal",DC=t=>{const{__scopeDropdownMenu:e,...n}=t,r=xr(e);return w.jsx(q6,{...r,...n})};DC.displayName=c4;var LC="DropdownMenuContent",PC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=RC(LC,n),s=xr(n),o=T.useRef(!1);return w.jsx(X6,{id:i.contentId,"aria-labelledby":i.triggerId,...s,...r,ref:e,onCloseAutoFocus:je(t.onCloseAutoFocus,l=>{o.current||i.triggerRef.current?.focus(),o.current=!1,l.preventDefault()}),onInteractOutside:je(t.onInteractOutside,l=>{const c=l.detail.originalEvent,d=c.button===0&&c.ctrlKey===!0,f=c.button===2||d;(!i.modal||f)&&(o.current=!0)}),style:{...t.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});PC.displayName=LC;var d4="DropdownMenuGroup",f4=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(Q6,{...i,...r,ref:e})});f4.displayName=d4;var h4="DropdownMenuLabel",FC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(Z6,{...i,...r,ref:e})});FC.displayName=h4;var p4="DropdownMenuItem",BC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(J6,{...i,...r,ref:e})});BC.displayName=p4;var m4="DropdownMenuCheckboxItem",UC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(e4,{...i,...r,ref:e})});UC.displayName=m4;var g4="DropdownMenuRadioGroup",b4=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(t4,{...i,...r,ref:e})});b4.displayName=g4;var E4="DropdownMenuRadioItem",HC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(n4,{...i,...r,ref:e})});HC.displayName=E4;var y4="DropdownMenuItemIndicator",zC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(r4,{...i,...r,ref:e})});zC.displayName=y4;var x4="DropdownMenuSeparator",jC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(i4,{...i,...r,ref:e})});jC.displayName=x4;var v4="DropdownMenuArrow",w4=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(s4,{...i,...r,ref:e})});w4.displayName=v4;var T4="DropdownMenuSubTrigger",$C=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(o4,{...i,...r,ref:e})});$C.displayName=T4;var S4="DropdownMenuSubContent",WC=T.forwardRef((t,e)=>{const{__scopeDropdownMenu:n,...r}=t,i=xr(n);return w.jsx(a4,{...i,...r,ref:e,style:{...t.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});WC.displayName=S4;var _4=IC,C4=MC,A4=DC,VC=PC,GC=FC,KC=BC,YC=UC,qC=HC,XC=zC,QC=jC,ZC=$C,JC=WC;const k4=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),eA=(...t)=>t.filter((e,n,r)=>!!e&&r.indexOf(e)===n).join(" ");var N4={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"};const R4=T.forwardRef(({color:t="currentColor",size:e=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:i="",children:s,iconNode:o,...l},c)=>T.createElement("svg",{ref:c,...N4,width:e,height:e,stroke:t,strokeWidth:r?Number(n)*24/Number(e):n,className:eA("lucide",i),...l},[...o.map(([d,f])=>T.createElement(d,f)),...Array.isArray(s)?s:[s]]));const Kr=(t,e)=>{const n=T.forwardRef(({className:r,...i},s)=>T.createElement(R4,{ref:s,iconNode:e,className:eA(`lucide-${k4(t)}`,r),...i}));return n.displayName=`${t}`,n};const CE=Kr("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);const tA=Kr("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);const I4=Kr("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const O4=Kr("ChevronUp",[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]]);const M4=Kr("Circle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);const D4=Kr("EyeOff",[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]]);const L4=Kr("Eye",[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);const nA=Kr("Flag",[["path",{d:"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z",key:"i9b6wo"}],["line",{x1:"4",x2:"4",y1:"22",y2:"15",key:"1cm3nv"}]]);const P4=Kr("Menu",[["line",{x1:"4",x2:"20",y1:"12",y2:"12",key:"1e0a9i"}],["line",{x1:"4",x2:"20",y1:"6",y2:"6",key:"1owob3"}],["line",{x1:"4",x2:"20",y1:"18",y2:"18",key:"yk5zj1"}]]);const F4=Kr("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);const B4=Kr("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);const Vv=Kr("ShieldEllipsis",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M8 12h.01",key:"czm47f"}],["path",{d:"M12 12h.01",key:"1mp3jc"}],["path",{d:"M16 12h.01",key:"1l6xoz"}]]);const gl=Kr("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]),rA=_4,iA=C4,U4=T.forwardRef(({className:t,inset:e,children:n,...r},i)=>w.jsxs(ZC,{ref:i,className:Rt("flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",e&&"pl-8",t),...r,children:[n,w.jsx(I4,{className:"ml-auto h-4 w-4"})]}));U4.displayName=ZC.displayName;const H4=T.forwardRef(({className:t,...e},n)=>w.jsx(JC,{ref:n,className:Rt("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",t),...e}));H4.displayName=JC.displayName;const AE=T.forwardRef(({className:t,sideOffset:e=4,...n},r)=>w.jsx(A4,{children:w.jsx(VC,{ref:r,sideOffset:e,className:Rt("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",t),...n})}));AE.displayName=VC.displayName;const rh=T.forwardRef(({className:t,inset:e,...n},r)=>w.jsx(KC,{ref:r,className:Rt("relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",e&&"pl-8",t),...n}));rh.displayName=KC.displayName;const z4=T.forwardRef(({className:t,children:e,checked:n,...r},i)=>w.jsxs(YC,{ref:i,className:Rt("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),checked:n,...r,children:[w.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:w.jsx(XC,{children:w.jsx(CE,{className:"h-4 w-4"})})}),e]}));z4.displayName=YC.displayName;const j4=T.forwardRef(({className:t,children:e,...n},r)=>w.jsxs(qC,{ref:r,className:Rt("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),...n,children:[w.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:w.jsx(XC,{children:w.jsx(M4,{className:"h-2 w-2 fill-current"})})}),e]}));j4.displayName=qC.displayName;const $4=T.forwardRef(({className:t,inset:e,...n},r)=>w.jsx(GC,{ref:r,className:Rt("px-2 py-1.5 text-sm font-semibold",e&&"pl-8",t),...n}));$4.displayName=GC.displayName;const W4=T.forwardRef(({className:t,...e},n)=>w.jsx(QC,{ref:n,className:Rt("-mx-1 my-1 h-px bg-muted",t),...e}));W4.displayName=QC.displayName;const sA=t=>{t=new Date(t);const e={year:"numeric",month:"long",day:"numeric"};return t.toLocaleDateString("en-US",e)},V4=t=>{t=new Date(t);const e={hour:"2-digit",minute:"2-digit",hour12:!1};return t.toLocaleTimeString("en-US",e)},G4="_editSession_1nfqv_1",K4={editSession:G4},vs=t=>{(t.key==="Enter"||t.key===" ")&&t.target.click()};function Y4(t){const e=t.getBoundingClientRect();return window.innerWidth-e.right}var Xh="Dialog",[oA]=Cs(Xh),[q4,Ai]=oA(Xh),aA=t=>{const{__scopeDialog:e,children:n,open:r,defaultOpen:i,onOpenChange:s,modal:o=!0}=t,l=T.useRef(null),c=T.useRef(null),[d,f]=Yo({prop:r,defaultProp:i??!1,onChange:s,caller:Xh});return w.jsx(q4,{scope:e,triggerRef:l,contentRef:c,contentId:Gi(),titleId:Gi(),descriptionId:Gi(),open:d,onOpenChange:f,onOpenToggle:T.useCallback(()=>f(p=>!p),[f]),modal:o,children:n})};aA.displayName=Xh;var lA="DialogTrigger",uA=T.forwardRef((t,e)=>{const{__scopeDialog:n,...r}=t,i=Ai(lA,n),s=Pt(e,i.triggerRef);return w.jsx(xt.button,{type:"button","aria-haspopup":"dialog","aria-expanded":i.open,"aria-controls":i.contentId,"data-state":OE(i.open),...r,ref:s,onClick:je(t.onClick,i.onOpenToggle)})});uA.displayName=lA;var kE="DialogPortal",[X4,cA]=oA(kE,{forceMount:void 0}),dA=t=>{const{__scopeDialog:e,forceMount:n,children:r,container:i}=t,s=Ai(kE,e);return w.jsx(X4,{scope:e,forceMount:n,children:T.Children.map(r,o=>w.jsx(Zi,{present:n||s.open,children:w.jsx(Hh,{asChild:!0,container:i,children:o})}))})};dA.displayName=kE;var ih="DialogOverlay",fA=T.forwardRef((t,e)=>{const n=cA(ih,t.__scopeDialog),{forceMount:r=n.forceMount,...i}=t,s=Ai(ih,t.__scopeDialog);return s.modal?w.jsx(Zi,{present:r||s.open,children:w.jsx(Z4,{...i,ref:e})}):null});fA.displayName=ih;var Q4=Go("DialogOverlay.RemoveScroll"),Z4=T.forwardRef((t,e)=>{const{__scopeDialog:n,...r}=t,i=Ai(ih,n);return w.jsx(Gh,{as:Q4,allowPinchZoom:!0,shards:[i.contentRef],children:w.jsx(xt.div,{"data-state":OE(i.open),...r,ref:e,style:{pointerEvents:"auto",...r.style}})})}),qo="DialogContent",hA=T.forwardRef((t,e)=>{const n=cA(qo,t.__scopeDialog),{forceMount:r=n.forceMount,...i}=t,s=Ai(qo,t.__scopeDialog);return w.jsx(Zi,{present:r||s.open,children:s.modal?w.jsx(J4,{...i,ref:e}):w.jsx(eF,{...i,ref:e})})});hA.displayName=qo;var J4=T.forwardRef((t,e)=>{const n=Ai(qo,t.__scopeDialog),r=T.useRef(null),i=Pt(e,n.contentRef,r);return T.useEffect(()=>{const s=r.current;if(s)return EE(s)},[]),w.jsx(pA,{...t,ref:i,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:je(t.onCloseAutoFocus,s=>{s.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:je(t.onPointerDownOutside,s=>{const o=s.detail.originalEvent,l=o.button===0&&o.ctrlKey===!0;(o.button===2||l)&&s.preventDefault()}),onFocusOutside:je(t.onFocusOutside,s=>s.preventDefault())})}),eF=T.forwardRef((t,e)=>{const n=Ai(qo,t.__scopeDialog),r=T.useRef(!1),i=T.useRef(!1);return w.jsx(pA,{...t,ref:e,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:s=>{t.onCloseAutoFocus?.(s),s.defaultPrevented||(r.current||n.triggerRef.current?.focus(),s.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:s=>{t.onInteractOutside?.(s),s.defaultPrevented||(r.current=!0,s.detail.originalEvent.type==="pointerdown"&&(i.current=!0));const o=s.target;n.triggerRef.current?.contains(o)&&s.preventDefault(),s.detail.originalEvent.type==="focusin"&&i.current&&s.preventDefault()}})}),pA=T.forwardRef((t,e)=>{const{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:s,...o}=t,l=Ai(qo,n),c=T.useRef(null),d=Pt(e,c);return bE(),w.jsxs(w.Fragment,{children:[w.jsx(Wh,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:s,children:w.jsx(kc,{role:"dialog",id:l.contentId,"aria-describedby":l.descriptionId,"aria-labelledby":l.titleId,"data-state":OE(l.open),...o,ref:d,onDismiss:()=>l.onOpenChange(!1)})}),w.jsxs(w.Fragment,{children:[w.jsx(tF,{titleId:l.titleId}),w.jsx(rF,{contentRef:c,descriptionId:l.descriptionId})]})]})}),NE="DialogTitle",RE=T.forwardRef((t,e)=>{const{__scopeDialog:n,...r}=t,i=Ai(NE,n);return w.jsx(xt.h2,{id:i.titleId,...r,ref:e})});RE.displayName=NE;var mA="DialogDescription",IE=T.forwardRef((t,e)=>{const{__scopeDialog:n,...r}=t,i=Ai(mA,n);return w.jsx(xt.p,{id:i.descriptionId,...r,ref:e})});IE.displayName=mA;var gA="DialogClose",bA=T.forwardRef((t,e)=>{const{__scopeDialog:n,...r}=t,i=Ai(gA,n);return w.jsx(xt.button,{type:"button",...r,ref:e,onClick:je(t.onClick,()=>i.onOpenChange(!1))})});bA.displayName=gA;function OE(t){return t?"open":"closed"}var EA="DialogTitleWarning",[UX,yA]=JD(EA,{contentName:qo,titleName:NE,docsSlug:"dialog"}),tF=({titleId:t})=>{const e=yA(EA),n=`\`${e.contentName}\` requires a \`${e.titleName}\` for the component to be accessible for screen reader users. + +If you want to hide the \`${e.titleName}\`, you can wrap it with our VisuallyHidden component. + +For more information, see https://radix-ui.com/primitives/docs/components/${e.docsSlug}`;return T.useEffect(()=>{t&&(document.getElementById(t)||console.error(n))},[n,t]),null},nF="DialogDescriptionWarning",rF=({contentRef:t,descriptionId:e})=>{const r=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${yA(nF).contentName}}.`;return T.useEffect(()=>{const i=t.current?.getAttribute("aria-describedby");e&&i&&(document.getElementById(e)||console.warn(r))},[r,t,e]),null},xA=aA,vA=uA,wA=dA,Qh=fA,Zh=hA,Jh=RE,ep=IE,ME=bA;const TA=xA,iF=vA,DE=wA,Gv=ME,SA=T.forwardRef(({className:t,...e},n)=>w.jsx(Qh,{ref:n,className:Rt("fixed inset-0 bg-black/80 z-[99] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",t),...e}));SA.displayName=Qh.displayName;const LE=T.forwardRef(({className:t,children:e,...n},r)=>w.jsxs(DE,{children:[w.jsx(SA,{}),w.jsxs(Zh,{ref:r,className:Rt("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",t),...n,children:[e,w.jsxs(ME,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[w.jsx(gl,{className:"h-4 w-4"}),w.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));LE.displayName=Zh.displayName;const PE=({className:t,...e})=>w.jsx("div",{className:Rt("flex flex-col space-y-1.5 text-center sm:text-left",t),...e});PE.displayName="DialogHeader";const FE=T.forwardRef(({className:t,...e},n)=>w.jsx(Jh,{ref:n,className:Rt("text-lg font-semibold leading-none tracking-tight",t),...e}));FE.displayName=Jh.displayName;const BE=T.forwardRef(({className:t,...e},n)=>w.jsx(ep,{ref:n,className:Rt("text-sm text-muted-foreground",t),...e}));BE.displayName=ep.displayName;const Bu={},Kv=(t,e)=>t.unstable_is?t.unstable_is(e):e===t,Yv=t=>"init"in t,_g=t=>!!t.write,qv=t=>"v"in t||"e"in t,af=t=>{if("e"in t)throw t.e;if((Bu?"production":void 0)!=="production"&&!("v"in t))throw new Error("[Bug] atom state is not initialized");return t.v},sh=new WeakMap,Xv=t=>{var e;return oh(t)&&!!((e=sh.get(t))!=null&&e[0])},sF=t=>{const e=sh.get(t);e?.[0]&&(e[0]=!1,e[1].forEach(n=>n()))},_A=(t,e)=>{let n=sh.get(t);if(!n){n=[!0,new Set],sh.set(t,n);const r=()=>{n[0]=!1};t.then(r,r)}n[1].add(e)},oh=t=>typeof t?.then=="function",CA=(t,e,n)=>{n.p.has(t)||(n.p.add(t),e.then(()=>{n.p.delete(t)},()=>{n.p.delete(t)}))},Cg=(t,e,n)=>{const r=n(t),i="v"in r,s=r.v;if(oh(e))for(const o of r.d.keys())CA(t,e,n(o));r.v=e,delete r.e,(!i||!Object.is(s,r.v))&&(++r.n,oh(s)&&sF(s))},Qv=(t,e,n)=>{var r;const i=new Set;for(const s of((r=n.get(t))==null?void 0:r.t)||[])n.has(s)&&i.add(s);for(const s of e.p)i.add(s);return i},oF=()=>{const t=new Set,e=()=>{t.forEach(n=>n())};return e.add=n=>(t.add(n),()=>{t.delete(n)}),e},Ag=()=>{const t={},e=new WeakMap,n=r=>{var i,s;(i=e.get(t))==null||i.forEach(o=>o(r)),(s=e.get(r))==null||s.forEach(o=>o())};return n.add=(r,i)=>{const s=r||t,o=(e.has(s)?e:e.set(s,new Set)).get(s);return o.add(i),()=>{o?.delete(i),o.size||e.delete(s)}},n},aF=t=>(t.c||(t.c=Ag()),t.m||(t.m=Ag()),t.u||(t.u=Ag()),t.f||(t.f=oF()),t),lF=Symbol(),uF=(t=new WeakMap,e=new WeakMap,n=new WeakMap,r=new Set,i=new Set,s=new Set,o={},l=(m,...g)=>m.read(...g),c=(m,...g)=>m.write(...g),d=(m,g)=>{var x;return(x=m.unstable_onInit)==null?void 0:x.call(m,g)},f=(m,g)=>{var x;return(x=m.onMount)==null?void 0:x.call(m,g)},...p)=>{const m=p[0]||(D=>{if((Bu?"production":void 0)!=="production"&&!D)throw new Error("Atom is undefined or null");let G=t.get(D);return G||(G={d:new Map,p:new Set,n:0},t.set(D,G),d?.(D,I)),G}),g=p[1]||(()=>{const D=[],G=X=>{try{X()}catch(P){D.push(P)}};do{o.f&&G(o.f);const X=new Set,P=X.add.bind(X);r.forEach(Y=>{var z;return(z=e.get(Y))==null?void 0:z.l.forEach(P)}),r.clear(),s.forEach(P),s.clear(),i.forEach(P),i.clear(),X.forEach(G),r.size&&x()}while(r.size||s.size||i.size);if(D.length)throw new AggregateError(D)}),x=p[2]||(()=>{const D=[],G=new WeakSet,X=new WeakSet,P=Array.from(r);for(;P.length;){const Y=P[P.length-1],z=m(Y);if(X.has(Y)){P.pop();continue}if(G.has(Y)){if(n.get(Y)===z.n)D.push([Y,z]);else if((Bu?"production":void 0)!=="production"&&n.has(Y))throw new Error("[Bug] invalidated atom exists");X.add(Y),P.pop();continue}G.add(Y);for(const ie of Qv(Y,z,e))G.has(ie)||P.push(ie)}for(let Y=D.length-1;Y>=0;--Y){const[z,ie]=D[Y];let Z=!1;for(const ee of ie.d.keys())if(ee!==z&&r.has(ee)){Z=!0;break}Z&&(v(z),A(z)),n.delete(z)}}),v=p[3]||(D=>{var G;const X=m(D);if(qv(X)&&(e.has(D)&&n.get(D)!==X.n||Array.from(X.d).every(([de,j])=>v(de).n===j)))return X;X.d.clear();let P=!0;const Y=()=>{e.has(D)&&(A(D),x(),g())},z=de=>{var j;if(Kv(D,de)){const O=m(de);if(!qv(O))if(Yv(de))Cg(de,de.init,m);else throw new Error("no atom init");return af(O)}const W=v(de);try{return af(W)}finally{X.d.set(de,W.n),Xv(X.v)&&CA(D,X.v,W),(j=e.get(de))==null||j.t.add(D),P||Y()}};let ie,Z;const ee={get signal(){return ie||(ie=new AbortController),ie.signal},get setSelf(){return(Bu?"production":void 0)!=="production"&&!_g(D)&&console.warn("setSelf function cannot be used with read-only atom"),!Z&&_g(D)&&(Z=(...de)=>{if((Bu?"production":void 0)!=="production"&&P&&console.warn("setSelf function cannot be called in sync"),!P)try{return C(D,...de)}finally{x(),g()}}),Z}},ae=X.n;try{const de=l(D,z,ee);return Cg(D,de,m),oh(de)&&(_A(de,()=>ie?.abort()),de.then(Y,Y)),X}catch(de){return delete X.v,X.e=de,++X.n,X}finally{P=!1,ae!==X.n&&n.get(D)===ae&&(n.set(D,X.n),r.add(D),(G=o.c)==null||G.call(o,D))}}),S=p[4]||(D=>{const G=[D];for(;G.length;){const X=G.pop(),P=m(X);for(const Y of Qv(X,P,e)){const z=m(Y);n.set(Y,z.n),G.push(Y)}}}),C=p[5]||((D,...G)=>{let X=!0;const P=z=>af(v(z)),Y=(z,...ie)=>{var Z;const ee=m(z);try{if(Kv(D,z)){if(!Yv(z))throw new Error("atom not writable");const ae=ee.n,de=ie[0];Cg(z,de,m),A(z),ae!==ee.n&&(r.add(z),(Z=o.c)==null||Z.call(o,z),S(z));return}else return C(z,...ie)}finally{X||(x(),g())}};try{return c(D,P,Y,...G)}finally{X=!1}}),A=p[6]||(D=>{var G;const X=m(D),P=e.get(D);if(P&&!Xv(X.v)){for(const[Y,z]of X.d)if(!P.d.has(Y)){const ie=m(Y);k(Y).t.add(D),P.d.add(Y),z!==ie.n&&(r.add(Y),(G=o.c)==null||G.call(o,Y),S(Y))}for(const Y of P.d||[])if(!X.d.has(Y)){P.d.delete(Y);const z=M(Y);z?.t.delete(D)}}}),k=p[7]||(D=>{var G;const X=m(D);let P=e.get(D);if(!P){v(D);for(const Y of X.d.keys())k(Y).t.add(D);if(P={l:new Set,d:new Set(X.d.keys()),t:new Set},e.set(D,P),(G=o.m)==null||G.call(o,D),_g(D)){const Y=()=>{let z=!0;const ie=(...Z)=>{try{return C(D,...Z)}finally{z||(x(),g())}};try{const Z=f(D,ie);Z&&(P.u=()=>{z=!0;try{Z()}finally{z=!1}})}finally{z=!1}};i.add(Y)}}return P}),M=p[8]||(D=>{var G;const X=m(D);let P=e.get(D);if(P&&!P.l.size&&!Array.from(P.t).some(Y=>{var z;return(z=e.get(Y))==null?void 0:z.d.has(D)})){P.u&&s.add(P.u),P=void 0,e.delete(D),(G=o.u)==null||G.call(o,D);for(const Y of X.d.keys()){const z=M(Y);z?.t.delete(D)}return}return P}),F=[t,e,n,r,i,s,o,l,c,d,f,m,g,x,v,S,C,A,k,M],I={get:D=>af(v(D)),set:(D,...G)=>{try{return C(D,...G)}finally{x(),g()}},sub:(D,G)=>{const P=k(D).l;return P.add(G),g(),()=>{P.delete(G),M(D),g()}}};return Object.defineProperty(I,lF,{value:F}),I},AA=uF,cF=aF,Zv=_A,UE={};let dF=0;function ki(t,e){const n=`atom${++dF}`,r={toString(){return(UE?"production":void 0)!=="production"&&this.debugLabel?n+":"+this.debugLabel:n}};return typeof t=="function"?r.read=t:(r.init=t,r.read=fF,r.write=hF),r}function fF(t){return t(this)}function hF(t,e,n){return e(this,typeof n=="function"?n(t(this)):n)}const pF=()=>{let t=0;const e=cF({}),n=new WeakMap,r=new WeakMap,i=AA(n,r,void 0,void 0,void 0,void 0,e,void 0,(l,c,d,...f)=>t?d(l,...f):l.write(c,d,...f)),s=new Set;return e.m.add(void 0,l=>{s.add(l);const c=n.get(l);c.m=r.get(l)}),e.u.add(void 0,l=>{s.delete(l);const c=n.get(l);delete c.m}),Object.assign(i,{dev4_get_internal_weak_map:()=>(console.log("Deprecated: Use devstore from the devtools library"),n),dev4_get_mounted_atoms:()=>s,dev4_restore_atoms:l=>{const c={read:()=>null,write:(d,f)=>{++t;try{for(const[p,m]of l)"init"in p&&f(p,m)}finally{--t}}};i.set(c)}})};function mF(){return(UE?"production":void 0)!=="production"?pF():AA()}let _u;function gF(){return _u||(_u=mF(),(UE?"production":void 0)!=="production"&&(globalThis.__JOTAI_DEFAULT_STORE__||(globalThis.__JOTAI_DEFAULT_STORE__=_u),globalThis.__JOTAI_DEFAULT_STORE__!==_u&&console.warn("Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044"))),_u}const bF={},EF=T.createContext(void 0);function kA(t){return T.useContext(EF)||gF()}const F0=t=>typeof t?.then=="function",B0=t=>{t.status||(t.status="pending",t.then(e=>{t.status="fulfilled",t.value=e},e=>{t.status="rejected",t.reason=e}))},yF=we.use||(t=>{if(t.status==="pending")throw t;if(t.status==="fulfilled")return t.value;throw t.status==="rejected"?t.reason:(B0(t),t)}),kg=new WeakMap,Jv=(t,e)=>{let n=kg.get(t);return n||(n=new Promise((r,i)=>{let s=t;const o=d=>f=>{s===d&&r(f)},l=d=>f=>{s===d&&i(f)},c=()=>{try{const d=e();F0(d)?(kg.set(d,n),s=d,d.then(o(d),l(d)),Zv(d,c)):r(d)}catch(d){i(d)}};t.then(o(t),l(t)),Zv(t,c)}),kg.set(t,n)),n};function xF(t,e){const{delay:n,unstable_promiseStatus:r=!we.use}={},i=kA(),[[s,o,l],c]=T.useReducer(f=>{const p=i.get(t);return Object.is(f[0],p)&&f[1]===i&&f[2]===t?f:[p,i,t]},void 0,()=>[i.get(t),i,t]);let d=s;if((o!==i||l!==t)&&(c(),d=i.get(t)),T.useEffect(()=>{const f=i.sub(t,()=>{if(r)try{const p=i.get(t);F0(p)&&B0(Jv(p,()=>i.get(t)))}catch{}if(typeof n=="number"){setTimeout(c,n);return}c()});return c(),f},[i,t,n,r]),T.useDebugValue(d),F0(d)){const f=Jv(d,()=>i.get(t));return r&&B0(f),yF(f)}return d}function vF(t,e){const n=kA();return T.useCallback((...i)=>{if((bF?"production":void 0)!=="production"&&!("write"in t))throw new Error("not writable atom");return n.set(t,...i)},[n,t])}function lt(t,e){return[xF(t),vF(t)]}const NA=()=>({kind:"message",source:"customer",creation_utc:new Date,serverStatus:"pending",offset:0,trace_id:"",data:{message:""}}),wF=()=>{try{return JSON.parse(localStorage.logs||"{}")}catch(t){return console.error(t),localStorage.removeItem("logs"),{}}};ki(wF());const tp=ki([]),HE=ki([]),np=ki(null),As=ki(null),oa=ki(null),zE=ki(null),rp=ki([]),TF=ki(null),SF=ki(NA()),ws=ki({closeDialog:()=>null,openDialog:()=>null}),Ft={green:{dark:"rgb(80 130 1)",light:"rgb(80 130 1 / 10%)",extraLight:"rgb(80 130 1 / 5%)"},purple:{dark:"rgb(85 1 104)",light:"rgb(85 1 104 / 10%)",extraLight:"rgb(85 1 104 / 5%)"},pink:{dark:"rgb(155 3 95)",light:"rgb(155 3 95 / 10%)",extraLight:"rgb(155 3 95 / 5%)"},orange:{dark:"rgb(183 99 0)",light:"rgb(183 99 0 / 10%)",extraLight:"rgb(183 99 0 / 5%)"},blue:{dark:"rgb(46 128 108)",light:"rgb(46 128 108 / 10%)",extraLight:"rgb(46 128 108 / 5%)"}},_F=[{text:"white",background:Ft.green.dark,outerBackground:Ft.green.light},{text:"white",background:Ft.purple.dark,outerBackground:Ft.purple.light},{text:"white",background:Ft.pink.dark,outerBackground:Ft.pink.light},{text:"white",background:Ft.orange.dark,outerBackground:Ft.orange.light},{text:"white",background:Ft.blue.dark,outerBackground:Ft.blue.light}],CF=[{iconBackground:Ft.green.dark,background:Ft.green.light,text:Ft.green.dark,outerBackground:Ft.green.extraLight},{iconBackground:Ft.purple.dark,background:Ft.purple.light,text:Ft.purple.dark,outerBackground:Ft.purple.extraLight},{iconBackground:Ft.pink.dark,background:Ft.pink.light,text:Ft.pink.dark,outerBackground:Ft.pink.extraLight},{iconBackground:Ft.orange.dark,background:Ft.orange.light,text:Ft.orange.dark,outerBackground:Ft.orange.extraLight},{iconBackground:Ft.blue.dark,background:Ft.blue.light,text:Ft.blue.dark,outerBackground:Ft.blue.extraLight}],U0=(t,e)=>{const n=e==="agent"?_F:CF,r=[...t].reduce((i,s)=>i+s.charCodeAt(0),0);return n[r%n.length]},H0=({agent:t,customer:e,tooltip:n=!0})=>{const r=U0(t.id,"agent"),i=e&&U0(e.id,"customer"),s=t?.name==="N/A",o=e?.name==="N/A",l=t.name.replaceAll(/>|{const[,t]=lt(As),[e,n]=lt(oa),[r]=lt(tp),[i]=lt(HE),[,s]=lt(np),[,o]=lt(zE),[l]=lt(ws);T.useEffect(()=>{r?.length&&r.length===1&&c(r[0])},[]);const c=f=>{n(f),i.length<2&&d(i?.[0],f)},d=(f,p)=>{n(e||p||null),s(f),o({...ew,agent_id:e?.id,customer_id:f.id}),t(ew),l.closeDialog()};return w.jsxs("div",{className:"h-full flex flex-col",children:[w.jsx(PE,{children:w.jsx(FE,{children:w.jsxs("div",{className:"mb-[12px] mt-[24px] w-full flex justify-between items-center ps-[30px] pe-[20px]",children:[w.jsx(BE,{className:"text-[20px] font-semibold",children:e?"Select a Customer":"Select an Agent"}),w.jsx("img",{role:"button",tabIndex:0,onKeyDown:vs,onClick:l.closeDialog,className:"cursor-pointer rounded-full",src:"icons/close.svg",alt:"close",height:24,width:24})]})})}),w.jsx("div",{className:"flex flex-col fixed-scroll overflow-auto relative flex-1",children:(e?i:r)?.map(f=>w.jsxs("div",{"data-testid":"agent",tabIndex:0,onKeyDown:vs,role:"button",onClick:()=>e?d(f):c(f),className:Al("cursor-pointer hover:bg-[#FBFBFB] min-h-[78px] h-[78px] w-full border-b-[0.6px] border-b-solid border-b-[#EBECF0] flex items-center ps-[30px] pe-[20px]"),children:[w.jsx(H0,{agent:f,tooltip:!1}),w.jsxs("div",{children:[w.jsx("div",{className:"text-[16px] font-medium",children:f.id==="guest"?"Guest":f.name}),w.jsxs("div",{className:"text-[14px] font-light text-[#A9A9A9]",children:["(id=",f.id,")"]})]})]},f.id))})]})},AF=xA,kF=vA,NF=wA,IA=T.forwardRef(({className:t,...e},n)=>w.jsx(Qh,{className:Rt("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",t),...e,ref:n}));IA.displayName=Qh.displayName;const RF=V_("fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",{variants:{side:{top:"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",bottom:"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",left:"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",right:"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"}},defaultVariants:{side:"right"}}),OA=T.forwardRef(({side:t="right",className:e,children:n,...r},i)=>w.jsxs(NF,{children:[w.jsx(IA,{}),w.jsxs(Zh,{ref:i,className:Rt(RF({side:t}),e),...r,children:[n,w.jsxs(ME,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary",children:[w.jsx(gl,{className:"h-4 w-4"}),w.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));OA.displayName=Zh.displayName;const MA=({className:t,...e})=>w.jsx("div",{className:Rt("flex flex-col space-y-2 text-center sm:text-left",t),...e});MA.displayName="SheetHeader";const DA=T.forwardRef(({className:t,...e},n)=>w.jsx(Jh,{ref:n,className:Rt("text-lg font-semibold text-foreground",t),...e}));DA.displayName=Jh.displayName;const LA=T.forwardRef(({className:t,...e},n)=>w.jsx(ep,{ref:n,className:Rt("text-sm text-muted-foreground",t),...e}));LA.displayName=ep.displayName;const PA=({children:t,className:e})=>w.jsxs("div",{className:Xe("h-[70px] bg-white min-h-[70px] rounded-se-[16px] border-[#F3F5F9] rounded-ss-[16px] flex justify-between sticky top-0 z-10",e),children:[w.jsx("div",{className:"w-[12px] min-w-[12px]"}),t,w.jsx("div",{className:"w-[12px] min-w-[12px]"})]}),Hi="NEW_SESSION",FA=({setFilterSessionVal:t,filterSessionVal:e})=>{const[n,r]=T.useState(!1),[i,s]=lt(As),[,o]=lt(oa),[l]=lt(ws);T.useEffect(()=>{n&&r(!1)},[i]);const c=()=>{s(null),o(null),l.openDialog("",w.jsx(RA,{}),{height:"536px",width:"604px"})};return w.jsx(PA,{className:"z-60 overflow-visible rounded-s-[16px] ",children:w.jsxs("div",{className:"w-[352px] rounded-ss-[16px] rounded-se-[16px] boder-b-[0.6px] border-b-[#ebecf0] max-mobile:w-full h-[70px] flex items-center max-mobile:justify-between bg-white",children:[w.jsxs("div",{className:"flex items-center min-[801px]:hidden",children:[w.jsx("div",{className:"flex items-center",children:w.jsx("img",{src:"/chat/app-logo.svg",alt:"logo","aria-hidden":!0,className:"self-center h-[30px]"})}),w.jsx("div",{children:w.jsxs(AF,{open:n,onOpenChange:()=>r(!n),children:[w.jsx(kF,{asChild:!0,onClick:()=>r(!0),children:w.jsx(P4,{className:"ms-[24px] cursor-pointer"})}),w.jsxs(OA,{side:"left",className:"w-fit p-0 [&>button[type=button]]:hidden",children:[w.jsxs(MA,{children:[w.jsx(DA,{className:"text-center"}),w.jsx(LA,{})]}),w.jsxs("div",{className:"flex items-center px-[12px] flex-1 relative !shadow-main",children:[w.jsx("img",{src:"icons/search.svg",alt:"",className:"absolute left-[24px]"}),w.jsx(sc,{placeholder:"Filter sessions",onChange:d=>t(d.target.value),className:"!ring-0 !ring-offset-0 h-[38px] w-full placeholder:font-light ps-[35px] rounded-[6px] !pointer-events-auto"})]}),w.jsx(UA,{filterSessionVal:e})]})]})})]}),w.jsx("a",{href:"https://parlant.io",target:"_blank",className:"flex items-center ms-[4px] -me-[6px] max-mobile:hidden",children:w.jsx("img",{src:"/chat/app-logo.svg",alt:"logo","aria-hidden":!0,className:"self-center h-[30px]"})}),w.jsxs("div",{className:"flex items-center ps-[12px] flex-1 relative !shadow-main max-mobile:hidden",children:[w.jsx("img",{src:"icons/search.svg",alt:"",className:"absolute left-[24px]"}),w.jsx(sc,{placeholder:"Filter sessions",onChange:d=>t(d.target.value),className:"!ring-0 !ring-offset-0 h-[38px] w-full placeholder:font-light ps-[35px] rounded-[6px] !pointer-events-auto"})]}),w.jsx("div",{className:"group ms-[8px]",children:w.jsx(Xn,{value:"New Session",side:"right",className:"group",children:w.jsxs(w.Fragment,{children:[w.jsx("img",{src:"buttons/new-session.svg",alt:"add session",className:"shadow-main cursor-pointer group-hover:hidden",tabIndex:1,role:"button",onKeyDown:vs,onClick:c}),w.jsx("img",{src:"buttons/new-session-hover.svg",alt:"add session",className:"shadow-main cursor-pointer hidden group-hover:block",tabIndex:1,role:"button",onKeyDown:vs,onClick:c})]})})})]})})};function BA({text:t,textToCopy:e,preText:n,className:r,element:i}){e||(e=t);const s=o=>{o.stopPropagation(),navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(e).then(()=>Ir.info(`Copied text: ${e}`)).catch(()=>{Xf(e,i)}):Xf(e,i)};return w.jsxs("div",{className:Xe("group flex gap-[6px] items-center cursor-pointer text-[#A9A9A9] text-[15px] font-light",r),onKeyDown:vs,onClick:s,children:[w.jsxs("div",{className:"flex items-center gap-[6px]",children:[n&&w.jsx("span",{className:"font-semibold",children:n}),w.jsx("span",{className:"group-hover:text-[#656565]",children:t})]}),w.jsx("div",{className:"copy-icon hidden group-hover:block group-hover:text-[#656565]",role:"button",tabIndex:0,children:w.jsx("img",{src:"icons/copy.svg",alt:""})})]})}const IF=({session:t,closeDialog:e,deleteClicked:n})=>w.jsxs("div",{"data-testid":"deleteDialogContent",children:[w.jsx(z0,{session:t,disabled:!0,className:"[&_.title]:max-w-[90%]"}),w.jsxs("div",{className:"h-[80px] flex items-center justify-end pe-[18px]",children:[w.jsx(An,{"data-testid":"cancel-delete",onClick:e,className:"h-[46px] w-[96px] !bg-white text-[#656565] hover:text-[#151515] rounded-[6px] py-[12px] px-[24px] me-[10px] text-[16px] font-normal border",children:"Cancel"}),w.jsx(An,{"data-testid":"gradient-button",onClick:n,className:"h-[46px] w-[161px] bg-green-main hover:bg-green-hover rounded-[6px] py-[10px] px-[29.5px] text-[15px] font-medium",children:"Delete Session"})]})]});function z0({session:t,isSelected:e,refetch:n,editingTitle:r,setEditingTitle:i,tabIndex:s,disabled:o,className:l}){const c=T.useRef(null),[d]=lt(tp),[f]=lt(HE),[p,m]=T.useState(new Map),[g,x]=T.useState(new Map),[,v]=lt(As),[,S]=lt(oa),[,C]=lt(np),[,A]=lt(zE),[,k]=lt(rp),[M]=lt(ws),[F,I]=T.useState(!1),D=T.useRef(null);T.useEffect(()=>{e&&(t.id===Hi&&!t.agent_id?S(null):(S(d?.find(j=>j.id===t.agent_id)||null),C(f?.find(j=>j.id===t.customer_id)||null)))},[e,S,t.id,t.agent_id,t.title]),T.useEffect(()=>{d&&m(new Map(d.map(j=>[j.id,j])))},[d]),T.useEffect(()=>{f&&x(new Map(f.map(j=>[j.id,j])))},[f]);const G=async j=>{j.stopPropagation();const W=O=>{if(M.closeDialog(),O.stopPropagation(),t.id===Hi){A(null),v(null),S(null);return}return I(!0),e&&(v(null),document.title="Parlant"),JS(`sessions/${t.id}`).then(()=>{k(U=>U.filter(Q=>Q.id!==t.id)),Ir.success(`Session "${t.title}" deleted successfully`),I(!1)}).catch(()=>{Ir.error("Something went wrong"),I(!1)})};M.openDialog("Delete Session",w.jsx(IF,{closeDialog:M.closeDialog,deleteClicked:W,session:t}),{height:"230px",width:"480px"},()=>document.body.style.pointerEvents="auto")},X=async j=>{const W=await a_("Parlant-flags","message_flags","sessionIndex",t.id,{name:"sessionIndex",keyPath:"sessionId"},!0);j.stopPropagation();try{const U=(await P(t.id)||[]).filter(ue=>ue.kind==="message"),Q=[];U?.length&&U.forEach(ue=>{Q.push({"Trace ID":ue.trace_id,Source:ue.source==="ai_agent"?"AI Agent":"Customer",Participant:ue?.data?.participant?.display_name||"",Timestamp:ue.creation_utc||"",Message:ue.data?.message||"",Draft:ue.data?.draft||"",Tags:ue.data?.tags||"",Flag:W?.[ue.trace_id]||""})});const R=["Trace ID","Source","Participant","Timestamp","Message","Draft","Tags","Flag"],oe=`session_${t.id}_"${t.title.replace(/[^a-zA-Z0-9]/g,"_")}.csv`;if(qD(Q,oe,{headers:R,dateFormat:"readable"}))Ir.success(`Session "${t.title}" exported successfully`);else throw new Error("Export failed")}catch(O){console.error("Export failed:",O),Ir.error("Failed to export session")}},P=async j=>{try{const W=await fetch(`${lo}/sessions/${j}/events`);if(!W.ok)throw new Error("Failed to fetch session data");return await W.json()}catch(W){return console.error("Failed to fetch session data:",W),{messages:[]}}},Y=async j=>{j.stopPropagation(),i?.(t.id),setTimeout(()=>c?.current?.select(),0)},z=j=>{j.stopPropagation();const W=c?.current?.value?.trim();if(W){if(t.id===Hi){i?.(null),A(O=>O&&{...O,title:W}),Ir.success("title changed successfully");return}WM(`sessions/${t.id}`,{title:W}).then(()=>{i?.(null),n?.(),Ir.success("title changed successfully")}).catch(()=>{Ir.error("Something went wrong")})}},ie=j=>{j.stopPropagation(),i?.(null)},Z=j=>{j.key==="Enter"&&z(j)},ee=[{title:"copy ID",onClick:j=>{j.stopPropagation(),hl(t.id,D?.current||void 0)},imgPath:"icons/copy-session.svg"},{title:"rename",onClick:Y,imgPath:"icons/rename.svg"},{title:"export",onClick:X,imgPath:"icons/export.svg"},{title:"delete",onClick:G,imgPath:"icons/delete.svg"}],ae=p.get(t.agent_id),de=g.get(t.customer_id);return w.jsx(Xn,{value:w.jsx("div",{className:"font-light text-[#a9a9a9] flex items-center",children:w.jsx(BA,{preText:"Session ID:",textToCopy:t.id,text:t.id,className:"!text-[#a9a9a9] hover:text-[#151515] !text-[13px] ms-[4px] [&_img]:opacity-60 [&_.copy-icon]:!block"})}),side:"right",children:w.jsxs("div",{"data-testid":"session",role:"button",tabIndex:s,onKeyDown:vs,onClick:()=>!o&&!r&&!F&&v(t),className:Xe("bg-white animate-fade-in text-[14px] hover:rounded-[6px] font-inter justify-between font-medium border-b-[0.6px] border-b-solid border-[#F9FAFC] cursor-pointer p-1 flex items-center ps-[8px] min-h-[74px] h-[74px] ml-0 mr-0 ",e&&" rounded-[6px]",r===t.id?K4.editSession+" !p-[4px_2px] ":r?" opacity-[33%] ":" hover:bg-main ",e&&r!==t.id?"!bg-[#F5F6F8]":"",o?" pointer-events-none":"",F?"opacity-[33%]":"",l),children:[w.jsxs("div",{className:"title flex-1 whitespace-nowrap flex overflow-hidden max-w-[210px] ms-[4px] h-[48px]",children:[r!==t.id&&w.jsxs("div",{className:"overflow-visible overflow-ellipsis flex items-center",children:[w.jsx("div",{children:w.jsx(H0,{agent:ae||{id:"",name:"N/A"},customer:de||{id:"",name:"N/A"}})}),w.jsxs("div",{className:On(!ae&&"opacity-50","ms-[4px] text-[15px]"),children:[t.title,w.jsxs("small",{className:"text-[13px] text-[#A9A9A9] -mb-[7px] font-light flex gap-[6px]",children:[sA(t.creation_utc),w.jsx("img",{src:"icons/dot-saparetor.svg",alt:"",height:18,width:3}),V4(t.creation_utc)]})]})]}),r===t.id&&w.jsxs("div",{className:"flex items-center ps-[6px]",children:[w.jsx("div",{children:ae&&w.jsx(H0,{agent:ae})}),w.jsx(sc,{"data-testid":"sessionTitle",ref:c,onKeyUp:Z,onClick:j=>j.stopPropagation(),defaultValue:t.title,className:"box-shadow-none border-none bg-[#F5F6F8] text-foreground h-fit p-1 ms-[6px]"})]})]}),w.jsxs("div",{className:"h-[39px] flex items-center",children:[!o&&r!==t.id&&t.id!==Hi&&w.jsxs(rA,{children:[w.jsx(iA,{disabled:!!r,className:"outline-none","data-testid":"menu-button",tabIndex:-1,onClick:j=>j.stopPropagation(),children:w.jsx("div",{tabIndex:s,role:"button",className:"rounded-full me-[14px]",onClick:j=>j.stopPropagation(),children:w.jsx("img",{src:"icons/more.svg",alt:"more",height:14,width:14})})}),w.jsx(AE,{ref:D,side:"right",align:"start",className:"-ms-[10px] flex flex-col gap-[8px] py-[14px] px-[10px] border-none w-[168px] [box-shadow:_0px_8px_20px_-8px_#00000012] rounded-[8px]",children:ee.map(j=>w.jsxs(rh,{tabIndex:0,onClick:j.onClick,className:"gap-0 font-normal text-[14px] px-[20px] font-inter capitalize hover:!bg-[#FAF9FF]",children:[w.jsx("img",{"data-testid":j.title,src:j.imgPath,height:16,width:18,className:"me-[8px]",alt:""}),j.title]},j.title))})]}),r==t.id&&w.jsxs("div",{className:"me-[18px]",children:[w.jsx(Xn,{value:"Cancel",children:w.jsx(An,{"data-testid":"cancel",variant:"ghost",className:"w-[28px] h-[28px] p-[8px] rounded-full",onClick:ie,children:w.jsx("img",{src:"icons/cancel.svg",alt:"cancel"})})}),w.jsx(Xn,{value:"Save",children:w.jsx(An,{variant:"ghost",className:"w-[28px] h-[28px] p-[8px] rounded-full",onClick:z,children:w.jsx("img",{src:"icons/save.svg",alt:"cancel"})})})]})]})]},t.id)})}function UA({filterSessionVal:t}){const[e,n]=T.useState(null),[r]=lt(As),{data:i,ErrorTemplate:s,loading:o,refetch:l}=hg("sessions"),{data:c}=hg("agents"),{data:d}=hg("customers"),[,f]=lt(tp),[,p]=lt(HE),[m]=lt(oa),[g]=lt(np),[x,v]=lt(rp),[S,C]=T.useState(x);return T.useEffect(()=>{c&&f(c)},[c]),T.useEffect(()=>{d&&p(d)},[d]),T.useEffect(()=>{i&&v(i)},[i]),T.useEffect(()=>{t?.trim()?C(x.filter(A=>A.title?.toLowerCase()?.includes(t?.toLowerCase())||A.id?.toLowerCase()?.includes(t?.toLowerCase()))):C(x)},[t,x]),w.jsx("div",{className:On("flex flex-col items-center h-[calc(100%-68px)] border-e"),children:w.jsxs("div",{"data-testid":"sessions",className:"bg-white px-[12px] border-b-[12px] border-white flex-1 fixed-scroll justify-center w-[352px] overflow-auto rounded-es-[16px] rounded-ee-[16px]",children:[o&&!x?.length&&w.jsx("div",{children:"loading..."}),r?.id===ah&&w.jsx(z0,{className:"opacity-50","data-testid":"session",isSelected:!0,session:{...r,agent_id:m?.id||"",customer_id:g?.id||""}},ah),S.toReversed().map((A,k)=>w.jsx(z0,{"data-testid":"session",tabIndex:x.length-k,editingTitle:e,setEditingTitle:n,isSelected:A.id===r?.id,refetch:l,session:A},A.id)),s&&w.jsx(s,{})]})})}class HA extends T.Component{constructor(e){super(e),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e){this.setState({errorStack:e.stack})}render(){return this.state.hasError?this.props.component||w.jsxs("div",{className:"flex bg-main items-center justify-center h-screen flex-col",children:[w.jsx("img",{src:"/chat/logo-color.svg",alt:"Logo",height:200,width:200,className:"mb-[10px]"}),w.jsx("h1",{className:"text-[20px]",children:"Oops! Something went wrong"}),w.jsxs("p",{className:"text-center",children:["We apologize for the inconvenience. Please try again later, or"," ",w.jsx("a",{href:"/",className:"underline",children:"try again now"}),"."]}),w.jsx("div",{className:"flex justify-center max-h-[300px] mt-[40px] bg-[#f0eeee] rounded-[10px] p-[10px] break-words border border-solid border-[#dedcdc]",children:w.jsx("code",{className:"max-h-[300px] w-[600px] max-w-[80vw] overflow-auto",children:this.state.errorStack})})]}):this.props.children}}const zA=()=>{const[t,e]=T.useState(null),[n,r]=T.useState(null),[i,s]=T.useState({height:"",width:""}),[o,l]=T.useState(null),c=(p,m,g,x=null)=>{p&&e(p),r(m),s({height:g.height,width:g.width}),x&&l(x)},d=p=>{p?.stopPropagation(),r(null),e(null),o?.(),l(null)};return{openDialog:c,DialogComponent:()=>w.jsx(TA,{open:!!n,children:w.jsx(DE,{children:w.jsx(LE,{"data-testid":"dialog","aria-hidden":!1,style:{maxHeight:i.height,width:i.width},className:"[&>button]:hidden z-[99] !pointer-events-auto p-0 h-[80%] font-inter bg-white block max-w-[95%]",children:w.jsxs("div",{className:"bg-white h-full rounded-[12px] flex flex-col","aria-hidden":!1,children:[w.jsx(PE,{className:Al(!t&&"hidden"),children:w.jsx(RE,{children:w.jsxs("div",{className:"mb-[12px] mt-[24px] w-full flex justify-between items-center ps-[30px] pe-[20px]",children:[w.jsx(IE,{className:"text-[20px] font-semibold",children:t}),w.jsx("img",{role:"button",tabIndex:0,onKeyDown:vs,onClick:d,className:"cursor-pointer rounded-full",src:"icons/close.svg",alt:"close",width:24,height:24})]})})}),w.jsx("div",{className:"overflow-auto flex-1",children:n})]})})})}),closeDialog:d}};var Ng={exports:{}},Rg,tw;function OF(){if(tw)return Rg;tw=1;var t="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";return Rg=t,Rg}var Ig,nw;function MF(){if(nw)return Ig;nw=1;var t=OF();function e(){}function n(){}return n.resetWarningCache=e,Ig=function(){function r(o,l,c,d,f,p){if(p!==t){var m=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw m.name="Invariant Violation",m}}r.isRequired=r;function i(){return r}var s={array:r,bigint:r,bool:r,func:r,number:r,object:r,string:r,symbol:r,any:r,arrayOf:i,element:r,elementType:r,instanceOf:i,node:r,objectOf:i,oneOf:i,oneOfType:i,shape:i,exact:i,checkPropTypes:n,resetWarningCache:e};return s.PropTypes=s,s},Ig}var rw;function DF(){return rw||(rw=1,Ng.exports=MF()()),Ng.exports}var LF=DF();const un=_s(LF);var Og,iw;function PF(){if(iw)return Og;iw=1;function t(l){return l&&typeof l=="object"&&"default"in l?l.default:l}var e=Dh(),n=t(e);function r(l,c,d){return c in l?Object.defineProperty(l,c,{value:d,enumerable:!0,configurable:!0,writable:!0}):l[c]=d,l}function i(l,c){l.prototype=Object.create(c.prototype),l.prototype.constructor=l,l.__proto__=c}var s=!!(typeof window<"u"&&window.document&&window.document.createElement);function o(l,c,d){if(typeof l!="function")throw new Error("Expected reducePropsToState to be a function.");if(typeof c!="function")throw new Error("Expected handleStateChangeOnClient to be a function.");if(typeof d<"u"&&typeof d!="function")throw new Error("Expected mapStateOnServer to either be undefined or a function.");function f(p){return p.displayName||p.name||"Component"}return function(m){if(typeof m!="function")throw new Error("Expected WrappedComponent to be a React component.");var g=[],x;function v(){x=l(g.map(function(C){return C.props})),S.canUseDOM?c(x):d&&(x=d(x))}var S=(function(C){i(A,C);function A(){return C.apply(this,arguments)||this}A.peek=function(){return x},A.rewind=function(){if(A.canUseDOM)throw new Error("You may only call rewind() on the server. Call peek() to read the current state.");var F=x;return x=void 0,g=[],F};var k=A.prototype;return k.UNSAFE_componentWillMount=function(){g.push(this),v()},k.componentDidUpdate=function(){v()},k.componentWillUnmount=function(){var F=g.indexOf(this);g.splice(F,1),v()},k.render=function(){return n.createElement(m,this.props)},A})(e.PureComponent);return r(S,"displayName","SideEffect("+f(m)+")"),r(S,"canUseDOM",s),S}}return Og=o,Og}var FF=PF();const BF=_s(FF);var Mg,sw;function UF(){if(sw)return Mg;sw=1;var t=typeof Element<"u",e=typeof Map=="function",n=typeof Set=="function",r=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function i(s,o){if(s===o)return!0;if(s&&o&&typeof s=="object"&&typeof o=="object"){if(s.constructor!==o.constructor)return!1;var l,c,d;if(Array.isArray(s)){if(l=s.length,l!=o.length)return!1;for(c=l;c--!==0;)if(!i(s[c],o[c]))return!1;return!0}var f;if(e&&s instanceof Map&&o instanceof Map){if(s.size!==o.size)return!1;for(f=s.entries();!(c=f.next()).done;)if(!o.has(c.value[0]))return!1;for(f=s.entries();!(c=f.next()).done;)if(!i(c.value[1],o.get(c.value[0])))return!1;return!0}if(n&&s instanceof Set&&o instanceof Set){if(s.size!==o.size)return!1;for(f=s.entries();!(c=f.next()).done;)if(!o.has(c.value[0]))return!1;return!0}if(r&&ArrayBuffer.isView(s)&&ArrayBuffer.isView(o)){if(l=s.length,l!=o.length)return!1;for(c=l;c--!==0;)if(s[c]!==o[c])return!1;return!0}if(s.constructor===RegExp)return s.source===o.source&&s.flags===o.flags;if(s.valueOf!==Object.prototype.valueOf&&typeof s.valueOf=="function"&&typeof o.valueOf=="function")return s.valueOf()===o.valueOf();if(s.toString!==Object.prototype.toString&&typeof s.toString=="function"&&typeof o.toString=="function")return s.toString()===o.toString();if(d=Object.keys(s),l=d.length,l!==Object.keys(o).length)return!1;for(c=l;c--!==0;)if(!Object.prototype.hasOwnProperty.call(o,d[c]))return!1;if(t&&s instanceof Element)return!1;for(c=l;c--!==0;)if(!((d[c]==="_owner"||d[c]==="__v"||d[c]==="__o")&&s.$$typeof)&&!i(s[d[c]],o[d[c]]))return!1;return!0}return s!==s&&o!==o}return Mg=function(o,l){try{return i(o,l)}catch(c){if((c.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw c}},Mg}var HF=UF();const zF=_s(HF);var Dg,ow;function jF(){if(ow)return Dg;ow=1;var t=Object.getOwnPropertySymbols,e=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable;function r(s){if(s==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(s)}function i(){try{if(!Object.assign)return!1;var s=new String("abc");if(s[5]="de",Object.getOwnPropertyNames(s)[0]==="5")return!1;for(var o={},l=0;l<10;l++)o["_"+String.fromCharCode(l)]=l;var c=Object.getOwnPropertyNames(o).map(function(f){return o[f]});if(c.join("")!=="0123456789")return!1;var d={};return"abcdefghijklmnopqrst".split("").forEach(function(f){d[f]=f}),Object.keys(Object.assign({},d)).join("")==="abcdefghijklmnopqrst"}catch{return!1}}return Dg=i()?Object.assign:function(s,o){for(var l,c=r(s),d,f=1;f=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n},QF=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e&&(typeof e=="object"||typeof e=="function")?e:t},j0=function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return n===!1?String(e):String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},ZF=function(e){var n=sl(e,ct.TITLE),r=sl(e,dc.TITLE_TEMPLATE);if(r&&n)return r.replace(/%s/g,function(){return Array.isArray(n)?n.join(""):n});var i=sl(e,dc.DEFAULT_TITLE);return n||i||void 0},JF=function(e){return sl(e,dc.ON_CHANGE_CLIENT_STATE)||function(){}},Lg=function(e,n){return n.filter(function(r){return typeof r[e]<"u"}).map(function(r){return r[e]}).reduce(function(r,i){return kr({},r,i)},{})},eB=function(e,n){return n.filter(function(r){return typeof r[ct.BASE]<"u"}).map(function(r){return r[ct.BASE]}).reverse().reduce(function(r,i){if(!r.length)for(var s=Object.keys(i),o=0;o=0;r--){var i=e[r];if(i.hasOwnProperty(n))return i[n]}return null},tB=function(e){return{baseTag:eB([dn.HREF,dn.TARGET],e),bodyAttributes:Lg($o.BODY,e),defer:sl(e,dc.DEFER),encode:sl(e,dc.ENCODE_SPECIAL_CHARACTERS),htmlAttributes:Lg($o.HTML,e),linkTags:Cu(ct.LINK,[dn.REL,dn.HREF],e),metaTags:Cu(ct.META,[dn.NAME,dn.CHARSET,dn.HTTPEQUIV,dn.PROPERTY,dn.ITEM_PROP],e),noscriptTags:Cu(ct.NOSCRIPT,[dn.INNER_HTML],e),onChangeClientState:JF(e),scriptTags:Cu(ct.SCRIPT,[dn.SRC,dn.INNER_HTML],e),styleTags:Cu(ct.STYLE,[dn.CSS_TEXT],e),title:ZF(e),titleAttributes:Lg($o.TITLE,e)}},$0=(function(){var t=Date.now();return function(e){var n=Date.now();n-t>16?(t=n,e(n)):setTimeout(function(){$0(e)},0)}})(),lw=function(e){return clearTimeout(e)},nB=typeof window<"u"?window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||$0:global.requestAnimationFrame||$0,rB=typeof window<"u"?window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||lw:global.cancelAnimationFrame||lw,iB=function(e){return console&&typeof console.warn=="function"&&console.warn(e)},Au=null,sB=function(e){Au&&rB(Au),e.defer?Au=nB(function(){uw(e,function(){Au=null})}):(uw(e),Au=null)},uw=function(e,n){var r=e.baseTag,i=e.bodyAttributes,s=e.htmlAttributes,o=e.linkTags,l=e.metaTags,c=e.noscriptTags,d=e.onChangeClientState,f=e.scriptTags,p=e.styleTags,m=e.title,g=e.titleAttributes;W0(ct.BODY,i),W0(ct.HTML,s),oB(m,g);var x={baseTag:Ha(ct.BASE,r),linkTags:Ha(ct.LINK,o),metaTags:Ha(ct.META,l),noscriptTags:Ha(ct.NOSCRIPT,c),scriptTags:Ha(ct.SCRIPT,f),styleTags:Ha(ct.STYLE,p)},v={},S={};Object.keys(x).forEach(function(C){var A=x[C],k=A.newTags,M=A.oldTags;k.length&&(v[C]=k),M.length&&(S[C]=x[C].oldTags)}),n&&n(),d(e,v,S)},jA=function(e){return Array.isArray(e)?e.join(""):e},oB=function(e,n){typeof e<"u"&&document.title!==e&&(document.title=jA(e)),W0(ct.TITLE,n)},W0=function(e,n){var r=document.getElementsByTagName(e)[0];if(r){for(var i=r.getAttribute(Ei),s=i?i.split(","):[],o=[].concat(s),l=Object.keys(n),c=0;c=0;m--)r.removeAttribute(o[m]);s.length===o.length?r.removeAttribute(Ei):r.getAttribute(Ei)!==l.join(",")&&r.setAttribute(Ei,l.join(","))}},Ha=function(e,n){var r=document.head||document.querySelector(ct.HEAD),i=r.querySelectorAll(e+"["+Ei+"]"),s=Array.prototype.slice.call(i),o=[],l=void 0;return n&&n.length&&n.forEach(function(c){var d=document.createElement(e);for(var f in c)if(c.hasOwnProperty(f))if(f===dn.INNER_HTML)d.innerHTML=c.innerHTML;else if(f===dn.CSS_TEXT)d.styleSheet?d.styleSheet.cssText=c.cssText:d.appendChild(document.createTextNode(c.cssText));else{var p=typeof c[f]>"u"?"":c[f];d.setAttribute(f,p)}d.setAttribute(Ei,"true"),s.some(function(m,g){return l=g,d.isEqualNode(m)})?s.splice(l,1):o.push(d)}),s.forEach(function(c){return c.parentNode.removeChild(c)}),o.forEach(function(c){return r.appendChild(c)}),{oldTags:s,newTags:o}},$A=function(e){return Object.keys(e).reduce(function(n,r){var i=typeof e[r]<"u"?r+'="'+e[r]+'"':""+r;return n?n+" "+i:i},"")},aB=function(e,n,r,i){var s=$A(r),o=jA(n);return s?"<"+e+" "+Ei+'="true" '+s+">"+j0(o,i)+"":"<"+e+" "+Ei+'="true">'+j0(o,i)+""},lB=function(e,n,r){return n.reduce(function(i,s){var o=Object.keys(s).filter(function(d){return!(d===dn.INNER_HTML||d===dn.CSS_TEXT)}).reduce(function(d,f){var p=typeof s[f]>"u"?f:f+'="'+j0(s[f],r)+'"';return d?d+" "+p:p},""),l=s.innerHTML||s.cssText||"",c=GF.indexOf(e)===-1;return i+"<"+e+" "+Ei+'="true" '+o+(c?"/>":">"+l+"")},"")},WA=function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Object.keys(e).reduce(function(r,i){return r[lh[i]||i]=e[i],r},n)},uB=function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Object.keys(e).reduce(function(r,i){return r[VF[i]||i]=e[i],r},n)},cB=function(e,n,r){var i,s=(i={key:n},i[Ei]=!0,i),o=WA(r,s);return[we.createElement(ct.TITLE,o,n)]},dB=function(e,n){return n.map(function(r,i){var s,o=(s={key:i},s[Ei]=!0,s);return Object.keys(r).forEach(function(l){var c=lh[l]||l;if(c===dn.INNER_HTML||c===dn.CSS_TEXT){var d=r.innerHTML||r.cssText;o.dangerouslySetInnerHTML={__html:d}}else o[c]=r[l]}),we.createElement(e,o)})},ds=function(e,n,r){switch(e){case ct.TITLE:return{toComponent:function(){return cB(e,n.title,n.titleAttributes)},toString:function(){return aB(e,n.title,n.titleAttributes,r)}};case $o.BODY:case $o.HTML:return{toComponent:function(){return WA(n)},toString:function(){return $A(n)}};default:return{toComponent:function(){return dB(e,n)},toString:function(){return lB(e,n,r)}}}},VA=function(e){var n=e.baseTag,r=e.bodyAttributes,i=e.encode,s=e.htmlAttributes,o=e.linkTags,l=e.metaTags,c=e.noscriptTags,d=e.scriptTags,f=e.styleTags,p=e.title,m=p===void 0?"":p,g=e.titleAttributes;return{base:ds(ct.BASE,n,i),bodyAttributes:ds($o.BODY,r,i),htmlAttributes:ds($o.HTML,s,i),link:ds(ct.LINK,o,i),meta:ds(ct.META,l,i),noscript:ds(ct.NOSCRIPT,c,i),script:ds(ct.SCRIPT,d,i),style:ds(ct.STYLE,f,i),title:ds(ct.TITLE,{title:m,titleAttributes:g},i)}},fB=function(e){var n,r;return r=n=(function(i){XF(s,i);function s(){return YF(this,s),QF(this,i.apply(this,arguments))}return s.prototype.shouldComponentUpdate=function(l){return!zF(this.props,l)},s.prototype.mapNestedChildrenToProps=function(l,c){if(!c)return null;switch(l.type){case ct.SCRIPT:case ct.NOSCRIPT:return{innerHTML:c};case ct.STYLE:return{cssText:c}}throw new Error("<"+l.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")},s.prototype.flattenArrayTypeChildren=function(l){var c,d=l.child,f=l.arrayTypeChildren,p=l.newChildProps,m=l.nestedChildren;return kr({},f,(c={},c[d.type]=[].concat(f[d.type]||[],[kr({},p,this.mapNestedChildrenToProps(d,m))]),c))},s.prototype.mapObjectTypeChildren=function(l){var c,d,f=l.child,p=l.newProps,m=l.newChildProps,g=l.nestedChildren;switch(f.type){case ct.TITLE:return kr({},p,(c={},c[f.type]=g,c.titleAttributes=kr({},m),c));case ct.BODY:return kr({},p,{bodyAttributes:kr({},m)});case ct.HTML:return kr({},p,{htmlAttributes:kr({},m)})}return kr({},p,(d={},d[f.type]=kr({},m),d))},s.prototype.mapArrayTypeChildrenToProps=function(l,c){var d=kr({},c);return Object.keys(l).forEach(function(f){var p;d=kr({},d,(p={},p[f]=l[f],p))}),d},s.prototype.warnOnInvalidChildren=function(l,c){return!0},s.prototype.mapChildrenToProps=function(l,c){var d=this,f={};return we.Children.forEach(l,function(p){if(!(!p||!p.props)){var m=p.props,g=m.children,x=aw(m,["children"]),v=uB(x);switch(d.warnOnInvalidChildren(p,g),p.type){case ct.LINK:case ct.META:case ct.NOSCRIPT:case ct.SCRIPT:case ct.STYLE:f=d.flattenArrayTypeChildren({child:p,arrayTypeChildren:f,newChildProps:v,nestedChildren:g});break;default:c=d.mapObjectTypeChildren({child:p,newProps:c,newChildProps:v,nestedChildren:g});break}}}),c=this.mapArrayTypeChildrenToProps(f,c),c},s.prototype.render=function(){var l=this.props,c=l.children,d=aw(l,["children"]),f=kr({},d);return c&&(f=this.mapChildrenToProps(c,f)),we.createElement(e,f)},qF(s,null,[{key:"canUseDOM",set:function(l){e.canUseDOM=l}}]),s})(we.Component),n.propTypes={base:un.object,bodyAttributes:un.object,children:un.oneOfType([un.arrayOf(un.node),un.node]),defaultTitle:un.string,defer:un.bool,encodeSpecialCharacters:un.bool,htmlAttributes:un.object,link:un.arrayOf(un.object),meta:un.arrayOf(un.object),noscript:un.arrayOf(un.object),onChangeClientState:un.func,script:un.arrayOf(un.object),style:un.arrayOf(un.object),title:un.string,titleAttributes:un.object,titleTemplate:un.string},n.defaultProps={defer:!0,encodeSpecialCharacters:!0},n.peek=e.peek,n.rewind=function(){var i=e.rewind();return i||(i=VA({baseTag:[],bodyAttributes:{},htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}})),i},r},hB=function(){return null},pB=BF(tB,sB,VA)(hB),V0=fB(pB);V0.renderStatic=V0.rewind;const ip=T.forwardRef(({className:t,...e},n)=>w.jsx("textarea",{className:Rt("flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",t),ref:n,...e}));ip.displayName="Textarea";function mB(t,e){return t.reduce((n,r)=>{let i=e(r);return i||(i=i?.toString()),n[i]||(n[i]=[]),n[i].push(r),n},{})}const gB=()=>w.jsx("div",{className:"w-[16px] min-w-[16px]"}),Qa=T.memo(gB);function cw(t){const e=[],n=String(t||"");let r=n.indexOf(","),i=0,s=!1;for(;!s;){r===-1&&(r=n.length,s=!0);const o=n.slice(i,r).trim();(o||!s)&&e.push(o),i=r+1,r=n.indexOf(",",i)}return e}function GA(t,e){const n={};return(t[t.length-1]===""?[...t,""]:t).join((n.padRight?" ":"")+","+(n.padLeft===!1?"":" ")).trim()}const bB=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,EB=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,yB={};function dw(t,e){return(yB.jsx?EB:bB).test(t)}const xB=/[ \t\n\f\r]/g;function vB(t){return typeof t=="object"?t.type==="text"?fw(t.value):!1:fw(t)}function fw(t){return t.replace(xB,"")===""}let Mc=class{constructor(e,n,r){this.normal=n,this.property=e,r&&(this.space=r)}};Mc.prototype.normal={};Mc.prototype.property={};Mc.prototype.space=void 0;function KA(t,e){const n={},r={};for(const i of t)Object.assign(n,i.property),Object.assign(r,i.normal);return new Mc(n,r,e)}function fc(t){return t.toLowerCase()}let Mr=class{constructor(e,n){this.attribute=n,this.property=e}};Mr.prototype.attribute="";Mr.prototype.booleanish=!1;Mr.prototype.boolean=!1;Mr.prototype.commaOrSpaceSeparated=!1;Mr.prototype.commaSeparated=!1;Mr.prototype.defined=!1;Mr.prototype.mustUseProperty=!1;Mr.prototype.number=!1;Mr.prototype.overloadedBoolean=!1;Mr.prototype.property="";Mr.prototype.spaceSeparated=!1;Mr.prototype.space=void 0;let wB=0;const pt=aa(),Nn=aa(),G0=aa(),Te=aa(),Zt=aa(),ol=aa(),Ur=aa();function aa(){return 2**++wB}const K0=Object.freeze(Object.defineProperty({__proto__:null,boolean:pt,booleanish:Nn,commaOrSpaceSeparated:Ur,commaSeparated:ol,number:Te,overloadedBoolean:G0,spaceSeparated:Zt},Symbol.toStringTag,{value:"Module"})),Pg=Object.keys(K0);let jE=class extends Mr{constructor(e,n,r,i){let s=-1;if(super(e,n),hw(this,"space",i),typeof r=="number")for(;++s4&&n.slice(0,4)==="data"&&AB.test(e)){if(e.charAt(4)==="-"){const s=e.slice(5).replace(pw,NB);r="data"+s.charAt(0).toUpperCase()+s.slice(1)}else{const s=e.slice(4);if(!pw.test(s)){let o=s.replace(CB,kB);o.charAt(0)!=="-"&&(o="-"+o),e="data"+o}}i=jE}return new i(r,e)}function kB(t){return"-"+t.toLowerCase()}function NB(t){return t.charAt(1).toUpperCase()}const sp=KA([YA,TB,QA,ZA,JA],"html"),Ml=KA([YA,SB,QA,ZA,JA],"svg");function mw(t){const e=String(t||"").trim();return e?e.split(/[ \t\n\r\f]+/g):[]}function ek(t){return t.join(" ").trim()}var za={},Fg,gw;function RB(){if(gw)return Fg;gw=1;var t=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,e=/\n/g,n=/^\s*/,r=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,i=/^:\s*/,s=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,o=/^[;\s]*/,l=/^\s+|\s+$/g,c=` +`,d="/",f="*",p="",m="comment",g="declaration";Fg=function(v,S){if(typeof v!="string")throw new TypeError("First argument must be a string");if(!v)return[];S=S||{};var C=1,A=1;function k(ie){var Z=ie.match(e);Z&&(C+=Z.length);var ee=ie.lastIndexOf(c);A=~ee?ie.length-ee:A+ie.length}function M(){var ie={line:C,column:A};return function(Z){return Z.position=new F(ie),G(),Z}}function F(ie){this.start=ie,this.end={line:C,column:A},this.source=S.source}F.prototype.content=v;function I(ie){var Z=new Error(S.source+":"+C+":"+A+": "+ie);if(Z.reason=ie,Z.filename=S.source,Z.line=C,Z.column=A,Z.source=v,!S.silent)throw Z}function D(ie){var Z=ie.exec(v);if(Z){var ee=Z[0];return k(ee),v=v.slice(ee.length),Z}}function G(){D(n)}function X(ie){var Z;for(ie=ie||[];Z=P();)Z!==!1&&ie.push(Z);return ie}function P(){var ie=M();if(!(d!=v.charAt(0)||f!=v.charAt(1))){for(var Z=2;p!=v.charAt(Z)&&(f!=v.charAt(Z)||d!=v.charAt(Z+1));)++Z;if(Z+=2,p===v.charAt(Z-1))return I("End of comment missing");var ee=v.slice(2,Z-2);return A+=2,k(ee),v=v.slice(Z),A+=2,ie({type:m,comment:ee})}}function Y(){var ie=M(),Z=D(r);if(Z){if(P(),!D(i))return I("property missing ':'");var ee=D(s),ae=ie({type:g,property:x(Z[0].replace(t,p)),value:ee?x(ee[0].replace(t,p)):p});return D(o),ae}}function z(){var ie=[];X(ie);for(var Z;Z=Y();)Z!==!1&&(ie.push(Z),X(ie));return ie}return G(),z()};function x(v){return v?v.replace(l,p):p}return Fg}var bw;function IB(){if(bw)return za;bw=1;var t=za&&za.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(za,"__esModule",{value:!0}),za.default=n;var e=t(RB());function n(r,i){var s=null;if(!r||typeof r!="string")return s;var o=(0,e.default)(r),l=typeof i=="function";return o.forEach(function(c){if(c.type==="declaration"){var d=c.property,f=c.value;l?i(d,f,c):f&&(s=s||{},s[d]=f)}}),s}return za}var ku={},Ew;function OB(){if(Ew)return ku;Ew=1,Object.defineProperty(ku,"__esModule",{value:!0}),ku.camelCase=void 0;var t=/^--[a-zA-Z0-9_-]+$/,e=/-([a-z])/g,n=/^[^-]+$/,r=/^-(webkit|moz|ms|o|khtml)-/,i=/^-(ms)-/,s=function(d){return!d||n.test(d)||t.test(d)},o=function(d,f){return f.toUpperCase()},l=function(d,f){return"".concat(f,"-")},c=function(d,f){return f===void 0&&(f={}),s(d)?d:(d=d.toLowerCase(),f.reactCompat?d=d.replace(i,l):d=d.replace(r,l),d.replace(e,o))};return ku.camelCase=c,ku}var Nu,yw;function MB(){if(yw)return Nu;yw=1;var t=Nu&&Nu.__importDefault||function(i){return i&&i.__esModule?i:{default:i}},e=t(IB()),n=OB();function r(i,s){var o={};return!i||typeof i!="string"||(0,e.default)(i,function(l,c){l&&c&&(o[(0,n.camelCase)(l,s)]=c)}),o}return r.default=r,Nu=r,Nu}var DB=MB();const LB=_s(DB),op=tk("end"),Ji=tk("start");function tk(t){return e;function e(n){const r=n&&n.position&&n.position[t]||{};if(typeof r.line=="number"&&r.line>0&&typeof r.column=="number"&&r.column>0)return{line:r.line,column:r.column,offset:typeof r.offset=="number"&&r.offset>-1?r.offset:void 0}}}function PB(t){const e=Ji(t),n=op(t);if(e&&n)return{start:e,end:n}}function Gu(t){return!t||typeof t!="object"?"":"position"in t||"type"in t?xw(t.position):"start"in t||"end"in t?xw(t):"line"in t||"column"in t?Y0(t):""}function Y0(t){return vw(t&&t.line)+":"+vw(t&&t.column)}function xw(t){return Y0(t&&t.start)+"-"+Y0(t&&t.end)}function vw(t){return t&&typeof t=="number"?t:1}class ur extends Error{constructor(e,n,r){super(),typeof n=="string"&&(r=n,n=void 0);let i="",s={},o=!1;if(n&&("line"in n&&"column"in n?s={place:n}:"start"in n&&"end"in n?s={place:n}:"type"in n?s={ancestors:[n],place:n.position}:s={...n}),typeof e=="string"?i=e:!s.cause&&e&&(o=!0,i=e.message,s.cause=e),!s.ruleId&&!s.source&&typeof r=="string"){const c=r.indexOf(":");c===-1?s.ruleId=r:(s.source=r.slice(0,c),s.ruleId=r.slice(c+1))}if(!s.place&&s.ancestors&&s.ancestors){const c=s.ancestors[s.ancestors.length-1];c&&(s.place=c.position)}const l=s.place&&"start"in s.place?s.place.start:s.place;this.ancestors=s.ancestors||void 0,this.cause=s.cause||void 0,this.column=l?l.column:void 0,this.fatal=void 0,this.file="",this.message=i,this.line=l?l.line:void 0,this.name=Gu(s.place)||"1:1",this.place=s.place||void 0,this.reason=this.message,this.ruleId=s.ruleId||void 0,this.source=s.source||void 0,this.stack=o&&s.cause&&typeof s.cause.stack=="string"?s.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}ur.prototype.file="";ur.prototype.name="";ur.prototype.reason="";ur.prototype.message="";ur.prototype.stack="";ur.prototype.column=void 0;ur.prototype.line=void 0;ur.prototype.ancestors=void 0;ur.prototype.cause=void 0;ur.prototype.fatal=void 0;ur.prototype.place=void 0;ur.prototype.ruleId=void 0;ur.prototype.source=void 0;const WE={}.hasOwnProperty,FB=new Map,BB=/[A-Z]/g,UB=new Set(["table","tbody","thead","tfoot","tr"]),HB=new Set(["td","th"]),nk="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function zB(t,e){if(!e||e.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const n=e.filePath||void 0;let r;if(e.development){if(typeof e.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");r=qB(n,e.jsxDEV)}else{if(typeof e.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof e.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");r=YB(n,e.jsx,e.jsxs)}const i={Fragment:e.Fragment,ancestors:[],components:e.components||{},create:r,elementAttributeNameCase:e.elementAttributeNameCase||"react",evaluater:e.createEvaluater?e.createEvaluater():void 0,filePath:n,ignoreInvalidStyle:e.ignoreInvalidStyle||!1,passKeys:e.passKeys!==!1,passNode:e.passNode||!1,schema:e.space==="svg"?Ml:sp,stylePropertyNameCase:e.stylePropertyNameCase||"dom",tableCellAlignToStyle:e.tableCellAlignToStyle!==!1},s=rk(i,t,void 0);return s&&typeof s!="string"?s:i.create(t,i.Fragment,{children:s||void 0},void 0)}function rk(t,e,n){if(e.type==="element")return jB(t,e,n);if(e.type==="mdxFlowExpression"||e.type==="mdxTextExpression")return $B(t,e);if(e.type==="mdxJsxFlowElement"||e.type==="mdxJsxTextElement")return VB(t,e,n);if(e.type==="mdxjsEsm")return WB(t,e);if(e.type==="root")return GB(t,e,n);if(e.type==="text")return KB(t,e)}function jB(t,e,n){const r=t.schema;let i=r;e.tagName.toLowerCase()==="svg"&&r.space==="html"&&(i=Ml,t.schema=i),t.ancestors.push(e);const s=sk(t,e.tagName,!1),o=XB(t,e);let l=GE(t,e);return UB.has(e.tagName)&&(l=l.filter(function(c){return typeof c=="string"?!vB(c):!0})),ik(t,o,s,e),VE(o,l),t.ancestors.pop(),t.schema=r,t.create(e,s,o,n)}function $B(t,e){if(e.data&&e.data.estree&&t.evaluater){const r=e.data.estree.body[0];return r.type,t.evaluater.evaluateExpression(r.expression)}hc(t,e.position)}function WB(t,e){if(e.data&&e.data.estree&&t.evaluater)return t.evaluater.evaluateProgram(e.data.estree);hc(t,e.position)}function VB(t,e,n){const r=t.schema;let i=r;e.name==="svg"&&r.space==="html"&&(i=Ml,t.schema=i),t.ancestors.push(e);const s=e.name===null?t.Fragment:sk(t,e.name,!0),o=QB(t,e),l=GE(t,e);return ik(t,o,s,e),VE(o,l),t.ancestors.pop(),t.schema=r,t.create(e,s,o,n)}function GB(t,e,n){const r={};return VE(r,GE(t,e)),t.create(e,t.Fragment,r,n)}function KB(t,e){return e.value}function ik(t,e,n,r){typeof n!="string"&&n!==t.Fragment&&t.passNode&&(e.node=r)}function VE(t,e){if(e.length>0){const n=e.length>1?e:e[0];n&&(t.children=n)}}function YB(t,e,n){return r;function r(i,s,o,l){const d=Array.isArray(o.children)?n:e;return l?d(s,o,l):d(s,o)}}function qB(t,e){return n;function n(r,i,s,o){const l=Array.isArray(s.children),c=Ji(r);return e(i,s,o,l,{columnNumber:c?c.column-1:void 0,fileName:t,lineNumber:c?c.line:void 0},void 0)}}function XB(t,e){const n={};let r,i;for(i in e.properties)if(i!=="children"&&WE.call(e.properties,i)){const s=ZB(t,i,e.properties[i]);if(s){const[o,l]=s;t.tableCellAlignToStyle&&o==="align"&&typeof l=="string"&&HB.has(e.tagName)?r=l:n[o]=l}}if(r){const s=n.style||(n.style={});s[t.stylePropertyNameCase==="css"?"text-align":"textAlign"]=r}return n}function QB(t,e){const n={};for(const r of e.attributes)if(r.type==="mdxJsxExpressionAttribute")if(r.data&&r.data.estree&&t.evaluater){const s=r.data.estree.body[0];s.type;const o=s.expression;o.type;const l=o.properties[0];l.type,Object.assign(n,t.evaluater.evaluateExpression(l.argument))}else hc(t,e.position);else{const i=r.name;let s;if(r.value&&typeof r.value=="object")if(r.value.data&&r.value.data.estree&&t.evaluater){const l=r.value.data.estree.body[0];l.type,s=t.evaluater.evaluateExpression(l.expression)}else hc(t,e.position);else s=r.value===null?!0:r.value;n[i]=s}return n}function GE(t,e){const n=[];let r=-1;const i=t.passKeys?new Map:FB;for(;++ri?0:i+e:e=e>i?i:e,n=n>0?n:0,r.length<1e4)o=Array.from(r),o.unshift(e,n),t.splice(...o);else for(n&&t.splice(e,n);s0?(Gr(t,t.length,0,e),t):e}const Sw={}.hasOwnProperty;function ak(t){const e={};let n=-1;for(;++n13&&n<32||n>126&&n<160||n>55295&&n<57344||n>64975&&n<65008||(n&65535)===65535||(n&65535)===65534||n>1114111?"�":String.fromCodePoint(n)}function vi(t){return t.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}const Er=po(/[A-Za-z]/),sr=po(/[\dA-Za-z]/),a5=po(/[#-'*+\--9=?A-Z^-~]/);function uh(t){return t!==null&&(t<32||t===127)}const q0=po(/\d/),l5=po(/[\dA-Fa-f]/),u5=po(/[!-/:-@[-`{-~]/);function et(t){return t!==null&&t<-2}function Kt(t){return t!==null&&(t<0||t===32)}function St(t){return t===-2||t===-1||t===32}const ap=po(new RegExp("\\p{P}|\\p{S}","u")),Xo=po(/\s/);function po(t){return e;function e(n){return n!==null&&n>-1&&t.test(String.fromCharCode(n))}}function Dl(t){const e=[];let n=-1,r=0,i=0;for(;++n55295&&s<57344){const l=t.charCodeAt(n+1);s<56320&&l>56319&&l<57344?(o=String.fromCharCode(s,l),i=1):o="�"}else o=String.fromCharCode(s);o&&(e.push(t.slice(r,n),encodeURIComponent(o)),r=n+i+1,o=""),i&&(n+=i,i=0)}return e.join("")+t.slice(r)}function Nt(t,e,n,r){const i=r?r-1:Number.POSITIVE_INFINITY;let s=0;return o;function o(c){return St(c)?(t.enter(n),l(c)):e(c)}function l(c){return St(c)&&s++o))return;const D=e.events.length;let G=D,X,P;for(;G--;)if(e.events[G][0]==="exit"&&e.events[G][1].type==="chunkFlow"){if(X){P=e.events[G][1].end;break}X=!0}for(C(r),I=D;Ik;){const F=n[M];e.containerState=F[1],F[0].exit.call(e,t)}n.length=k}function A(){i.write([null]),s=void 0,i=void 0,e.containerState._closeFlow=void 0}}function p5(t,e,n){return Nt(t,t.attempt(this.parser.constructs.document,e,n),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function bl(t){if(t===null||Kt(t)||Xo(t))return 1;if(ap(t))return 2}function lp(t,e,n){const r=[];let i=-1;for(;++i1&&t[n][1].end.offset-t[n][1].start.offset>1?2:1;const p={...t[r][1].end},m={...t[n][1].start};Cw(p,-c),Cw(m,c),o={type:c>1?"strongSequence":"emphasisSequence",start:p,end:{...t[r][1].end}},l={type:c>1?"strongSequence":"emphasisSequence",start:{...t[n][1].start},end:m},s={type:c>1?"strongText":"emphasisText",start:{...t[r][1].end},end:{...t[n][1].start}},i={type:c>1?"strong":"emphasis",start:{...o.start},end:{...l.end}},t[r][1].end={...o.start},t[n][1].start={...l.end},d=[],t[r][1].end.offset-t[r][1].start.offset&&(d=ti(d,[["enter",t[r][1],e],["exit",t[r][1],e]])),d=ti(d,[["enter",i,e],["enter",o,e],["exit",o,e],["enter",s,e]]),d=ti(d,lp(e.parser.constructs.insideSpan.null,t.slice(r+1,n),e)),d=ti(d,[["exit",s,e],["enter",l,e],["exit",l,e],["exit",i,e]]),t[n][1].end.offset-t[n][1].start.offset?(f=2,d=ti(d,[["enter",t[n][1],e],["exit",t[n][1],e]])):f=0,Gr(t,r-1,n-r+3,d),n=r+d.length-f-2;break}}for(n=-1;++n0&&St(I)?Nt(t,A,"linePrefix",s+1)(I):A(I)}function A(I){return I===null||et(I)?t.check(Aw,v,M)(I):(t.enter("codeFlowValue"),k(I))}function k(I){return I===null||et(I)?(t.exit("codeFlowValue"),A(I)):(t.consume(I),k)}function M(I){return t.exit("codeFenced"),e(I)}function F(I,D,G){let X=0;return P;function P(ee){return I.enter("lineEnding"),I.consume(ee),I.exit("lineEnding"),Y}function Y(ee){return I.enter("codeFencedFence"),St(ee)?Nt(I,z,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(ee):z(ee)}function z(ee){return ee===l?(I.enter("codeFencedFenceSequence"),ie(ee)):G(ee)}function ie(ee){return ee===l?(X++,I.consume(ee),ie):X>=o?(I.exit("codeFencedFenceSequence"),St(ee)?Nt(I,Z,"whitespace")(ee):Z(ee)):G(ee)}function Z(ee){return ee===null||et(ee)?(I.exit("codeFencedFence"),D(ee)):G(ee)}}}function C5(t,e,n){const r=this;return i;function i(o){return o===null?n(o):(t.enter("lineEnding"),t.consume(o),t.exit("lineEnding"),s)}function s(o){return r.parser.lazy[r.now().line]?n(o):e(o)}}const Ug={name:"codeIndented",tokenize:k5},A5={partial:!0,tokenize:N5};function k5(t,e,n){const r=this;return i;function i(d){return t.enter("codeIndented"),Nt(t,s,"linePrefix",5)(d)}function s(d){const f=r.events[r.events.length-1];return f&&f[1].type==="linePrefix"&&f[2].sliceSerialize(f[1],!0).length>=4?o(d):n(d)}function o(d){return d===null?c(d):et(d)?t.attempt(A5,o,c)(d):(t.enter("codeFlowValue"),l(d))}function l(d){return d===null||et(d)?(t.exit("codeFlowValue"),o(d)):(t.consume(d),l)}function c(d){return t.exit("codeIndented"),e(d)}}function N5(t,e,n){const r=this;return i;function i(o){return r.parser.lazy[r.now().line]?n(o):et(o)?(t.enter("lineEnding"),t.consume(o),t.exit("lineEnding"),i):Nt(t,s,"linePrefix",5)(o)}function s(o){const l=r.events[r.events.length-1];return l&&l[1].type==="linePrefix"&&l[2].sliceSerialize(l[1],!0).length>=4?e(o):et(o)?i(o):n(o)}}const R5={name:"codeText",previous:O5,resolve:I5,tokenize:M5};function I5(t){let e=t.length-4,n=3,r,i;if((t[n][1].type==="lineEnding"||t[n][1].type==="space")&&(t[e][1].type==="lineEnding"||t[e][1].type==="space")){for(r=n;++r=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+e+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return ethis.left.length?this.right.slice(this.right.length-r+this.left.length,this.right.length-e+this.left.length).reverse():this.left.slice(e).concat(this.right.slice(this.right.length-r+this.left.length).reverse())}splice(e,n,r){const i=n||0;this.setCursor(Math.trunc(e));const s=this.right.splice(this.right.length-i,Number.POSITIVE_INFINITY);return r&&Ru(this.left,r),s.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(e){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(e)}pushMany(e){this.setCursor(Number.POSITIVE_INFINITY),Ru(this.left,e)}unshift(e){this.setCursor(0),this.right.push(e)}unshiftMany(e){this.setCursor(0),Ru(this.right,e.reverse())}setCursor(e){if(!(e===this.left.length||e>this.left.length&&this.right.length===0||e<0&&this.left.length===0))if(e=4?e(o):t.interrupt(r.parser.constructs.flow,n,e)(o)}}function hk(t,e,n,r,i,s,o,l,c){const d=c||Number.POSITIVE_INFINITY;let f=0;return p;function p(C){return C===60?(t.enter(r),t.enter(i),t.enter(s),t.consume(C),t.exit(s),m):C===null||C===32||C===41||uh(C)?n(C):(t.enter(r),t.enter(o),t.enter(l),t.enter("chunkString",{contentType:"string"}),v(C))}function m(C){return C===62?(t.enter(s),t.consume(C),t.exit(s),t.exit(i),t.exit(r),e):(t.enter(l),t.enter("chunkString",{contentType:"string"}),g(C))}function g(C){return C===62?(t.exit("chunkString"),t.exit(l),m(C)):C===null||C===60||et(C)?n(C):(t.consume(C),C===92?x:g)}function x(C){return C===60||C===62||C===92?(t.consume(C),g):g(C)}function v(C){return!f&&(C===null||C===41||Kt(C))?(t.exit("chunkString"),t.exit(l),t.exit(o),t.exit(r),e(C)):f999||g===null||g===91||g===93&&!c||g===94&&!l&&"_hiddenFootnoteSupport"in o.parser.constructs?n(g):g===93?(t.exit(s),t.enter(i),t.consume(g),t.exit(i),t.exit(r),e):et(g)?(t.enter("lineEnding"),t.consume(g),t.exit("lineEnding"),f):(t.enter("chunkString",{contentType:"string"}),p(g))}function p(g){return g===null||g===91||g===93||et(g)||l++>999?(t.exit("chunkString"),f(g)):(t.consume(g),c||(c=!St(g)),g===92?m:p)}function m(g){return g===91||g===92||g===93?(t.consume(g),l++,p):p(g)}}function mk(t,e,n,r,i,s){let o;return l;function l(m){return m===34||m===39||m===40?(t.enter(r),t.enter(i),t.consume(m),t.exit(i),o=m===40?41:m,c):n(m)}function c(m){return m===o?(t.enter(i),t.consume(m),t.exit(i),t.exit(r),e):(t.enter(s),d(m))}function d(m){return m===o?(t.exit(s),c(o)):m===null?n(m):et(m)?(t.enter("lineEnding"),t.consume(m),t.exit("lineEnding"),Nt(t,d,"linePrefix")):(t.enter("chunkString",{contentType:"string"}),f(m))}function f(m){return m===o||m===null||et(m)?(t.exit("chunkString"),d(m)):(t.consume(m),m===92?p:f)}function p(m){return m===o||m===92?(t.consume(m),f):f(m)}}function Ku(t,e){let n;return r;function r(i){return et(i)?(t.enter("lineEnding"),t.consume(i),t.exit("lineEnding"),n=!0,r):St(i)?Nt(t,r,n?"linePrefix":"lineSuffix")(i):e(i)}}const z5={name:"definition",tokenize:$5},j5={partial:!0,tokenize:W5};function $5(t,e,n){const r=this;let i;return s;function s(g){return t.enter("definition"),o(g)}function o(g){return pk.call(r,t,l,n,"definitionLabel","definitionLabelMarker","definitionLabelString")(g)}function l(g){return i=vi(r.sliceSerialize(r.events[r.events.length-1][1]).slice(1,-1)),g===58?(t.enter("definitionMarker"),t.consume(g),t.exit("definitionMarker"),c):n(g)}function c(g){return Kt(g)?Ku(t,d)(g):d(g)}function d(g){return hk(t,f,n,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(g)}function f(g){return t.attempt(j5,p,p)(g)}function p(g){return St(g)?Nt(t,m,"whitespace")(g):m(g)}function m(g){return g===null||et(g)?(t.exit("definition"),r.parser.defined.push(i),e(g)):n(g)}}function W5(t,e,n){return r;function r(l){return Kt(l)?Ku(t,i)(l):n(l)}function i(l){return mk(t,s,n,"definitionTitle","definitionTitleMarker","definitionTitleString")(l)}function s(l){return St(l)?Nt(t,o,"whitespace")(l):o(l)}function o(l){return l===null||et(l)?e(l):n(l)}}const V5={name:"hardBreakEscape",tokenize:G5};function G5(t,e,n){return r;function r(s){return t.enter("hardBreakEscape"),t.consume(s),i}function i(s){return et(s)?(t.exit("hardBreakEscape"),e(s)):n(s)}}const K5={name:"headingAtx",resolve:Y5,tokenize:q5};function Y5(t,e){let n=t.length-2,r=3,i,s;return t[r][1].type==="whitespace"&&(r+=2),n-2>r&&t[n][1].type==="whitespace"&&(n-=2),t[n][1].type==="atxHeadingSequence"&&(r===n-1||n-4>r&&t[n-2][1].type==="whitespace")&&(n-=r+1===n?2:4),n>r&&(i={type:"atxHeadingText",start:t[r][1].start,end:t[n][1].end},s={type:"chunkText",start:t[r][1].start,end:t[n][1].end,contentType:"text"},Gr(t,r,n-r+1,[["enter",i,e],["enter",s,e],["exit",s,e],["exit",i,e]])),t}function q5(t,e,n){let r=0;return i;function i(f){return t.enter("atxHeading"),s(f)}function s(f){return t.enter("atxHeadingSequence"),o(f)}function o(f){return f===35&&r++<6?(t.consume(f),o):f===null||Kt(f)?(t.exit("atxHeadingSequence"),l(f)):n(f)}function l(f){return f===35?(t.enter("atxHeadingSequence"),c(f)):f===null||et(f)?(t.exit("atxHeading"),e(f)):St(f)?Nt(t,l,"whitespace")(f):(t.enter("atxHeadingText"),d(f))}function c(f){return f===35?(t.consume(f),c):(t.exit("atxHeadingSequence"),l(f))}function d(f){return f===null||f===35||Kt(f)?(t.exit("atxHeadingText"),l(f)):(t.consume(f),d)}}const X5=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],Nw=["pre","script","style","textarea"],Q5={concrete:!0,name:"htmlFlow",resolveTo:e8,tokenize:t8},Z5={partial:!0,tokenize:r8},J5={partial:!0,tokenize:n8};function e8(t){let e=t.length;for(;e--&&!(t[e][0]==="enter"&&t[e][1].type==="htmlFlow"););return e>1&&t[e-2][1].type==="linePrefix"&&(t[e][1].start=t[e-2][1].start,t[e+1][1].start=t[e-2][1].start,t.splice(e-2,2)),t}function t8(t,e,n){const r=this;let i,s,o,l,c;return d;function d(R){return f(R)}function f(R){return t.enter("htmlFlow"),t.enter("htmlFlowData"),t.consume(R),p}function p(R){return R===33?(t.consume(R),m):R===47?(t.consume(R),s=!0,v):R===63?(t.consume(R),i=3,r.interrupt?e:O):Er(R)?(t.consume(R),o=String.fromCharCode(R),S):n(R)}function m(R){return R===45?(t.consume(R),i=2,g):R===91?(t.consume(R),i=5,l=0,x):Er(R)?(t.consume(R),i=4,r.interrupt?e:O):n(R)}function g(R){return R===45?(t.consume(R),r.interrupt?e:O):n(R)}function x(R){const oe="CDATA[";return R===oe.charCodeAt(l++)?(t.consume(R),l===oe.length?r.interrupt?e:z:x):n(R)}function v(R){return Er(R)?(t.consume(R),o=String.fromCharCode(R),S):n(R)}function S(R){if(R===null||R===47||R===62||Kt(R)){const oe=R===47,pe=o.toLowerCase();return!oe&&!s&&Nw.includes(pe)?(i=1,r.interrupt?e(R):z(R)):X5.includes(o.toLowerCase())?(i=6,oe?(t.consume(R),C):r.interrupt?e(R):z(R)):(i=7,r.interrupt&&!r.parser.lazy[r.now().line]?n(R):s?A(R):k(R))}return R===45||sr(R)?(t.consume(R),o+=String.fromCharCode(R),S):n(R)}function C(R){return R===62?(t.consume(R),r.interrupt?e:z):n(R)}function A(R){return St(R)?(t.consume(R),A):P(R)}function k(R){return R===47?(t.consume(R),P):R===58||R===95||Er(R)?(t.consume(R),M):St(R)?(t.consume(R),k):P(R)}function M(R){return R===45||R===46||R===58||R===95||sr(R)?(t.consume(R),M):F(R)}function F(R){return R===61?(t.consume(R),I):St(R)?(t.consume(R),F):k(R)}function I(R){return R===null||R===60||R===61||R===62||R===96?n(R):R===34||R===39?(t.consume(R),c=R,D):St(R)?(t.consume(R),I):G(R)}function D(R){return R===c?(t.consume(R),c=null,X):R===null||et(R)?n(R):(t.consume(R),D)}function G(R){return R===null||R===34||R===39||R===47||R===60||R===61||R===62||R===96||Kt(R)?F(R):(t.consume(R),G)}function X(R){return R===47||R===62||St(R)?k(R):n(R)}function P(R){return R===62?(t.consume(R),Y):n(R)}function Y(R){return R===null||et(R)?z(R):St(R)?(t.consume(R),Y):n(R)}function z(R){return R===45&&i===2?(t.consume(R),ae):R===60&&i===1?(t.consume(R),de):R===62&&i===4?(t.consume(R),U):R===63&&i===3?(t.consume(R),O):R===93&&i===5?(t.consume(R),W):et(R)&&(i===6||i===7)?(t.exit("htmlFlowData"),t.check(Z5,Q,ie)(R)):R===null||et(R)?(t.exit("htmlFlowData"),ie(R)):(t.consume(R),z)}function ie(R){return t.check(J5,Z,Q)(R)}function Z(R){return t.enter("lineEnding"),t.consume(R),t.exit("lineEnding"),ee}function ee(R){return R===null||et(R)?ie(R):(t.enter("htmlFlowData"),z(R))}function ae(R){return R===45?(t.consume(R),O):z(R)}function de(R){return R===47?(t.consume(R),o="",j):z(R)}function j(R){if(R===62){const oe=o.toLowerCase();return Nw.includes(oe)?(t.consume(R),U):z(R)}return Er(R)&&o.length<8?(t.consume(R),o+=String.fromCharCode(R),j):z(R)}function W(R){return R===93?(t.consume(R),O):z(R)}function O(R){return R===62?(t.consume(R),U):R===45&&i===2?(t.consume(R),O):z(R)}function U(R){return R===null||et(R)?(t.exit("htmlFlowData"),Q(R)):(t.consume(R),U)}function Q(R){return t.exit("htmlFlow"),e(R)}}function n8(t,e,n){const r=this;return i;function i(o){return et(o)?(t.enter("lineEnding"),t.consume(o),t.exit("lineEnding"),s):n(o)}function s(o){return r.parser.lazy[r.now().line]?n(o):e(o)}}function r8(t,e,n){return r;function r(i){return t.enter("lineEnding"),t.consume(i),t.exit("lineEnding"),t.attempt(Dc,e,n)}}const i8={name:"htmlText",tokenize:s8};function s8(t,e,n){const r=this;let i,s,o;return l;function l(O){return t.enter("htmlText"),t.enter("htmlTextData"),t.consume(O),c}function c(O){return O===33?(t.consume(O),d):O===47?(t.consume(O),F):O===63?(t.consume(O),k):Er(O)?(t.consume(O),G):n(O)}function d(O){return O===45?(t.consume(O),f):O===91?(t.consume(O),s=0,x):Er(O)?(t.consume(O),A):n(O)}function f(O){return O===45?(t.consume(O),g):n(O)}function p(O){return O===null?n(O):O===45?(t.consume(O),m):et(O)?(o=p,de(O)):(t.consume(O),p)}function m(O){return O===45?(t.consume(O),g):p(O)}function g(O){return O===62?ae(O):O===45?m(O):p(O)}function x(O){const U="CDATA[";return O===U.charCodeAt(s++)?(t.consume(O),s===U.length?v:x):n(O)}function v(O){return O===null?n(O):O===93?(t.consume(O),S):et(O)?(o=v,de(O)):(t.consume(O),v)}function S(O){return O===93?(t.consume(O),C):v(O)}function C(O){return O===62?ae(O):O===93?(t.consume(O),C):v(O)}function A(O){return O===null||O===62?ae(O):et(O)?(o=A,de(O)):(t.consume(O),A)}function k(O){return O===null?n(O):O===63?(t.consume(O),M):et(O)?(o=k,de(O)):(t.consume(O),k)}function M(O){return O===62?ae(O):k(O)}function F(O){return Er(O)?(t.consume(O),I):n(O)}function I(O){return O===45||sr(O)?(t.consume(O),I):D(O)}function D(O){return et(O)?(o=D,de(O)):St(O)?(t.consume(O),D):ae(O)}function G(O){return O===45||sr(O)?(t.consume(O),G):O===47||O===62||Kt(O)?X(O):n(O)}function X(O){return O===47?(t.consume(O),ae):O===58||O===95||Er(O)?(t.consume(O),P):et(O)?(o=X,de(O)):St(O)?(t.consume(O),X):ae(O)}function P(O){return O===45||O===46||O===58||O===95||sr(O)?(t.consume(O),P):Y(O)}function Y(O){return O===61?(t.consume(O),z):et(O)?(o=Y,de(O)):St(O)?(t.consume(O),Y):X(O)}function z(O){return O===null||O===60||O===61||O===62||O===96?n(O):O===34||O===39?(t.consume(O),i=O,ie):et(O)?(o=z,de(O)):St(O)?(t.consume(O),z):(t.consume(O),Z)}function ie(O){return O===i?(t.consume(O),i=void 0,ee):O===null?n(O):et(O)?(o=ie,de(O)):(t.consume(O),ie)}function Z(O){return O===null||O===34||O===39||O===60||O===61||O===96?n(O):O===47||O===62||Kt(O)?X(O):(t.consume(O),Z)}function ee(O){return O===47||O===62||Kt(O)?X(O):n(O)}function ae(O){return O===62?(t.consume(O),t.exit("htmlTextData"),t.exit("htmlText"),e):n(O)}function de(O){return t.exit("htmlTextData"),t.enter("lineEnding"),t.consume(O),t.exit("lineEnding"),j}function j(O){return St(O)?Nt(t,W,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(O):W(O)}function W(O){return t.enter("htmlTextData"),o(O)}}const qE={name:"labelEnd",resolveAll:u8,resolveTo:c8,tokenize:d8},o8={tokenize:f8},a8={tokenize:h8},l8={tokenize:p8};function u8(t){let e=-1;const n=[];for(;++e=3&&(d===null||et(d))?(t.exit("thematicBreak"),e(d)):n(d)}function c(d){return d===i?(t.consume(d),r++,c):(t.exit("thematicBreakSequence"),St(d)?Nt(t,l,"whitespace")(d):l(d))}}const Nr={continuation:{tokenize:S8},exit:C8,name:"list",tokenize:T8},v8={partial:!0,tokenize:A8},w8={partial:!0,tokenize:_8};function T8(t,e,n){const r=this,i=r.events[r.events.length-1];let s=i&&i[1].type==="linePrefix"?i[2].sliceSerialize(i[1],!0).length:0,o=0;return l;function l(g){const x=r.containerState.type||(g===42||g===43||g===45?"listUnordered":"listOrdered");if(x==="listUnordered"?!r.containerState.marker||g===r.containerState.marker:q0(g)){if(r.containerState.type||(r.containerState.type=x,t.enter(x,{_container:!0})),x==="listUnordered")return t.enter("listItemPrefix"),g===42||g===45?t.check(Bf,n,d)(g):d(g);if(!r.interrupt||g===49)return t.enter("listItemPrefix"),t.enter("listItemValue"),c(g)}return n(g)}function c(g){return q0(g)&&++o<10?(t.consume(g),c):(!r.interrupt||o<2)&&(r.containerState.marker?g===r.containerState.marker:g===41||g===46)?(t.exit("listItemValue"),d(g)):n(g)}function d(g){return t.enter("listItemMarker"),t.consume(g),t.exit("listItemMarker"),r.containerState.marker=r.containerState.marker||g,t.check(Dc,r.interrupt?n:f,t.attempt(v8,m,p))}function f(g){return r.containerState.initialBlankLine=!0,s++,m(g)}function p(g){return St(g)?(t.enter("listItemPrefixWhitespace"),t.consume(g),t.exit("listItemPrefixWhitespace"),m):n(g)}function m(g){return r.containerState.size=s+r.sliceSerialize(t.exit("listItemPrefix"),!0).length,e(g)}}function S8(t,e,n){const r=this;return r.containerState._closeFlow=void 0,t.check(Dc,i,s);function i(l){return r.containerState.furtherBlankLines=r.containerState.furtherBlankLines||r.containerState.initialBlankLine,Nt(t,e,"listItemIndent",r.containerState.size+1)(l)}function s(l){return r.containerState.furtherBlankLines||!St(l)?(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,o(l)):(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,t.attempt(w8,e,o)(l))}function o(l){return r.containerState._closeFlow=!0,r.interrupt=void 0,Nt(t,t.attempt(Nr,e,n),"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(l)}}function _8(t,e,n){const r=this;return Nt(t,i,"listItemIndent",r.containerState.size+1);function i(s){const o=r.events[r.events.length-1];return o&&o[1].type==="listItemIndent"&&o[2].sliceSerialize(o[1],!0).length===r.containerState.size?e(s):n(s)}}function C8(t){t.exit(this.containerState.type)}function A8(t,e,n){const r=this;return Nt(t,i,"listItemPrefixWhitespace",r.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function i(s){const o=r.events[r.events.length-1];return!St(s)&&o&&o[1].type==="listItemPrefixWhitespace"?e(s):n(s)}}const Rw={name:"setextUnderline",resolveTo:k8,tokenize:N8};function k8(t,e){let n=t.length,r,i,s;for(;n--;)if(t[n][0]==="enter"){if(t[n][1].type==="content"){r=n;break}t[n][1].type==="paragraph"&&(i=n)}else t[n][1].type==="content"&&t.splice(n,1),!s&&t[n][1].type==="definition"&&(s=n);const o={type:"setextHeading",start:{...t[r][1].start},end:{...t[t.length-1][1].end}};return t[i][1].type="setextHeadingText",s?(t.splice(i,0,["enter",o,e]),t.splice(s+1,0,["exit",t[r][1],e]),t[r][1].end={...t[s][1].end}):t[r][1]=o,t.push(["exit",o,e]),t}function N8(t,e,n){const r=this;let i;return s;function s(d){let f=r.events.length,p;for(;f--;)if(r.events[f][1].type!=="lineEnding"&&r.events[f][1].type!=="linePrefix"&&r.events[f][1].type!=="content"){p=r.events[f][1].type==="paragraph";break}return!r.parser.lazy[r.now().line]&&(r.interrupt||p)?(t.enter("setextHeadingLine"),i=d,o(d)):n(d)}function o(d){return t.enter("setextHeadingLineSequence"),l(d)}function l(d){return d===i?(t.consume(d),l):(t.exit("setextHeadingLineSequence"),St(d)?Nt(t,c,"lineSuffix")(d):c(d))}function c(d){return d===null||et(d)?(t.exit("setextHeadingLine"),e(d)):n(d)}}const R8={tokenize:I8};function I8(t){const e=this,n=t.attempt(Dc,r,t.attempt(this.parser.constructs.flowInitial,i,Nt(t,t.attempt(this.parser.constructs.flow,i,t.attempt(P5,i)),"linePrefix")));return n;function r(s){if(s===null){t.consume(s);return}return t.enter("lineEndingBlank"),t.consume(s),t.exit("lineEndingBlank"),e.currentConstruct=void 0,n}function i(s){if(s===null){t.consume(s);return}return t.enter("lineEnding"),t.consume(s),t.exit("lineEnding"),e.currentConstruct=void 0,n}}const O8={resolveAll:bk()},M8=gk("string"),D8=gk("text");function gk(t){return{resolveAll:bk(t==="text"?L8:void 0),tokenize:e};function e(n){const r=this,i=this.parser.constructs[t],s=n.attempt(i,o,l);return o;function o(f){return d(f)?s(f):l(f)}function l(f){if(f===null){n.consume(f);return}return n.enter("data"),n.consume(f),c}function c(f){return d(f)?(n.exit("data"),s(f)):(n.consume(f),c)}function d(f){if(f===null)return!0;const p=i[f];let m=-1;if(p)for(;++m-1){const l=o[0];typeof l=="string"?o[0]=l.slice(r):o.shift()}s>0&&o.push(t[i].slice(0,s))}return o}function Y8(t,e){let n=-1;const r=[];let i;for(;++n0){const an=Qe.tokenStack[Qe.tokenStack.length-1];(an[1]||Ow).call(Qe,void 0,an[0])}for(ye.position={start:Qs(ce.length>0?ce[0][1].start:{line:1,column:1,offset:0}),end:Qs(ce.length>0?ce[ce.length-2][1].end:{line:1,column:1,offset:0})},rt=-1;++rt0&&(r.className=["language-"+i[0]]);let s={type:"element",tagName:"code",properties:r,children:[{type:"text",value:n}]};return e.meta&&(s.data={meta:e.meta}),t.patch(e,s),s=t.applyData(e,s),s={type:"element",tagName:"pre",properties:{},children:[s]},t.patch(e,s),s}function l9(t,e){const n={type:"element",tagName:"del",properties:{},children:t.all(e)};return t.patch(e,n),t.applyData(e,n)}function u9(t,e){const n={type:"element",tagName:"em",properties:{},children:t.all(e)};return t.patch(e,n),t.applyData(e,n)}function c9(t,e){const n=typeof t.options.clobberPrefix=="string"?t.options.clobberPrefix:"user-content-",r=String(e.identifier).toUpperCase(),i=Dl(r.toLowerCase()),s=t.footnoteOrder.indexOf(r);let o,l=t.footnoteCounts.get(r);l===void 0?(l=0,t.footnoteOrder.push(r),o=t.footnoteOrder.length):o=s+1,l+=1,t.footnoteCounts.set(r,l);const c={type:"element",tagName:"a",properties:{href:"#"+n+"fn-"+i,id:n+"fnref-"+i+(l>1?"-"+l:""),dataFootnoteRef:!0,ariaDescribedBy:["footnote-label"]},children:[{type:"text",value:String(o)}]};t.patch(e,c);const d={type:"element",tagName:"sup",properties:{},children:[c]};return t.patch(e,d),t.applyData(e,d)}function d9(t,e){const n={type:"element",tagName:"h"+e.depth,properties:{},children:t.all(e)};return t.patch(e,n),t.applyData(e,n)}function f9(t,e){if(t.options.allowDangerousHtml){const n={type:"raw",value:e.value};return t.patch(e,n),t.applyData(e,n)}}function xk(t,e){const n=e.referenceType;let r="]";if(n==="collapsed"?r+="[]":n==="full"&&(r+="["+(e.label||e.identifier)+"]"),e.type==="imageReference")return[{type:"text",value:"!["+e.alt+r}];const i=t.all(e),s=i[0];s&&s.type==="text"?s.value="["+s.value:i.unshift({type:"text",value:"["});const o=i[i.length-1];return o&&o.type==="text"?o.value+=r:i.push({type:"text",value:r}),i}function h9(t,e){const n=String(e.identifier).toUpperCase(),r=t.definitionById.get(n);if(!r)return xk(t,e);const i={src:Dl(r.url||""),alt:e.alt};r.title!==null&&r.title!==void 0&&(i.title=r.title);const s={type:"element",tagName:"img",properties:i,children:[]};return t.patch(e,s),t.applyData(e,s)}function p9(t,e){const n={src:Dl(e.url)};e.alt!==null&&e.alt!==void 0&&(n.alt=e.alt),e.title!==null&&e.title!==void 0&&(n.title=e.title);const r={type:"element",tagName:"img",properties:n,children:[]};return t.patch(e,r),t.applyData(e,r)}function m9(t,e){const n={type:"text",value:e.value.replace(/\r?\n|\r/g," ")};t.patch(e,n);const r={type:"element",tagName:"code",properties:{},children:[n]};return t.patch(e,r),t.applyData(e,r)}function g9(t,e){const n=String(e.identifier).toUpperCase(),r=t.definitionById.get(n);if(!r)return xk(t,e);const i={href:Dl(r.url||"")};r.title!==null&&r.title!==void 0&&(i.title=r.title);const s={type:"element",tagName:"a",properties:i,children:t.all(e)};return t.patch(e,s),t.applyData(e,s)}function b9(t,e){const n={href:Dl(e.url)};e.title!==null&&e.title!==void 0&&(n.title=e.title);const r={type:"element",tagName:"a",properties:n,children:t.all(e)};return t.patch(e,r),t.applyData(e,r)}function E9(t,e,n){const r=t.all(e),i=n?y9(n):vk(e),s={},o=[];if(typeof e.checked=="boolean"){const f=r[0];let p;f&&f.type==="element"&&f.tagName==="p"?p=f:(p={type:"element",tagName:"p",properties:{},children:[]},r.unshift(p)),p.children.length>0&&p.children.unshift({type:"text",value:" "}),p.children.unshift({type:"element",tagName:"input",properties:{type:"checkbox",checked:e.checked,disabled:!0},children:[]}),s.className=["task-list-item"]}let l=-1;for(;++l1}function x9(t,e){const n={},r=t.all(e);let i=-1;for(typeof e.start=="number"&&e.start!==1&&(n.start=e.start);++i0){const o={type:"element",tagName:"tbody",properties:{},children:t.wrap(n,!0)},l=Ji(e.children[1]),c=op(e.children[e.children.length-1]);l&&c&&(o.position={start:l,end:c}),i.push(o)}const s={type:"element",tagName:"table",properties:{},children:t.wrap(i,!0)};return t.patch(e,s),t.applyData(e,s)}function _9(t,e,n){const r=n?n.children:void 0,s=(r?r.indexOf(e):1)===0?"th":"td",o=n&&n.type==="table"?n.align:void 0,l=o?o.length:e.children.length;let c=-1;const d=[];for(;++c0,!0),r[0]),i=r.index+r[0].length,r=n.exec(e);return s.push(Lw(e.slice(i),i>0,!1)),s.join("")}function Lw(t,e,n){let r=0,i=t.length;if(e){let s=t.codePointAt(r);for(;s===Mw||s===Dw;)r++,s=t.codePointAt(r)}if(n){let s=t.codePointAt(i-1);for(;s===Mw||s===Dw;)i--,s=t.codePointAt(i-1)}return i>r?t.slice(r,i):""}function k9(t,e){const n={type:"text",value:A9(String(e.value))};return t.patch(e,n),t.applyData(e,n)}function N9(t,e){const n={type:"element",tagName:"hr",properties:{},children:[]};return t.patch(e,n),t.applyData(e,n)}const R9={blockquote:s9,break:o9,code:a9,delete:l9,emphasis:u9,footnoteReference:c9,heading:d9,html:f9,imageReference:h9,image:p9,inlineCode:m9,linkReference:g9,link:b9,listItem:E9,list:x9,paragraph:v9,root:w9,strong:T9,table:S9,tableCell:C9,tableRow:_9,text:k9,thematicBreak:N9,toml:lf,yaml:lf,definition:lf,footnoteDefinition:lf};function lf(){}const wk=-1,up=0,Yu=1,ch=2,XE=3,QE=4,ZE=5,JE=6,Tk=7,Sk=8,Pw=typeof self=="object"?self:globalThis,I9=(t,e)=>{const n=(i,s)=>(t.set(s,i),i),r=i=>{if(t.has(i))return t.get(i);const[s,o]=e[i];switch(s){case up:case wk:return n(o,i);case Yu:{const l=n([],i);for(const c of o)l.push(r(c));return l}case ch:{const l=n({},i);for(const[c,d]of o)l[r(c)]=r(d);return l}case XE:return n(new Date(o),i);case QE:{const{source:l,flags:c}=o;return n(new RegExp(l,c),i)}case ZE:{const l=n(new Map,i);for(const[c,d]of o)l.set(r(c),r(d));return l}case JE:{const l=n(new Set,i);for(const c of o)l.add(r(c));return l}case Tk:{const{name:l,message:c}=o;return n(new Pw[l](c),i)}case Sk:return n(BigInt(o),i);case"BigInt":return n(Object(BigInt(o)),i);case"ArrayBuffer":return n(new Uint8Array(o).buffer,o);case"DataView":{const{buffer:l}=new Uint8Array(o);return n(new DataView(l),o)}}return n(new Pw[s](o),i)};return r},Fw=t=>I9(new Map,t)(0),ja="",{toString:O9}={},{keys:M9}=Object,Iu=t=>{const e=typeof t;if(e!=="object"||!t)return[up,e];const n=O9.call(t).slice(8,-1);switch(n){case"Array":return[Yu,ja];case"Object":return[ch,ja];case"Date":return[XE,ja];case"RegExp":return[QE,ja];case"Map":return[ZE,ja];case"Set":return[JE,ja];case"DataView":return[Yu,n]}return n.includes("Array")?[Yu,n]:n.includes("Error")?[Tk,n]:[ch,n]},uf=([t,e])=>t===up&&(e==="function"||e==="symbol"),D9=(t,e,n,r)=>{const i=(o,l)=>{const c=r.push(o)-1;return n.set(l,c),c},s=o=>{if(n.has(o))return n.get(o);let[l,c]=Iu(o);switch(l){case up:{let f=o;switch(c){case"bigint":l=Sk,f=o.toString();break;case"function":case"symbol":if(t)throw new TypeError("unable to serialize "+c);f=null;break;case"undefined":return i([wk],o)}return i([l,f],o)}case Yu:{if(c){let m=o;return c==="DataView"?m=new Uint8Array(o.buffer):c==="ArrayBuffer"&&(m=new Uint8Array(o)),i([c,[...m]],o)}const f=[],p=i([l,f],o);for(const m of o)f.push(s(m));return p}case ch:{if(c)switch(c){case"BigInt":return i([c,o.toString()],o);case"Boolean":case"Number":case"String":return i([c,o.valueOf()],o)}if(e&&"toJSON"in o)return s(o.toJSON());const f=[],p=i([l,f],o);for(const m of M9(o))(t||!uf(Iu(o[m])))&&f.push([s(m),s(o[m])]);return p}case XE:return i([l,o.toISOString()],o);case QE:{const{source:f,flags:p}=o;return i([l,{source:f,flags:p}],o)}case ZE:{const f=[],p=i([l,f],o);for(const[m,g]of o)(t||!(uf(Iu(m))||uf(Iu(g))))&&f.push([s(m),s(g)]);return p}case JE:{const f=[],p=i([l,f],o);for(const m of o)(t||!uf(Iu(m)))&&f.push(s(m));return p}}const{message:d}=o;return i([l,{name:c,message:d}],o)};return s},Bw=(t,{json:e,lossy:n}={})=>{const r=[];return D9(!(e||n),!!e,new Map,r)(t),r},El=typeof structuredClone=="function"?(t,e)=>e&&("json"in e||"lossy"in e)?Fw(Bw(t,e)):structuredClone(t):(t,e)=>Fw(Bw(t,e));function L9(t,e){const n=[{type:"text",value:"↩"}];return e>1&&n.push({type:"element",tagName:"sup",properties:{},children:[{type:"text",value:String(e)}]}),n}function P9(t,e){return"Back to reference "+(t+1)+(e>1?"-"+e:"")}function F9(t){const e=typeof t.options.clobberPrefix=="string"?t.options.clobberPrefix:"user-content-",n=t.options.footnoteBackContent||L9,r=t.options.footnoteBackLabel||P9,i=t.options.footnoteLabel||"Footnotes",s=t.options.footnoteLabelTagName||"h2",o=t.options.footnoteLabelProperties||{className:["sr-only"]},l=[];let c=-1;for(;++c0&&x.push({type:"text",value:" "});let A=typeof n=="string"?n:n(c,g);typeof A=="string"&&(A={type:"text",value:A}),x.push({type:"element",tagName:"a",properties:{href:"#"+e+"fnref-"+m+(g>1?"-"+g:""),dataFootnoteBackref:"",ariaLabel:typeof r=="string"?r:r(c,g),className:["data-footnote-backref"]},children:Array.isArray(A)?A:[A]})}const S=f[f.length-1];if(S&&S.type==="element"&&S.tagName==="p"){const A=S.children[S.children.length-1];A&&A.type==="text"?A.value+=" ":S.children.push({type:"text",value:" "}),S.children.push(...x)}else f.push(...x);const C={type:"element",tagName:"li",properties:{id:e+"fn-"+m},children:t.wrap(f,!0)};t.patch(d,C),l.push(C)}if(l.length!==0)return{type:"element",tagName:"section",properties:{dataFootnotes:!0,className:["footnotes"]},children:[{type:"element",tagName:s,properties:{...El(o),id:"footnote-label"},children:[{type:"text",value:i}]},{type:"text",value:` +`},{type:"element",tagName:"ol",properties:{},children:t.wrap(l,!0)},{type:"text",value:` +`}]}}const Lc=(function(t){if(t==null)return z9;if(typeof t=="function")return cp(t);if(typeof t=="object")return Array.isArray(t)?B9(t):U9(t);if(typeof t=="string")return H9(t);throw new Error("Expected function, string, or object as test")});function B9(t){const e=[];let n=-1;for(;++n":""))+")"})}return m;function m(){let g=_k,x,v,S;if((!e||s(c,d,f[f.length-1]||void 0))&&(g=V9(n(c,f)),g[0]===Q0))return g;if("children"in c&&c.children){const C=c;if(C.children&&g[0]!==W9)for(v=(r?C.children.length:-1)+o,S=f.concat(C);v>-1&&v0&&n.push({type:"text",value:` +`}),n}function Uw(t){let e=0,n=t.charCodeAt(e);for(;n===9||n===32;)e++,n=t.charCodeAt(e);return t.slice(e)}function Hw(t,e){const n=K9(t,e),r=n.one(t,void 0),i=F9(n),s=Array.isArray(r)?{type:"root",children:r}:r||{type:"root",children:[]};return i&&s.children.push({type:"text",value:` +`},i),s}function Z9(t,e){return t&&"run"in t?async function(n,r){const i=Hw(n,{file:r,...e});await t.run(i,r)}:function(n,r){return Hw(n,{file:r,...t||e})}}function zw(t){if(t)throw t}var zg,jw;function J9(){if(jw)return zg;jw=1;var t=Object.prototype.hasOwnProperty,e=Object.prototype.toString,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=function(d){return typeof Array.isArray=="function"?Array.isArray(d):e.call(d)==="[object Array]"},s=function(d){if(!d||e.call(d)!=="[object Object]")return!1;var f=t.call(d,"constructor"),p=d.constructor&&d.constructor.prototype&&t.call(d.constructor.prototype,"isPrototypeOf");if(d.constructor&&!f&&!p)return!1;var m;for(m in d);return typeof m>"u"||t.call(d,m)},o=function(d,f){n&&f.name==="__proto__"?n(d,f.name,{enumerable:!0,configurable:!0,value:f.newValue,writable:!0}):d[f.name]=f.newValue},l=function(d,f){if(f==="__proto__")if(t.call(d,f)){if(r)return r(d,f).value}else return;return d[f]};return zg=function c(){var d,f,p,m,g,x,v=arguments[0],S=1,C=arguments.length,A=!1;for(typeof v=="boolean"&&(A=v,v=arguments[1]||{},S=2),(v==null||typeof v!="object"&&typeof v!="function")&&(v={});So.length;let c;l&&o.push(i);try{c=t.apply(this,o)}catch(d){const f=d;if(l&&n)throw f;return i(f)}l||(c&&c.then&&typeof c.then=="function"?c.then(s,i):c instanceof Error?i(c):s(c))}function i(o,...l){n||(n=!0,e(o,...l))}function s(o){i(null,o)}}const Ui={basename:rU,dirname:iU,extname:sU,join:oU,sep:"/"};function rU(t,e){if(e!==void 0&&typeof e!="string")throw new TypeError('"ext" argument must be a string');Fc(t);let n=0,r=-1,i=t.length,s;if(e===void 0||e.length===0||e.length>t.length){for(;i--;)if(t.codePointAt(i)===47){if(s){n=i+1;break}}else r<0&&(s=!0,r=i+1);return r<0?"":t.slice(n,r)}if(e===t)return"";let o=-1,l=e.length-1;for(;i--;)if(t.codePointAt(i)===47){if(s){n=i+1;break}}else o<0&&(s=!0,o=i+1),l>-1&&(t.codePointAt(i)===e.codePointAt(l--)?l<0&&(r=i):(l=-1,r=o));return n===r?r=o:r<0&&(r=t.length),t.slice(n,r)}function iU(t){if(Fc(t),t.length===0)return".";let e=-1,n=t.length,r;for(;--n;)if(t.codePointAt(n)===47){if(r){e=n;break}}else r||(r=!0);return e<0?t.codePointAt(0)===47?"/":".":e===1&&t.codePointAt(0)===47?"//":t.slice(0,e)}function sU(t){Fc(t);let e=t.length,n=-1,r=0,i=-1,s=0,o;for(;e--;){const l=t.codePointAt(e);if(l===47){if(o){r=e+1;break}continue}n<0&&(o=!0,n=e+1),l===46?i<0?i=e:s!==1&&(s=1):i>-1&&(s=-1)}return i<0||n<0||s===0||s===1&&i===n-1&&i===r+1?"":t.slice(i,n)}function oU(...t){let e=-1,n;for(;++e0&&t.codePointAt(t.length-1)===47&&(n+="/"),e?"/"+n:n}function lU(t,e){let n="",r=0,i=-1,s=0,o=-1,l,c;for(;++o<=t.length;){if(o2){if(c=n.lastIndexOf("/"),c!==n.length-1){c<0?(n="",r=0):(n=n.slice(0,c),r=n.length-1-n.lastIndexOf("/")),i=o,s=0;continue}}else if(n.length>0){n="",r=0,i=o,s=0;continue}}e&&(n=n.length>0?n+"/..":"..",r=2)}else n.length>0?n+="/"+t.slice(i+1,o):n=t.slice(i+1,o),r=o-i-1;i=o,s=0}else l===46&&s>-1?s++:s=-1}return n}function Fc(t){if(typeof t!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(t))}const uU={cwd:cU};function cU(){return"/"}function eb(t){return!!(t!==null&&typeof t=="object"&&"href"in t&&t.href&&"protocol"in t&&t.protocol&&t.auth===void 0)}function dU(t){if(typeof t=="string")t=new URL(t);else if(!eb(t)){const e=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+t+"`");throw e.code="ERR_INVALID_ARG_TYPE",e}if(t.protocol!=="file:"){const e=new TypeError("The URL must be of scheme file");throw e.code="ERR_INVALID_URL_SCHEME",e}return fU(t)}function fU(t){if(t.hostname!==""){const r=new TypeError('File URL host must be "localhost" or empty on darwin');throw r.code="ERR_INVALID_FILE_URL_HOST",r}const e=t.pathname;let n=-1;for(;++n0){let[g,...x]=f;const v=r[m][1];J0(v)&&J0(g)&&(g=jg(!0,v,g)),r[m]=[d,g,...x]}}}}const gU=new e1().freeze();function Gg(t,e){if(typeof e!="function")throw new TypeError("Cannot `"+t+"` without `parser`")}function Kg(t,e){if(typeof e!="function")throw new TypeError("Cannot `"+t+"` without `compiler`")}function Yg(t,e){if(e)throw new Error("Cannot call `"+t+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Ww(t){if(!J0(t)||typeof t.type!="string")throw new TypeError("Expected node, got `"+t+"`")}function Vw(t,e,n){if(!n)throw new Error("`"+t+"` finished async. Use `"+e+"` instead")}function cf(t){return bU(t)?t:new Ak(t)}function bU(t){return!!(t&&typeof t=="object"&&"message"in t&&"messages"in t)}function EU(t){return typeof t=="string"||yU(t)}function yU(t){return!!(t&&typeof t=="object"&&"byteLength"in t&&"byteOffset"in t)}const xU="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",Gw=[],Kw={allowDangerousHtml:!0},vU=/^(https?|ircs?|mailto|xmpp)$/i,wU=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function TU(t){const e=SU(t),n=_U(t);return CU(e.runSync(e.parse(n),n),t)}function SU(t){const e=t.rehypePlugins||Gw,n=t.remarkPlugins||Gw,r=t.remarkRehypeOptions?{...t.remarkRehypeOptions,...Kw}:Kw;return gU().use(i9).use(n).use(Z9,r).use(e)}function _U(t){const e=t.children||"",n=new Ak;return typeof e=="string"&&(n.value=e),n}function CU(t,e){const n=e.allowedElements,r=e.allowElement,i=e.components,s=e.disallowedElements,o=e.skipHtml,l=e.unwrapDisallowed,c=e.urlTransform||AU;for(const f of wU)Object.hasOwn(e,f.from)&&(""+f.from+(f.to?"use `"+f.to+"` instead":"remove it")+xU+f.id,void 0);return e.className&&(t={type:"element",tagName:"div",properties:{className:e.className},children:t.type==="root"?t.children:[t]}),Pc(t,d),zB(t,{Fragment:w.Fragment,components:i,ignoreInvalidStyle:!0,jsx:w.jsx,jsxs:w.jsxs,passKeys:!0,passNode:!0});function d(f,p,m){if(f.type==="raw"&&m&&typeof p=="number")return o?m.children.splice(p,1):m.children[p]={type:"text",value:f.value},p;if(f.type==="element"){let g;for(g in Bg)if(Object.hasOwn(Bg,g)&&Object.hasOwn(f.properties,g)){const x=f.properties[g],v=Bg[g];(v===null||v.includes(f.tagName))&&(f.properties[g]=c(String(x||""),g,f))}}if(f.type==="element"){let g=n?!n.includes(f.tagName):s?s.includes(f.tagName):!1;if(!g&&r&&typeof p=="number"&&(g=!r(f,p,m)),g&&m&&typeof p=="number")return l&&f.children?m.children.splice(p,1,...f.children):m.children.splice(p,1),p}}}function AU(t){const e=t.indexOf(":"),n=t.indexOf("?"),r=t.indexOf("#"),i=t.indexOf("/");return e===-1||i!==-1&&e>i||n!==-1&&e>n||r!==-1&&e>r||vU.test(t.slice(0,e))?t:""}function Yw(t,e){const n=String(t);if(typeof e!="string")throw new TypeError("Expected character");let r=0,i=n.indexOf(e);for(;i!==-1;)r++,i=n.indexOf(e,i+e.length);return r}function kU(t){if(typeof t!="string")throw new TypeError("Expected a string");return t.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}function NU(t,e,n){const i=Lc((n||{}).ignore||[]),s=RU(e);let o=-1;for(;++o0?{type:"text",value:I}:void 0),I===!1?m.lastIndex=M+1:(x!==M&&A.push({type:"text",value:d.value.slice(x,M)}),Array.isArray(I)?A.push(...I):I&&A.push(I),x=M+k[0].length,C=!0),!m.global)break;k=m.exec(d.value)}return C?(x?\]}]+$/.exec(t);if(!e)return[t,void 0];t=t.slice(0,e.index);let n=e[0],r=n.indexOf(")");const i=Yw(t,"(");let s=Yw(t,")");for(;r!==-1&&i>s;)t+=n.slice(0,r+1),n=n.slice(r+1),r=n.indexOf(")"),s++;return[t,n]}function kk(t,e){const n=t.input.charCodeAt(t.index-1);return(t.index===0||Xo(n)||ap(n))&&(!e||n!==47)}Nk.peek=JU;function VU(){this.buffer()}function GU(t){this.enter({type:"footnoteReference",identifier:"",label:""},t)}function KU(){this.buffer()}function YU(t){this.enter({type:"footnoteDefinition",identifier:"",label:"",children:[]},t)}function qU(t){const e=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=vi(this.sliceSerialize(t)).toLowerCase(),n.label=e}function XU(t){this.exit(t)}function QU(t){const e=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=vi(this.sliceSerialize(t)).toLowerCase(),n.label=e}function ZU(t){this.exit(t)}function JU(){return"["}function Nk(t,e,n,r){const i=n.createTracker(r);let s=i.move("[^");const o=n.enter("footnoteReference"),l=n.enter("reference");return s+=i.move(n.safe(n.associationId(t),{after:"]",before:s})),l(),o(),s+=i.move("]"),s}function eH(){return{enter:{gfmFootnoteCallString:VU,gfmFootnoteCall:GU,gfmFootnoteDefinitionLabelString:KU,gfmFootnoteDefinition:YU},exit:{gfmFootnoteCallString:qU,gfmFootnoteCall:XU,gfmFootnoteDefinitionLabelString:QU,gfmFootnoteDefinition:ZU}}}function tH(t){let e=!1;return t&&t.firstLineBlank&&(e=!0),{handlers:{footnoteDefinition:n,footnoteReference:Nk},unsafe:[{character:"[",inConstruct:["label","phrasing","reference"]}]};function n(r,i,s,o){const l=s.createTracker(o);let c=l.move("[^");const d=s.enter("footnoteDefinition"),f=s.enter("label");return c+=l.move(s.safe(s.associationId(r),{before:c,after:"]"})),f(),c+=l.move("]:"),r.children&&r.children.length>0&&(l.shift(4),c+=l.move((e?` +`:" ")+s.indentLines(s.containerFlow(r,l.current()),e?Rk:nH))),d(),c}}function nH(t,e,n){return e===0?t:Rk(t,e,n)}function Rk(t,e,n){return(n?"":" ")+t}const rH=["autolink","destinationLiteral","destinationRaw","reference","titleQuote","titleApostrophe"];Ik.peek=lH;function iH(){return{canContainEols:["delete"],enter:{strikethrough:oH},exit:{strikethrough:aH}}}function sH(){return{unsafe:[{character:"~",inConstruct:"phrasing",notInConstruct:rH}],handlers:{delete:Ik}}}function oH(t){this.enter({type:"delete",children:[]},t)}function aH(t){this.exit(t)}function Ik(t,e,n,r){const i=n.createTracker(r),s=n.enter("strikethrough");let o=i.move("~~");return o+=n.containerPhrasing(t,{...i.current(),before:o,after:"~"}),o+=i.move("~~"),s(),o}function lH(){return"~"}function uH(t){return t.length}function cH(t,e){const n=e||{},r=(n.align||[]).concat(),i=n.stringLength||uH,s=[],o=[],l=[],c=[];let d=0,f=-1;for(;++fd&&(d=t[f].length);++Cc[C])&&(c[C]=k)}v.push(A)}o[f]=v,l[f]=S}let p=-1;if(typeof r=="object"&&"length"in r)for(;++pc[p]&&(c[p]=A),g[p]=A),m[p]=k}o.splice(1,0,m),l.splice(1,0,g),f=-1;const x=[];for(;++f "),s.shift(2);const o=n.indentLines(n.containerFlow(t,s.current()),hH);return i(),o}function hH(t,e,n){return">"+(n?"":" ")+t}function pH(t,e){return Qw(t,e.inConstruct,!0)&&!Qw(t,e.notInConstruct,!1)}function Qw(t,e,n){if(typeof e=="string"&&(e=[e]),!e||e.length===0)return n;let r=-1;for(;++ro&&(o=s):s=1,i=r+e.length,r=n.indexOf(e,i);return o}function gH(t,e){return!!(e.options.fences===!1&&t.value&&!t.lang&&/[^ \r\n]/.test(t.value)&&!/^[\t ]*(?:[\r\n]|$)|(?:^|[\r\n])[\t ]*$/.test(t.value))}function bH(t){const e=t.options.fence||"`";if(e!=="`"&&e!=="~")throw new Error("Cannot serialize code with `"+e+"` for `options.fence`, expected `` ` `` or `~`");return e}function EH(t,e,n,r){const i=bH(n),s=t.value||"",o=i==="`"?"GraveAccent":"Tilde";if(gH(t,n)){const p=n.enter("codeIndented"),m=n.indentLines(s,yH);return p(),m}const l=n.createTracker(r),c=i.repeat(Math.max(mH(s,i)+1,3)),d=n.enter("codeFenced");let f=l.move(c);if(t.lang){const p=n.enter(`codeFencedLang${o}`);f+=l.move(n.safe(t.lang,{before:f,after:" ",encode:["`"],...l.current()})),p()}if(t.lang&&t.meta){const p=n.enter(`codeFencedMeta${o}`);f+=l.move(" "),f+=l.move(n.safe(t.meta,{before:f,after:` +`,encode:["`"],...l.current()})),p()}return f+=l.move(` +`),s&&(f+=l.move(s+` +`)),f+=l.move(c),d(),f}function yH(t,e,n){return(n?"":" ")+t}function t1(t){const e=t.options.quote||'"';if(e!=='"'&&e!=="'")throw new Error("Cannot serialize title with `"+e+"` for `options.quote`, expected `\"`, or `'`");return e}function xH(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.enter("definition");let l=n.enter("label");const c=n.createTracker(r);let d=c.move("[");return d+=c.move(n.safe(n.associationId(t),{before:d,after:"]",...c.current()})),d+=c.move("]: "),l(),!t.url||/[\0- \u007F]/.test(t.url)?(l=n.enter("destinationLiteral"),d+=c.move("<"),d+=c.move(n.safe(t.url,{before:d,after:">",...c.current()})),d+=c.move(">")):(l=n.enter("destinationRaw"),d+=c.move(n.safe(t.url,{before:d,after:t.title?" ":` +`,...c.current()}))),l(),t.title&&(l=n.enter(`title${s}`),d+=c.move(" "+i),d+=c.move(n.safe(t.title,{before:d,after:i,...c.current()})),d+=c.move(i),l()),o(),d}function vH(t){const e=t.options.emphasis||"*";if(e!=="*"&&e!=="_")throw new Error("Cannot serialize emphasis with `"+e+"` for `options.emphasis`, expected `*`, or `_`");return e}function pc(t){return"&#x"+t.toString(16).toUpperCase()+";"}function dh(t,e,n){const r=bl(t),i=bl(e);return r===void 0?i===void 0?n==="_"?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!0}:r===1?i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!1}:{inside:!1,outside:!1}}Mk.peek=wH;function Mk(t,e,n,r){const i=vH(n),s=n.enter("emphasis"),o=n.createTracker(r),l=o.move(i);let c=o.move(n.containerPhrasing(t,{after:i,before:l,...o.current()}));const d=c.charCodeAt(0),f=dh(r.before.charCodeAt(r.before.length-1),d,i);f.inside&&(c=pc(d)+c.slice(1));const p=c.charCodeAt(c.length-1),m=dh(r.after.charCodeAt(0),p,i);m.inside&&(c=c.slice(0,-1)+pc(p));const g=o.move(i);return s(),n.attentionEncodeSurroundingInfo={after:m.outside,before:f.outside},l+c+g}function wH(t,e,n){return n.options.emphasis||"*"}function TH(t,e){let n=!1;return Pc(t,function(r){if("value"in r&&/\r?\n|\r/.test(r.value)||r.type==="break")return n=!0,Q0}),!!((!t.depth||t.depth<3)&&KE(t)&&(e.options.setext||n))}function SH(t,e,n,r){const i=Math.max(Math.min(6,t.depth||1),1),s=n.createTracker(r);if(TH(t,n)){const f=n.enter("headingSetext"),p=n.enter("phrasing"),m=n.containerPhrasing(t,{...s.current(),before:` +`,after:` +`});return p(),f(),m+` +`+(i===1?"=":"-").repeat(m.length-(Math.max(m.lastIndexOf("\r"),m.lastIndexOf(` +`))+1))}const o="#".repeat(i),l=n.enter("headingAtx"),c=n.enter("phrasing");s.move(o+" ");let d=n.containerPhrasing(t,{before:"# ",after:` +`,...s.current()});return/^[\t ]/.test(d)&&(d=pc(d.charCodeAt(0))+d.slice(1)),d=d?o+" "+d:o,n.options.closeAtx&&(d+=" "+o),c(),l(),d}Dk.peek=_H;function Dk(t){return t.value||""}function _H(){return"<"}Lk.peek=CH;function Lk(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.enter("image");let l=n.enter("label");const c=n.createTracker(r);let d=c.move("![");return d+=c.move(n.safe(t.alt,{before:d,after:"]",...c.current()})),d+=c.move("]("),l(),!t.url&&t.title||/[\0- \u007F]/.test(t.url)?(l=n.enter("destinationLiteral"),d+=c.move("<"),d+=c.move(n.safe(t.url,{before:d,after:">",...c.current()})),d+=c.move(">")):(l=n.enter("destinationRaw"),d+=c.move(n.safe(t.url,{before:d,after:t.title?" ":")",...c.current()}))),l(),t.title&&(l=n.enter(`title${s}`),d+=c.move(" "+i),d+=c.move(n.safe(t.title,{before:d,after:i,...c.current()})),d+=c.move(i),l()),d+=c.move(")"),o(),d}function CH(){return"!"}Pk.peek=AH;function Pk(t,e,n,r){const i=t.referenceType,s=n.enter("imageReference");let o=n.enter("label");const l=n.createTracker(r);let c=l.move("![");const d=n.safe(t.alt,{before:c,after:"]",...l.current()});c+=l.move(d+"]["),o();const f=n.stack;n.stack=[],o=n.enter("reference");const p=n.safe(n.associationId(t),{before:c,after:"]",...l.current()});return o(),n.stack=f,s(),i==="full"||!d||d!==p?c+=l.move(p+"]"):i==="shortcut"?c=c.slice(0,-1):c+=l.move("]"),c}function AH(){return"!"}Fk.peek=kH;function Fk(t,e,n){let r=t.value||"",i="`",s=-1;for(;new RegExp("(^|[^`])"+i+"([^`]|$)").test(r);)i+="`";for(/[^ \r\n]/.test(r)&&(/^[ \r\n]/.test(r)&&/[ \r\n]$/.test(r)||/^`|`$/.test(r))&&(r=" "+r+" ");++s\u007F]/.test(t.url))}Uk.peek=NH;function Uk(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.createTracker(r);let l,c;if(Bk(t,n)){const f=n.stack;n.stack=[],l=n.enter("autolink");let p=o.move("<");return p+=o.move(n.containerPhrasing(t,{before:p,after:">",...o.current()})),p+=o.move(">"),l(),n.stack=f,p}l=n.enter("link"),c=n.enter("label");let d=o.move("[");return d+=o.move(n.containerPhrasing(t,{before:d,after:"](",...o.current()})),d+=o.move("]("),c(),!t.url&&t.title||/[\0- \u007F]/.test(t.url)?(c=n.enter("destinationLiteral"),d+=o.move("<"),d+=o.move(n.safe(t.url,{before:d,after:">",...o.current()})),d+=o.move(">")):(c=n.enter("destinationRaw"),d+=o.move(n.safe(t.url,{before:d,after:t.title?" ":")",...o.current()}))),c(),t.title&&(c=n.enter(`title${s}`),d+=o.move(" "+i),d+=o.move(n.safe(t.title,{before:d,after:i,...o.current()})),d+=o.move(i),c()),d+=o.move(")"),l(),d}function NH(t,e,n){return Bk(t,n)?"<":"["}Hk.peek=RH;function Hk(t,e,n,r){const i=t.referenceType,s=n.enter("linkReference");let o=n.enter("label");const l=n.createTracker(r);let c=l.move("[");const d=n.containerPhrasing(t,{before:c,after:"]",...l.current()});c+=l.move(d+"]["),o();const f=n.stack;n.stack=[],o=n.enter("reference");const p=n.safe(n.associationId(t),{before:c,after:"]",...l.current()});return o(),n.stack=f,s(),i==="full"||!d||d!==p?c+=l.move(p+"]"):i==="shortcut"?c=c.slice(0,-1):c+=l.move("]"),c}function RH(){return"["}function n1(t){const e=t.options.bullet||"*";if(e!=="*"&&e!=="+"&&e!=="-")throw new Error("Cannot serialize items with `"+e+"` for `options.bullet`, expected `*`, `+`, or `-`");return e}function IH(t){const e=n1(t),n=t.options.bulletOther;if(!n)return e==="*"?"-":"*";if(n!=="*"&&n!=="+"&&n!=="-")throw new Error("Cannot serialize items with `"+n+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(n===e)throw new Error("Expected `bullet` (`"+e+"`) and `bulletOther` (`"+n+"`) to be different");return n}function OH(t){const e=t.options.bulletOrdered||".";if(e!=="."&&e!==")")throw new Error("Cannot serialize items with `"+e+"` for `options.bulletOrdered`, expected `.` or `)`");return e}function zk(t){const e=t.options.rule||"*";if(e!=="*"&&e!=="-"&&e!=="_")throw new Error("Cannot serialize rules with `"+e+"` for `options.rule`, expected `*`, `-`, or `_`");return e}function MH(t,e,n,r){const i=n.enter("list"),s=n.bulletCurrent;let o=t.ordered?OH(n):n1(n);const l=t.ordered?o==="."?")":".":IH(n);let c=e&&n.bulletLastUsed?o===n.bulletLastUsed:!1;if(!t.ordered){const f=t.children?t.children[0]:void 0;if((o==="*"||o==="-")&&f&&(!f.children||!f.children[0])&&n.stack[n.stack.length-1]==="list"&&n.stack[n.stack.length-2]==="listItem"&&n.stack[n.stack.length-3]==="list"&&n.stack[n.stack.length-4]==="listItem"&&n.indexStack[n.indexStack.length-1]===0&&n.indexStack[n.indexStack.length-2]===0&&n.indexStack[n.indexStack.length-3]===0&&(c=!0),zk(n)===o&&f){let p=-1;for(;++p-1?e.start:1)+(n.options.incrementListMarker===!1?0:e.children.indexOf(t))+s);let o=s.length+1;(i==="tab"||i==="mixed"&&(e&&e.type==="list"&&e.spread||t.spread))&&(o=Math.ceil(o/4)*4);const l=n.createTracker(r);l.move(s+" ".repeat(o-s.length)),l.shift(o);const c=n.enter("listItem"),d=n.indentLines(n.containerFlow(t,l.current()),f);return c(),d;function f(p,m,g){return m?(g?"":" ".repeat(o))+p:(g?s:s+" ".repeat(o-s.length))+p}}function PH(t,e,n,r){const i=n.enter("paragraph"),s=n.enter("phrasing"),o=n.containerPhrasing(t,r);return s(),i(),o}const FH=Lc(["break","delete","emphasis","footnote","footnoteReference","image","imageReference","inlineCode","inlineMath","link","linkReference","mdxJsxTextElement","mdxTextExpression","strong","text","textDirective"]);function BH(t,e,n,r){return(t.children.some(function(o){return FH(o)})?n.containerPhrasing:n.containerFlow).call(n,t,r)}function UH(t){const e=t.options.strong||"*";if(e!=="*"&&e!=="_")throw new Error("Cannot serialize strong with `"+e+"` for `options.strong`, expected `*`, or `_`");return e}jk.peek=HH;function jk(t,e,n,r){const i=UH(n),s=n.enter("strong"),o=n.createTracker(r),l=o.move(i+i);let c=o.move(n.containerPhrasing(t,{after:i,before:l,...o.current()}));const d=c.charCodeAt(0),f=dh(r.before.charCodeAt(r.before.length-1),d,i);f.inside&&(c=pc(d)+c.slice(1));const p=c.charCodeAt(c.length-1),m=dh(r.after.charCodeAt(0),p,i);m.inside&&(c=c.slice(0,-1)+pc(p));const g=o.move(i+i);return s(),n.attentionEncodeSurroundingInfo={after:m.outside,before:f.outside},l+c+g}function HH(t,e,n){return n.options.strong||"*"}function zH(t,e,n,r){return n.safe(t.value,r)}function jH(t){const e=t.options.ruleRepetition||3;if(e<3)throw new Error("Cannot serialize rules with repetition `"+e+"` for `options.ruleRepetition`, expected `3` or more");return e}function $H(t,e,n){const r=(zk(n)+(n.options.ruleSpaces?" ":"")).repeat(jH(n));return n.options.ruleSpaces?r.slice(0,-1):r}const $k={blockquote:fH,break:Zw,code:EH,definition:xH,emphasis:Mk,hardBreak:Zw,heading:SH,html:Dk,image:Lk,imageReference:Pk,inlineCode:Fk,link:Uk,linkReference:Hk,list:MH,listItem:LH,paragraph:PH,root:BH,strong:jk,text:zH,thematicBreak:$H};function WH(){return{enter:{table:VH,tableData:Jw,tableHeader:Jw,tableRow:KH},exit:{codeText:YH,table:GH,tableData:Zg,tableHeader:Zg,tableRow:Zg}}}function VH(t){const e=t._align;this.enter({type:"table",align:e.map(function(n){return n==="none"?null:n}),children:[]},t),this.data.inTable=!0}function GH(t){this.exit(t),this.data.inTable=void 0}function KH(t){this.enter({type:"tableRow",children:[]},t)}function Zg(t){this.exit(t)}function Jw(t){this.enter({type:"tableCell",children:[]},t)}function YH(t){let e=this.resume();this.data.inTable&&(e=e.replace(/\\([\\|])/g,qH));const n=this.stack[this.stack.length-1];n.type,n.value=e,this.exit(t)}function qH(t,e){return e==="|"?e:t}function XH(t){const e=t||{},n=e.tableCellPadding,r=e.tablePipeAlign,i=e.stringLength,s=n?" ":"|";return{unsafe:[{character:"\r",inConstruct:"tableCell"},{character:` +`,inConstruct:"tableCell"},{atBreak:!0,character:"|",after:"[ :-]"},{character:"|",inConstruct:"tableCell"},{atBreak:!0,character:":",after:"-"},{atBreak:!0,character:"-",after:"[:|-]"}],handlers:{inlineCode:m,table:o,tableCell:c,tableRow:l}};function o(g,x,v,S){return d(f(g,v,S),g.align)}function l(g,x,v,S){const C=p(g,v,S),A=d([C]);return A.slice(0,A.indexOf(` +`))}function c(g,x,v,S){const C=v.enter("tableCell"),A=v.enter("phrasing"),k=v.containerPhrasing(g,{...S,before:s,after:s});return A(),C(),k}function d(g,x){return cH(g,{align:x,alignDelimiters:r,padding:n,stringLength:i})}function f(g,x,v){const S=g.children;let C=-1;const A=[],k=x.enter("table");for(;++C0&&!n&&(t[t.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}const pz={tokenize:wz,partial:!0};function mz(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize:yz,continuation:{tokenize:xz},exit:vz}},text:{91:{name:"gfmFootnoteCall",tokenize:Ez},93:{name:"gfmPotentialFootnoteCall",add:"after",tokenize:gz,resolveTo:bz}}}}function gz(t,e,n){const r=this;let i=r.events.length;const s=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let o;for(;i--;){const c=r.events[i][1];if(c.type==="labelImage"){o=c;break}if(c.type==="gfmFootnoteCall"||c.type==="labelLink"||c.type==="label"||c.type==="image"||c.type==="link")break}return l;function l(c){if(!o||!o._balanced)return n(c);const d=vi(r.sliceSerialize({start:o.end,end:r.now()}));return d.codePointAt(0)!==94||!s.includes(d.slice(1))?n(c):(t.enter("gfmFootnoteCallLabelMarker"),t.consume(c),t.exit("gfmFootnoteCallLabelMarker"),e(c))}}function bz(t,e){let n=t.length;for(;n--;)if(t[n][1].type==="labelImage"&&t[n][0]==="enter"){t[n][1];break}t[n+1][1].type="data",t[n+3][1].type="gfmFootnoteCallLabelMarker";const r={type:"gfmFootnoteCall",start:Object.assign({},t[n+3][1].start),end:Object.assign({},t[t.length-1][1].end)},i={type:"gfmFootnoteCallMarker",start:Object.assign({},t[n+3][1].end),end:Object.assign({},t[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;const s={type:"gfmFootnoteCallString",start:Object.assign({},i.end),end:Object.assign({},t[t.length-1][1].start)},o={type:"chunkString",contentType:"string",start:Object.assign({},s.start),end:Object.assign({},s.end)},l=[t[n+1],t[n+2],["enter",r,e],t[n+3],t[n+4],["enter",i,e],["exit",i,e],["enter",s,e],["enter",o,e],["exit",o,e],["exit",s,e],t[t.length-2],t[t.length-1],["exit",r,e]];return t.splice(n,t.length-n+1,...l),t}function Ez(t,e,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let s=0,o;return l;function l(p){return t.enter("gfmFootnoteCall"),t.enter("gfmFootnoteCallLabelMarker"),t.consume(p),t.exit("gfmFootnoteCallLabelMarker"),c}function c(p){return p!==94?n(p):(t.enter("gfmFootnoteCallMarker"),t.consume(p),t.exit("gfmFootnoteCallMarker"),t.enter("gfmFootnoteCallString"),t.enter("chunkString").contentType="string",d)}function d(p){if(s>999||p===93&&!o||p===null||p===91||Kt(p))return n(p);if(p===93){t.exit("chunkString");const m=t.exit("gfmFootnoteCallString");return i.includes(vi(r.sliceSerialize(m)))?(t.enter("gfmFootnoteCallLabelMarker"),t.consume(p),t.exit("gfmFootnoteCallLabelMarker"),t.exit("gfmFootnoteCall"),e):n(p)}return Kt(p)||(o=!0),s++,t.consume(p),p===92?f:d}function f(p){return p===91||p===92||p===93?(t.consume(p),s++,d):d(p)}}function yz(t,e,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let s,o=0,l;return c;function c(x){return t.enter("gfmFootnoteDefinition")._container=!0,t.enter("gfmFootnoteDefinitionLabel"),t.enter("gfmFootnoteDefinitionLabelMarker"),t.consume(x),t.exit("gfmFootnoteDefinitionLabelMarker"),d}function d(x){return x===94?(t.enter("gfmFootnoteDefinitionMarker"),t.consume(x),t.exit("gfmFootnoteDefinitionMarker"),t.enter("gfmFootnoteDefinitionLabelString"),t.enter("chunkString").contentType="string",f):n(x)}function f(x){if(o>999||x===93&&!l||x===null||x===91||Kt(x))return n(x);if(x===93){t.exit("chunkString");const v=t.exit("gfmFootnoteDefinitionLabelString");return s=vi(r.sliceSerialize(v)),t.enter("gfmFootnoteDefinitionLabelMarker"),t.consume(x),t.exit("gfmFootnoteDefinitionLabelMarker"),t.exit("gfmFootnoteDefinitionLabel"),m}return Kt(x)||(l=!0),o++,t.consume(x),x===92?p:f}function p(x){return x===91||x===92||x===93?(t.consume(x),o++,f):f(x)}function m(x){return x===58?(t.enter("definitionMarker"),t.consume(x),t.exit("definitionMarker"),i.includes(s)||i.push(s),Nt(t,g,"gfmFootnoteDefinitionWhitespace")):n(x)}function g(x){return e(x)}}function xz(t,e,n){return t.check(Dc,e,t.attempt(pz,e,n))}function vz(t){t.exit("gfmFootnoteDefinition")}function wz(t,e,n){const r=this;return Nt(t,i,"gfmFootnoteDefinitionIndent",5);function i(s){const o=r.events[r.events.length-1];return o&&o[1].type==="gfmFootnoteDefinitionIndent"&&o[2].sliceSerialize(o[1],!0).length===4?e(s):n(s)}}function Tz(t){let n=(t||{}).singleTilde;const r={name:"strikethrough",tokenize:s,resolveAll:i};return n==null&&(n=!0),{text:{126:r},insideSpan:{null:[r]},attentionMarkers:{null:[126]}};function i(o,l){let c=-1;for(;++c1?c(x):(o.consume(x),p++,g);if(p<2&&!n)return c(x);const S=o.exit("strikethroughSequenceTemporary"),C=bl(x);return S._open=!C||C===2&&!!v,S._close=!v||v===2&&!!C,l(x)}}}class Sz{constructor(){this.map=[]}add(e,n,r){_z(this,e,n,r)}consume(e){if(this.map.sort(function(s,o){return s[0]-o[0]}),this.map.length===0)return;let n=this.map.length;const r=[];for(;n>0;)n-=1,r.push(e.slice(this.map[n][0]+this.map[n][1]),this.map[n][2]),e.length=this.map[n][0];r.push(e.slice()),e.length=0;let i=r.pop();for(;i;){for(const s of i)e.push(s);i=r.pop()}this.map.length=0}}function _z(t,e,n,r){let i=0;if(!(n===0&&r.length===0)){for(;i-1;){const Z=r.events[Y][1].type;if(Z==="lineEnding"||Z==="linePrefix")Y--;else break}const z=Y>-1?r.events[Y][1].type:null,ie=z==="tableHead"||z==="tableRow"?I:c;return ie===I&&r.parser.lazy[r.now().line]?n(P):ie(P)}function c(P){return t.enter("tableHead"),t.enter("tableRow"),d(P)}function d(P){return P===124||(o=!0,s+=1),f(P)}function f(P){return P===null?n(P):et(P)?s>1?(s=0,r.interrupt=!0,t.exit("tableRow"),t.enter("lineEnding"),t.consume(P),t.exit("lineEnding"),g):n(P):St(P)?Nt(t,f,"whitespace")(P):(s+=1,o&&(o=!1,i+=1),P===124?(t.enter("tableCellDivider"),t.consume(P),t.exit("tableCellDivider"),o=!0,f):(t.enter("data"),p(P)))}function p(P){return P===null||P===124||Kt(P)?(t.exit("data"),f(P)):(t.consume(P),P===92?m:p)}function m(P){return P===92||P===124?(t.consume(P),p):p(P)}function g(P){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(P):(t.enter("tableDelimiterRow"),o=!1,St(P)?Nt(t,x,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(P):x(P))}function x(P){return P===45||P===58?S(P):P===124?(o=!0,t.enter("tableCellDivider"),t.consume(P),t.exit("tableCellDivider"),v):F(P)}function v(P){return St(P)?Nt(t,S,"whitespace")(P):S(P)}function S(P){return P===58?(s+=1,o=!0,t.enter("tableDelimiterMarker"),t.consume(P),t.exit("tableDelimiterMarker"),C):P===45?(s+=1,C(P)):P===null||et(P)?M(P):F(P)}function C(P){return P===45?(t.enter("tableDelimiterFiller"),A(P)):F(P)}function A(P){return P===45?(t.consume(P),A):P===58?(o=!0,t.exit("tableDelimiterFiller"),t.enter("tableDelimiterMarker"),t.consume(P),t.exit("tableDelimiterMarker"),k):(t.exit("tableDelimiterFiller"),k(P))}function k(P){return St(P)?Nt(t,M,"whitespace")(P):M(P)}function M(P){return P===124?x(P):P===null||et(P)?!o||i!==s?F(P):(t.exit("tableDelimiterRow"),t.exit("tableHead"),e(P)):F(P)}function F(P){return n(P)}function I(P){return t.enter("tableRow"),D(P)}function D(P){return P===124?(t.enter("tableCellDivider"),t.consume(P),t.exit("tableCellDivider"),D):P===null||et(P)?(t.exit("tableRow"),e(P)):St(P)?Nt(t,D,"whitespace")(P):(t.enter("data"),G(P))}function G(P){return P===null||P===124||Kt(P)?(t.exit("data"),D(P)):(t.consume(P),P===92?X:G)}function X(P){return P===92||P===124?(t.consume(P),G):G(P)}}function Nz(t,e){let n=-1,r=!0,i=0,s=[0,0,0,0],o=[0,0,0,0],l=!1,c=0,d,f,p;const m=new Sz;for(;++nn[2]+1){const x=n[2]+1,v=n[3]-n[2]-1;t.add(x,v,[])}}t.add(n[3]+1,0,[["exit",p,e]])}return i!==void 0&&(s.end=Object.assign({},Va(e.events,i)),t.add(i,0,[["exit",s,e]]),s=void 0),s}function tT(t,e,n,r,i){const s=[],o=Va(e.events,n);i&&(i.end=Object.assign({},o),s.push(["exit",i,e])),r.end=Object.assign({},o),s.push(["exit",r,e]),t.add(n+1,0,s)}function Va(t,e){const n=t[e],r=n[0]==="enter"?"start":"end";return n[1][r]}const Rz={name:"tasklistCheck",tokenize:Oz};function Iz(){return{text:{91:Rz}}}function Oz(t,e,n){const r=this;return i;function i(c){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(c):(t.enter("taskListCheck"),t.enter("taskListCheckMarker"),t.consume(c),t.exit("taskListCheckMarker"),s)}function s(c){return Kt(c)?(t.enter("taskListCheckValueUnchecked"),t.consume(c),t.exit("taskListCheckValueUnchecked"),o):c===88||c===120?(t.enter("taskListCheckValueChecked"),t.consume(c),t.exit("taskListCheckValueChecked"),o):n(c)}function o(c){return c===93?(t.enter("taskListCheckMarker"),t.consume(c),t.exit("taskListCheckMarker"),t.exit("taskListCheck"),l):n(c)}function l(c){return et(c)?e(c):St(c)?t.check({tokenize:Mz},e,n)(c):n(c)}}function Mz(t,e,n){return Nt(t,r,"whitespace");function r(i){return i===null?n(i):e(i)}}function Dz(t){return ak([sz(),mz(),Tz(t),Az(),Iz()])}const Lz={};function Pz(t){const e=this,n=t||Lz,r=e.data(),i=r.micromarkExtensions||(r.micromarkExtensions=[]),s=r.fromMarkdownExtensions||(r.fromMarkdownExtensions=[]),o=r.toMarkdownExtensions||(r.toMarkdownExtensions=[]);i.push(Dz(n)),s.push(tz()),o.push(nz(n))}const nT=(function(t,e,n){const r=Lc(n);if(!t||!t.type||!t.children)throw new Error("Expected parent node");if(typeof e=="number"){if(e<0||e===Number.POSITIVE_INFINITY)throw new Error("Expected positive finite number as index")}else if(e=t.children.indexOf(e),e<0)throw new Error("Expected child node or index");for(;++ed&&(d=f):f&&(d!==void 0&&d>-1&&c.push(` +`.repeat(d)||" "),d=-1,c.push(f))}return c.join("")}function Jk(t,e,n){return t.type==="element"?Wz(t,e,n):t.type==="text"?n.whitespace==="normal"?eN(t,n):Vz(t):[]}function Wz(t,e,n){const r=tN(t,n),i=t.children||[];let s=-1,o=[];if(jz(t))return o;let l,c;for(nb(t)||oT(t)&&nT(e,t,oT)?c=` +`:zz(t)?(l=2,c=2):Zk(t)&&(l=1,c=1);++s]+>")+")",l={className:"type",begin:"\\b[a-z\\d_]*_t\\b"},d={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[t.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'("+"\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)"+"|.)",end:"'",illegal:"."},t.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},f={className:"number",variants:[{begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"},{begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"}],relevance:0},p={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},t.inherit(d,{className:"string"}),{className:"string",begin:/<.*?>/},n,t.C_BLOCK_COMMENT_MODE]},m={className:"title",begin:e.optional(i)+t.IDENT_RE,relevance:0},g=e.optional(i)+t.IDENT_RE+"\\s*\\(",x=["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],v=["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],S=["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","flat_map","flat_set","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"],C=["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"],M={type:v,keyword:x,literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],_type_hints:S},F={className:"function.dispatch",relevance:0,keywords:{_hint:C},begin:e.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,t.IDENT_RE,e.lookahead(/(<[^<>]+>|)\s*\(/))},I=[F,p,l,n,t.C_BLOCK_COMMENT_MODE,f,d],D={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:M,contains:I.concat([{begin:/\(/,end:/\)/,keywords:M,contains:I.concat(["self"]),relevance:0}]),relevance:0},G={className:"function",begin:"("+o+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:M,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:r,keywords:M,relevance:0},{begin:g,returnBegin:!0,contains:[m],relevance:0},{begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[d,f]},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:M,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,d,f,l,{begin:/\(/,end:/\)/,keywords:M,relevance:0,contains:["self",n,t.C_BLOCK_COMMENT_MODE,d,f,l]}]},l,n,t.C_BLOCK_COMMENT_MODE,p]};return{name:"C++",aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:M,illegal:"",keywords:M,contains:["self",l]},{begin:t.IDENT_RE+"::",keywords:M},{match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],className:{1:"keyword",3:"title.class"}}])}}function Qz(t){const e={type:["boolean","byte","word","String"],built_in:["KeyboardController","MouseController","SoftwareSerial","EthernetServer","EthernetClient","LiquidCrystal","RobotControl","GSMVoiceCall","EthernetUDP","EsploraTFT","HttpClient","RobotMotor","WiFiClient","GSMScanner","FileSystem","Scheduler","GSMServer","YunClient","YunServer","IPAddress","GSMClient","GSMModem","Keyboard","Ethernet","Console","GSMBand","Esplora","Stepper","Process","WiFiUDP","GSM_SMS","Mailbox","USBHost","Firmata","PImage","Client","Server","GSMPIN","FileIO","Bridge","Serial","EEPROM","Stream","Mouse","Audio","Servo","File","Task","GPRS","WiFi","Wire","TFT","GSM","SPI","SD"],_hints:["setup","loop","runShellCommandAsynchronously","analogWriteResolution","retrieveCallingNumber","printFirmwareVersion","analogReadResolution","sendDigitalPortPair","noListenOnLocalhost","readJoystickButton","setFirmwareVersion","readJoystickSwitch","scrollDisplayRight","getVoiceCallStatus","scrollDisplayLeft","writeMicroseconds","delayMicroseconds","beginTransmission","getSignalStrength","runAsynchronously","getAsynchronously","listenOnLocalhost","getCurrentCarrier","readAccelerometer","messageAvailable","sendDigitalPorts","lineFollowConfig","countryNameWrite","runShellCommand","readStringUntil","rewindDirectory","readTemperature","setClockDivider","readLightSensor","endTransmission","analogReference","detachInterrupt","countryNameRead","attachInterrupt","encryptionType","readBytesUntil","robotNameWrite","readMicrophone","robotNameRead","cityNameWrite","userNameWrite","readJoystickY","readJoystickX","mouseReleased","openNextFile","scanNetworks","noInterrupts","digitalWrite","beginSpeaker","mousePressed","isActionDone","mouseDragged","displayLogos","noAutoscroll","addParameter","remoteNumber","getModifiers","keyboardRead","userNameRead","waitContinue","processInput","parseCommand","printVersion","readNetworks","writeMessage","blinkVersion","cityNameRead","readMessage","setDataMode","parsePacket","isListening","setBitOrder","beginPacket","isDirectory","motorsWrite","drawCompass","digitalRead","clearScreen","serialEvent","rightToLeft","setTextSize","leftToRight","requestFrom","keyReleased","compassRead","analogWrite","interrupts","WiFiServer","disconnect","playMelody","parseFloat","autoscroll","getPINUsed","setPINUsed","setTimeout","sendAnalog","readSlider","analogRead","beginWrite","createChar","motorsStop","keyPressed","tempoWrite","readButton","subnetMask","debugPrint","macAddress","writeGreen","randomSeed","attachGPRS","readString","sendString","remotePort","releaseAll","mouseMoved","background","getXChange","getYChange","answerCall","getResult","voiceCall","endPacket","constrain","getSocket","writeJSON","getButton","available","connected","findUntil","readBytes","exitValue","readGreen","writeBlue","startLoop","IPAddress","isPressed","sendSysex","pauseMode","gatewayIP","setCursor","getOemKey","tuneWrite","noDisplay","loadImage","switchPIN","onRequest","onReceive","changePIN","playFile","noBuffer","parseInt","overflow","checkPIN","knobRead","beginTFT","bitClear","updateIR","bitWrite","position","writeRGB","highByte","writeRed","setSpeed","readBlue","noStroke","remoteIP","transfer","shutdown","hangCall","beginSMS","endWrite","attached","maintain","noCursor","checkReg","checkPUK","shiftOut","isValid","shiftIn","pulseIn","connect","println","localIP","pinMode","getIMEI","display","noBlink","process","getBand","running","beginSD","drawBMP","lowByte","setBand","release","bitRead","prepare","pointTo","readRed","setMode","noFill","remove","listen","stroke","detach","attach","noTone","exists","buffer","height","bitSet","circle","config","cursor","random","IRread","setDNS","endSMS","getKey","micros","millis","begin","print","write","ready","flush","width","isPIN","blink","clear","press","mkdir","rmdir","close","point","yield","image","BSSID","click","delay","read","text","move","peek","beep","rect","line","open","seek","fill","size","turn","stop","home","find","step","tone","sqrt","RSSI","SSID","end","bit","tan","cos","sin","pow","map","abs","max","min","get","run","put"],literal:["DIGITAL_MESSAGE","FIRMATA_STRING","ANALOG_MESSAGE","REPORT_DIGITAL","REPORT_ANALOG","INPUT_PULLUP","SET_PIN_MODE","INTERNAL2V56","SYSTEM_RESET","LED_BUILTIN","INTERNAL1V1","SYSEX_START","INTERNAL","EXTERNAL","DEFAULT","OUTPUT","INPUT","HIGH","LOW"]},n=Xz(t),r=n.keywords;return r.type=[...r.type,...e.type],r.literal=[...r.literal,...e.literal],r.built_in=[...r.built_in,...e.built_in],r._hints=e._hints,n.name="Arduino",n.aliases=["ino"],n.supersetOf="cpp",n}function Zz(t){const e=t.regex,n={},r={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[n]}]};Object.assign(n,{className:"variable",variants:[{begin:e.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},r]});const i={className:"subst",begin:/\$\(/,end:/\)/,contains:[t.BACKSLASH_ESCAPE]},s=t.inherit(t.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),o={begin:/<<-?\s*(?=\w+)/,starts:{contains:[t.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},l={className:"string",begin:/"/,end:/"/,contains:[t.BACKSLASH_ESCAPE,n,i]};i.contains.push(l);const c={match:/\\"/},d={className:"string",begin:/'/,end:/'/},f={match:/\\'/},p={begin:/\$?\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},t.NUMBER_MODE,n]},m=["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"],g=t.SHEBANG({binary:`(${m.join("|")})`,relevance:10}),x={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[t.inherit(t.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},v=["if","then","else","elif","fi","time","for","while","until","in","do","done","case","esac","coproc","function","select"],S=["true","false"],C={match:/(\/[a-z._-]+)+/},A=["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset"],k=["alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias"],M=["autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp"],F=["chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"];return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,keyword:v,literal:S,built_in:[...A,...k,"set","shopt",...M,...F]},contains:[g,t.SHEBANG(),x,p,s,o,C,l,c,d,f,n]}}function Jz(t){const e=t.regex,n=t.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),r="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",o="("+r+"|"+e.optional(i)+"[a-zA-Z_]\\w*"+e.optional("<[^<>]+>")+")",l={className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{match:/\batomic_[a-z]{3,6}\b/}]},d={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[t.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'("+"\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)"+"|.)",end:"'",illegal:"."},t.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},f={className:"number",variants:[{match:/\b(0b[01']+)/},{match:/(-?)\b([\d']+(\.[\d']*)?|\.[\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)/},{match:/(-?)\b(0[xX][a-fA-F0-9]+(?:'[a-fA-F0-9]+)*(?:\.[a-fA-F0-9]*(?:'[a-fA-F0-9]*)*)?(?:[pP][-+]?[0-9]+)?(l|L)?(u|U)?)/},{match:/(-?)\b\d+(?:'\d+)*(?:\.\d*(?:'\d*)*)?(?:[eE][-+]?\d+)?/}],relevance:0},p={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef elifdef elifndef include"},contains:[{begin:/\\\n/,relevance:0},t.inherit(d,{className:"string"}),{className:"string",begin:/<.*?>/},n,t.C_BLOCK_COMMENT_MODE]},m={className:"title",begin:e.optional(i)+t.IDENT_RE,relevance:0},g=e.optional(i)+t.IDENT_RE+"\\s*\\(",S={keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","typeof","typeof_unqual","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_BitInt","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal96","_Decimal128","_Decimal64x","_Decimal128x","_Float16","_Float32","_Float64","_Float128","_Float32x","_Float64x","_Float128x","const","static","constexpr","complex","bool","imaginary"],literal:"true false NULL",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"},C=[p,l,n,t.C_BLOCK_COMMENT_MODE,f,d],A={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:S,contains:C.concat([{begin:/\(/,end:/\)/,keywords:S,contains:C.concat(["self"]),relevance:0}]),relevance:0},k={begin:"("+o+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:S,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:r,keywords:S,relevance:0},{begin:g,returnBegin:!0,contains:[t.inherit(m,{className:"title.function"})],relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:S,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,d,f,l,{begin:/\(/,end:/\)/,keywords:S,relevance:0,contains:["self",n,t.C_BLOCK_COMMENT_MODE,d,f,l]}]},l,n,t.C_BLOCK_COMMENT_MODE,p]};return{name:"C",aliases:["h"],keywords:S,disableAutodetect:!0,illegal:"=]/,contains:[{beginKeywords:"final class struct"},t.TITLE_MODE]}]),exports:{preprocessor:p,strings:d,keywords:S}}}function e7(t){const e=t.regex,n=t.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),r="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",o="(?!struct)("+r+"|"+e.optional(i)+"[a-zA-Z_]\\w*"+e.optional("<[^<>]+>")+")",l={className:"type",begin:"\\b[a-z\\d_]*_t\\b"},d={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[t.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'("+"\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)"+"|.)",end:"'",illegal:"."},t.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},f={className:"number",variants:[{begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"},{begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"}],relevance:0},p={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},t.inherit(d,{className:"string"}),{className:"string",begin:/<.*?>/},n,t.C_BLOCK_COMMENT_MODE]},m={className:"title",begin:e.optional(i)+t.IDENT_RE,relevance:0},g=e.optional(i)+t.IDENT_RE+"\\s*\\(",x=["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],v=["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],S=["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","flat_map","flat_set","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"],C=["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"],M={type:v,keyword:x,literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],_type_hints:S},F={className:"function.dispatch",relevance:0,keywords:{_hint:C},begin:e.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,t.IDENT_RE,e.lookahead(/(<[^<>]+>|)\s*\(/))},I=[F,p,l,n,t.C_BLOCK_COMMENT_MODE,f,d],D={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:M,contains:I.concat([{begin:/\(/,end:/\)/,keywords:M,contains:I.concat(["self"]),relevance:0}]),relevance:0},G={className:"function",begin:"("+o+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:M,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:r,keywords:M,relevance:0},{begin:g,returnBegin:!0,contains:[m],relevance:0},{begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[d,f]},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:M,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,d,f,l,{begin:/\(/,end:/\)/,keywords:M,relevance:0,contains:["self",n,t.C_BLOCK_COMMENT_MODE,d,f,l]}]},l,n,t.C_BLOCK_COMMENT_MODE,p]};return{name:"C++",aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:M,illegal:"",keywords:M,contains:["self",l]},{begin:t.IDENT_RE+"::",keywords:M},{match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],className:{1:"keyword",3:"title.class"}}])}}function t7(t){const e=["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],n=["public","private","protected","static","internal","protected","abstract","async","extern","override","unsafe","virtual","new","sealed","partial"],r=["default","false","null","true"],i=["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"],s=["add","alias","and","ascending","args","async","await","by","descending","dynamic","equals","file","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","record","remove","required","scoped","select","set","unmanaged","value|0","var","when","where","with","yield"],o={keyword:i.concat(s),built_in:e,literal:r},l=t.inherit(t.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),c={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},d={className:"string",begin:/"""("*)(?!")(.|\n)*?"""\1/,relevance:1},f={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},p=t.inherit(f,{illegal:/\n/}),m={className:"subst",begin:/\{/,end:/\}/,keywords:o},g=t.inherit(m,{illegal:/\n/}),x={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},t.BACKSLASH_ESCAPE,g]},v={className:"string",begin:/\$@"/,end:'"',contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},m]},S=t.inherit(v,{illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},g]});m.contains=[v,x,f,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,c,t.C_BLOCK_COMMENT_MODE],g.contains=[S,x,p,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,c,t.inherit(t.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];const C={variants:[d,v,x,f,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE]},A={begin:"<",end:">",contains:[{beginKeywords:"in out"},l]},k=t.IDENT_RE+"(<"+t.IDENT_RE+"(\\s*,\\s*"+t.IDENT_RE+")*>)?(\\[\\])?",M={begin:"@"+t.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:o,illegal:/::/,contains:[t.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:""},{begin:""}]}]}),t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{keyword:"if else elif endif define undef warning error line region endregion pragma checksum"}},C,c,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},l,A,t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[l,t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},{beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[l,A,t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+k+"\\s+)+"+t.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:o,contains:[{beginKeywords:n.join(" "),relevance:0},{begin:t.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,contains:[t.TITLE_MODE,A],relevance:0},{match:/\(\)/},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,relevance:0,contains:[C,c,t.C_BLOCK_COMMENT_MODE]},t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},M]}}const n7=t=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:t.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:t.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/}}),r7=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","optgroup","option","p","picture","q","quote","samp","section","select","source","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],i7=["defs","g","marker","mask","pattern","svg","switch","symbol","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feGaussianBlur","feImage","feMerge","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","linearGradient","radialGradient","stop","circle","ellipse","image","line","path","polygon","polyline","rect","text","use","textPath","tspan","foreignObject","clipPath"],s7=[...r7,...i7],o7=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"].sort().reverse(),a7=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"].sort().reverse(),l7=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"].sort().reverse(),u7=["accent-color","align-content","align-items","align-self","alignment-baseline","all","anchor-name","animation","animation-composition","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-range","animation-range-end","animation-range-start","animation-timeline","animation-timing-function","appearance","aspect-ratio","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-end-end-radius","border-end-start-radius","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-start-end-radius","border-start-start-radius","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-align","box-decoration-break","box-direction","box-flex","box-flex-group","box-lines","box-ordinal-group","box-orient","box-pack","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","color-scheme","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","contain-intrinsic-block-size","contain-intrinsic-height","contain-intrinsic-inline-size","contain-intrinsic-size","contain-intrinsic-width","container","container-name","container-type","content","content-visibility","counter-increment","counter-reset","counter-set","cue","cue-after","cue-before","cursor","cx","cy","direction","display","dominant-baseline","empty-cells","enable-background","field-sizing","fill","fill-opacity","fill-rule","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flood-color","flood-opacity","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-palette","font-size","font-size-adjust","font-smooth","font-smoothing","font-stretch","font-style","font-synthesis","font-synthesis-position","font-synthesis-small-caps","font-synthesis-style","font-synthesis-weight","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-emoji","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","forced-color-adjust","gap","glyph-orientation-horizontal","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphenate-character","hyphenate-limit-chars","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","initial-letter","initial-letter-align","inline-size","inset","inset-area","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","kerning","left","letter-spacing","lighting-color","line-break","line-height","line-height-step","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","margin-trim","marker","marker-end","marker-mid","marker-start","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","masonry-auto-flow","math-depth","math-shift","math-style","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-anchor","overflow-block","overflow-clip-margin","overflow-inline","overflow-wrap","overflow-x","overflow-y","overlay","overscroll-behavior","overscroll-behavior-block","overscroll-behavior-inline","overscroll-behavior-x","overscroll-behavior-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","paint-order","pause","pause-after","pause-before","perspective","perspective-origin","place-content","place-items","place-self","pointer-events","position","position-anchor","position-visibility","print-color-adjust","quotes","r","resize","rest","rest-after","rest-before","right","rotate","row-gap","ruby-align","ruby-position","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scroll-timeline","scroll-timeline-axis","scroll-timeline-name","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","shape-rendering","speak","speak-as","src","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","tab-size","table-layout","text-align","text-align-all","text-align-last","text-anchor","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-decoration-thickness","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-size-adjust","text-transform","text-underline-offset","text-underline-position","text-wrap","text-wrap-mode","text-wrap-style","timeline-scope","top","touch-action","transform","transform-box","transform-origin","transform-style","transition","transition-behavior","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-modify","user-select","vector-effect","vertical-align","view-timeline","view-timeline-axis","view-timeline-inset","view-timeline-name","view-transition-name","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","white-space-collapse","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","x","y","z-index","zoom"].sort().reverse();function c7(t){const e=t.regex,n=n7(t),r={begin:/-(webkit|moz|ms|o)-(?=[a-z])/},i="and or not only",s=/@-?\w[\w]*(-\w+)*/,o="[a-zA-Z-][a-zA-Z0-9_-]*",l=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[n.BLOCK_COMMENT,r,n.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\."+o,relevance:0},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+a7.join("|")+")"},{begin:":(:)?("+l7.join("|")+")"}]},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+u7.join("|")+")\\b"},{begin:/:/,end:/[;}{]/,contains:[n.BLOCK_COMMENT,n.HEXCOLOR,n.IMPORTANT,n.CSS_NUMBER_MODE,...l,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[...l,{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},n.FUNCTION_DISPATCH]},{begin:e.lookahead(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:s},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:i,attribute:o7.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...l,n.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+s7.join("|")+")\\b"}]}}function d7(t){const e=t.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:e.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:e.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}function f7(t){const s={keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"],type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],literal:["true","false","iota","nil"],built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]};return{name:"Go",aliases:["golang"],keywords:s,illegal:"nN(t,e,n-1))}function m7(t){const e=t.regex,n="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",r=n+nN("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),c={keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits","goto","when"],literal:["false","true","null"],type:["char","boolean","long","float","int","byte","short","double"],built_in:["super","this"]},d={className:"meta",begin:"@"+n,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},f={className:"params",begin:/\(/,end:/\)/,keywords:c,relevance:0,contains:[t.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:c,illegal:/<\/|#/,contains:[t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[t.BACKSLASH_ESCAPE]},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{begin:[e.concat(/(?!else)/,n),/\s+/,n,/\s+/,/=(?!=)/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword",3:"title.class"},contains:[f,t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+r+"\\s+)",t.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:c,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:c,relevance:0,contains:[d,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,aT,t.C_BLOCK_COMMENT_MODE]},t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},aT,d]}}const lT="[A-Za-z$_][0-9A-Za-z$_]*",g7=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends","using"],b7=["true","false","null","undefined","NaN","Infinity"],rN=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],iN=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],sN=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],E7=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],y7=[].concat(sN,rN,iN);function x7(t){const e=t.regex,n=(j,{after:W})=>{const O="",end:""},s=/<[A-Za-z0-9\\._:-]+\s*\/>/,o={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(j,W)=>{const O=j[0].length+j.index,U=j.input[O];if(U==="<"||U===","){W.ignoreMatch();return}U===">"&&(n(j,{after:O})||W.ignoreMatch());let Q;const R=j.input.substring(O);if(Q=R.match(/^\s*=/)){W.ignoreMatch();return}if((Q=R.match(/^\s+extends\s+/))&&Q.index===0){W.ignoreMatch();return}}},l={$pattern:lT,keyword:g7,literal:b7,built_in:y7,"variable.language":E7},c="[0-9](_?[0-9])*",d=`\\.(${c})`,f="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",p={className:"number",variants:[{begin:`(\\b(${f})((${d})|\\.)?|(${d}))[eE][+-]?(${c})\\b`},{begin:`\\b(${f})\\b((${d})\\b|\\.)?|(${d})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},m={className:"subst",begin:"\\$\\{",end:"\\}",keywords:l,contains:[]},g={begin:".?html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"xml"}},x={begin:".?css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"css"}},v={begin:".?gql`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"graphql"}},S={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,m]},A={className:"comment",variants:[t.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,excludeBegin:!0,relevance:0},{className:"variable",begin:r+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]},k=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,g,x,v,S,{match:/\$\d+/},p];m.contains=k.concat({begin:/\{/,end:/\}/,keywords:l,contains:["self"].concat(k)});const M=[].concat(A,m.contains),F=M.concat([{begin:/(\s*)\(/,end:/\)/,keywords:l,contains:["self"].concat(M)}]),I={className:"params",begin:/(\s*)\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:F},D={variants:[{match:[/class/,/\s+/,r,/\s+/,/extends/,/\s+/,e.concat(r,"(",e.concat(/\./,r),")*")],scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{match:[/class/,/\s+/,r],scope:{1:"keyword",3:"title.class"}}]},G={relevance:0,match:e.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),className:"title.class",keywords:{_:[...rN,...iN]}},X={label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},P={variants:[{match:[/function/,/\s+/,r,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},label:"func.def",contains:[I],illegal:/%/},Y={relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"};function z(j){return e.concat("(?!",j.join("|"),")")}const ie={match:e.concat(/\b/,z([...sN,"super","import"].map(j=>`${j}\\s*\\(`)),r,e.lookahead(/\s*\(/)),className:"title.function",relevance:0},Z={begin:e.concat(/\./,e.lookahead(e.concat(r,/(?![0-9A-Za-z$_(])/))),end:r,excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},ee={match:[/get|set/,/\s+/,r,/(?=\()/],className:{1:"keyword",3:"title.function"},contains:[{begin:/\(\)/},I]},ae="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",de={match:[/const|var|let/,/\s+/,r,/\s*/,/=\s*/,/(async\s*)?/,e.lookahead(ae)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[I]};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:l,exports:{PARAMS_CONTAINS:F,CLASS_REFERENCE:G},illegal:/#(?![$_A-z])/,contains:[t.SHEBANG({label:"shebang",binary:"node",relevance:5}),X,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,g,x,v,S,A,{match:/\$\d+/},p,G,{scope:"attr",match:r+e.lookahead(":"),relevance:0},de,{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[A,t.REGEXP_MODE,{className:"function",begin:ae,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/(\s*)\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:F}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:i.begin,end:i.end},{match:s},{begin:o.begin,"on:begin":o.isTrulyOpeningTag,end:o.end}],subLanguage:"xml",contains:[{begin:o.begin,end:o.end,skip:!0,contains:["self"]}]}]},P,{beginKeywords:"while if switch catch for"},{begin:"\\b(?!function)"+t.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[I,t.inherit(t.TITLE_MODE,{begin:r,className:"title.function"})]},{match:/\.\.\./,relevance:0},Z,{match:"\\$"+r,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[I]},ie,Y,D,ee,{match:/\$[(.]/}]}}function v7(t){const e={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},n={match:/[{}[\],:]/,className:"punctuation",relevance:0},r=["true","false","null"],i={scope:"literal",beginKeywords:r.join(" ")};return{name:"JSON",aliases:["jsonc"],keywords:{literal:r},contains:[e,n,t.QUOTE_STRING_MODE,i,t.C_NUMBER_MODE,t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}var Ka="[0-9](_*[0-9])*",pf=`\\.(${Ka})`,mf="[0-9a-fA-F](_*[0-9a-fA-F])*",w7={className:"number",variants:[{begin:`(\\b(${Ka})((${pf})|\\.)?|(${pf}))[eE][+-]?(${Ka})[fFdD]?\\b`},{begin:`\\b(${Ka})((${pf})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${pf})[fFdD]?\\b`},{begin:`\\b(${Ka})[fFdD]\\b`},{begin:`\\b0[xX]((${mf})\\.?|(${mf})?\\.(${mf}))[pP][+-]?(${Ka})[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${mf})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function T7(t){const e={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},n={className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},r={className:"symbol",begin:t.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:/\$\{/,end:/\}/,contains:[t.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+t.UNDERSCORE_IDENT_RE},o={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[t.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[t.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(o);const l={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+t.UNDERSCORE_IDENT_RE+")?"},c={className:"meta",begin:"@"+t.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[t.inherit(o,{className:"string"}),"self"]}]},d=w7,f=t.COMMENT("/\\*","\\*/",{contains:[t.C_BLOCK_COMMENT_MODE]}),p={variants:[{className:"type",begin:t.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},m=p;return m.variants[1].contains=[p],p.variants[1].contains=[m],{name:"Kotlin",aliases:["kt","kts"],keywords:e,contains:[t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),t.C_LINE_COMMENT_MODE,f,n,r,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:e,relevance:5,contains:[{begin:t.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[t.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:e,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[p,t.C_LINE_COMMENT_MODE,f],relevance:0},t.C_LINE_COMMENT_MODE,f,l,c,o,t.C_NUMBER_MODE]},f]},{begin:[/class|interface|trait/,/\s+/,t.UNDERSCORE_IDENT_RE],beginScope:{3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},t.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/,excludeBegin:!0,returnEnd:!0},l,c]},o,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:` +`},d]}}const S7=t=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:t.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:t.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/}}),_7=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","optgroup","option","p","picture","q","quote","samp","section","select","source","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],C7=["defs","g","marker","mask","pattern","svg","switch","symbol","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feGaussianBlur","feImage","feMerge","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","linearGradient","radialGradient","stop","circle","ellipse","image","line","path","polygon","polyline","rect","text","use","textPath","tspan","foreignObject","clipPath"],A7=[..._7,...C7],k7=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"].sort().reverse(),oN=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"].sort().reverse(),aN=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"].sort().reverse(),N7=["accent-color","align-content","align-items","align-self","alignment-baseline","all","anchor-name","animation","animation-composition","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-range","animation-range-end","animation-range-start","animation-timeline","animation-timing-function","appearance","aspect-ratio","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-end-end-radius","border-end-start-radius","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-start-end-radius","border-start-start-radius","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-align","box-decoration-break","box-direction","box-flex","box-flex-group","box-lines","box-ordinal-group","box-orient","box-pack","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","color-scheme","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","contain-intrinsic-block-size","contain-intrinsic-height","contain-intrinsic-inline-size","contain-intrinsic-size","contain-intrinsic-width","container","container-name","container-type","content","content-visibility","counter-increment","counter-reset","counter-set","cue","cue-after","cue-before","cursor","cx","cy","direction","display","dominant-baseline","empty-cells","enable-background","field-sizing","fill","fill-opacity","fill-rule","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flood-color","flood-opacity","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-palette","font-size","font-size-adjust","font-smooth","font-smoothing","font-stretch","font-style","font-synthesis","font-synthesis-position","font-synthesis-small-caps","font-synthesis-style","font-synthesis-weight","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-emoji","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","forced-color-adjust","gap","glyph-orientation-horizontal","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphenate-character","hyphenate-limit-chars","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","initial-letter","initial-letter-align","inline-size","inset","inset-area","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","kerning","left","letter-spacing","lighting-color","line-break","line-height","line-height-step","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","margin-trim","marker","marker-end","marker-mid","marker-start","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","masonry-auto-flow","math-depth","math-shift","math-style","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-anchor","overflow-block","overflow-clip-margin","overflow-inline","overflow-wrap","overflow-x","overflow-y","overlay","overscroll-behavior","overscroll-behavior-block","overscroll-behavior-inline","overscroll-behavior-x","overscroll-behavior-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","paint-order","pause","pause-after","pause-before","perspective","perspective-origin","place-content","place-items","place-self","pointer-events","position","position-anchor","position-visibility","print-color-adjust","quotes","r","resize","rest","rest-after","rest-before","right","rotate","row-gap","ruby-align","ruby-position","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scroll-timeline","scroll-timeline-axis","scroll-timeline-name","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","shape-rendering","speak","speak-as","src","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","tab-size","table-layout","text-align","text-align-all","text-align-last","text-anchor","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-decoration-thickness","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-size-adjust","text-transform","text-underline-offset","text-underline-position","text-wrap","text-wrap-mode","text-wrap-style","timeline-scope","top","touch-action","transform","transform-box","transform-origin","transform-style","transition","transition-behavior","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-modify","user-select","vector-effect","vertical-align","view-timeline","view-timeline-axis","view-timeline-inset","view-timeline-name","view-transition-name","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","white-space-collapse","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","x","y","z-index","zoom"].sort().reverse(),R7=oN.concat(aN).sort().reverse();function I7(t){const e=S7(t),n=R7,r="and or not only",i="[\\w-]+",s="("+i+"|@\\{"+i+"\\})",o=[],l=[],c=function(k){return{className:"string",begin:"~?"+k+".*?"+k}},d=function(k,M,F){return{className:k,begin:M,relevance:F}},f={$pattern:/[a-z-]+/,keyword:r,attribute:k7.join(" ")},p={begin:"\\(",end:"\\)",contains:l,keywords:f,relevance:0};l.push(t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,c("'"),c('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},e.HEXCOLOR,p,d("variable","@@?"+i,10),d("variable","@\\{"+i+"\\}"),d("built_in","~?`[^`]*?`"),{className:"attribute",begin:i+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0},e.IMPORTANT,{beginKeywords:"and not"},e.FUNCTION_DISPATCH);const m=l.concat({begin:/\{/,end:/\}/,contains:o}),g={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(l)},x={begin:s+"\\s*:",returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/},e.CSS_VARIABLE,{className:"attribute",begin:"\\b("+N7.join("|")+")\\b",end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:l}}]},v={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",keywords:f,returnEnd:!0,contains:l,relevance:0}},S={className:"variable",variants:[{begin:"@"+i+"\\s*:",relevance:15},{begin:"@"+i}],starts:{end:"[;}]",returnEnd:!0,contains:m}},C={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:s,end:/\{/}],returnBegin:!0,returnEnd:!0,illegal:`[<='$"]`,relevance:0,contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,g,d("keyword","all\\b"),d("variable","@\\{"+i+"\\}"),{begin:"\\b("+A7.join("|")+")\\b",className:"selector-tag"},e.CSS_NUMBER_MODE,d("selector-tag",s,0),d("selector-id","#"+s),d("selector-class","\\."+s,0),d("selector-tag","&",0),e.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",begin:":("+oN.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+aN.join("|")+")"},{begin:/\(/,end:/\)/,relevance:0,contains:m},{begin:"!important"},e.FUNCTION_DISPATCH]},A={begin:i+`:(:)?(${n.join("|")})`,returnBegin:!0,contains:[C]};return o.push(t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,v,S,A,x,C,g,e.FUNCTION_DISPATCH),{name:"Less",case_insensitive:!0,illegal:`[=>'/<($"]`,contains:o}}function O7(t){const e="\\[=*\\[",n="\\]=*\\]",r={begin:e,end:n,contains:["self"]},i=[t.COMMENT("--(?!"+e+")","$"),t.COMMENT("--"+e,n,{contains:[r],relevance:10})];return{name:"Lua",aliases:["pluto"],keywords:{$pattern:t.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[t.inherit(t.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:i}].concat(i)},t.C_NUMBER_MODE,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,{className:"string",begin:e,end:n,contains:[r],relevance:5}])}}function M7(t){const e={className:"variable",variants:[{begin:"\\$\\("+t.UNDERSCORE_IDENT_RE+"\\)",contains:[t.BACKSLASH_ESCAPE]},{begin:/\$[@%",subLanguage:"xml",relevance:0},r={begin:"^[-\\*]{3,}",end:"$"},i={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},s={className:"bullet",begin:"^[ ]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},o={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},l=/[A-Za-z][A-Za-z0-9+.-]*/,c={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,l,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},d={className:"strong",contains:[],variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}]},f={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{begin:/_(?![_\s])/,end:/_/,relevance:0}]},p=t.inherit(d,{contains:[]}),m=t.inherit(f,{contains:[]});d.contains.push(m),f.contains.push(p);let g=[n,c];return[d,f,p,m].forEach(C=>{C.contains=C.contains.concat(g)}),g=g.concat(d,f),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:g},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:g}]}]},n,s,d,f,{className:"quote",begin:"^>\\s+",contains:g,end:"$"},i,r,c,o,{scope:"literal",match:/&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/}]}}function L7(t){const e={className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},n=/[a-zA-Z@][a-zA-Z0-9_]*/,l={"variable.language":["this","super"],$pattern:n,keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"]},c={$pattern:n,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:l,illegal:"/,end:/$/,illegal:"\\n"},t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+c.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:c,contains:[t.UNDERSCORE_TITLE_MODE]},{begin:"\\."+t.UNDERSCORE_IDENT_RE,relevance:0}]}}function P7(t){const e=t.regex,n=["abs","accept","alarm","and","atan2","bind","binmode","bless","break","caller","chdir","chmod","chomp","chop","chown","chr","chroot","class","close","closedir","connect","continue","cos","crypt","dbmclose","dbmopen","defined","delete","die","do","dump","each","else","elsif","endgrent","endhostent","endnetent","endprotoent","endpwent","endservent","eof","eval","exec","exists","exit","exp","fcntl","field","fileno","flock","for","foreach","fork","format","formline","getc","getgrent","getgrgid","getgrnam","gethostbyaddr","gethostbyname","gethostent","getlogin","getnetbyaddr","getnetbyname","getnetent","getpeername","getpgrp","getpriority","getprotobyname","getprotobynumber","getprotoent","getpwent","getpwnam","getpwuid","getservbyname","getservbyport","getservent","getsockname","getsockopt","given","glob","gmtime","goto","grep","gt","hex","if","index","int","ioctl","join","keys","kill","last","lc","lcfirst","length","link","listen","local","localtime","log","lstat","lt","ma","map","method","mkdir","msgctl","msgget","msgrcv","msgsnd","my","ne","next","no","not","oct","open","opendir","or","ord","our","pack","package","pipe","pop","pos","print","printf","prototype","push","q|0","qq","quotemeta","qw","qx","rand","read","readdir","readline","readlink","readpipe","recv","redo","ref","rename","require","reset","return","reverse","rewinddir","rindex","rmdir","say","scalar","seek","seekdir","select","semctl","semget","semop","send","setgrent","sethostent","setnetent","setpgrp","setpriority","setprotoent","setpwent","setservent","setsockopt","shift","shmctl","shmget","shmread","shmwrite","shutdown","sin","sleep","socket","socketpair","sort","splice","split","sprintf","sqrt","srand","stat","state","study","sub","substr","symlink","syscall","sysopen","sysread","sysseek","system","syswrite","tell","telldir","tie","tied","time","times","tr","truncate","uc","ucfirst","umask","undef","unless","unlink","unpack","unshift","untie","until","use","utime","values","vec","wait","waitpid","wantarray","warn","when","while","write","x|0","xor","y|0"],r=/[dualxmsipngr]{0,12}/,i={$pattern:/[\w.]+/,keyword:n.join(" ")},s={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:i},o={begin:/->\{/,end:/\}/},l={scope:"attr",match:/\s+:\s*\w+(\s*\(.*?\))?/},c={scope:"variable",variants:[{begin:/\$\d/},{begin:e.concat(/[$%@](?!")(\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")},{begin:/[$%@](?!")[^\s\w{=]|\$=/,relevance:0}],contains:[l]},d={className:"number",variants:[{match:/0?\.[0-9][0-9_]+\b/},{match:/\bv?(0|[1-9][0-9_]*(\.[0-9_]+)?|[1-9][0-9_]*)\b/},{match:/\b0[0-7][0-7_]*\b/},{match:/\b0x[0-9a-fA-F][0-9a-fA-F_]*\b/},{match:/\b0b[0-1][0-1_]*\b/}],relevance:0},f=[t.BACKSLASH_ESCAPE,s,c],p=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],m=(v,S,C="\\1")=>{const A=C==="\\1"?C:e.concat(C,S);return e.concat(e.concat("(?:",v,")"),S,/(?:\\.|[^\\\/])*?/,A,/(?:\\.|[^\\\/])*?/,C,r)},g=(v,S,C)=>e.concat(e.concat("(?:",v,")"),S,/(?:\\.|[^\\\/])*?/,C,r),x=[c,t.HASH_COMMENT_MODE,t.COMMENT(/^=\w/,/=cut/,{endsWithParent:!0}),o,{className:"string",contains:f,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[t.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{begin:"-?\\w+\\s*=>",relevance:0}]},d,{begin:"(\\/\\/|"+t.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[t.HASH_COMMENT_MODE,{className:"regexp",variants:[{begin:m("s|tr|y",e.either(...p,{capture:!0}))},{begin:m("s|tr|y","\\(","\\)")},{begin:m("s|tr|y","\\[","\\]")},{begin:m("s|tr|y","\\{","\\}")}],relevance:2},{className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{begin:g("(?:m|qr)?",/\//,/\//)},{begin:g("m|qr",e.either(...p,{capture:!0}),/\1/)},{begin:g("m|qr",/\(/,/\)/)},{begin:g("m|qr",/\[/,/\]/)},{begin:g("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub method",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[t.TITLE_MODE,l]},{className:"class",beginKeywords:"class",end:"[;{]",excludeEnd:!0,relevance:5,contains:[t.TITLE_MODE,l,d]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return s.contains=x,o.contains=x,{name:"Perl",aliases:["pl","pm"],keywords:i,contains:x}}function F7(t){const e=t.regex,n=/(?![A-Za-z0-9])(?![$])/,r=e.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,n),i=e.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,n),s=e.concat(/[A-Z]+/,n),o={scope:"variable",match:"\\$+"+r},l={scope:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{begin:/\?>/}]},c={scope:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},d=t.inherit(t.APOS_STRING_MODE,{illegal:null}),f=t.inherit(t.QUOTE_STRING_MODE,{illegal:null,contains:t.QUOTE_STRING_MODE.contains.concat(c)}),p={begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/,contains:t.QUOTE_STRING_MODE.contains.concat(c),"on:begin":(Z,ee)=>{ee.data._beginMatch=Z[1]||Z[2]},"on:end":(Z,ee)=>{ee.data._beginMatch!==Z[1]&&ee.ignoreMatch()}},m=t.END_SAME_AS_BEGIN({begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/}),g=`[ +]`,x={scope:"string",variants:[f,d,p,m]},v={scope:"number",variants:[{begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?"}],relevance:0},S=["false","null","true"],C=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],A=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],M={keyword:C,literal:(Z=>{const ee=[];return Z.forEach(ae=>{ee.push(ae),ae.toLowerCase()===ae?ee.push(ae.toUpperCase()):ee.push(ae.toLowerCase())}),ee})(S),built_in:A},F=Z=>Z.map(ee=>ee.replace(/\|\d+$/,"")),I={variants:[{match:[/new/,e.concat(g,"+"),e.concat("(?!",F(A).join("\\b|"),"\\b)"),i],scope:{1:"keyword",4:"title.class"}}]},D=e.concat(r,"\\b(?!\\()"),G={variants:[{match:[e.concat(/::/,e.lookahead(/(?!class\b)/)),D],scope:{2:"variable.constant"}},{match:[/::/,/class/],scope:{2:"variable.language"}},{match:[i,e.concat(/::/,e.lookahead(/(?!class\b)/)),D],scope:{1:"title.class",3:"variable.constant"}},{match:[i,e.concat("::",e.lookahead(/(?!class\b)/))],scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class",3:"variable.language"}}]},X={scope:"attr",match:e.concat(r,e.lookahead(":"),e.lookahead(/(?!::)/))},P={relevance:0,begin:/\(/,end:/\)/,keywords:M,contains:[X,o,G,t.C_BLOCK_COMMENT_MODE,x,v,I]},Y={relevance:0,match:[/\b/,e.concat("(?!fn\\b|function\\b|",F(C).join("\\b|"),"|",F(A).join("\\b|"),"\\b)"),r,e.concat(g,"*"),e.lookahead(/(?=\()/)],scope:{3:"title.function.invoke"},contains:[P]};P.contains.push(Y);const z=[X,G,t.C_BLOCK_COMMENT_MODE,x,v,I],ie={begin:e.concat(/#\[\s*\\?/,e.either(i,s)),beginScope:"meta",end:/]/,endScope:"meta",keywords:{literal:S,keyword:["new","array"]},contains:[{begin:/\[/,end:/]/,keywords:{literal:S,keyword:["new","array"]},contains:["self",...z]},...z,{scope:"meta",variants:[{match:i},{match:s}]}]};return{case_insensitive:!1,keywords:M,contains:[ie,t.HASH_COMMENT_MODE,t.COMMENT("//","$"),t.COMMENT("/\\*","\\*/",{contains:[{scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/,keywords:"__halt_compiler",starts:{scope:"comment",end:t.MATCH_NOTHING_RE,contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},l,{scope:"variable.language",match:/\$this\b/},o,Y,G,{match:[/const/,/\s/,r],scope:{1:"keyword",3:"variable.constant"}},I,{scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"},t.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:M,contains:["self",ie,o,G,t.C_BLOCK_COMMENT_MODE,x,v]}]},{scope:"class",variants:[{beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{beginKeywords:"extends implements"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[t.inherit(t.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{beginKeywords:"use",relevance:0,end:";",contains:[{match:/\b(as|const|function)\b/,scope:"keyword"},t.UNDERSCORE_TITLE_MODE]},x,v]}}function B7(t){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},t.inherit(t.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),t.inherit(t.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}function U7(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}function H7(t){const e=t.regex,n=new RegExp("[\\p{XID_Start}_]\\p{XID_Continue}*","u"),r=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],l={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:r,built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]},c={className:"meta",begin:/^(>>>|\.\.\.) /},d={className:"subst",begin:/\{/,end:/\}/,keywords:l,illegal:/#/},f={begin:/\{\{/,relevance:0},p={className:"string",contains:[t.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[t.BACKSLASH_ESCAPE,c],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[t.BACKSLASH_ESCAPE,c],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[t.BACKSLASH_ESCAPE,c,f,d]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[t.BACKSLASH_ESCAPE,c,f,d]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[t.BACKSLASH_ESCAPE,f,d]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[t.BACKSLASH_ESCAPE,f,d]},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE]},m="[0-9](_?[0-9])*",g=`(\\b(${m}))?\\.(${m})|\\b(${m})\\.`,x=`\\b|${r.join("|")}`,v={className:"number",relevance:0,variants:[{begin:`(\\b(${m})|(${g}))[eE][+-]?(${m})[jJ]?(?=${x})`},{begin:`(${g})[jJ]?`},{begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${x})`},{begin:`\\b0[bB](_?[01])+[lL]?(?=${x})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${x})`},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${x})`},{begin:`\\b(${m})[jJ](?=${x})`}]},S={className:"comment",begin:e.lookahead(/# type:/),end:/$/,keywords:l,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},C={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:["self",c,v,p,t.HASH_COMMENT_MODE]}]};return d.contains=[p,v,c],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:l,illegal:/(<\/|\?)|=>/,contains:[c,v,{scope:"variable.language",match:/\bself\b/},{beginKeywords:"if",relevance:0},{match:/\bor\b/,scope:"keyword"},p,S,t.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,n],scope:{1:"keyword",3:"title.function"},contains:[C]},{variants:[{match:[/\bclass/,/\s+/,n,/\s*/,/\(\s*/,n,/\s*\)/]},{match:[/\bclass/,/\s+/,n]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[v,C,p]}]}}function z7(t){return{aliases:["pycon"],contains:[{className:"meta.prompt",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}function j7(t){const e=t.regex,n=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,r=e.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,s=e.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/);return{name:"R",keywords:{$pattern:n,keyword:"function if in break next repeat else for while",literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"},contains:[t.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/,starts:{end:e.lookahead(e.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)),endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{scope:"variable",variants:[{match:n},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}]}),t.HASH_COMMENT_MODE,{scope:"string",contains:[t.BACKSLASH_ESCAPE],variants:[t.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/}),t.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/}),t.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/}),t.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/}),t.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/}),t.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{1:"operator",2:"number"},match:[i,r]},{scope:{1:"operator",2:"number"},match:[/%[^%]*%/,r]},{scope:{1:"punctuation",2:"number"},match:[s,r]},{scope:{2:"number"},match:[/[^a-zA-Z0-9._]|^/,r]}]},{scope:{3:"operator"},match:[n,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:s},{begin:"`",end:"`",contains:[{begin:/\\./}]}]}}function $7(t){const e=t.regex,n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",r=e.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=e.concat(r,/(::\w+)*/),o={"variable.constant":["__FILE__","__LINE__","__ENCODING__"],"variable.language":["self","super"],keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield",...["include","extend","prepend","public","private","protected","raise","throw"]],built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"],literal:["true","false","nil"]},l={className:"doctag",begin:"@[A-Za-z]+"},c={begin:"#<",end:">"},d=[t.COMMENT("#","$",{contains:[l]}),t.COMMENT("^=begin","^=end",{contains:[l],relevance:10}),t.COMMENT("^__END__",t.MATCH_NOTHING_RE)],f={className:"subst",begin:/#\{/,end:/\}/,keywords:o},p={className:"string",contains:[t.BACKSLASH_ESCAPE,f],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:e.concat(/<<[-~]?'?/,e.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[t.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[t.BACKSLASH_ESCAPE,f]})]}]},m="[1-9](_?[0-9])*|0",g="[0-9](_?[0-9])*",x={className:"number",relevance:0,variants:[{begin:`\\b(${m})(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},v={variants:[{match:/\(\)/},{className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,keywords:o}]},I=[p,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class",4:"title.class.inherited"},keywords:o},{match:[/(include|extend)\s+/,i],scope:{2:"title.class"},keywords:o},{relevance:0,match:[i,/\.new[. (]/],scope:{1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{relevance:0,match:r,scope:"title.class"},{match:[/def/,/\s+/,n],scope:{1:"keyword",3:"title.function"},contains:[v]},{begin:t.IDENT_RE+"::"},{className:"symbol",begin:t.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[p,{begin:n}],relevance:0},x,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|(?!=)/,end:/\|/,excludeBegin:!0,excludeEnd:!0,relevance:0,keywords:o},{begin:"("+t.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[t.BACKSLASH_ESCAPE,f],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(c,d),relevance:0}].concat(c,d);f.contains=I,v.contains=I;const P=[{begin:/^\s*=>/,starts:{end:"$",contains:I}},{className:"meta.prompt",begin:"^("+"[>?]>"+"|"+"[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]"+"|"+"(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>"+")(?=[ ])",starts:{end:"$",keywords:o,contains:I}}];return d.unshift(c),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:o,illegal:/\/\*/,contains:[t.SHEBANG({binary:"ruby"})].concat(P).concat(d).concat(I)}}function W7(t){const e=t.regex,n=/(r#)?/,r=e.concat(n,t.UNDERSCORE_IDENT_RE),i=e.concat(n,t.IDENT_RE),s={className:"title.function.invoke",relevance:0,begin:e.concat(/\b/,/(?!let|for|while|if|else|match\b)/,i,e.lookahead(/\s*\(/))},o="([ui](8|16|32|64|128|size)|f(32|64))?",l=["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","union","unsafe","unsized","use","virtual","where","while","yield"],c=["true","false","Some","None","Ok","Err"],d=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],f=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"];return{name:"Rust",aliases:["rs"],keywords:{$pattern:t.IDENT_RE+"!?",type:f,keyword:l,literal:c,built_in:d},illegal:""},s]}}const V7=t=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:t.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:t.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/}}),G7=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","optgroup","option","p","picture","q","quote","samp","section","select","source","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],K7=["defs","g","marker","mask","pattern","svg","switch","symbol","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feGaussianBlur","feImage","feMerge","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","linearGradient","radialGradient","stop","circle","ellipse","image","line","path","polygon","polyline","rect","text","use","textPath","tspan","foreignObject","clipPath"],Y7=[...G7,...K7],q7=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"].sort().reverse(),X7=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"].sort().reverse(),Q7=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"].sort().reverse(),Z7=["accent-color","align-content","align-items","align-self","alignment-baseline","all","anchor-name","animation","animation-composition","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-range","animation-range-end","animation-range-start","animation-timeline","animation-timing-function","appearance","aspect-ratio","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-end-end-radius","border-end-start-radius","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-start-end-radius","border-start-start-radius","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-align","box-decoration-break","box-direction","box-flex","box-flex-group","box-lines","box-ordinal-group","box-orient","box-pack","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","color-scheme","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","contain-intrinsic-block-size","contain-intrinsic-height","contain-intrinsic-inline-size","contain-intrinsic-size","contain-intrinsic-width","container","container-name","container-type","content","content-visibility","counter-increment","counter-reset","counter-set","cue","cue-after","cue-before","cursor","cx","cy","direction","display","dominant-baseline","empty-cells","enable-background","field-sizing","fill","fill-opacity","fill-rule","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flood-color","flood-opacity","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-palette","font-size","font-size-adjust","font-smooth","font-smoothing","font-stretch","font-style","font-synthesis","font-synthesis-position","font-synthesis-small-caps","font-synthesis-style","font-synthesis-weight","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-emoji","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","forced-color-adjust","gap","glyph-orientation-horizontal","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphenate-character","hyphenate-limit-chars","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","initial-letter","initial-letter-align","inline-size","inset","inset-area","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","kerning","left","letter-spacing","lighting-color","line-break","line-height","line-height-step","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","margin-trim","marker","marker-end","marker-mid","marker-start","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","masonry-auto-flow","math-depth","math-shift","math-style","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-anchor","overflow-block","overflow-clip-margin","overflow-inline","overflow-wrap","overflow-x","overflow-y","overlay","overscroll-behavior","overscroll-behavior-block","overscroll-behavior-inline","overscroll-behavior-x","overscroll-behavior-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","paint-order","pause","pause-after","pause-before","perspective","perspective-origin","place-content","place-items","place-self","pointer-events","position","position-anchor","position-visibility","print-color-adjust","quotes","r","resize","rest","rest-after","rest-before","right","rotate","row-gap","ruby-align","ruby-position","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scroll-timeline","scroll-timeline-axis","scroll-timeline-name","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","shape-rendering","speak","speak-as","src","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","tab-size","table-layout","text-align","text-align-all","text-align-last","text-anchor","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-decoration-thickness","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-size-adjust","text-transform","text-underline-offset","text-underline-position","text-wrap","text-wrap-mode","text-wrap-style","timeline-scope","top","touch-action","transform","transform-box","transform-origin","transform-style","transition","transition-behavior","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-modify","user-select","vector-effect","vertical-align","view-timeline","view-timeline-axis","view-timeline-inset","view-timeline-name","view-transition-name","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","white-space-collapse","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","x","y","z-index","zoom"].sort().reverse();function J7(t){const e=V7(t),n=Q7,r=X7,i="@[a-z-]+",s="and or not only",l={className:"variable",begin:"(\\$"+"[a-zA-Z-][a-zA-Z0-9_-]*"+")\\b",relevance:0};return{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,e.CSS_NUMBER_MODE,{className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},e.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",begin:"\\b("+Y7.join("|")+")\\b",relevance:0},{className:"selector-pseudo",begin:":("+r.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+n.join("|")+")"},l,{begin:/\(/,end:/\)/,contains:[e.CSS_NUMBER_MODE]},e.CSS_VARIABLE,{className:"attribute",begin:"\\b("+Z7.join("|")+")\\b"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:/:/,end:/[;}{]/,relevance:0,contains:[e.BLOCK_COMMENT,l,e.HEXCOLOR,e.CSS_NUMBER_MODE,t.QUOTE_STRING_MODE,t.APOS_STRING_MODE,e.IMPORTANT,e.FUNCTION_DISPATCH]},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,keyword:s,attribute:q7.join(" ")},contains:[{begin:i,className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"},l,t.QUOTE_STRING_MODE,t.APOS_STRING_MODE,e.HEXCOLOR,e.CSS_NUMBER_MODE]},e.FUNCTION_DISPATCH]}}function ej(t){return{name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta.prompt",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}}function tj(t){const e=t.regex,n=t.COMMENT("--","$"),r={scope:"string",variants:[{begin:/'/,end:/'/,contains:[{match:/''/}]}]},i={begin:/"/,end:/"/,contains:[{match:/""/}]},s=["true","false","unknown"],o=["double precision","large object","with timezone","without timezone"],l=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],c=["add","asc","collation","desc","final","first","last","view"],d=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year"],f=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],p=["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"],m=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],g=f,x=[...d,...c].filter(F=>!f.includes(F)),v={scope:"variable",match:/@[a-z0-9][a-z0-9_]*/},S={scope:"operator",match:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0},C={match:e.concat(/\b/,e.either(...g),/\s*\(/),relevance:0,keywords:{built_in:g}};function A(F){return e.concat(/\b/,e.either(...F.map(I=>I.replace(/\s+/,"\\s+"))),/\b/)}const k={scope:"keyword",match:A(m),relevance:0};function M(F,{exceptions:I,when:D}={}){const G=D;return I=I||[],F.map(X=>X.match(/\|\d+$/)||I.includes(X)?X:G(X)?`${X}|0`:X)}return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{$pattern:/\b[\w\.]+/,keyword:M(x,{when:F=>F.length<3}),literal:s,type:l,built_in:p},contains:[{scope:"type",match:A(o)},k,C,v,r,i,t.C_NUMBER_MODE,t.C_BLOCK_COMMENT_MODE,n,S]}}function lN(t){return t?typeof t=="string"?t:t.source:null}function Ou(t){return zt("(?=",t,")")}function zt(...t){return t.map(n=>lN(n)).join("")}function nj(t){const e=t[t.length-1];return typeof e=="object"&&e.constructor===Object?(t.splice(t.length-1,1),e):{}}function br(...t){return"("+(nj(t).capture?"":"?:")+t.map(r=>lN(r)).join("|")+")"}const s1=t=>zt(/\b/,t,/\w$/.test(t)?/\b/:/\B/),rj=["Protocol","Type"].map(s1),uT=["init","self"].map(s1),ij=["Any","Self"],Jg=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","package","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],cT=["false","nil","true"],sj=["assignment","associativity","higherThan","left","lowerThan","none","right"],oj=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],dT=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],uN=br(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),cN=br(uN,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),e0=zt(uN,cN,"*"),dN=br(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),fh=br(dN,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Bi=zt(dN,fh,"*"),gf=zt(/[A-Z]/,fh,"*"),aj=["attached","autoclosure",zt(/convention\(/,br("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",zt(/objc\(/,Bi,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],lj=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"];function uj(t){const e={match:/\s+/,relevance:0},n=t.COMMENT("/\\*","\\*/",{contains:["self"]}),r=[t.C_LINE_COMMENT_MODE,n],i={match:[/\./,br(...rj,...uT)],className:{2:"keyword"}},s={match:zt(/\./,br(...Jg)),relevance:0},o=Jg.filter(nt=>typeof nt=="string").concat(["_|0"]),l=Jg.filter(nt=>typeof nt!="string").concat(ij).map(s1),c={variants:[{className:"keyword",match:br(...l,...uT)}]},d={$pattern:br(/\b\w+/,/#\w+/),keyword:o.concat(oj),literal:cT},f=[i,s,c],p={match:zt(/\./,br(...dT)),relevance:0},m={className:"built_in",match:zt(/\b/,br(...dT),/(?=\()/)},g=[p,m],x={match:/->/,relevance:0},v={className:"operator",relevance:0,variants:[{match:e0},{match:`\\.(\\.|${cN})+`}]},S=[x,v],C="([0-9]_*)+",A="([0-9a-fA-F]_*)+",k={className:"number",relevance:0,variants:[{match:`\\b(${C})(\\.(${C}))?([eE][+-]?(${C}))?\\b`},{match:`\\b0x(${A})(\\.(${A}))?([pP][+-]?(${C}))?\\b`},{match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},M=(nt="")=>({className:"subst",variants:[{match:zt(/\\/,nt,/[0\\tnr"']/)},{match:zt(/\\/,nt,/u\{[0-9a-fA-F]{1,8}\}/)}]}),F=(nt="")=>({className:"subst",match:zt(/\\/,nt,/[\t ]*(?:[\r\n]|\r\n)/)}),I=(nt="")=>({className:"subst",label:"interpol",begin:zt(/\\/,nt,/\(/),end:/\)/}),D=(nt="")=>({begin:zt(nt,/"""/),end:zt(/"""/,nt),contains:[M(nt),F(nt),I(nt)]}),G=(nt="")=>({begin:zt(nt,/"/),end:zt(/"/,nt),contains:[M(nt),I(nt)]}),X={className:"string",variants:[D(),D("#"),D("##"),D("###"),G(),G("#"),G("##"),G("###")]},P=[t.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,contains:[t.BACKSLASH_ESCAPE]}],Y={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//,contains:P},z=nt=>{const Yt=zt(nt,/\//),Ct=zt(/\//,nt);return{begin:Yt,end:Ct,contains:[...P,{scope:"comment",begin:`#(?!.*${Ct})`,end:/$/}]}},ie={scope:"regexp",variants:[z("###"),z("##"),z("#"),Y]},Z={match:zt(/`/,Bi,/`/)},ee={className:"variable",match:/\$\d+/},ae={className:"variable",match:`\\$${fh}+`},de=[Z,ee,ae],j={match:/(@|#(un)?)available/,scope:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:lj,contains:[...S,k,X]}]}},W={scope:"keyword",match:zt(/@/,br(...aj),Ou(br(/\(/,/\s+/)))},O={scope:"meta",match:zt(/@/,Bi)},U=[j,W,O],Q={match:Ou(/\b[A-Z]/),relevance:0,contains:[{className:"type",match:zt(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,fh,"+")},{className:"type",match:gf,relevance:0},{match:/[?!]+/,relevance:0},{match:/\.\.\./,relevance:0},{match:zt(/\s+&\s+/,Ou(gf)),relevance:0}]},R={begin://,keywords:d,contains:[...r,...f,...U,x,Q]};Q.contains.push(R);const oe={match:zt(Bi,/\s*:/),keywords:"_|0",relevance:0},pe={begin:/\(/,end:/\)/,relevance:0,keywords:d,contains:["self",oe,...r,ie,...f,...g,...S,k,X,...de,...U,Q]},ue={begin://,keywords:"repeat each",contains:[...r,Q]},J={begin:br(Ou(zt(Bi,/\s*:/)),Ou(zt(Bi,/\s+/,Bi,/\s*:/))),end:/:/,relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Bi}]},he={begin:/\(/,end:/\)/,keywords:d,contains:[J,...r,...f,...S,k,X,...U,Q,pe],endsParent:!0,illegal:/["']/},_e={match:[/(func|macro)/,/\s+/,br(Z.match,Bi,e0)],className:{1:"keyword",3:"title.function"},contains:[ue,he,e],illegal:[/\[/,/%/]},ke={match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},contains:[ue,he,e],illegal:/\[|%/},Ve={match:[/operator/,/\s+/,e0],className:{1:"keyword",3:"title"}},ot={begin:[/precedencegroup/,/\s+/,gf],className:{1:"keyword",3:"title"},contains:[Q],keywords:[...sj,...cT],end:/}/},qe={match:[/class\b/,/\s+/,/func\b/,/\s+/,/\b[A-Za-z_][A-Za-z0-9_]*\b/],scope:{1:"keyword",3:"keyword",5:"title.function"}},kt={match:[/class\b/,/\s+/,/var\b/],scope:{1:"keyword",3:"keyword"}},fn={begin:[/(struct|protocol|class|extension|enum|actor)/,/\s+/,Bi,/\s*/],beginScope:{1:"keyword",3:"title.class"},keywords:d,contains:[ue,...f,{begin:/:/,end:/\{/,keywords:d,contains:[{scope:"title.class.inherited",match:gf},...f],relevance:0}]};for(const nt of X.variants){const Yt=nt.contains.find(Pn=>Pn.label==="interpol");Yt.keywords=d;const Ct=[...f,...g,...S,k,X,...de];Yt.contains=[...Ct,{begin:/\(/,end:/\)/,contains:["self",...Ct]}]}return{name:"Swift",keywords:d,contains:[...r,_e,ke,qe,kt,fn,Ve,ot,{beginKeywords:"import",end:/$/,contains:[...r],relevance:0},ie,...f,...g,...S,k,X,...de,...U,Q,pe]}}const hh="[A-Za-z$_][0-9A-Za-z$_]*",fN=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends","using"],hN=["true","false","null","undefined","NaN","Infinity"],pN=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],mN=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],gN=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],bN=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],EN=[].concat(gN,pN,mN);function cj(t){const e=t.regex,n=(j,{after:W})=>{const O="",end:""},s=/<[A-Za-z0-9\\._:-]+\s*\/>/,o={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(j,W)=>{const O=j[0].length+j.index,U=j.input[O];if(U==="<"||U===","){W.ignoreMatch();return}U===">"&&(n(j,{after:O})||W.ignoreMatch());let Q;const R=j.input.substring(O);if(Q=R.match(/^\s*=/)){W.ignoreMatch();return}if((Q=R.match(/^\s+extends\s+/))&&Q.index===0){W.ignoreMatch();return}}},l={$pattern:hh,keyword:fN,literal:hN,built_in:EN,"variable.language":bN},c="[0-9](_?[0-9])*",d=`\\.(${c})`,f="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",p={className:"number",variants:[{begin:`(\\b(${f})((${d})|\\.)?|(${d}))[eE][+-]?(${c})\\b`},{begin:`\\b(${f})\\b((${d})\\b|\\.)?|(${d})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},m={className:"subst",begin:"\\$\\{",end:"\\}",keywords:l,contains:[]},g={begin:".?html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"xml"}},x={begin:".?css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"css"}},v={begin:".?gql`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,m],subLanguage:"graphql"}},S={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,m]},A={className:"comment",variants:[t.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,excludeBegin:!0,relevance:0},{className:"variable",begin:r+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]},k=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,g,x,v,S,{match:/\$\d+/},p];m.contains=k.concat({begin:/\{/,end:/\}/,keywords:l,contains:["self"].concat(k)});const M=[].concat(A,m.contains),F=M.concat([{begin:/(\s*)\(/,end:/\)/,keywords:l,contains:["self"].concat(M)}]),I={className:"params",begin:/(\s*)\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:F},D={variants:[{match:[/class/,/\s+/,r,/\s+/,/extends/,/\s+/,e.concat(r,"(",e.concat(/\./,r),")*")],scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{match:[/class/,/\s+/,r],scope:{1:"keyword",3:"title.class"}}]},G={relevance:0,match:e.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),className:"title.class",keywords:{_:[...pN,...mN]}},X={label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},P={variants:[{match:[/function/,/\s+/,r,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},label:"func.def",contains:[I],illegal:/%/},Y={relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"};function z(j){return e.concat("(?!",j.join("|"),")")}const ie={match:e.concat(/\b/,z([...gN,"super","import"].map(j=>`${j}\\s*\\(`)),r,e.lookahead(/\s*\(/)),className:"title.function",relevance:0},Z={begin:e.concat(/\./,e.lookahead(e.concat(r,/(?![0-9A-Za-z$_(])/))),end:r,excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},ee={match:[/get|set/,/\s+/,r,/(?=\()/],className:{1:"keyword",3:"title.function"},contains:[{begin:/\(\)/},I]},ae="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",de={match:[/const|var|let/,/\s+/,r,/\s*/,/=\s*/,/(async\s*)?/,e.lookahead(ae)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[I]};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:l,exports:{PARAMS_CONTAINS:F,CLASS_REFERENCE:G},illegal:/#(?![$_A-z])/,contains:[t.SHEBANG({label:"shebang",binary:"node",relevance:5}),X,t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,g,x,v,S,A,{match:/\$\d+/},p,G,{scope:"attr",match:r+e.lookahead(":"),relevance:0},de,{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[A,t.REGEXP_MODE,{className:"function",begin:ae,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/(\s*)\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:F}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:i.begin,end:i.end},{match:s},{begin:o.begin,"on:begin":o.isTrulyOpeningTag,end:o.end}],subLanguage:"xml",contains:[{begin:o.begin,end:o.end,skip:!0,contains:["self"]}]}]},P,{beginKeywords:"while if switch catch for"},{begin:"\\b(?!function)"+t.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[I,t.inherit(t.TITLE_MODE,{begin:r,className:"title.function"})]},{match:/\.\.\./,relevance:0},Z,{match:"\\$"+r,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[I]},ie,Y,D,ee,{match:/\$[(.]/}]}}function dj(t){const e=t.regex,n=cj(t),r=hh,i=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],s={begin:[/namespace/,/\s+/,t.IDENT_RE],beginScope:{1:"keyword",3:"title.class"}},o={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{keyword:"interface extends",built_in:i},contains:[n.exports.CLASS_REFERENCE]},l={className:"meta",relevance:10,begin:/^\s*['"]use strict['"]/},c=["type","interface","public","private","protected","implements","declare","abstract","readonly","enum","override","satisfies"],d={$pattern:hh,keyword:fN.concat(c),literal:hN,built_in:EN.concat(i),"variable.language":bN},f={className:"meta",begin:"@"+r},p=(v,S,C)=>{const A=v.contains.findIndex(k=>k.label===S);if(A===-1)throw new Error("can not find mode to replace");v.contains.splice(A,1,C)};Object.assign(n.keywords,d),n.exports.PARAMS_CONTAINS.push(f);const m=n.contains.find(v=>v.scope==="attr"),g=Object.assign({},m,{match:e.concat(r,e.lookahead(/\s*\?:/))});n.exports.PARAMS_CONTAINS.push([n.exports.CLASS_REFERENCE,m,g]),n.contains=n.contains.concat([f,s,o,g]),p(n,"shebang",t.SHEBANG()),p(n,"use_strict",l);const x=n.contains.find(v=>v.label==="func.def");return x.relevance=0,Object.assign(n,{name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n}function fj(t){const e=t.regex,n={className:"string",begin:/"(""|[^/n])"C\b/},r={className:"string",begin:/"/,end:/"/,illegal:/\n/,contains:[{begin:/""/}]},i=/\d{1,2}\/\d{1,2}\/\d{4}/,s=/\d{4}-\d{1,2}-\d{1,2}/,o=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,l=/\d{1,2}(:\d{1,2}){1,2}/,c={className:"literal",variants:[{begin:e.concat(/# */,e.either(s,i),/ *#/)},{begin:e.concat(/# */,l,/ *#/)},{begin:e.concat(/# */,o,/ *#/)},{begin:e.concat(/# */,e.either(s,i),/ +/,e.either(o,l),/ *#/)}]},d={className:"number",relevance:0,variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},f={className:"label",begin:/^\w+:/},p=t.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}]}),m=t.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]});return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0,classNameAliases:{label:"symbol"},keywords:{keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",literal:"true false nothing"},illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[n,r,c,d,f,p,m,{className:"meta",begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,end:/$/,keywords:{keyword:"const disable else elseif enable end externalsource if region then"},contains:[m]}]}}function hj(t){t.regex;const e=t.COMMENT(/\(;/,/;\)/);e.contains.push("self");const n=t.COMMENT(/;;/,/$/),r=["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"],i={begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword",3:"title.function"}},s={className:"variable",begin:/\$[\w_]+/},o={match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},l={className:"number",relevance:0,match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/},c={match:/(i32|i64|f32|f64)(?!\.)/,className:"type"},d={className:"keyword",match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/};return{name:"WebAssembly",keywords:{$pattern:/[\w.]+/,keyword:r},contains:[n,e,{match:[/(?:offset|align)/,/\s*/,/=/],className:{1:"keyword",3:"operator"}},s,o,i,t.QUOTE_STRING_MODE,c,d,l]}}function pj(t){const e=t.regex,n=e.concat(/[\p{L}_]/u,e.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),r=/[\p{L}0-9._:-]+/u,i={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},s={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},o=t.inherit(s,{begin:/\(/,end:/\)/}),l=t.inherit(t.APOS_STRING_MODE,{className:"string"}),c=t.inherit(t.QUOTE_STRING_MODE,{className:"string"}),d={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[s,c,l,o,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[s,o,c,l]}]}]},t.COMMENT(//,{relevance:10}),{begin://,relevance:10},i,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/,relevance:10,contains:[c]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[d],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[d],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:e.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:n,relevance:0,starts:d}]},{className:"tag",begin:e.concat(/<\//,e.lookahead(e.concat(n,/>/))),contains:[{className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}function mj(t){const e="true false yes no null",n="[\\w#;/?:@&=+$,.~*'()[\\]]+",r={className:"attr",variants:[{begin:/[\w*@][\w*@ :()\./-]*:(?=[ \t]|$)/},{begin:/"[\w*@][\w*@ :()\./-]*":(?=[ \t]|$)/},{begin:/'[\w*@][\w*@ :()\./-]*':(?=[ \t]|$)/}]},i={className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]},s={className:"string",relevance:0,begin:/'/,end:/'/,contains:[{match:/''/,scope:"char.escape",relevance:0}]},o={className:"string",relevance:0,variants:[{begin:/"/,end:/"/},{begin:/\S+/}],contains:[t.BACKSLASH_ESCAPE,i]},l=t.inherit(o,{variants:[{begin:/'/,end:/'/,contains:[{begin:/''/,relevance:0}]},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),m={className:"number",begin:"\\b"+"[0-9]{4}(-[0-9][0-9]){0,2}"+"([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?"+"(\\.[0-9]*)?"+"([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?"+"\\b"},g={end:",",endsWithParent:!0,excludeEnd:!0,keywords:e,relevance:0},x={begin:/\{/,end:/\}/,contains:[g],illegal:"\\n",relevance:0},v={begin:"\\[",end:"\\]",contains:[g],illegal:"\\n",relevance:0},S=[r,{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+n},{className:"type",begin:"!<"+n+">"},{className:"type",begin:"!"+n},{className:"type",begin:"!!"+n},{className:"meta",begin:"&"+t.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+t.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},t.HASH_COMMENT_MODE,{beginKeywords:e,keywords:{literal:e}},m,{className:"number",begin:t.C_NUMBER_RE+"\\b",relevance:0},x,v,s,o],C=[...S];return C.pop(),C.push(l),g.contains=C,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:S}}const gj={arduino:Qz,bash:Zz,c:Jz,cpp:e7,csharp:t7,css:c7,diff:d7,go:f7,graphql:h7,ini:p7,java:m7,javascript:x7,json:v7,kotlin:T7,less:I7,lua:O7,makefile:M7,markdown:D7,objectivec:L7,perl:P7,php:F7,"php-template":B7,plaintext:U7,python:H7,"python-repl":z7,r:j7,ruby:$7,rust:W7,scss:J7,shell:ej,sql:tj,swift:uj,typescript:dj,vbnet:fj,wasm:hj,xml:pj,yaml:mj};var t0,fT;function bj(){if(fT)return t0;fT=1;function t(V){return V instanceof Map?V.clear=V.delete=V.set=function(){throw new Error("map is read-only")}:V instanceof Set&&(V.add=V.clear=V.delete=function(){throw new Error("set is read-only")}),Object.freeze(V),Object.getOwnPropertyNames(V).forEach(te=>{const me=V[te],De=typeof me;(De==="object"||De==="function")&&!Object.isFrozen(me)&&t(me)}),V}class e{constructor(te){te.data===void 0&&(te.data={}),this.data=te.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function n(V){return V.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(V,...te){const me=Object.create(null);for(const De in V)me[De]=V[De];return te.forEach(function(De){for(const wt in De)me[wt]=De[wt]}),me}const i="",s=V=>!!V.scope,o=(V,{prefix:te})=>{if(V.startsWith("language:"))return V.replace("language:","language-");if(V.includes(".")){const me=V.split(".");return[`${te}${me.shift()}`,...me.map((De,wt)=>`${De}${"_".repeat(wt+1)}`)].join(" ")}return`${te}${V}`};class l{constructor(te,me){this.buffer="",this.classPrefix=me.classPrefix,te.walk(this)}addText(te){this.buffer+=n(te)}openNode(te){if(!s(te))return;const me=o(te.scope,{prefix:this.classPrefix});this.span(me)}closeNode(te){s(te)&&(this.buffer+=i)}value(){return this.buffer}span(te){this.buffer+=``}}const c=(V={})=>{const te={children:[]};return Object.assign(te,V),te};class d{constructor(){this.rootNode=c(),this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(te){this.top.children.push(te)}openNode(te){const me=c({scope:te});this.add(me),this.stack.push(me)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(te){return this.constructor._walk(te,this.rootNode)}static _walk(te,me){return typeof me=="string"?te.addText(me):me.children&&(te.openNode(me),me.children.forEach(De=>this._walk(te,De)),te.closeNode(me)),te}static _collapse(te){typeof te!="string"&&te.children&&(te.children.every(me=>typeof me=="string")?te.children=[te.children.join("")]:te.children.forEach(me=>{d._collapse(me)}))}}class f extends d{constructor(te){super(),this.options=te}addText(te){te!==""&&this.add(te)}startScope(te){this.openNode(te)}endScope(){this.closeNode()}__addSublanguage(te,me){const De=te.root;me&&(De.scope=`language:${me}`),this.add(De)}toHTML(){return new l(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}}function p(V){return V?typeof V=="string"?V:V.source:null}function m(V){return v("(?=",V,")")}function g(V){return v("(?:",V,")*")}function x(V){return v("(?:",V,")?")}function v(...V){return V.map(me=>p(me)).join("")}function S(V){const te=V[V.length-1];return typeof te=="object"&&te.constructor===Object?(V.splice(V.length-1,1),te):{}}function C(...V){return"("+(S(V).capture?"":"?:")+V.map(De=>p(De)).join("|")+")"}function A(V){return new RegExp(V.toString()+"|").exec("").length-1}function k(V,te){const me=V&&V.exec(te);return me&&me.index===0}const M=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function F(V,{joinWith:te}){let me=0;return V.map(De=>{me+=1;const wt=me;let _t=p(De),Oe="";for(;_t.length>0;){const Ie=M.exec(_t);if(!Ie){Oe+=_t;break}Oe+=_t.substring(0,Ie.index),_t=_t.substring(Ie.index+Ie[0].length),Ie[0][0]==="\\"&&Ie[1]?Oe+="\\"+String(Number(Ie[1])+wt):(Oe+=Ie[0],Ie[0]==="("&&me++)}return Oe}).map(De=>`(${De})`).join(te)}const I=/\b\B/,D="[a-zA-Z]\\w*",G="[a-zA-Z_]\\w*",X="\\b\\d+(\\.\\d+)?",P="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",Y="\\b(0b[01]+)",z="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",ie=(V={})=>{const te=/^#![ ]*\//;return V.binary&&(V.begin=v(te,/.*\b/,V.binary,/\b.*/)),r({scope:"meta",begin:te,end:/$/,relevance:0,"on:begin":(me,De)=>{me.index!==0&&De.ignoreMatch()}},V)},Z={begin:"\\\\[\\s\\S]",relevance:0},ee={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[Z]},ae={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[Z]},de={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},j=function(V,te,me={}){const De=r({scope:"comment",begin:V,end:te,contains:[]},me);De.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const wt=C("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return De.contains.push({begin:v(/[ ]+/,"(",wt,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),De},W=j("//","$"),O=j("/\\*","\\*/"),U=j("#","$"),Q={scope:"number",begin:X,relevance:0},R={scope:"number",begin:P,relevance:0},oe={scope:"number",begin:Y,relevance:0},pe={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[Z,{begin:/\[/,end:/\]/,relevance:0,contains:[Z]}]},ue={scope:"title",begin:D,relevance:0},J={scope:"title",begin:G,relevance:0},he={begin:"\\.\\s*"+G,relevance:0};var ke=Object.freeze({__proto__:null,APOS_STRING_MODE:ee,BACKSLASH_ESCAPE:Z,BINARY_NUMBER_MODE:oe,BINARY_NUMBER_RE:Y,COMMENT:j,C_BLOCK_COMMENT_MODE:O,C_LINE_COMMENT_MODE:W,C_NUMBER_MODE:R,C_NUMBER_RE:P,END_SAME_AS_BEGIN:function(V){return Object.assign(V,{"on:begin":(te,me)=>{me.data._beginMatch=te[1]},"on:end":(te,me)=>{me.data._beginMatch!==te[1]&&me.ignoreMatch()}})},HASH_COMMENT_MODE:U,IDENT_RE:D,MATCH_NOTHING_RE:I,METHOD_GUARD:he,NUMBER_MODE:Q,NUMBER_RE:X,PHRASAL_WORDS_MODE:de,QUOTE_STRING_MODE:ae,REGEXP_MODE:pe,RE_STARTERS_RE:z,SHEBANG:ie,TITLE_MODE:ue,UNDERSCORE_IDENT_RE:G,UNDERSCORE_TITLE_MODE:J});function Ve(V,te){V.input[V.index-1]==="."&&te.ignoreMatch()}function ot(V,te){V.className!==void 0&&(V.scope=V.className,delete V.className)}function qe(V,te){te&&V.beginKeywords&&(V.begin="\\b("+V.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",V.__beforeBegin=Ve,V.keywords=V.keywords||V.beginKeywords,delete V.beginKeywords,V.relevance===void 0&&(V.relevance=0))}function kt(V,te){Array.isArray(V.illegal)&&(V.illegal=C(...V.illegal))}function fn(V,te){if(V.match){if(V.begin||V.end)throw new Error("begin & end are not supported with match");V.begin=V.match,delete V.match}}function nt(V,te){V.relevance===void 0&&(V.relevance=1)}const Yt=(V,te)=>{if(!V.beforeMatch)return;if(V.starts)throw new Error("beforeMatch cannot be used with starts");const me=Object.assign({},V);Object.keys(V).forEach(De=>{delete V[De]}),V.keywords=me.keywords,V.begin=v(me.beforeMatch,m(me.begin)),V.starts={relevance:0,contains:[Object.assign(me,{endsParent:!0})]},V.relevance=0,delete me.beforeMatch},Ct=["of","and","for","in","not","or","if","then","parent","list","value"],Pn="keyword";function Fn(V,te,me=Pn){const De=Object.create(null);return typeof V=="string"?wt(me,V.split(" ")):Array.isArray(V)?wt(me,V):Object.keys(V).forEach(function(_t){Object.assign(De,Fn(V[_t],te,_t))}),De;function wt(_t,Oe){te&&(Oe=Oe.map(Ie=>Ie.toLowerCase())),Oe.forEach(function(Ie){const He=Ie.split("|");De[He[0]]=[_t,on(He[0],He[1])]})}}function on(V,te){return te?Number(te):dr(V)?0:1}function dr(V){return Ct.includes(V.toLowerCase())}const Mn={},Qn=V=>{console.error(V)},li=(V,...te)=>{console.log(`WARN: ${V}`,...te)},ce=(V,te)=>{Mn[`${V}/${te}`]||(console.log(`Deprecated as of ${V}. ${te}`),Mn[`${V}/${te}`]=!0)},ye=new Error;function Qe(V,te,{key:me}){let De=0;const wt=V[me],_t={},Oe={};for(let Ie=1;Ie<=te.length;Ie++)Oe[Ie+De]=wt[Ie],_t[Ie+De]=!0,De+=A(te[Ie-1]);V[me]=Oe,V[me]._emit=_t,V[me]._multi=!0}function ut(V){if(Array.isArray(V.begin)){if(V.skip||V.excludeBegin||V.returnBegin)throw Qn("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),ye;if(typeof V.beginScope!="object"||V.beginScope===null)throw Qn("beginScope must be object"),ye;Qe(V,V.begin,{key:"beginScope"}),V.begin=F(V.begin,{joinWith:""})}}function rt(V){if(Array.isArray(V.end)){if(V.skip||V.excludeEnd||V.returnEnd)throw Qn("skip, excludeEnd, returnEnd not compatible with endScope: {}"),ye;if(typeof V.endScope!="object"||V.endScope===null)throw Qn("endScope must be object"),ye;Qe(V,V.end,{key:"endScope"}),V.end=F(V.end,{joinWith:""})}}function an(V){V.scope&&typeof V.scope=="object"&&V.scope!==null&&(V.beginScope=V.scope,delete V.scope)}function Zn(V){an(V),typeof V.beginScope=="string"&&(V.beginScope={_wrap:V.beginScope}),typeof V.endScope=="string"&&(V.endScope={_wrap:V.endScope}),ut(V),rt(V)}function Re(V){function te(Oe,Ie){return new RegExp(p(Oe),"m"+(V.case_insensitive?"i":"")+(V.unicodeRegex?"u":"")+(Ie?"g":""))}class me{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(Ie,He){He.position=this.position++,this.matchIndexes[this.matchAt]=He,this.regexes.push([He,Ie]),this.matchAt+=A(Ie)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);const Ie=this.regexes.map(He=>He[1]);this.matcherRe=te(F(Ie,{joinWith:"|"}),!0),this.lastIndex=0}exec(Ie){this.matcherRe.lastIndex=this.lastIndex;const He=this.matcherRe.exec(Ie);if(!He)return null;const Bt=He.findIndex((Ri,Ns)=>Ns>0&&Ri!==void 0),Xt=this.matchIndexes[Bt];return He.splice(0,Bt),Object.assign(He,Xt)}}class De{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(Ie){if(this.multiRegexes[Ie])return this.multiRegexes[Ie];const He=new me;return this.rules.slice(Ie).forEach(([Bt,Xt])=>He.addRule(Bt,Xt)),He.compile(),this.multiRegexes[Ie]=He,He}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(Ie,He){this.rules.push([Ie,He]),He.type==="begin"&&this.count++}exec(Ie){const He=this.getMatcher(this.regexIndex);He.lastIndex=this.lastIndex;let Bt=He.exec(Ie);if(this.resumingScanAtSamePosition()&&!(Bt&&Bt.index===this.lastIndex)){const Xt=this.getMatcher(0);Xt.lastIndex=this.lastIndex+1,Bt=Xt.exec(Ie)}return Bt&&(this.regexIndex+=Bt.position+1,this.regexIndex===this.count&&this.considerAll()),Bt}}function wt(Oe){const Ie=new De;return Oe.contains.forEach(He=>Ie.addRule(He.begin,{rule:He,type:"begin"})),Oe.terminatorEnd&&Ie.addRule(Oe.terminatorEnd,{type:"end"}),Oe.illegal&&Ie.addRule(Oe.illegal,{type:"illegal"}),Ie}function _t(Oe,Ie){const He=Oe;if(Oe.isCompiled)return He;[ot,fn,Zn,Yt].forEach(Xt=>Xt(Oe,Ie)),V.compilerExtensions.forEach(Xt=>Xt(Oe,Ie)),Oe.__beforeBegin=null,[qe,kt,nt].forEach(Xt=>Xt(Oe,Ie)),Oe.isCompiled=!0;let Bt=null;return typeof Oe.keywords=="object"&&Oe.keywords.$pattern&&(Oe.keywords=Object.assign({},Oe.keywords),Bt=Oe.keywords.$pattern,delete Oe.keywords.$pattern),Bt=Bt||/\w+/,Oe.keywords&&(Oe.keywords=Fn(Oe.keywords,V.case_insensitive)),He.keywordPatternRe=te(Bt,!0),Ie&&(Oe.begin||(Oe.begin=/\B|\b/),He.beginRe=te(He.begin),!Oe.end&&!Oe.endsWithParent&&(Oe.end=/\B|\b/),Oe.end&&(He.endRe=te(He.end)),He.terminatorEnd=p(He.end)||"",Oe.endsWithParent&&Ie.terminatorEnd&&(He.terminatorEnd+=(Oe.end?"|":"")+Ie.terminatorEnd)),Oe.illegal&&(He.illegalRe=te(Oe.illegal)),Oe.contains||(Oe.contains=[]),Oe.contains=[].concat(...Oe.contains.map(function(Xt){return Ge(Xt==="self"?Oe:Xt)})),Oe.contains.forEach(function(Xt){_t(Xt,He)}),Oe.starts&&_t(Oe.starts,Ie),He.matcher=wt(He),He}if(V.compilerExtensions||(V.compilerExtensions=[]),V.contains&&V.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return V.classNameAliases=r(V.classNameAliases||{}),_t(V)}function Me(V){return V?V.endsWithParent||Me(V.starts):!1}function Ge(V){return V.variants&&!V.cachedVariants&&(V.cachedVariants=V.variants.map(function(te){return r(V,{variants:null},te)})),V.cachedVariants?V.cachedVariants:Me(V)?r(V,{starts:V.starts?r(V.starts):null}):Object.isFrozen(V)?r(V):V}var Ke="11.11.1";class bt extends Error{constructor(te,me){super(te),this.name="HTMLInjectionError",this.html=me}}const vt=n,jt=r,fr=Symbol("nomatch"),Dt=7,$t=function(V){const te=Object.create(null),me=Object.create(null),De=[];let wt=!0;const _t="Could not find the language '{}', did you forget to load/include a language module?",Oe={disableAutodetect:!0,name:"Plain text",contains:[]};let Ie={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:f};function He(Ce){return Ie.noHighlightRe.test(Ce)}function Bt(Ce){let Ye=Ce.className+" ";Ye+=Ce.parentNode?Ce.parentNode.className:"";const mt=Ie.languageDetectRe.exec(Ye);if(mt){const Tt=ui(mt[1]);return Tt||(li(_t.replace("{}",mt[1])),li("Falling back to no-highlight mode for this block.",Ce)),Tt?mt[1]:"no-highlight"}return Ye.split(/\s+/).find(Tt=>He(Tt)||ui(Tt))}function Xt(Ce,Ye,mt){let Tt="",vn="";typeof Ye=="object"?(Tt=Ce,mt=Ye.ignoreIllegals,vn=Ye.language):(ce("10.7.0","highlight(lang, code, ...args) has been deprecated."),ce("10.7.0",`Please use highlight(code, options) instead. +https://github.com/highlightjs/highlight.js/issues/2277`),vn=Ce,Tt=Ye),mt===void 0&&(mt=!0);const pn={code:Tt,language:vn};yo("before:highlight",pn);const Ii=pn.result?pn.result:Ri(pn.language,pn.code,mt);return Ii.code=pn.code,yo("after:highlight",Ii),Ii}function Ri(Ce,Ye,mt,Tt){const vn=Object.create(null);function pn(Ne,Be){return Ne.keywords[Be]}function Ii(){if(!at.keywords){wn.addText(Ut);return}let Ne=0;at.keywordPatternRe.lastIndex=0;let Be=at.keywordPatternRe.exec(Ut),it="";for(;Be;){it+=Ut.substring(Ne,Be.index);const At=Yr.case_insensitive?Be[0].toLowerCase():Be[0],En=pn(at,At);if(En){const[Bn,Mp]=En;if(wn.addText(it),it="",vn[At]=(vn[At]||0)+1,vn[At]<=Dt&&(wo+=Mp),Bn.startsWith("_"))it+=Be[0];else{const Qc=Yr.classNameAliases[Bn]||Bn;pr(Be[0],Qc)}}else it+=Be[0];Ne=at.keywordPatternRe.lastIndex,Be=at.keywordPatternRe.exec(Ut)}it+=Ut.substring(Ne),wn.addText(it)}function pa(){if(Ut==="")return;let Ne=null;if(typeof at.subLanguage=="string"){if(!te[at.subLanguage]){wn.addText(Ut);return}Ne=Ri(at.subLanguage,Ut,!0,Gl[at.subLanguage]),Gl[at.subLanguage]=Ne._top}else Ne=Eo(Ut,at.subLanguage.length?at.subLanguage:null);at.relevance>0&&(wo+=Ne.relevance),wn.__addSublanguage(Ne._emitter,Ne.language)}function hr(){at.subLanguage!=null?pa():Ii(),Ut=""}function pr(Ne,Be){Ne!==""&&(wn.startScope(Be),wn.addText(Ne),wn.endScope())}function xo(Ne,Be){let it=1;const At=Be.length-1;for(;it<=At;){if(!Ne._emit[it]){it++;continue}const En=Yr.classNameAliases[Ne[it]]||Ne[it],Bn=Be[it];En?pr(Bn,En):(Ut=Bn,Ii(),Ut=""),it++}}function Rs(Ne,Be){return Ne.scope&&typeof Ne.scope=="string"&&wn.openNode(Yr.classNameAliases[Ne.scope]||Ne.scope),Ne.beginScope&&(Ne.beginScope._wrap?(pr(Ut,Yr.classNameAliases[Ne.beginScope._wrap]||Ne.beginScope._wrap),Ut=""):Ne.beginScope._multi&&(xo(Ne.beginScope,Be),Ut="")),at=Object.create(Ne,{parent:{value:at}}),at}function vo(Ne,Be,it){let At=k(Ne.endRe,it);if(At){if(Ne["on:end"]){const En=new e(Ne);Ne["on:end"](Be,En),En.isMatchIgnored&&(At=!1)}if(At){for(;Ne.endsParent&&Ne.parent;)Ne=Ne.parent;return Ne}}if(Ne.endsWithParent)return vo(Ne.parent,Be,it)}function Ip(Ne){return at.matcher.regexIndex===0?(Ut+=Ne[0],1):(Ms=!0,0)}function Op(Ne){const Be=Ne[0],it=Ne.rule,At=new e(it),En=[it.__beforeBegin,it["on:begin"]];for(const Bn of En)if(Bn&&(Bn(Ne,At),At.isMatchIgnored))return Ip(Be);return it.skip?Ut+=Be:(it.excludeBegin&&(Ut+=Be),hr(),!it.returnBegin&&!it.excludeBegin&&(Ut=Be)),Rs(it,Ne),it.returnBegin?0:Be.length}function Wl(Ne){const Be=Ne[0],it=Ye.substring(Ne.index),At=vo(at,Ne,it);if(!At)return fr;const En=at;at.endScope&&at.endScope._wrap?(hr(),pr(Be,at.endScope._wrap)):at.endScope&&at.endScope._multi?(hr(),xo(at.endScope,Ne)):En.skip?Ut+=Be:(En.returnEnd||En.excludeEnd||(Ut+=Be),hr(),En.excludeEnd&&(Ut=Be));do at.scope&&wn.closeNode(),!at.skip&&!at.subLanguage&&(wo+=at.relevance),at=at.parent;while(at!==At.parent);return At.starts&&Rs(At.starts,Ne),En.returnEnd?0:Be.length}function Xc(){const Ne=[];for(let Be=at;Be!==Yr;Be=Be.parent)Be.scope&&Ne.unshift(Be.scope);Ne.forEach(Be=>wn.openNode(Be))}let Is={};function Os(Ne,Be){const it=Be&&Be[0];if(Ut+=Ne,it==null)return hr(),0;if(Is.type==="begin"&&Be.type==="end"&&Is.index===Be.index&&it===""){if(Ut+=Ye.slice(Be.index,Be.index+1),!wt){const At=new Error(`0 width match regex (${Ce})`);throw At.languageName=Ce,At.badRule=Is.rule,At}return 1}if(Is=Be,Be.type==="begin")return Op(Be);if(Be.type==="illegal"&&!mt){const At=new Error('Illegal lexeme "'+it+'" for mode "'+(at.scope||"")+'"');throw At.mode=at,At}else if(Be.type==="end"){const At=Wl(Be);if(At!==fr)return At}if(Be.type==="illegal"&&it==="")return Ut+=` +`,1;if(To>1e5&&To>Be.index*3)throw new Error("potential infinite loop, way more iterations than matches");return Ut+=it,it.length}const Yr=ui(Ce);if(!Yr)throw Qn(_t.replace("{}",Ce)),new Error('Unknown language: "'+Ce+'"');const Vl=Re(Yr);let It="",at=Tt||Vl;const Gl={},wn=new Ie.__emitter(Ie);Xc();let Ut="",wo=0,Oi=0,To=0,Ms=!1;try{if(Yr.__emitTokens)Yr.__emitTokens(Ye,wn);else{for(at.matcher.considerAll();;){To++,Ms?Ms=!1:at.matcher.considerAll(),at.matcher.lastIndex=Oi;const Ne=at.matcher.exec(Ye);if(!Ne)break;const Be=Ye.substring(Oi,Ne.index),it=Os(Be,Ne);Oi=Ne.index+it}Os(Ye.substring(Oi))}return wn.finalize(),It=wn.toHTML(),{language:Ce,value:It,relevance:wo,illegal:!1,_emitter:wn,_top:at}}catch(Ne){if(Ne.message&&Ne.message.includes("Illegal"))return{language:Ce,value:vt(Ye),illegal:!0,relevance:0,_illegalBy:{message:Ne.message,index:Oi,context:Ye.slice(Oi-100,Oi+100),mode:Ne.mode,resultSoFar:It},_emitter:wn};if(wt)return{language:Ce,value:vt(Ye),illegal:!1,relevance:0,errorRaised:Ne,_emitter:wn,_top:at};throw Ne}}function Ns(Ce){const Ye={value:vt(Ce),illegal:!1,relevance:0,_top:Oe,_emitter:new Ie.__emitter(Ie)};return Ye._emitter.addText(Ce),Ye}function Eo(Ce,Ye){Ye=Ye||Ie.languages||Object.keys(te);const mt=Ns(Ce),Tt=Ye.filter(ui).filter(qc).map(hr=>Ri(hr,Ce,!1));Tt.unshift(mt);const vn=Tt.sort((hr,pr)=>{if(hr.relevance!==pr.relevance)return pr.relevance-hr.relevance;if(hr.language&&pr.language){if(ui(hr.language).supersetOf===pr.language)return 1;if(ui(pr.language).supersetOf===hr.language)return-1}return 0}),[pn,Ii]=vn,pa=pn;return pa.secondBest=Ii,pa}function kp(Ce,Ye,mt){const Tt=Ye&&me[Ye]||mt;Ce.classList.add("hljs"),Ce.classList.add(`language-${Tt}`)}function zl(Ce){let Ye=null;const mt=Bt(Ce);if(He(mt))return;if(yo("before:highlightElement",{el:Ce,language:mt}),Ce.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",Ce);return}if(Ce.children.length>0&&(Ie.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(Ce)),Ie.throwUnescapedHTML))throw new bt("One of your code blocks includes unescaped HTML.",Ce.innerHTML);Ye=Ce;const Tt=Ye.textContent,vn=mt?Xt(Tt,{language:mt,ignoreIllegals:!0}):Eo(Tt);Ce.innerHTML=vn.value,Ce.dataset.highlighted="yes",kp(Ce,mt,vn.language),Ce.result={language:vn.language,re:vn.relevance,relevance:vn.relevance},vn.secondBest&&(Ce.secondBest={language:vn.secondBest.language,relevance:vn.secondBest.relevance}),yo("after:highlightElement",{el:Ce,result:vn,text:Tt})}function Np(Ce){Ie=jt(Ie,Ce)}const ts=()=>{fa(),ce("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function Wc(){fa(),ce("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let jl=!1;function fa(){function Ce(){fa()}if(document.readyState==="loading"){jl||window.addEventListener("DOMContentLoaded",Ce,!1),jl=!0;return}document.querySelectorAll(Ie.cssSelector).forEach(zl)}function Vc(Ce,Ye){let mt=null;try{mt=Ye(V)}catch(Tt){if(Qn("Language definition for '{}' could not be registered.".replace("{}",Ce)),wt)Qn(Tt);else throw Tt;mt=Oe}mt.name||(mt.name=Ce),te[Ce]=mt,mt.rawDefinition=Ye.bind(null,V),mt.aliases&&Yc(mt.aliases,{languageName:Ce})}function Gc(Ce){delete te[Ce];for(const Ye of Object.keys(me))me[Ye]===Ce&&delete me[Ye]}function Kc(){return Object.keys(te)}function ui(Ce){return Ce=(Ce||"").toLowerCase(),te[Ce]||te[me[Ce]]}function Yc(Ce,{languageName:Ye}){typeof Ce=="string"&&(Ce=[Ce]),Ce.forEach(mt=>{me[mt.toLowerCase()]=Ye})}function qc(Ce){const Ye=ui(Ce);return Ye&&!Ye.disableAutodetect}function hn(Ce){Ce["before:highlightBlock"]&&!Ce["before:highlightElement"]&&(Ce["before:highlightElement"]=Ye=>{Ce["before:highlightBlock"](Object.assign({block:Ye.el},Ye))}),Ce["after:highlightBlock"]&&!Ce["after:highlightElement"]&&(Ce["after:highlightElement"]=Ye=>{Ce["after:highlightBlock"](Object.assign({block:Ye.el},Ye))})}function Rp(Ce){hn(Ce),De.push(Ce)}function $l(Ce){const Ye=De.indexOf(Ce);Ye!==-1&&De.splice(Ye,1)}function yo(Ce,Ye){const mt=Ce;De.forEach(function(Tt){Tt[mt]&&Tt[mt](Ye)})}function ha(Ce){return ce("10.7.0","highlightBlock will be removed entirely in v12.0"),ce("10.7.0","Please use highlightElement now."),zl(Ce)}Object.assign(V,{highlight:Xt,highlightAuto:Eo,highlightAll:fa,highlightElement:zl,highlightBlock:ha,configure:Np,initHighlighting:ts,initHighlightingOnLoad:Wc,registerLanguage:Vc,unregisterLanguage:Gc,listLanguages:Kc,getLanguage:ui,registerAliases:Yc,autoDetection:qc,inherit:jt,addPlugin:Rp,removePlugin:$l}),V.debugMode=function(){wt=!1},V.safeMode=function(){wt=!0},V.versionString=Ke,V.regex={concat:v,lookahead:m,either:C,optional:x,anyNumberOfTimes:g};for(const Ce in ke)typeof ke[Ce]=="object"&&t(ke[Ce]);return Object.assign(V,ke),V},qt=$t({});return qt.newInstance=()=>$t({}),t0=qt,qt.HighlightJS=qt,qt.default=qt,t0}var Ej=bj();const yj=_s(Ej),hT={},xj="hljs-";function vj(t){const e=yj.newInstance();return t&&s(t),{highlight:n,highlightAuto:r,listLanguages:i,register:s,registerAlias:o,registered:l};function n(c,d,f){const p=f||hT,m=typeof p.prefix=="string"?p.prefix:xj;if(!e.getLanguage(c))throw new Error("Unknown language: `"+c+"` is not registered");e.configure({__emitter:wj,classPrefix:m});const g=e.highlight(d,{ignoreIllegals:!0,language:c});if(g.errorRaised)throw new Error("Could not highlight with `Highlight.js`",{cause:g.errorRaised});const x=g._emitter.root,v=x.data;return v.language=g.language,v.relevance=g.relevance,x}function r(c,d){const p=(d||hT).subset||i();let m=-1,g=0,x;for(;++mg&&(g=S.data.relevance,x=S)}return x||{type:"root",children:[],data:{language:void 0,relevance:g}}}function i(){return e.listLanguages()}function s(c,d){if(typeof c=="string")e.registerLanguage(c,d);else{let f;for(f in c)Object.hasOwn(c,f)&&e.registerLanguage(f,c[f])}}function o(c,d){if(typeof c=="string")e.registerAliases(typeof d=="string"?d:[...d],{languageName:c});else{let f;for(f in c)if(Object.hasOwn(c,f)){const p=c[f];e.registerAliases(typeof p=="string"?p:[...p],{languageName:f})}}}function l(c){return!!e.getLanguage(c)}}class wj{constructor(e){this.options=e,this.root={type:"root",children:[],data:{language:void 0,relevance:0}},this.stack=[this.root]}addText(e){if(e==="")return;const n=this.stack[this.stack.length-1],r=n.children[n.children.length-1];r&&r.type==="text"?r.value+=e:n.children.push({type:"text",value:e})}startScope(e){this.openNode(String(e))}endScope(){this.closeNode()}__addSublanguage(e,n){const r=this.stack[this.stack.length-1],i=e.root.children;n?r.children.push({type:"element",tagName:"span",properties:{className:[n]},children:i}):r.children.push(...i)}openNode(e){const n=this,r=e.split(".").map(function(o,l){return l?o+"_".repeat(l):n.options.classPrefix+o}),i=this.stack[this.stack.length-1],s={type:"element",tagName:"span",properties:{className:r},children:[]};i.children.push(s),this.stack.push(s)}closeNode(){this.stack.pop()}finalize(){}toHTML(){return""}}const Tj={};function Sj(t){const e=t||Tj,n=e.aliases,r=e.detect||!1,i=e.languages||gj,s=e.plainText,o=e.prefix,l=e.subset;let c="hljs";const d=vj(i);if(n&&d.registerAlias(n),o){const f=o.indexOf("-");c=f===-1?o:o.slice(0,f)}return function(f,p){Pc(f,"element",function(m,g,x){if(m.tagName!=="code"||!x||x.type!=="element"||x.tagName!=="pre")return;const v=_j(m);if(v===!1||!v&&!r||v&&s&&s.includes(v))return;Array.isArray(m.properties.className)||(m.properties.className=[]),m.properties.className.includes(c)||m.properties.className.unshift(c);const S=$z(m,{whitespace:"pre"});let C;try{C=v?d.highlight(v,S,{prefix:o}):d.highlightAuto(S,{prefix:o,subset:l})}catch(A){const k=A;if(v&&/Unknown language/.test(k.message)){p.message("Cannot highlight as `"+v+"`, it’s not registered",{ancestors:[x,m],cause:k,place:m.position,ruleId:"missing-language",source:"rehype-highlight"});return}throw k}!v&&C.data&&C.data.language&&m.properties.className.push("language-"+C.data.language),C.children.length>0&&(m.children=C.children)})}}function _j(t){const e=t.properties.className;let n=-1;if(!Array.isArray(e))return;let r;for(;++n-1&&s<=e.length){let o=0;for(;;){let l=n[o];if(l===void 0){const c=gT(e,n[o-1]);l=c===-1?e.length+1:c+1,n[o]=l}if(l>s)return{line:o+1,column:s-(o>0?n[o-1]:0)+1,offset:s};o++}}}function i(s){if(s&&typeof s.line=="number"&&typeof s.column=="number"&&!Number.isNaN(s.line)&&!Number.isNaN(s.column)){for(;n.length1?n[s.line-2]:0)+s.column-1;if(o4&&n.slice(0,4)==="data"&&$j.test(e)){if(e.charAt(4)==="-"){const s=e.slice(5).replace(yT,Kj);r="data"+s.charAt(0).toUpperCase()+s.slice(1)}else{const s=e.slice(4);if(!yT.test(s)){let o=s.replace(Wj,Gj);o.charAt(0)!=="-"&&(o="-"+o),e="data"+o}}i=a1}return new i(r,e)}function Gj(t){return"-"+t.toLowerCase()}function Kj(t){return t.charAt(1).toUpperCase()}const Yj=wN([_N,SN,kN,NN,zj],"html"),RN=wN([_N,SN,kN,NN,jj],"svg"),qj={},Xj={}.hasOwnProperty,IN=Ok("type",{handlers:{root:Zj,element:r$,text:t$,comment:n$,doctype:e$}});function Qj(t,e){const r=(e||qj).space;return IN(t,r==="svg"?RN:Yj)}function Zj(t,e){const n={nodeName:"#document",mode:(t.data||{}).quirksMode?"quirks":"no-quirks",childNodes:[]};return n.childNodes=l1(t.children,n,e),Pl(t,n),n}function Jj(t,e){const n={nodeName:"#document-fragment",childNodes:[]};return n.childNodes=l1(t.children,n,e),Pl(t,n),n}function e$(t){const e={nodeName:"#documentType",name:"html",publicId:"",systemId:"",parentNode:null};return Pl(t,e),e}function t$(t){const e={nodeName:"#text",value:t.value,parentNode:null};return Pl(t,e),e}function n$(t){const e={nodeName:"#comment",data:t.value,parentNode:null};return Pl(t,e),e}function r$(t,e){const n=e;let r=n;t.type==="element"&&t.tagName.toLowerCase()==="svg"&&n.space==="html"&&(r=RN);const i=[];let s;if(t.properties){for(s in t.properties)if(s!=="children"&&Xj.call(t.properties,s)){const c=i$(r,s,t.properties[s]);c&&i.push(c)}}const o=r.space,l={nodeName:t.tagName,tagName:t.tagName,attrs:i,namespaceURI:Ho[o],childNodes:[],parentNode:null};return l.childNodes=l1(t.children,l,r),Pl(t,l),t.tagName==="template"&&t.content&&(l.content=Jj(t.content,r)),l}function i$(t,e,n){const r=Vj(t,e);if(n===!1||n===null||n===void 0||typeof n=="number"&&Number.isNaN(n)||!n&&r.boolean)return;Array.isArray(n)&&(n=r.commaSeparated?GA(n):ek(n));const i={name:r.attribute,value:n===!0?"":String(n)};if(r.space&&r.space!=="html"&&r.space!=="svg"){const s=i.name.indexOf(":");s<0?i.prefix="":(i.name=i.name.slice(s+1),i.prefix=r.attribute.slice(0,s)),i.namespace=Ho[r.space]}return i}function l1(t,e,n){let r=-1;const i=[];if(t)for(;++r=55296&&t<=57343}function a$(t){return t>=56320&&t<=57343}function l$(t,e){return(t-55296)*1024+9216+e}function MN(t){return t!==32&&t!==10&&t!==13&&t!==9&&t!==12&&t>=1&&t<=31||t>=127&&t<=159}function DN(t){return t>=64976&&t<=65007||o$.has(t)}var fe;(function(t){t.controlCharacterInInputStream="control-character-in-input-stream",t.noncharacterInInputStream="noncharacter-in-input-stream",t.surrogateInInputStream="surrogate-in-input-stream",t.nonVoidHtmlElementStartTagWithTrailingSolidus="non-void-html-element-start-tag-with-trailing-solidus",t.endTagWithAttributes="end-tag-with-attributes",t.endTagWithTrailingSolidus="end-tag-with-trailing-solidus",t.unexpectedSolidusInTag="unexpected-solidus-in-tag",t.unexpectedNullCharacter="unexpected-null-character",t.unexpectedQuestionMarkInsteadOfTagName="unexpected-question-mark-instead-of-tag-name",t.invalidFirstCharacterOfTagName="invalid-first-character-of-tag-name",t.unexpectedEqualsSignBeforeAttributeName="unexpected-equals-sign-before-attribute-name",t.missingEndTagName="missing-end-tag-name",t.unexpectedCharacterInAttributeName="unexpected-character-in-attribute-name",t.unknownNamedCharacterReference="unknown-named-character-reference",t.missingSemicolonAfterCharacterReference="missing-semicolon-after-character-reference",t.unexpectedCharacterAfterDoctypeSystemIdentifier="unexpected-character-after-doctype-system-identifier",t.unexpectedCharacterInUnquotedAttributeValue="unexpected-character-in-unquoted-attribute-value",t.eofBeforeTagName="eof-before-tag-name",t.eofInTag="eof-in-tag",t.missingAttributeValue="missing-attribute-value",t.missingWhitespaceBetweenAttributes="missing-whitespace-between-attributes",t.missingWhitespaceAfterDoctypePublicKeyword="missing-whitespace-after-doctype-public-keyword",t.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers="missing-whitespace-between-doctype-public-and-system-identifiers",t.missingWhitespaceAfterDoctypeSystemKeyword="missing-whitespace-after-doctype-system-keyword",t.missingQuoteBeforeDoctypePublicIdentifier="missing-quote-before-doctype-public-identifier",t.missingQuoteBeforeDoctypeSystemIdentifier="missing-quote-before-doctype-system-identifier",t.missingDoctypePublicIdentifier="missing-doctype-public-identifier",t.missingDoctypeSystemIdentifier="missing-doctype-system-identifier",t.abruptDoctypePublicIdentifier="abrupt-doctype-public-identifier",t.abruptDoctypeSystemIdentifier="abrupt-doctype-system-identifier",t.cdataInHtmlContent="cdata-in-html-content",t.incorrectlyOpenedComment="incorrectly-opened-comment",t.eofInScriptHtmlCommentLikeText="eof-in-script-html-comment-like-text",t.eofInDoctype="eof-in-doctype",t.nestedComment="nested-comment",t.abruptClosingOfEmptyComment="abrupt-closing-of-empty-comment",t.eofInComment="eof-in-comment",t.incorrectlyClosedComment="incorrectly-closed-comment",t.eofInCdata="eof-in-cdata",t.absenceOfDigitsInNumericCharacterReference="absence-of-digits-in-numeric-character-reference",t.nullCharacterReference="null-character-reference",t.surrogateCharacterReference="surrogate-character-reference",t.characterReferenceOutsideUnicodeRange="character-reference-outside-unicode-range",t.controlCharacterReference="control-character-reference",t.noncharacterCharacterReference="noncharacter-character-reference",t.missingWhitespaceBeforeDoctypeName="missing-whitespace-before-doctype-name",t.missingDoctypeName="missing-doctype-name",t.invalidCharacterSequenceAfterDoctypeName="invalid-character-sequence-after-doctype-name",t.duplicateAttribute="duplicate-attribute",t.nonConformingDoctype="non-conforming-doctype",t.missingDoctype="missing-doctype",t.misplacedDoctype="misplaced-doctype",t.endTagWithoutMatchingOpenElement="end-tag-without-matching-open-element",t.closingOfElementWithOpenChildElements="closing-of-element-with-open-child-elements",t.disallowedContentInNoscriptInHead="disallowed-content-in-noscript-in-head",t.openElementsLeftAfterEof="open-elements-left-after-eof",t.abandonedHeadElementChild="abandoned-head-element-child",t.misplacedStartTagForHeadElement="misplaced-start-tag-for-head-element",t.nestedNoscriptInHead="nested-noscript-in-head",t.eofInElementThatCanContainOnlyText="eof-in-element-that-can-contain-only-text"})(fe||(fe={}));const u$=65536;class c${constructor(e){this.handler=e,this.html="",this.pos=-1,this.lastGapPos=-2,this.gapStack=[],this.skipNextNewLine=!1,this.lastChunkWritten=!1,this.endOfChunkHit=!1,this.bufferWaterline=u$,this.isEol=!1,this.lineStartPos=0,this.droppedBufferSize=0,this.line=1,this.lastErrOffset=-1}get col(){return this.pos-this.lineStartPos+ +(this.lastGapPos!==this.pos)}get offset(){return this.droppedBufferSize+this.pos}getError(e,n){const{line:r,col:i,offset:s}=this,o=i+n,l=s+n;return{code:e,startLine:r,endLine:r,startCol:o,endCol:o,startOffset:l,endOffset:l}}_err(e){this.handler.onParseError&&this.lastErrOffset!==this.offset&&(this.lastErrOffset=this.offset,this.handler.onParseError(this.getError(e,0)))}_addGap(){this.gapStack.push(this.lastGapPos),this.lastGapPos=this.pos}_processSurrogate(e){if(this.pos!==this.html.length-1){const n=this.html.charCodeAt(this.pos+1);if(a$(n))return this.pos++,this._addGap(),l$(e,n)}else if(!this.lastChunkWritten)return this.endOfChunkHit=!0,L.EOF;return this._err(fe.surrogateInInputStream),e}willDropParsedChunk(){return this.pos>this.bufferWaterline}dropParsedChunk(){this.willDropParsedChunk()&&(this.html=this.html.substring(this.pos),this.lineStartPos-=this.pos,this.droppedBufferSize+=this.pos,this.pos=0,this.lastGapPos=-2,this.gapStack.length=0)}write(e,n){this.html.length>0?this.html+=e:this.html=e,this.endOfChunkHit=!1,this.lastChunkWritten=n}insertHtmlAtCurrentPos(e){this.html=this.html.substring(0,this.pos+1)+e+this.html.substring(this.pos+1),this.endOfChunkHit=!1}startsWith(e,n){if(this.pos+e.length>this.html.length)return this.endOfChunkHit=!this.lastChunkWritten,!1;if(n)return this.html.startsWith(e,this.pos);for(let r=0;r=this.html.length)return this.endOfChunkHit=!this.lastChunkWritten,L.EOF;const r=this.html.charCodeAt(n);return r===L.CARRIAGE_RETURN?L.LINE_FEED:r}advance(){if(this.pos++,this.isEol&&(this.isEol=!1,this.line++,this.lineStartPos=this.pos),this.pos>=this.html.length)return this.endOfChunkHit=!this.lastChunkWritten,L.EOF;let e=this.html.charCodeAt(this.pos);return e===L.CARRIAGE_RETURN?(this.isEol=!0,this.skipNextNewLine=!0,L.LINE_FEED):e===L.LINE_FEED&&(this.isEol=!0,this.skipNextNewLine)?(this.line--,this.skipNextNewLine=!1,this._addGap(),this.advance()):(this.skipNextNewLine=!1,ON(e)&&(e=this._processSurrogate(e)),this.handler.onParseError===null||e>31&&e<127||e===L.LINE_FEED||e===L.CARRIAGE_RETURN||e>159&&e<64976||this._checkForProblematicCharacters(e),e)}_checkForProblematicCharacters(e){MN(e)?this._err(fe.controlCharacterInInputStream):DN(e)&&this._err(fe.noncharacterInInputStream)}retreat(e){for(this.pos-=e;this.pos=0;n--)if(t.attrs[n].name===e)return t.attrs[n].value;return null}const d$=new Uint16Array('ᵁ<Õıʊҝջאٵ۞ޢߖࠏ੊ઑඡ๭༉༦჊ረዡᐕᒝᓃᓟᔥ\0\0\0\0\0\0ᕫᛍᦍᰒᷝ὾⁠↰⊍⏀⏻⑂⠤⤒ⴈ⹈⿎〖㊺㘹㞬㣾㨨㩱㫠㬮ࠀEMabcfglmnoprstu\\bfms„‹•˜¦³¹ÈÏlig耻Æ䃆P耻&䀦cute耻Á䃁reve;䄂Āiyx}rc耻Â䃂;䐐r;쀀𝔄rave耻À䃀pha;䎑acr;䄀d;橓Āgp¡on;䄄f;쀀𝔸plyFunction;恡ing耻Å䃅Ācs¾Ãr;쀀𝒜ign;扔ilde耻Ã䃃ml耻Ä䃄ЀaceforsuåûþėĜĢħĪĀcrêòkslash;或Ŷöø;櫧ed;挆y;䐑ƀcrtąċĔause;戵noullis;愬a;䎒r;쀀𝔅pf;쀀𝔹eve;䋘còēmpeq;扎܀HOacdefhilorsuōőŖƀƞƢƵƷƺǜȕɳɸɾcy;䐧PY耻©䂩ƀcpyŝŢźute;䄆Ā;iŧŨ拒talDifferentialD;慅leys;愭ȀaeioƉƎƔƘron;䄌dil耻Ç䃇rc;䄈nint;戰ot;䄊ĀdnƧƭilla;䂸terDot;䂷òſi;䎧rcleȀDMPTLJNjǑǖot;抙inus;抖lus;投imes;抗oĀcsǢǸkwiseContourIntegral;戲eCurlyĀDQȃȏoubleQuote;思uote;怙ȀlnpuȞȨɇɕonĀ;eȥȦ户;橴ƀgitȯȶȺruent;扡nt;戯ourIntegral;戮ĀfrɌɎ;愂oduct;成nterClockwiseContourIntegral;戳oss;樯cr;쀀𝒞pĀ;Cʄʅ拓ap;才րDJSZacefiosʠʬʰʴʸˋ˗ˡ˦̳ҍĀ;oŹʥtrahd;椑cy;䐂cy;䐅cy;䐏ƀgrsʿ˄ˇger;怡r;憡hv;櫤Āayː˕ron;䄎;䐔lĀ;t˝˞戇a;䎔r;쀀𝔇Āaf˫̧Ācm˰̢riticalȀADGT̖̜̀̆cute;䂴oŴ̋̍;䋙bleAcute;䋝rave;䁠ilde;䋜ond;拄ferentialD;慆Ѱ̽\0\0\0͔͂\0Ѕf;쀀𝔻ƀ;DE͈͉͍䂨ot;惜qual;扐blèCDLRUVͣͲ΂ϏϢϸontourIntegraìȹoɴ͹\0\0ͻ»͉nArrow;懓Āeo·ΤftƀARTΐΖΡrrow;懐ightArrow;懔eåˊngĀLRΫτeftĀARγιrrow;柸ightArrow;柺ightArrow;柹ightĀATϘϞrrow;懒ee;抨pɁϩ\0\0ϯrrow;懑ownArrow;懕erticalBar;戥ǹABLRTaВЪаўѿͼrrowƀ;BUНОТ憓ar;椓pArrow;懵reve;䌑eft˒к\0ц\0ѐightVector;楐eeVector;楞ectorĀ;Bљњ憽ar;楖ightǔѧ\0ѱeeVector;楟ectorĀ;BѺѻ懁ar;楗eeĀ;A҆҇护rrow;憧ĀctҒҗr;쀀𝒟rok;䄐ࠀNTacdfglmopqstuxҽӀӄӋӞӢӧӮӵԡԯԶՒ՝ՠեG;䅊H耻Ð䃐cute耻É䃉ƀaiyӒӗӜron;䄚rc耻Ê䃊;䐭ot;䄖r;쀀𝔈rave耻È䃈ement;戈ĀapӺӾcr;䄒tyɓԆ\0\0ԒmallSquare;旻erySmallSquare;斫ĀgpԦԪon;䄘f;쀀𝔼silon;䎕uĀaiԼՉlĀ;TՂՃ橵ilde;扂librium;懌Āci՗՚r;愰m;橳a;䎗ml耻Ë䃋Āipժկsts;戃onentialE;慇ʀcfiosօֈ֍ֲ׌y;䐤r;쀀𝔉lledɓ֗\0\0֣mallSquare;旼erySmallSquare;斪Ͱֺ\0ֿ\0\0ׄf;쀀𝔽All;戀riertrf;愱cò׋؀JTabcdfgorstר׬ׯ׺؀ؒؖ؛؝أ٬ٲcy;䐃耻>䀾mmaĀ;d׷׸䎓;䏜reve;䄞ƀeiy؇،ؐdil;䄢rc;䄜;䐓ot;䄠r;쀀𝔊;拙pf;쀀𝔾eater̀EFGLSTصلَٖٛ٦qualĀ;Lؾؿ扥ess;招ullEqual;执reater;檢ess;扷lantEqual;橾ilde;扳cr;쀀𝒢;扫ЀAacfiosuڅڋږڛڞڪھۊRDcy;䐪Āctڐڔek;䋇;䁞irc;䄤r;愌lbertSpace;愋ǰگ\0ڲf;愍izontalLine;攀Āctۃۅòکrok;䄦mpńېۘownHumðįqual;扏܀EJOacdfgmnostuۺ۾܃܇܎ܚܞܡܨ݄ݸދޏޕcy;䐕lig;䄲cy;䐁cute耻Í䃍Āiyܓܘrc耻Î䃎;䐘ot;䄰r;愑rave耻Ì䃌ƀ;apܠܯܿĀcgܴܷr;䄪inaryI;慈lieóϝǴ݉\0ݢĀ;eݍݎ戬Āgrݓݘral;戫section;拂isibleĀCTݬݲomma;恣imes;恢ƀgptݿރވon;䄮f;쀀𝕀a;䎙cr;愐ilde;䄨ǫޚ\0ޞcy;䐆l耻Ï䃏ʀcfosuެ޷޼߂ߐĀiyޱ޵rc;䄴;䐙r;쀀𝔍pf;쀀𝕁ǣ߇\0ߌr;쀀𝒥rcy;䐈kcy;䐄΀HJacfosߤߨ߽߬߱ࠂࠈcy;䐥cy;䐌ppa;䎚Āey߶߻dil;䄶;䐚r;쀀𝔎pf;쀀𝕂cr;쀀𝒦րJTaceflmostࠥࠩࠬࡐࡣ঳সে্਷ੇcy;䐉耻<䀼ʀcmnpr࠷࠼ࡁࡄࡍute;䄹bda;䎛g;柪lacetrf;愒r;憞ƀaeyࡗ࡜ࡡron;䄽dil;䄻;䐛Āfsࡨ॰tԀACDFRTUVarࡾࢩࢱࣦ࣠ࣼयज़ΐ४Ānrࢃ࢏gleBracket;柨rowƀ;BR࢙࢚࢞憐ar;懤ightArrow;懆eiling;挈oǵࢷ\0ࣃbleBracket;柦nǔࣈ\0࣒eeVector;楡ectorĀ;Bࣛࣜ懃ar;楙loor;挊ightĀAV࣯ࣵrrow;憔ector;楎Āerँगeƀ;AVउऊऐ抣rrow;憤ector;楚iangleƀ;BEतथऩ抲ar;槏qual;抴pƀDTVषूौownVector;楑eeVector;楠ectorĀ;Bॖॗ憿ar;楘ectorĀ;B॥०憼ar;楒ightáΜs̀EFGLSTॾঋকঝঢভqualGreater;拚ullEqual;扦reater;扶ess;檡lantEqual;橽ilde;扲r;쀀𝔏Ā;eঽা拘ftarrow;懚idot;䄿ƀnpw৔ਖਛgȀLRlr৞৷ਂਐeftĀAR০৬rrow;柵ightArrow;柷ightArrow;柶eftĀarγਊightáοightáϊf;쀀𝕃erĀLRਢਬeftArrow;憙ightArrow;憘ƀchtਾੀੂòࡌ;憰rok;䅁;扪Ѐacefiosuਗ਼੝੠੷੼અઋ઎p;椅y;䐜Ādl੥੯iumSpace;恟lintrf;愳r;쀀𝔐nusPlus;戓pf;쀀𝕄cò੶;䎜ҀJacefostuણધભીଔଙඑ඗ඞcy;䐊cute;䅃ƀaey઴હાron;䅇dil;䅅;䐝ƀgswે૰଎ativeƀMTV૓૟૨ediumSpace;怋hiĀcn૦૘ë૙eryThiî૙tedĀGL૸ଆreaterGreateòٳessLesóੈLine;䀊r;쀀𝔑ȀBnptଢନଷ଺reak;恠BreakingSpace;䂠f;愕ڀ;CDEGHLNPRSTV୕ୖ୪୼஡௫ఄ౞಄ದ೘ൡඅ櫬Āou୛୤ngruent;扢pCap;扭oubleVerticalBar;戦ƀlqxஃஊ஛ement;戉ualĀ;Tஒஓ扠ilde;쀀≂̸ists;戄reater΀;EFGLSTஶஷ஽௉௓௘௥扯qual;扱ullEqual;쀀≧̸reater;쀀≫̸ess;批lantEqual;쀀⩾̸ilde;扵umpń௲௽ownHump;쀀≎̸qual;쀀≏̸eĀfsఊధtTriangleƀ;BEచఛడ拪ar;쀀⧏̸qual;括s̀;EGLSTవశ఼ౄోౘ扮qual;扰reater;扸ess;쀀≪̸lantEqual;쀀⩽̸ilde;扴estedĀGL౨౹reaterGreater;쀀⪢̸essLess;쀀⪡̸recedesƀ;ESಒಓಛ技qual;쀀⪯̸lantEqual;拠ĀeiಫಹverseElement;戌ghtTriangleƀ;BEೋೌ೒拫ar;쀀⧐̸qual;拭ĀquೝഌuareSuĀbp೨೹setĀ;E೰ೳ쀀⊏̸qual;拢ersetĀ;Eഃആ쀀⊐̸qual;拣ƀbcpഓതൎsetĀ;Eഛഞ쀀⊂⃒qual;抈ceedsȀ;ESTലള഻െ抁qual;쀀⪰̸lantEqual;拡ilde;쀀≿̸ersetĀ;E൘൛쀀⊃⃒qual;抉ildeȀ;EFT൮൯൵ൿ扁qual;扄ullEqual;扇ilde;扉erticalBar;戤cr;쀀𝒩ilde耻Ñ䃑;䎝܀Eacdfgmoprstuvලෂ෉෕ෛ෠෧෼ขภยา฿ไlig;䅒cute耻Ó䃓Āiy෎ීrc耻Ô䃔;䐞blac;䅐r;쀀𝔒rave耻Ò䃒ƀaei෮ෲ෶cr;䅌ga;䎩cron;䎟pf;쀀𝕆enCurlyĀDQฎบoubleQuote;怜uote;怘;橔Āclวฬr;쀀𝒪ash耻Ø䃘iŬื฼de耻Õ䃕es;樷ml耻Ö䃖erĀBP๋๠Āar๐๓r;怾acĀek๚๜;揞et;掴arenthesis;揜Ҁacfhilors๿ງຊຏຒດຝະ໼rtialD;戂y;䐟r;쀀𝔓i;䎦;䎠usMinus;䂱Āipຢອncareplanåڝf;愙Ȁ;eio຺ູ໠໤檻cedesȀ;EST່້໏໚扺qual;檯lantEqual;扼ilde;找me;怳Ādp໩໮uct;戏ortionĀ;aȥ໹l;戝Āci༁༆r;쀀𝒫;䎨ȀUfos༑༖༛༟OT耻"䀢r;쀀𝔔pf;愚cr;쀀𝒬؀BEacefhiorsu༾གྷཇའཱིྦྷྪྭ႖ႩႴႾarr;椐G耻®䂮ƀcnrཎནབute;䅔g;柫rĀ;tཛྷཝ憠l;椖ƀaeyཧཬཱron;䅘dil;䅖;䐠Ā;vླྀཹ愜erseĀEUྂྙĀlq྇ྎement;戋uilibrium;懋pEquilibrium;楯r»ཹo;䎡ghtЀACDFTUVa࿁࿫࿳ဢဨၛႇϘĀnr࿆࿒gleBracket;柩rowƀ;BL࿜࿝࿡憒ar;懥eftArrow;懄eiling;按oǵ࿹\0စbleBracket;柧nǔည\0နeeVector;楝ectorĀ;Bဝသ懂ar;楕loor;挋Āerိ၃eƀ;AVဵံြ抢rrow;憦ector;楛iangleƀ;BEၐၑၕ抳ar;槐qual;抵pƀDTVၣၮၸownVector;楏eeVector;楜ectorĀ;Bႂႃ憾ar;楔ectorĀ;B႑႒懀ar;楓Āpuႛ႞f;愝ndImplies;楰ightarrow;懛ĀchႹႼr;愛;憱leDelayed;槴ڀHOacfhimoqstuფჱჷჽᄙᄞᅑᅖᅡᅧᆵᆻᆿĀCcჩხHcy;䐩y;䐨FTcy;䐬cute;䅚ʀ;aeiyᄈᄉᄎᄓᄗ檼ron;䅠dil;䅞rc;䅜;䐡r;쀀𝔖ortȀDLRUᄪᄴᄾᅉownArrow»ОeftArrow»࢚ightArrow»࿝pArrow;憑gma;䎣allCircle;战pf;쀀𝕊ɲᅭ\0\0ᅰt;戚areȀ;ISUᅻᅼᆉᆯ斡ntersection;抓uĀbpᆏᆞsetĀ;Eᆗᆘ抏qual;抑ersetĀ;Eᆨᆩ抐qual;抒nion;抔cr;쀀𝒮ar;拆ȀbcmpᇈᇛሉላĀ;sᇍᇎ拐etĀ;Eᇍᇕqual;抆ĀchᇠህeedsȀ;ESTᇭᇮᇴᇿ扻qual;檰lantEqual;扽ilde;承Tháྌ;我ƀ;esሒሓሣ拑rsetĀ;Eሜም抃qual;抇et»ሓրHRSacfhiorsሾቄ቉ቕ቞ቱቶኟዂወዑORN耻Þ䃞ADE;愢ĀHc቎ቒcy;䐋y;䐦Ābuቚቜ;䀉;䎤ƀaeyብቪቯron;䅤dil;䅢;䐢r;쀀𝔗Āeiቻ኉Dzኀ\0ኇefore;戴a;䎘Ācn኎ኘkSpace;쀀  Space;怉ldeȀ;EFTካኬኲኼ戼qual;扃ullEqual;扅ilde;扈pf;쀀𝕋ipleDot;惛Āctዖዛr;쀀𝒯rok;䅦ૡዷጎጚጦ\0ጬጱ\0\0\0\0\0ጸጽ፷ᎅ\0᏿ᐄᐊᐐĀcrዻጁute耻Ú䃚rĀ;oጇገ憟cir;楉rǣጓ\0጖y;䐎ve;䅬Āiyጞጣrc耻Û䃛;䐣blac;䅰r;쀀𝔘rave耻Ù䃙acr;䅪Ādiፁ፩erĀBPፈ፝Āarፍፐr;䁟acĀekፗፙ;揟et;掵arenthesis;揝onĀ;P፰፱拃lus;抎Āgp፻፿on;䅲f;쀀𝕌ЀADETadps᎕ᎮᎸᏄϨᏒᏗᏳrrowƀ;BDᅐᎠᎤar;椒ownArrow;懅ownArrow;憕quilibrium;楮eeĀ;AᏋᏌ报rrow;憥ownáϳerĀLRᏞᏨeftArrow;憖ightArrow;憗iĀ;lᏹᏺ䏒on;䎥ing;䅮cr;쀀𝒰ilde;䅨ml耻Ü䃜ҀDbcdefosvᐧᐬᐰᐳᐾᒅᒊᒐᒖash;披ar;櫫y;䐒ashĀ;lᐻᐼ抩;櫦Āerᑃᑅ;拁ƀbtyᑌᑐᑺar;怖Ā;iᑏᑕcalȀBLSTᑡᑥᑪᑴar;戣ine;䁼eparator;杘ilde;所ThinSpace;怊r;쀀𝔙pf;쀀𝕍cr;쀀𝒱dash;抪ʀcefosᒧᒬᒱᒶᒼirc;䅴dge;拀r;쀀𝔚pf;쀀𝕎cr;쀀𝒲Ȁfiosᓋᓐᓒᓘr;쀀𝔛;䎞pf;쀀𝕏cr;쀀𝒳ҀAIUacfosuᓱᓵᓹᓽᔄᔏᔔᔚᔠcy;䐯cy;䐇cy;䐮cute耻Ý䃝Āiyᔉᔍrc;䅶;䐫r;쀀𝔜pf;쀀𝕐cr;쀀𝒴ml;䅸ЀHacdefosᔵᔹᔿᕋᕏᕝᕠᕤcy;䐖cute;䅹Āayᕄᕉron;䅽;䐗ot;䅻Dzᕔ\0ᕛoWidtè૙a;䎖r;愨pf;愤cr;쀀𝒵௡ᖃᖊᖐ\0ᖰᖶᖿ\0\0\0\0ᗆᗛᗫᙟ᙭\0ᚕ᚛ᚲᚹ\0ᚾcute耻á䃡reve;䄃̀;Ediuyᖜᖝᖡᖣᖨᖭ戾;쀀∾̳;房rc耻â䃢te肻´̆;䐰lig耻æ䃦Ā;r²ᖺ;쀀𝔞rave耻à䃠ĀepᗊᗖĀfpᗏᗔsym;愵èᗓha;䎱ĀapᗟcĀclᗤᗧr;䄁g;樿ɤᗰ\0\0ᘊʀ;adsvᗺᗻᗿᘁᘇ戧nd;橕;橜lope;橘;橚΀;elmrszᘘᘙᘛᘞᘿᙏᙙ戠;榤e»ᘙsdĀ;aᘥᘦ戡ѡᘰᘲᘴᘶᘸᘺᘼᘾ;榨;榩;榪;榫;榬;榭;榮;榯tĀ;vᙅᙆ戟bĀ;dᙌᙍ抾;榝Āptᙔᙗh;戢»¹arr;捼Āgpᙣᙧon;䄅f;쀀𝕒΀;Eaeiop዁ᙻᙽᚂᚄᚇᚊ;橰cir;橯;扊d;手s;䀧roxĀ;e዁ᚒñᚃing耻å䃥ƀctyᚡᚦᚨr;쀀𝒶;䀪mpĀ;e዁ᚯñʈilde耻ã䃣ml耻ä䃤Āciᛂᛈoninôɲnt;樑ࠀNabcdefiklnoprsu᛭ᛱᜰ᜼ᝃᝈ᝸᝽០៦ᠹᡐᜍ᤽᥈ᥰot;櫭Ācrᛶ᜞kȀcepsᜀᜅᜍᜓong;扌psilon;䏶rime;怵imĀ;e᜚᜛戽q;拍Ŷᜢᜦee;抽edĀ;gᜬᜭ挅e»ᜭrkĀ;t፜᜷brk;掶Āoyᜁᝁ;䐱quo;怞ʀcmprtᝓ᝛ᝡᝤᝨausĀ;eĊĉptyv;榰séᜌnoõēƀahwᝯ᝱ᝳ;䎲;愶een;扬r;쀀𝔟g΀costuvwឍឝឳេ៕៛៞ƀaiuបពរðݠrc;旯p»፱ƀdptឤឨឭot;樀lus;樁imes;樂ɱឹ\0\0ើcup;樆ar;昅riangleĀdu៍្own;施p;斳plus;樄eåᑄåᒭarow;植ƀako៭ᠦᠵĀcn៲ᠣkƀlst៺֫᠂ozenge;槫riangleȀ;dlr᠒᠓᠘᠝斴own;斾eft;旂ight;斸k;搣Ʊᠫ\0ᠳƲᠯ\0ᠱ;斒;斑4;斓ck;斈ĀeoᠾᡍĀ;qᡃᡆ쀀=⃥uiv;쀀≡⃥t;挐Ȁptwxᡙᡞᡧᡬf;쀀𝕓Ā;tᏋᡣom»Ꮜtie;拈؀DHUVbdhmptuvᢅᢖᢪᢻᣗᣛᣬ᣿ᤅᤊᤐᤡȀLRlrᢎᢐᢒᢔ;敗;敔;敖;敓ʀ;DUduᢡᢢᢤᢦᢨ敐;敦;敩;敤;敧ȀLRlrᢳᢵᢷᢹ;敝;敚;敜;教΀;HLRhlrᣊᣋᣍᣏᣑᣓᣕ救;敬;散;敠;敫;敢;敟ox;槉ȀLRlrᣤᣦᣨᣪ;敕;敒;攐;攌ʀ;DUduڽ᣷᣹᣻᣽;敥;敨;攬;攴inus;抟lus;択imes;抠ȀLRlrᤙᤛᤝ᤟;敛;敘;攘;攔΀;HLRhlrᤰᤱᤳᤵᤷ᤻᤹攂;敪;敡;敞;攼;攤;攜Āevģ᥂bar耻¦䂦Ȁceioᥑᥖᥚᥠr;쀀𝒷mi;恏mĀ;e᜚᜜lƀ;bhᥨᥩᥫ䁜;槅sub;柈Ŭᥴ᥾lĀ;e᥹᥺怢t»᥺pƀ;Eeįᦅᦇ;檮Ā;qۜۛೡᦧ\0᧨ᨑᨕᨲ\0ᨷᩐ\0\0᪴\0\0᫁\0\0ᬡᬮ᭍᭒\0᯽\0ᰌƀcpr᦭ᦲ᧝ute;䄇̀;abcdsᦿᧀᧄ᧊᧕᧙戩nd;橄rcup;橉Āau᧏᧒p;橋p;橇ot;橀;쀀∩︀Āeo᧢᧥t;恁îړȀaeiu᧰᧻ᨁᨅǰ᧵\0᧸s;橍on;䄍dil耻ç䃧rc;䄉psĀ;sᨌᨍ橌m;橐ot;䄋ƀdmnᨛᨠᨦil肻¸ƭptyv;榲t脀¢;eᨭᨮ䂢räƲr;쀀𝔠ƀceiᨽᩀᩍy;䑇ckĀ;mᩇᩈ朓ark»ᩈ;䏇r΀;Ecefms᩟᩠ᩢᩫ᪤᪪᪮旋;槃ƀ;elᩩᩪᩭ䋆q;扗eɡᩴ\0\0᪈rrowĀlr᩼᪁eft;憺ight;憻ʀRSacd᪒᪔᪖᪚᪟»ཇ;擈st;抛irc;抚ash;抝nint;樐id;櫯cir;槂ubsĀ;u᪻᪼晣it»᪼ˬ᫇᫔᫺\0ᬊonĀ;eᫍᫎ䀺Ā;qÇÆɭ᫙\0\0᫢aĀ;t᫞᫟䀬;䁀ƀ;fl᫨᫩᫫戁îᅠeĀmx᫱᫶ent»᫩eóɍǧ᫾\0ᬇĀ;dኻᬂot;橭nôɆƀfryᬐᬔᬗ;쀀𝕔oäɔ脀©;sŕᬝr;愗Āaoᬥᬩrr;憵ss;朗Ācuᬲᬷr;쀀𝒸Ābpᬼ᭄Ā;eᭁᭂ櫏;櫑Ā;eᭉᭊ櫐;櫒dot;拯΀delprvw᭠᭬᭷ᮂᮬᯔ᯹arrĀlr᭨᭪;椸;椵ɰ᭲\0\0᭵r;拞c;拟arrĀ;p᭿ᮀ憶;椽̀;bcdosᮏᮐᮖᮡᮥᮨ截rcap;橈Āauᮛᮞp;橆p;橊ot;抍r;橅;쀀∪︀Ȁalrv᮵ᮿᯞᯣrrĀ;mᮼᮽ憷;椼yƀevwᯇᯔᯘqɰᯎ\0\0ᯒreã᭳uã᭵ee;拎edge;拏en耻¤䂤earrowĀlrᯮ᯳eft»ᮀight»ᮽeäᯝĀciᰁᰇoninôǷnt;戱lcty;挭ঀAHabcdefhijlorstuwz᰸᰻᰿ᱝᱩᱵᲊᲞᲬᲷ᳻᳿ᴍᵻᶑᶫᶻ᷆᷍rò΁ar;楥Ȁglrs᱈ᱍ᱒᱔ger;怠eth;愸òᄳhĀ;vᱚᱛ怐»ऊūᱡᱧarow;椏aã̕Āayᱮᱳron;䄏;䐴ƀ;ao̲ᱼᲄĀgrʿᲁr;懊tseq;橷ƀglmᲑᲔᲘ耻°䂰ta;䎴ptyv;榱ĀirᲣᲨsht;楿;쀀𝔡arĀlrᲳᲵ»ࣜ»သʀaegsv᳂͸᳖᳜᳠mƀ;oș᳊᳔ndĀ;ș᳑uit;晦amma;䏝in;拲ƀ;io᳧᳨᳸䃷de脀÷;o᳧ᳰntimes;拇nø᳷cy;䑒cɯᴆ\0\0ᴊrn;挞op;挍ʀlptuwᴘᴝᴢᵉᵕlar;䀤f;쀀𝕕ʀ;emps̋ᴭᴷᴽᵂqĀ;d͒ᴳot;扑inus;戸lus;戔quare;抡blebarwedgåúnƀadhᄮᵝᵧownarrowóᲃarpoonĀlrᵲᵶefôᲴighôᲶŢᵿᶅkaro÷གɯᶊ\0\0ᶎrn;挟op;挌ƀcotᶘᶣᶦĀryᶝᶡ;쀀𝒹;䑕l;槶rok;䄑Ādrᶰᶴot;拱iĀ;fᶺ᠖斿Āah᷀᷃ròЩaòྦangle;榦Āci᷒ᷕy;䑟grarr;柿ऀDacdefglmnopqrstuxḁḉḙḸոḼṉṡṾấắẽỡἪἷὄ὎὚ĀDoḆᴴoôᲉĀcsḎḔute耻é䃩ter;橮ȀaioyḢḧḱḶron;䄛rĀ;cḭḮ扖耻ê䃪lon;払;䑍ot;䄗ĀDrṁṅot;扒;쀀𝔢ƀ;rsṐṑṗ檚ave耻è䃨Ā;dṜṝ檖ot;檘Ȁ;ilsṪṫṲṴ檙nters;揧;愓Ā;dṹṺ檕ot;檗ƀapsẅẉẗcr;䄓tyƀ;svẒẓẕ戅et»ẓpĀ1;ẝẤijạả;怄;怅怃ĀgsẪẬ;䅋p;怂ĀgpẴẸon;䄙f;쀀𝕖ƀalsỄỎỒrĀ;sỊị拕l;槣us;橱iƀ;lvỚớở䎵on»ớ;䏵ȀcsuvỪỳἋἣĀioữḱrc»Ḯɩỹ\0\0ỻíՈantĀglἂἆtr»ṝess»Ṻƀaeiἒ἖Ἒls;䀽st;扟vĀ;DȵἠD;橸parsl;槥ĀDaἯἳot;打rr;楱ƀcdiἾὁỸr;愯oô͒ĀahὉὋ;䎷耻ð䃰Āmrὓὗl耻ë䃫o;悬ƀcipὡὤὧl;䀡sôծĀeoὬὴctatioîՙnentialåչৡᾒ\0ᾞ\0ᾡᾧ\0\0ῆῌ\0ΐ\0ῦῪ \0 ⁚llingdotseñṄy;䑄male;晀ƀilrᾭᾳ῁lig;耀ffiɩᾹ\0\0᾽g;耀ffig;耀ffl;쀀𝔣lig;耀filig;쀀fjƀaltῙ῜ῡt;晭ig;耀flns;斱of;䆒ǰ΅\0ῳf;쀀𝕗ĀakֿῷĀ;vῼ´拔;櫙artint;樍Āao‌⁕Ācs‑⁒ႉ‸⁅⁈\0⁐β•‥‧‪‬\0‮耻½䂽;慓耻¼䂼;慕;慙;慛Ƴ‴\0‶;慔;慖ʴ‾⁁\0\0⁃耻¾䂾;慗;慜5;慘ƶ⁌\0⁎;慚;慝8;慞l;恄wn;挢cr;쀀𝒻ࢀEabcdefgijlnorstv₂₉₟₥₰₴⃰⃵⃺⃿℃ℒℸ̗ℾ⅒↞Ā;lٍ₇;檌ƀcmpₐₕ₝ute;䇵maĀ;dₜ᳚䎳;檆reve;䄟Āiy₪₮rc;䄝;䐳ot;䄡Ȁ;lqsؾق₽⃉ƀ;qsؾٌ⃄lanô٥Ȁ;cdl٥⃒⃥⃕c;檩otĀ;o⃜⃝檀Ā;l⃢⃣檂;檄Ā;e⃪⃭쀀⋛︀s;檔r;쀀𝔤Ā;gٳ؛mel;愷cy;䑓Ȁ;Eajٚℌℎℐ;檒;檥;檤ȀEaesℛℝ℩ℴ;扩pĀ;p℣ℤ檊rox»ℤĀ;q℮ℯ檈Ā;q℮ℛim;拧pf;쀀𝕘Āci⅃ⅆr;愊mƀ;el٫ⅎ⅐;檎;檐茀>;cdlqr׮ⅠⅪⅮⅳⅹĀciⅥⅧ;檧r;橺ot;拗Par;榕uest;橼ʀadelsↄⅪ←ٖ↛ǰ↉\0↎proø₞r;楸qĀlqؿ↖lesó₈ií٫Āen↣↭rtneqq;쀀≩︀Å↪ԀAabcefkosy⇄⇇⇱⇵⇺∘∝∯≨≽ròΠȀilmr⇐⇔⇗⇛rsðᒄf»․ilôکĀdr⇠⇤cy;䑊ƀ;cwࣴ⇫⇯ir;楈;憭ar;意irc;䄥ƀalr∁∎∓rtsĀ;u∉∊晥it»∊lip;怦con;抹r;쀀𝔥sĀew∣∩arow;椥arow;椦ʀamopr∺∾≃≞≣rr;懿tht;戻kĀlr≉≓eftarrow;憩ightarrow;憪f;쀀𝕙bar;怕ƀclt≯≴≸r;쀀𝒽asè⇴rok;䄧Ābp⊂⊇ull;恃hen»ᱛૡ⊣\0⊪\0⊸⋅⋎\0⋕⋳\0\0⋸⌢⍧⍢⍿\0⎆⎪⎴cute耻í䃭ƀ;iyݱ⊰⊵rc耻î䃮;䐸Ācx⊼⊿y;䐵cl耻¡䂡ĀfrΟ⋉;쀀𝔦rave耻ì䃬Ȁ;inoܾ⋝⋩⋮Āin⋢⋦nt;樌t;戭fin;槜ta;愩lig;䄳ƀaop⋾⌚⌝ƀcgt⌅⌈⌗r;䄫ƀelpܟ⌏⌓inåގarôܠh;䄱f;抷ed;䆵ʀ;cfotӴ⌬⌱⌽⍁are;愅inĀ;t⌸⌹戞ie;槝doô⌙ʀ;celpݗ⍌⍐⍛⍡al;抺Āgr⍕⍙eróᕣã⍍arhk;樗rod;樼Ȁcgpt⍯⍲⍶⍻y;䑑on;䄯f;쀀𝕚a;䎹uest耻¿䂿Āci⎊⎏r;쀀𝒾nʀ;EdsvӴ⎛⎝⎡ӳ;拹ot;拵Ā;v⎦⎧拴;拳Ā;iݷ⎮lde;䄩ǫ⎸\0⎼cy;䑖l耻ï䃯̀cfmosu⏌⏗⏜⏡⏧⏵Āiy⏑⏕rc;䄵;䐹r;쀀𝔧ath;䈷pf;쀀𝕛ǣ⏬\0⏱r;쀀𝒿rcy;䑘kcy;䑔Ѐacfghjos␋␖␢␧␭␱␵␻ppaĀ;v␓␔䎺;䏰Āey␛␠dil;䄷;䐺r;쀀𝔨reen;䄸cy;䑅cy;䑜pf;쀀𝕜cr;쀀𝓀஀ABEHabcdefghjlmnoprstuv⑰⒁⒆⒍⒑┎┽╚▀♎♞♥♹♽⚚⚲⛘❝❨➋⟀⠁⠒ƀart⑷⑺⑼rò৆òΕail;椛arr;椎Ā;gঔ⒋;檋ar;楢ॣ⒥\0⒪\0⒱\0\0\0\0\0⒵Ⓔ\0ⓆⓈⓍ\0⓹ute;䄺mptyv;榴raîࡌbda;䎻gƀ;dlࢎⓁⓃ;榑åࢎ;檅uo耻«䂫rЀ;bfhlpst࢙ⓞⓦⓩ⓫⓮⓱⓵Ā;f࢝ⓣs;椟s;椝ë≒p;憫l;椹im;楳l;憢ƀ;ae⓿─┄檫il;椙Ā;s┉┊檭;쀀⪭︀ƀabr┕┙┝rr;椌rk;杲Āak┢┬cĀek┨┪;䁻;䁛Āes┱┳;榋lĀdu┹┻;榏;榍Ȁaeuy╆╋╖╘ron;䄾Ādi═╔il;䄼ìࢰâ┩;䐻Ȁcqrs╣╦╭╽a;椶uoĀ;rนᝆĀdu╲╷har;楧shar;楋h;憲ʀ;fgqs▋▌উ◳◿扤tʀahlrt▘▤▷◂◨rrowĀ;t࢙□aé⓶arpoonĀdu▯▴own»њp»०eftarrows;懇ightƀahs◍◖◞rrowĀ;sࣴࢧarpoonó྘quigarro÷⇰hreetimes;拋ƀ;qs▋ও◺lanôবʀ;cdgsব☊☍☝☨c;檨otĀ;o☔☕橿Ā;r☚☛檁;檃Ā;e☢☥쀀⋚︀s;檓ʀadegs☳☹☽♉♋pproøⓆot;拖qĀgq♃♅ôউgtò⒌ôছiíলƀilr♕࣡♚sht;楼;쀀𝔩Ā;Eজ♣;檑š♩♶rĀdu▲♮Ā;l॥♳;楪lk;斄cy;䑙ʀ;achtੈ⚈⚋⚑⚖rò◁orneòᴈard;楫ri;旺Āio⚟⚤dot;䅀ustĀ;a⚬⚭掰che»⚭ȀEaes⚻⚽⛉⛔;扨pĀ;p⛃⛄檉rox»⛄Ā;q⛎⛏檇Ā;q⛎⚻im;拦Ѐabnoptwz⛩⛴⛷✚✯❁❇❐Ānr⛮⛱g;柬r;懽rëࣁgƀlmr⛿✍✔eftĀar০✇ightá৲apsto;柼ightá৽parrowĀlr✥✩efô⓭ight;憬ƀafl✶✹✽r;榅;쀀𝕝us;樭imes;樴š❋❏st;戗áፎƀ;ef❗❘᠀旊nge»❘arĀ;l❤❥䀨t;榓ʀachmt❳❶❼➅➇ròࢨorneòᶌarĀ;d྘➃;業;怎ri;抿̀achiqt➘➝ੀ➢➮➻quo;怹r;쀀𝓁mƀ;egল➪➬;檍;檏Ābu┪➳oĀ;rฟ➹;怚rok;䅂萀<;cdhilqrࠫ⟒☹⟜⟠⟥⟪⟰Āci⟗⟙;檦r;橹reå◲mes;拉arr;楶uest;橻ĀPi⟵⟹ar;榖ƀ;ef⠀भ᠛旃rĀdu⠇⠍shar;楊har;楦Āen⠗⠡rtneqq;쀀≨︀Å⠞܀Dacdefhilnopsu⡀⡅⢂⢎⢓⢠⢥⢨⣚⣢⣤ઃ⣳⤂Dot;戺Ȁclpr⡎⡒⡣⡽r耻¯䂯Āet⡗⡙;時Ā;e⡞⡟朠se»⡟Ā;sျ⡨toȀ;dluျ⡳⡷⡻owîҌefôएðᏑker;斮Āoy⢇⢌mma;権;䐼ash;怔asuredangle»ᘦr;쀀𝔪o;愧ƀcdn⢯⢴⣉ro耻µ䂵Ȁ;acdᑤ⢽⣀⣄sôᚧir;櫰ot肻·Ƶusƀ;bd⣒ᤃ⣓戒Ā;uᴼ⣘;横ţ⣞⣡p;櫛ò−ðઁĀdp⣩⣮els;抧f;쀀𝕞Āct⣸⣽r;쀀𝓂pos»ᖝƀ;lm⤉⤊⤍䎼timap;抸ఀGLRVabcdefghijlmoprstuvw⥂⥓⥾⦉⦘⧚⧩⨕⨚⩘⩝⪃⪕⪤⪨⬄⬇⭄⭿⮮ⰴⱧⱼ⳩Āgt⥇⥋;쀀⋙̸Ā;v⥐௏쀀≫⃒ƀelt⥚⥲⥶ftĀar⥡⥧rrow;懍ightarrow;懎;쀀⋘̸Ā;v⥻ే쀀≪⃒ightarrow;懏ĀDd⦎⦓ash;抯ash;抮ʀbcnpt⦣⦧⦬⦱⧌la»˞ute;䅄g;쀀∠⃒ʀ;Eiop඄⦼⧀⧅⧈;쀀⩰̸d;쀀≋̸s;䅉roø඄urĀ;a⧓⧔普lĀ;s⧓ସdz⧟\0⧣p肻 ଷmpĀ;e௹ఀʀaeouy⧴⧾⨃⨐⨓ǰ⧹\0⧻;橃on;䅈dil;䅆ngĀ;dൾ⨊ot;쀀⩭̸p;橂;䐽ash;怓΀;Aadqsxஒ⨩⨭⨻⩁⩅⩐rr;懗rĀhr⨳⨶k;椤Ā;oᏲᏰot;쀀≐̸uiöୣĀei⩊⩎ar;椨í஘istĀ;s஠டr;쀀𝔫ȀEest௅⩦⩹⩼ƀ;qs஼⩭௡ƀ;qs஼௅⩴lanô௢ií௪Ā;rஶ⪁»ஷƀAap⪊⪍⪑rò⥱rr;憮ar;櫲ƀ;svྍ⪜ྌĀ;d⪡⪢拼;拺cy;䑚΀AEadest⪷⪺⪾⫂⫅⫶⫹rò⥦;쀀≦̸rr;憚r;急Ȁ;fqs఻⫎⫣⫯tĀar⫔⫙rro÷⫁ightarro÷⪐ƀ;qs఻⪺⫪lanôౕĀ;sౕ⫴»శiíౝĀ;rవ⫾iĀ;eచథiäඐĀpt⬌⬑f;쀀𝕟膀¬;in⬙⬚⬶䂬nȀ;Edvஉ⬤⬨⬮;쀀⋹̸ot;쀀⋵̸ǡஉ⬳⬵;拷;拶iĀ;vಸ⬼ǡಸ⭁⭃;拾;拽ƀaor⭋⭣⭩rȀ;ast୻⭕⭚⭟lleì୻l;쀀⫽⃥;쀀∂̸lint;樔ƀ;ceಒ⭰⭳uåಥĀ;cಘ⭸Ā;eಒ⭽ñಘȀAait⮈⮋⮝⮧rò⦈rrƀ;cw⮔⮕⮙憛;쀀⤳̸;쀀↝̸ghtarrow»⮕riĀ;eೋೖ΀chimpqu⮽⯍⯙⬄୸⯤⯯Ȁ;cerല⯆ഷ⯉uå൅;쀀𝓃ortɭ⬅\0\0⯖ará⭖mĀ;e൮⯟Ā;q൴൳suĀbp⯫⯭å೸åഋƀbcp⯶ⰑⰙȀ;Ees⯿ⰀഢⰄ抄;쀀⫅̸etĀ;eഛⰋqĀ;qണⰀcĀ;eലⰗñസȀ;EesⰢⰣൟⰧ抅;쀀⫆̸etĀ;e൘ⰮqĀ;qൠⰣȀgilrⰽⰿⱅⱇìௗlde耻ñ䃱çృiangleĀlrⱒⱜeftĀ;eచⱚñదightĀ;eೋⱥñ೗Ā;mⱬⱭ䎽ƀ;esⱴⱵⱹ䀣ro;愖p;怇ҀDHadgilrsⲏⲔⲙⲞⲣⲰⲶⳓⳣash;抭arr;椄p;쀀≍⃒ash;抬ĀetⲨⲬ;쀀≥⃒;쀀>⃒nfin;槞ƀAetⲽⳁⳅrr;椂;쀀≤⃒Ā;rⳊⳍ쀀<⃒ie;쀀⊴⃒ĀAtⳘⳜrr;椃rie;쀀⊵⃒im;쀀∼⃒ƀAan⳰⳴ⴂrr;懖rĀhr⳺⳽k;椣Ā;oᏧᏥear;椧ቓ᪕\0\0\0\0\0\0\0\0\0\0\0\0\0ⴭ\0ⴸⵈⵠⵥ⵲ⶄᬇ\0\0ⶍⶫ\0ⷈⷎ\0ⷜ⸙⸫⸾⹃Ācsⴱ᪗ute耻ó䃳ĀiyⴼⵅrĀ;c᪞ⵂ耻ô䃴;䐾ʀabios᪠ⵒⵗLjⵚlac;䅑v;樸old;榼lig;䅓Ācr⵩⵭ir;榿;쀀𝔬ͯ⵹\0\0⵼\0ⶂn;䋛ave耻ò䃲;槁Ābmⶈ෴ar;榵Ȁacitⶕ⶘ⶥⶨrò᪀Āir⶝ⶠr;榾oss;榻nå๒;槀ƀaeiⶱⶵⶹcr;䅍ga;䏉ƀcdnⷀⷅǍron;䎿;榶pf;쀀𝕠ƀaelⷔ⷗ǒr;榷rp;榹΀;adiosvⷪⷫⷮ⸈⸍⸐⸖戨rò᪆Ȁ;efmⷷⷸ⸂⸅橝rĀ;oⷾⷿ愴f»ⷿ耻ª䂪耻º䂺gof;抶r;橖lope;橗;橛ƀclo⸟⸡⸧ò⸁ash耻ø䃸l;折iŬⸯ⸴de耻õ䃵esĀ;aǛ⸺s;樶ml耻ö䃶bar;挽ૡ⹞\0⹽\0⺀⺝\0⺢⺹\0\0⻋ຜ\0⼓\0\0⼫⾼\0⿈rȀ;astЃ⹧⹲຅脀¶;l⹭⹮䂶leìЃɩ⹸\0\0⹻m;櫳;櫽y;䐿rʀcimpt⺋⺏⺓ᡥ⺗nt;䀥od;䀮il;怰enk;怱r;쀀𝔭ƀimo⺨⺰⺴Ā;v⺭⺮䏆;䏕maô੶ne;明ƀ;tv⺿⻀⻈䏀chfork»´;䏖Āau⻏⻟nĀck⻕⻝kĀ;h⇴⻛;愎ö⇴sҀ;abcdemst⻳⻴ᤈ⻹⻽⼄⼆⼊⼎䀫cir;樣ir;樢Āouᵀ⼂;樥;橲n肻±ຝim;樦wo;樧ƀipu⼙⼠⼥ntint;樕f;쀀𝕡nd耻£䂣Ԁ;Eaceinosu່⼿⽁⽄⽇⾁⾉⾒⽾⾶;檳p;檷uå໙Ā;c໎⽌̀;acens່⽙⽟⽦⽨⽾pproø⽃urlyeñ໙ñ໎ƀaes⽯⽶⽺pprox;檹qq;檵im;拨iíໟmeĀ;s⾈ຮ怲ƀEas⽸⾐⽺ð⽵ƀdfp໬⾙⾯ƀals⾠⾥⾪lar;挮ine;挒urf;挓Ā;t໻⾴ï໻rel;抰Āci⿀⿅r;쀀𝓅;䏈ncsp;怈̀fiopsu⿚⋢⿟⿥⿫⿱r;쀀𝔮pf;쀀𝕢rime;恗cr;쀀𝓆ƀaeo⿸〉〓tĀei⿾々rnionóڰnt;樖stĀ;e【】䀿ñἙô༔઀ABHabcdefhilmnoprstux぀けさすムㄎㄫㅇㅢㅲㆎ㈆㈕㈤㈩㉘㉮㉲㊐㊰㊷ƀartぇおがròႳòϝail;検aròᱥar;楤΀cdenqrtとふへみわゔヌĀeuねぱ;쀀∽̱te;䅕iãᅮmptyv;榳gȀ;del࿑らるろ;榒;榥å࿑uo耻»䂻rր;abcfhlpstw࿜ガクシスゼゾダッデナp;極Ā;f࿠ゴs;椠;椳s;椞ë≝ð✮l;楅im;楴l;憣;憝Āaiパフil;椚oĀ;nホボ戶aló༞ƀabrョリヮrò៥rk;杳ĀakンヽcĀekヹ・;䁽;䁝Āes㄂㄄;榌lĀduㄊㄌ;榎;榐Ȁaeuyㄗㄜㄧㄩron;䅙Ādiㄡㄥil;䅗ì࿲âヺ;䑀Ȁclqsㄴㄷㄽㅄa;椷dhar;楩uoĀ;rȎȍh;憳ƀacgㅎㅟངlȀ;ipsླྀㅘㅛႜnåႻarôྩt;断ƀilrㅩဣㅮsht;楽;쀀𝔯ĀaoㅷㆆrĀduㅽㅿ»ѻĀ;l႑ㆄ;楬Ā;vㆋㆌ䏁;䏱ƀgns㆕ㇹㇼht̀ahlrstㆤㆰ㇂㇘㇤㇮rrowĀ;t࿜ㆭaéトarpoonĀduㆻㆿowîㅾp»႒eftĀah㇊㇐rrowó࿪arpoonóՑightarrows;應quigarro÷ニhreetimes;拌g;䋚ingdotseñἲƀahm㈍㈐㈓rò࿪aòՑ;怏oustĀ;a㈞㈟掱che»㈟mid;櫮Ȁabpt㈲㈽㉀㉒Ānr㈷㈺g;柭r;懾rëဃƀafl㉇㉊㉎r;榆;쀀𝕣us;樮imes;樵Āap㉝㉧rĀ;g㉣㉤䀩t;榔olint;樒arò㇣Ȁachq㉻㊀Ⴜ㊅quo;怺r;쀀𝓇Ābu・㊊oĀ;rȔȓƀhir㊗㊛㊠reåㇸmes;拊iȀ;efl㊪ၙᠡ㊫方tri;槎luhar;楨;愞ൡ㋕㋛㋟㌬㌸㍱\0㍺㎤\0\0㏬㏰\0㐨㑈㑚㒭㒱㓊㓱\0㘖\0\0㘳cute;䅛quï➺Ԁ;Eaceinpsyᇭ㋳㋵㋿㌂㌋㌏㌟㌦㌩;檴ǰ㋺\0㋼;檸on;䅡uåᇾĀ;dᇳ㌇il;䅟rc;䅝ƀEas㌖㌘㌛;檶p;檺im;择olint;樓iíሄ;䑁otƀ;be㌴ᵇ㌵担;橦΀Aacmstx㍆㍊㍗㍛㍞㍣㍭rr;懘rĀhr㍐㍒ë∨Ā;oਸ਼਴t耻§䂧i;䀻war;椩mĀin㍩ðnuóñt;朶rĀ;o㍶⁕쀀𝔰Ȁacoy㎂㎆㎑㎠rp;景Āhy㎋㎏cy;䑉;䑈rtɭ㎙\0\0㎜iäᑤaraì⹯耻­䂭Āgm㎨㎴maƀ;fv㎱㎲㎲䏃;䏂Ѐ;deglnprካ㏅㏉㏎㏖㏞㏡㏦ot;橪Ā;q኱ኰĀ;E㏓㏔檞;檠Ā;E㏛㏜檝;檟e;扆lus;樤arr;楲aròᄽȀaeit㏸㐈㐏㐗Āls㏽㐄lsetmé㍪hp;樳parsl;槤Ādlᑣ㐔e;挣Ā;e㐜㐝檪Ā;s㐢㐣檬;쀀⪬︀ƀflp㐮㐳㑂tcy;䑌Ā;b㐸㐹䀯Ā;a㐾㐿槄r;挿f;쀀𝕤aĀdr㑍ЂesĀ;u㑔㑕晠it»㑕ƀcsu㑠㑹㒟Āau㑥㑯pĀ;sᆈ㑫;쀀⊓︀pĀ;sᆴ㑵;쀀⊔︀uĀbp㑿㒏ƀ;esᆗᆜ㒆etĀ;eᆗ㒍ñᆝƀ;esᆨᆭ㒖etĀ;eᆨ㒝ñᆮƀ;afᅻ㒦ְrť㒫ֱ»ᅼaròᅈȀcemt㒹㒾㓂㓅r;쀀𝓈tmîñiì㐕aræᆾĀar㓎㓕rĀ;f㓔ឿ昆Āan㓚㓭ightĀep㓣㓪psiloîỠhé⺯s»⡒ʀbcmnp㓻㕞ሉ㖋㖎Ҁ;Edemnprs㔎㔏㔑㔕㔞㔣㔬㔱㔶抂;櫅ot;檽Ā;dᇚ㔚ot;櫃ult;櫁ĀEe㔨㔪;櫋;把lus;檿arr;楹ƀeiu㔽㕒㕕tƀ;en㔎㕅㕋qĀ;qᇚ㔏eqĀ;q㔫㔨m;櫇Ābp㕚㕜;櫕;櫓c̀;acensᇭ㕬㕲㕹㕻㌦pproø㋺urlyeñᇾñᇳƀaes㖂㖈㌛pproø㌚qñ㌗g;晪ڀ123;Edehlmnps㖩㖬㖯ሜ㖲㖴㗀㗉㗕㗚㗟㗨㗭耻¹䂹耻²䂲耻³䂳;櫆Āos㖹㖼t;檾ub;櫘Ā;dሢ㗅ot;櫄sĀou㗏㗒l;柉b;櫗arr;楻ult;櫂ĀEe㗤㗦;櫌;抋lus;櫀ƀeiu㗴㘉㘌tƀ;enሜ㗼㘂qĀ;qሢ㖲eqĀ;q㗧㗤m;櫈Ābp㘑㘓;櫔;櫖ƀAan㘜㘠㘭rr;懙rĀhr㘦㘨ë∮Ā;oਫ਩war;椪lig耻ß䃟௡㙑㙝㙠ዎ㙳㙹\0㙾㛂\0\0\0\0\0㛛㜃\0㜉㝬\0\0\0㞇ɲ㙖\0\0㙛get;挖;䏄rë๟ƀaey㙦㙫㙰ron;䅥dil;䅣;䑂lrec;挕r;쀀𝔱Ȁeiko㚆㚝㚵㚼Dz㚋\0㚑eĀ4fኄኁaƀ;sv㚘㚙㚛䎸ym;䏑Ācn㚢㚲kĀas㚨㚮pproø዁im»ኬsðኞĀas㚺㚮ð዁rn耻þ䃾Ǭ̟㛆⋧es膀×;bd㛏㛐㛘䃗Ā;aᤏ㛕r;樱;樰ƀeps㛡㛣㜀á⩍Ȁ;bcf҆㛬㛰㛴ot;挶ir;櫱Ā;o㛹㛼쀀𝕥rk;櫚á㍢rime;怴ƀaip㜏㜒㝤dåቈ΀adempst㜡㝍㝀㝑㝗㝜㝟ngleʀ;dlqr㜰㜱㜶㝀㝂斵own»ᶻeftĀ;e⠀㜾ñम;扜ightĀ;e㊪㝋ñၚot;旬inus;樺lus;樹b;槍ime;樻ezium;揢ƀcht㝲㝽㞁Āry㝷㝻;쀀𝓉;䑆cy;䑛rok;䅧Āio㞋㞎xô᝷headĀlr㞗㞠eftarro÷ࡏightarrow»ཝऀAHabcdfghlmoprstuw㟐㟓㟗㟤㟰㟼㠎㠜㠣㠴㡑㡝㡫㢩㣌㣒㣪㣶ròϭar;楣Ācr㟜㟢ute耻ú䃺òᅐrǣ㟪\0㟭y;䑞ve;䅭Āiy㟵㟺rc耻û䃻;䑃ƀabh㠃㠆㠋ròᎭlac;䅱aòᏃĀir㠓㠘sht;楾;쀀𝔲rave耻ù䃹š㠧㠱rĀlr㠬㠮»ॗ»ႃlk;斀Āct㠹㡍ɯ㠿\0\0㡊rnĀ;e㡅㡆挜r»㡆op;挏ri;旸Āal㡖㡚cr;䅫肻¨͉Āgp㡢㡦on;䅳f;쀀𝕦̀adhlsuᅋ㡸㡽፲㢑㢠ownáᎳarpoonĀlr㢈㢌efô㠭ighô㠯iƀ;hl㢙㢚㢜䏅»ᏺon»㢚parrows;懈ƀcit㢰㣄㣈ɯ㢶\0\0㣁rnĀ;e㢼㢽挝r»㢽op;挎ng;䅯ri;旹cr;쀀𝓊ƀdir㣙㣝㣢ot;拰lde;䅩iĀ;f㜰㣨»᠓Āam㣯㣲rò㢨l耻ü䃼angle;榧ހABDacdeflnoprsz㤜㤟㤩㤭㦵㦸㦽㧟㧤㧨㧳㧹㧽㨁㨠ròϷarĀ;v㤦㤧櫨;櫩asèϡĀnr㤲㤷grt;榜΀eknprst㓣㥆㥋㥒㥝㥤㦖appá␕othinçẖƀhir㓫⻈㥙opô⾵Ā;hᎷ㥢ïㆍĀiu㥩㥭gmá㎳Ābp㥲㦄setneqĀ;q㥽㦀쀀⊊︀;쀀⫋︀setneqĀ;q㦏㦒쀀⊋︀;쀀⫌︀Āhr㦛㦟etá㚜iangleĀlr㦪㦯eft»थight»ၑy;䐲ash»ံƀelr㧄㧒㧗ƀ;beⷪ㧋㧏ar;抻q;扚lip;拮Ābt㧜ᑨaòᑩr;쀀𝔳tré㦮suĀbp㧯㧱»ജ»൙pf;쀀𝕧roð໻tré㦴Ācu㨆㨋r;쀀𝓋Ābp㨐㨘nĀEe㦀㨖»㥾nĀEe㦒㨞»㦐igzag;榚΀cefoprs㨶㨻㩖㩛㩔㩡㩪irc;䅵Ādi㩀㩑Ābg㩅㩉ar;機eĀ;qᗺ㩏;扙erp;愘r;쀀𝔴pf;쀀𝕨Ā;eᑹ㩦atèᑹcr;쀀𝓌ૣណ㪇\0㪋\0㪐㪛\0\0㪝㪨㪫㪯\0\0㫃㫎\0㫘ៜ៟tré៑r;쀀𝔵ĀAa㪔㪗ròσrò৶;䎾ĀAa㪡㪤ròθrò৫að✓is;拻ƀdptឤ㪵㪾Āfl㪺ឩ;쀀𝕩imåឲĀAa㫇㫊ròώròਁĀcq㫒ីr;쀀𝓍Āpt៖㫜ré។Ѐacefiosu㫰㫽㬈㬌㬑㬕㬛㬡cĀuy㫶㫻te耻ý䃽;䑏Āiy㬂㬆rc;䅷;䑋n耻¥䂥r;쀀𝔶cy;䑗pf;쀀𝕪cr;쀀𝓎Ācm㬦㬩y;䑎l耻ÿ䃿Ԁacdefhiosw㭂㭈㭔㭘㭤㭩㭭㭴㭺㮀cute;䅺Āay㭍㭒ron;䅾;䐷ot;䅼Āet㭝㭡træᕟa;䎶r;쀀𝔷cy;䐶grarr;懝pf;쀀𝕫cr;쀀𝓏Ājn㮅㮇;怍j;怌'.split("").map(t=>t.charCodeAt(0))),f$=new Map([[0,65533],[128,8364],[130,8218],[131,402],[132,8222],[133,8230],[134,8224],[135,8225],[136,710],[137,8240],[138,352],[139,8249],[140,338],[142,381],[145,8216],[146,8217],[147,8220],[148,8221],[149,8226],[150,8211],[151,8212],[152,732],[153,8482],[154,353],[155,8250],[156,339],[158,382],[159,376]]);function h$(t){var e;return t>=55296&&t<=57343||t>1114111?65533:(e=f$.get(t))!==null&&e!==void 0?e:t}var Wn;(function(t){t[t.NUM=35]="NUM",t[t.SEMI=59]="SEMI",t[t.EQUALS=61]="EQUALS",t[t.ZERO=48]="ZERO",t[t.NINE=57]="NINE",t[t.LOWER_A=97]="LOWER_A",t[t.LOWER_F=102]="LOWER_F",t[t.LOWER_X=120]="LOWER_X",t[t.LOWER_Z=122]="LOWER_Z",t[t.UPPER_A=65]="UPPER_A",t[t.UPPER_F=70]="UPPER_F",t[t.UPPER_Z=90]="UPPER_Z"})(Wn||(Wn={}));const p$=32;var ro;(function(t){t[t.VALUE_LENGTH=49152]="VALUE_LENGTH",t[t.BRANCH_LENGTH=16256]="BRANCH_LENGTH",t[t.JUMP_TABLE=127]="JUMP_TABLE"})(ro||(ro={}));function ob(t){return t>=Wn.ZERO&&t<=Wn.NINE}function m$(t){return t>=Wn.UPPER_A&&t<=Wn.UPPER_F||t>=Wn.LOWER_A&&t<=Wn.LOWER_F}function g$(t){return t>=Wn.UPPER_A&&t<=Wn.UPPER_Z||t>=Wn.LOWER_A&&t<=Wn.LOWER_Z||ob(t)}function b$(t){return t===Wn.EQUALS||g$(t)}var jn;(function(t){t[t.EntityStart=0]="EntityStart",t[t.NumericStart=1]="NumericStart",t[t.NumericDecimal=2]="NumericDecimal",t[t.NumericHex=3]="NumericHex",t[t.NamedEntity=4]="NamedEntity"})(jn||(jn={}));var hs;(function(t){t[t.Legacy=0]="Legacy",t[t.Strict=1]="Strict",t[t.Attribute=2]="Attribute"})(hs||(hs={}));class E${constructor(e,n,r){this.decodeTree=e,this.emitCodePoint=n,this.errors=r,this.state=jn.EntityStart,this.consumed=1,this.result=0,this.treeIndex=0,this.excess=1,this.decodeMode=hs.Strict}startEntity(e){this.decodeMode=e,this.state=jn.EntityStart,this.result=0,this.treeIndex=0,this.excess=1,this.consumed=1}write(e,n){switch(this.state){case jn.EntityStart:return e.charCodeAt(n)===Wn.NUM?(this.state=jn.NumericStart,this.consumed+=1,this.stateNumericStart(e,n+1)):(this.state=jn.NamedEntity,this.stateNamedEntity(e,n));case jn.NumericStart:return this.stateNumericStart(e,n);case jn.NumericDecimal:return this.stateNumericDecimal(e,n);case jn.NumericHex:return this.stateNumericHex(e,n);case jn.NamedEntity:return this.stateNamedEntity(e,n)}}stateNumericStart(e,n){return n>=e.length?-1:(e.charCodeAt(n)|p$)===Wn.LOWER_X?(this.state=jn.NumericHex,this.consumed+=1,this.stateNumericHex(e,n+1)):(this.state=jn.NumericDecimal,this.stateNumericDecimal(e,n))}addToNumericResult(e,n,r,i){if(n!==r){const s=r-n;this.result=this.result*Math.pow(i,s)+Number.parseInt(e.substr(n,s),i),this.consumed+=s}}stateNumericHex(e,n){const r=n;for(;n>14;for(;n>14,s!==0){if(o===Wn.SEMI)return this.emitNamedEntityData(this.treeIndex,s,this.consumed+this.excess);this.decodeMode!==hs.Strict&&(this.result=this.treeIndex,this.consumed+=this.excess,this.excess=0)}}return-1}emitNotTerminatedNamedEntity(){var e;const{result:n,decodeTree:r}=this,i=(r[n]&ro.VALUE_LENGTH)>>14;return this.emitNamedEntityData(n,i,this.consumed),(e=this.errors)===null||e===void 0||e.missingSemicolonAfterCharacterReference(),this.consumed}emitNamedEntityData(e,n,r){const{decodeTree:i}=this;return this.emitCodePoint(n===1?i[e]&~ro.VALUE_LENGTH:i[e+1],r),n===3&&this.emitCodePoint(i[e+2],r),r}end(){var e;switch(this.state){case jn.NamedEntity:return this.result!==0&&(this.decodeMode!==hs.Attribute||this.result===this.treeIndex)?this.emitNotTerminatedNamedEntity():0;case jn.NumericDecimal:return this.emitNumericEntity(0,2);case jn.NumericHex:return this.emitNumericEntity(0,3);case jn.NumericStart:return(e=this.errors)===null||e===void 0||e.absenceOfDigitsInNumericCharacterReference(this.consumed),0;case jn.EntityStart:return 0}}}function y$(t,e,n,r){const i=(e&ro.BRANCH_LENGTH)>>7,s=e&ro.JUMP_TABLE;if(i===0)return s!==0&&r===s?n:-1;if(s){const c=r-s;return c<0||c>=i?-1:t[n+c]-1}let o=n,l=o+i-1;for(;o<=l;){const c=o+l>>>1,d=t[c];if(dr)l=c-1;else return t[c+i]}return-1}var be;(function(t){t.HTML="http://www.w3.org/1999/xhtml",t.MATHML="http://www.w3.org/1998/Math/MathML",t.SVG="http://www.w3.org/2000/svg",t.XLINK="http://www.w3.org/1999/xlink",t.XML="http://www.w3.org/XML/1998/namespace",t.XMLNS="http://www.w3.org/2000/xmlns/"})(be||(be={}));var Wo;(function(t){t.TYPE="type",t.ACTION="action",t.ENCODING="encoding",t.PROMPT="prompt",t.NAME="name",t.COLOR="color",t.FACE="face",t.SIZE="size"})(Wo||(Wo={}));var ni;(function(t){t.NO_QUIRKS="no-quirks",t.QUIRKS="quirks",t.LIMITED_QUIRKS="limited-quirks"})(ni||(ni={}));var re;(function(t){t.A="a",t.ADDRESS="address",t.ANNOTATION_XML="annotation-xml",t.APPLET="applet",t.AREA="area",t.ARTICLE="article",t.ASIDE="aside",t.B="b",t.BASE="base",t.BASEFONT="basefont",t.BGSOUND="bgsound",t.BIG="big",t.BLOCKQUOTE="blockquote",t.BODY="body",t.BR="br",t.BUTTON="button",t.CAPTION="caption",t.CENTER="center",t.CODE="code",t.COL="col",t.COLGROUP="colgroup",t.DD="dd",t.DESC="desc",t.DETAILS="details",t.DIALOG="dialog",t.DIR="dir",t.DIV="div",t.DL="dl",t.DT="dt",t.EM="em",t.EMBED="embed",t.FIELDSET="fieldset",t.FIGCAPTION="figcaption",t.FIGURE="figure",t.FONT="font",t.FOOTER="footer",t.FOREIGN_OBJECT="foreignObject",t.FORM="form",t.FRAME="frame",t.FRAMESET="frameset",t.H1="h1",t.H2="h2",t.H3="h3",t.H4="h4",t.H5="h5",t.H6="h6",t.HEAD="head",t.HEADER="header",t.HGROUP="hgroup",t.HR="hr",t.HTML="html",t.I="i",t.IMG="img",t.IMAGE="image",t.INPUT="input",t.IFRAME="iframe",t.KEYGEN="keygen",t.LABEL="label",t.LI="li",t.LINK="link",t.LISTING="listing",t.MAIN="main",t.MALIGNMARK="malignmark",t.MARQUEE="marquee",t.MATH="math",t.MENU="menu",t.META="meta",t.MGLYPH="mglyph",t.MI="mi",t.MO="mo",t.MN="mn",t.MS="ms",t.MTEXT="mtext",t.NAV="nav",t.NOBR="nobr",t.NOFRAMES="noframes",t.NOEMBED="noembed",t.NOSCRIPT="noscript",t.OBJECT="object",t.OL="ol",t.OPTGROUP="optgroup",t.OPTION="option",t.P="p",t.PARAM="param",t.PLAINTEXT="plaintext",t.PRE="pre",t.RB="rb",t.RP="rp",t.RT="rt",t.RTC="rtc",t.RUBY="ruby",t.S="s",t.SCRIPT="script",t.SEARCH="search",t.SECTION="section",t.SELECT="select",t.SOURCE="source",t.SMALL="small",t.SPAN="span",t.STRIKE="strike",t.STRONG="strong",t.STYLE="style",t.SUB="sub",t.SUMMARY="summary",t.SUP="sup",t.TABLE="table",t.TBODY="tbody",t.TEMPLATE="template",t.TEXTAREA="textarea",t.TFOOT="tfoot",t.TD="td",t.TH="th",t.THEAD="thead",t.TITLE="title",t.TR="tr",t.TRACK="track",t.TT="tt",t.U="u",t.UL="ul",t.SVG="svg",t.VAR="var",t.WBR="wbr",t.XMP="xmp"})(re||(re={}));var E;(function(t){t[t.UNKNOWN=0]="UNKNOWN",t[t.A=1]="A",t[t.ADDRESS=2]="ADDRESS",t[t.ANNOTATION_XML=3]="ANNOTATION_XML",t[t.APPLET=4]="APPLET",t[t.AREA=5]="AREA",t[t.ARTICLE=6]="ARTICLE",t[t.ASIDE=7]="ASIDE",t[t.B=8]="B",t[t.BASE=9]="BASE",t[t.BASEFONT=10]="BASEFONT",t[t.BGSOUND=11]="BGSOUND",t[t.BIG=12]="BIG",t[t.BLOCKQUOTE=13]="BLOCKQUOTE",t[t.BODY=14]="BODY",t[t.BR=15]="BR",t[t.BUTTON=16]="BUTTON",t[t.CAPTION=17]="CAPTION",t[t.CENTER=18]="CENTER",t[t.CODE=19]="CODE",t[t.COL=20]="COL",t[t.COLGROUP=21]="COLGROUP",t[t.DD=22]="DD",t[t.DESC=23]="DESC",t[t.DETAILS=24]="DETAILS",t[t.DIALOG=25]="DIALOG",t[t.DIR=26]="DIR",t[t.DIV=27]="DIV",t[t.DL=28]="DL",t[t.DT=29]="DT",t[t.EM=30]="EM",t[t.EMBED=31]="EMBED",t[t.FIELDSET=32]="FIELDSET",t[t.FIGCAPTION=33]="FIGCAPTION",t[t.FIGURE=34]="FIGURE",t[t.FONT=35]="FONT",t[t.FOOTER=36]="FOOTER",t[t.FOREIGN_OBJECT=37]="FOREIGN_OBJECT",t[t.FORM=38]="FORM",t[t.FRAME=39]="FRAME",t[t.FRAMESET=40]="FRAMESET",t[t.H1=41]="H1",t[t.H2=42]="H2",t[t.H3=43]="H3",t[t.H4=44]="H4",t[t.H5=45]="H5",t[t.H6=46]="H6",t[t.HEAD=47]="HEAD",t[t.HEADER=48]="HEADER",t[t.HGROUP=49]="HGROUP",t[t.HR=50]="HR",t[t.HTML=51]="HTML",t[t.I=52]="I",t[t.IMG=53]="IMG",t[t.IMAGE=54]="IMAGE",t[t.INPUT=55]="INPUT",t[t.IFRAME=56]="IFRAME",t[t.KEYGEN=57]="KEYGEN",t[t.LABEL=58]="LABEL",t[t.LI=59]="LI",t[t.LINK=60]="LINK",t[t.LISTING=61]="LISTING",t[t.MAIN=62]="MAIN",t[t.MALIGNMARK=63]="MALIGNMARK",t[t.MARQUEE=64]="MARQUEE",t[t.MATH=65]="MATH",t[t.MENU=66]="MENU",t[t.META=67]="META",t[t.MGLYPH=68]="MGLYPH",t[t.MI=69]="MI",t[t.MO=70]="MO",t[t.MN=71]="MN",t[t.MS=72]="MS",t[t.MTEXT=73]="MTEXT",t[t.NAV=74]="NAV",t[t.NOBR=75]="NOBR",t[t.NOFRAMES=76]="NOFRAMES",t[t.NOEMBED=77]="NOEMBED",t[t.NOSCRIPT=78]="NOSCRIPT",t[t.OBJECT=79]="OBJECT",t[t.OL=80]="OL",t[t.OPTGROUP=81]="OPTGROUP",t[t.OPTION=82]="OPTION",t[t.P=83]="P",t[t.PARAM=84]="PARAM",t[t.PLAINTEXT=85]="PLAINTEXT",t[t.PRE=86]="PRE",t[t.RB=87]="RB",t[t.RP=88]="RP",t[t.RT=89]="RT",t[t.RTC=90]="RTC",t[t.RUBY=91]="RUBY",t[t.S=92]="S",t[t.SCRIPT=93]="SCRIPT",t[t.SEARCH=94]="SEARCH",t[t.SECTION=95]="SECTION",t[t.SELECT=96]="SELECT",t[t.SOURCE=97]="SOURCE",t[t.SMALL=98]="SMALL",t[t.SPAN=99]="SPAN",t[t.STRIKE=100]="STRIKE",t[t.STRONG=101]="STRONG",t[t.STYLE=102]="STYLE",t[t.SUB=103]="SUB",t[t.SUMMARY=104]="SUMMARY",t[t.SUP=105]="SUP",t[t.TABLE=106]="TABLE",t[t.TBODY=107]="TBODY",t[t.TEMPLATE=108]="TEMPLATE",t[t.TEXTAREA=109]="TEXTAREA",t[t.TFOOT=110]="TFOOT",t[t.TD=111]="TD",t[t.TH=112]="TH",t[t.THEAD=113]="THEAD",t[t.TITLE=114]="TITLE",t[t.TR=115]="TR",t[t.TRACK=116]="TRACK",t[t.TT=117]="TT",t[t.U=118]="U",t[t.UL=119]="UL",t[t.SVG=120]="SVG",t[t.VAR=121]="VAR",t[t.WBR=122]="WBR",t[t.XMP=123]="XMP"})(E||(E={}));const x$=new Map([[re.A,E.A],[re.ADDRESS,E.ADDRESS],[re.ANNOTATION_XML,E.ANNOTATION_XML],[re.APPLET,E.APPLET],[re.AREA,E.AREA],[re.ARTICLE,E.ARTICLE],[re.ASIDE,E.ASIDE],[re.B,E.B],[re.BASE,E.BASE],[re.BASEFONT,E.BASEFONT],[re.BGSOUND,E.BGSOUND],[re.BIG,E.BIG],[re.BLOCKQUOTE,E.BLOCKQUOTE],[re.BODY,E.BODY],[re.BR,E.BR],[re.BUTTON,E.BUTTON],[re.CAPTION,E.CAPTION],[re.CENTER,E.CENTER],[re.CODE,E.CODE],[re.COL,E.COL],[re.COLGROUP,E.COLGROUP],[re.DD,E.DD],[re.DESC,E.DESC],[re.DETAILS,E.DETAILS],[re.DIALOG,E.DIALOG],[re.DIR,E.DIR],[re.DIV,E.DIV],[re.DL,E.DL],[re.DT,E.DT],[re.EM,E.EM],[re.EMBED,E.EMBED],[re.FIELDSET,E.FIELDSET],[re.FIGCAPTION,E.FIGCAPTION],[re.FIGURE,E.FIGURE],[re.FONT,E.FONT],[re.FOOTER,E.FOOTER],[re.FOREIGN_OBJECT,E.FOREIGN_OBJECT],[re.FORM,E.FORM],[re.FRAME,E.FRAME],[re.FRAMESET,E.FRAMESET],[re.H1,E.H1],[re.H2,E.H2],[re.H3,E.H3],[re.H4,E.H4],[re.H5,E.H5],[re.H6,E.H6],[re.HEAD,E.HEAD],[re.HEADER,E.HEADER],[re.HGROUP,E.HGROUP],[re.HR,E.HR],[re.HTML,E.HTML],[re.I,E.I],[re.IMG,E.IMG],[re.IMAGE,E.IMAGE],[re.INPUT,E.INPUT],[re.IFRAME,E.IFRAME],[re.KEYGEN,E.KEYGEN],[re.LABEL,E.LABEL],[re.LI,E.LI],[re.LINK,E.LINK],[re.LISTING,E.LISTING],[re.MAIN,E.MAIN],[re.MALIGNMARK,E.MALIGNMARK],[re.MARQUEE,E.MARQUEE],[re.MATH,E.MATH],[re.MENU,E.MENU],[re.META,E.META],[re.MGLYPH,E.MGLYPH],[re.MI,E.MI],[re.MO,E.MO],[re.MN,E.MN],[re.MS,E.MS],[re.MTEXT,E.MTEXT],[re.NAV,E.NAV],[re.NOBR,E.NOBR],[re.NOFRAMES,E.NOFRAMES],[re.NOEMBED,E.NOEMBED],[re.NOSCRIPT,E.NOSCRIPT],[re.OBJECT,E.OBJECT],[re.OL,E.OL],[re.OPTGROUP,E.OPTGROUP],[re.OPTION,E.OPTION],[re.P,E.P],[re.PARAM,E.PARAM],[re.PLAINTEXT,E.PLAINTEXT],[re.PRE,E.PRE],[re.RB,E.RB],[re.RP,E.RP],[re.RT,E.RT],[re.RTC,E.RTC],[re.RUBY,E.RUBY],[re.S,E.S],[re.SCRIPT,E.SCRIPT],[re.SEARCH,E.SEARCH],[re.SECTION,E.SECTION],[re.SELECT,E.SELECT],[re.SOURCE,E.SOURCE],[re.SMALL,E.SMALL],[re.SPAN,E.SPAN],[re.STRIKE,E.STRIKE],[re.STRONG,E.STRONG],[re.STYLE,E.STYLE],[re.SUB,E.SUB],[re.SUMMARY,E.SUMMARY],[re.SUP,E.SUP],[re.TABLE,E.TABLE],[re.TBODY,E.TBODY],[re.TEMPLATE,E.TEMPLATE],[re.TEXTAREA,E.TEXTAREA],[re.TFOOT,E.TFOOT],[re.TD,E.TD],[re.TH,E.TH],[re.THEAD,E.THEAD],[re.TITLE,E.TITLE],[re.TR,E.TR],[re.TRACK,E.TRACK],[re.TT,E.TT],[re.U,E.U],[re.UL,E.UL],[re.SVG,E.SVG],[re.VAR,E.VAR],[re.WBR,E.WBR],[re.XMP,E.XMP]]);function Fl(t){var e;return(e=x$.get(t))!==null&&e!==void 0?e:E.UNKNOWN}const ve=E,v$={[be.HTML]:new Set([ve.ADDRESS,ve.APPLET,ve.AREA,ve.ARTICLE,ve.ASIDE,ve.BASE,ve.BASEFONT,ve.BGSOUND,ve.BLOCKQUOTE,ve.BODY,ve.BR,ve.BUTTON,ve.CAPTION,ve.CENTER,ve.COL,ve.COLGROUP,ve.DD,ve.DETAILS,ve.DIR,ve.DIV,ve.DL,ve.DT,ve.EMBED,ve.FIELDSET,ve.FIGCAPTION,ve.FIGURE,ve.FOOTER,ve.FORM,ve.FRAME,ve.FRAMESET,ve.H1,ve.H2,ve.H3,ve.H4,ve.H5,ve.H6,ve.HEAD,ve.HEADER,ve.HGROUP,ve.HR,ve.HTML,ve.IFRAME,ve.IMG,ve.INPUT,ve.LI,ve.LINK,ve.LISTING,ve.MAIN,ve.MARQUEE,ve.MENU,ve.META,ve.NAV,ve.NOEMBED,ve.NOFRAMES,ve.NOSCRIPT,ve.OBJECT,ve.OL,ve.P,ve.PARAM,ve.PLAINTEXT,ve.PRE,ve.SCRIPT,ve.SECTION,ve.SELECT,ve.SOURCE,ve.STYLE,ve.SUMMARY,ve.TABLE,ve.TBODY,ve.TD,ve.TEMPLATE,ve.TEXTAREA,ve.TFOOT,ve.TH,ve.THEAD,ve.TITLE,ve.TR,ve.TRACK,ve.UL,ve.WBR,ve.XMP]),[be.MATHML]:new Set([ve.MI,ve.MO,ve.MN,ve.MS,ve.MTEXT,ve.ANNOTATION_XML]),[be.SVG]:new Set([ve.TITLE,ve.FOREIGN_OBJECT,ve.DESC]),[be.XLINK]:new Set,[be.XML]:new Set,[be.XMLNS]:new Set},ab=new Set([ve.H1,ve.H2,ve.H3,ve.H4,ve.H5,ve.H6]);re.STYLE,re.SCRIPT,re.XMP,re.IFRAME,re.NOEMBED,re.NOFRAMES,re.PLAINTEXT;var B;(function(t){t[t.DATA=0]="DATA",t[t.RCDATA=1]="RCDATA",t[t.RAWTEXT=2]="RAWTEXT",t[t.SCRIPT_DATA=3]="SCRIPT_DATA",t[t.PLAINTEXT=4]="PLAINTEXT",t[t.TAG_OPEN=5]="TAG_OPEN",t[t.END_TAG_OPEN=6]="END_TAG_OPEN",t[t.TAG_NAME=7]="TAG_NAME",t[t.RCDATA_LESS_THAN_SIGN=8]="RCDATA_LESS_THAN_SIGN",t[t.RCDATA_END_TAG_OPEN=9]="RCDATA_END_TAG_OPEN",t[t.RCDATA_END_TAG_NAME=10]="RCDATA_END_TAG_NAME",t[t.RAWTEXT_LESS_THAN_SIGN=11]="RAWTEXT_LESS_THAN_SIGN",t[t.RAWTEXT_END_TAG_OPEN=12]="RAWTEXT_END_TAG_OPEN",t[t.RAWTEXT_END_TAG_NAME=13]="RAWTEXT_END_TAG_NAME",t[t.SCRIPT_DATA_LESS_THAN_SIGN=14]="SCRIPT_DATA_LESS_THAN_SIGN",t[t.SCRIPT_DATA_END_TAG_OPEN=15]="SCRIPT_DATA_END_TAG_OPEN",t[t.SCRIPT_DATA_END_TAG_NAME=16]="SCRIPT_DATA_END_TAG_NAME",t[t.SCRIPT_DATA_ESCAPE_START=17]="SCRIPT_DATA_ESCAPE_START",t[t.SCRIPT_DATA_ESCAPE_START_DASH=18]="SCRIPT_DATA_ESCAPE_START_DASH",t[t.SCRIPT_DATA_ESCAPED=19]="SCRIPT_DATA_ESCAPED",t[t.SCRIPT_DATA_ESCAPED_DASH=20]="SCRIPT_DATA_ESCAPED_DASH",t[t.SCRIPT_DATA_ESCAPED_DASH_DASH=21]="SCRIPT_DATA_ESCAPED_DASH_DASH",t[t.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN=22]="SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN",t[t.SCRIPT_DATA_ESCAPED_END_TAG_OPEN=23]="SCRIPT_DATA_ESCAPED_END_TAG_OPEN",t[t.SCRIPT_DATA_ESCAPED_END_TAG_NAME=24]="SCRIPT_DATA_ESCAPED_END_TAG_NAME",t[t.SCRIPT_DATA_DOUBLE_ESCAPE_START=25]="SCRIPT_DATA_DOUBLE_ESCAPE_START",t[t.SCRIPT_DATA_DOUBLE_ESCAPED=26]="SCRIPT_DATA_DOUBLE_ESCAPED",t[t.SCRIPT_DATA_DOUBLE_ESCAPED_DASH=27]="SCRIPT_DATA_DOUBLE_ESCAPED_DASH",t[t.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH=28]="SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH",t[t.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN=29]="SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN",t[t.SCRIPT_DATA_DOUBLE_ESCAPE_END=30]="SCRIPT_DATA_DOUBLE_ESCAPE_END",t[t.BEFORE_ATTRIBUTE_NAME=31]="BEFORE_ATTRIBUTE_NAME",t[t.ATTRIBUTE_NAME=32]="ATTRIBUTE_NAME",t[t.AFTER_ATTRIBUTE_NAME=33]="AFTER_ATTRIBUTE_NAME",t[t.BEFORE_ATTRIBUTE_VALUE=34]="BEFORE_ATTRIBUTE_VALUE",t[t.ATTRIBUTE_VALUE_DOUBLE_QUOTED=35]="ATTRIBUTE_VALUE_DOUBLE_QUOTED",t[t.ATTRIBUTE_VALUE_SINGLE_QUOTED=36]="ATTRIBUTE_VALUE_SINGLE_QUOTED",t[t.ATTRIBUTE_VALUE_UNQUOTED=37]="ATTRIBUTE_VALUE_UNQUOTED",t[t.AFTER_ATTRIBUTE_VALUE_QUOTED=38]="AFTER_ATTRIBUTE_VALUE_QUOTED",t[t.SELF_CLOSING_START_TAG=39]="SELF_CLOSING_START_TAG",t[t.BOGUS_COMMENT=40]="BOGUS_COMMENT",t[t.MARKUP_DECLARATION_OPEN=41]="MARKUP_DECLARATION_OPEN",t[t.COMMENT_START=42]="COMMENT_START",t[t.COMMENT_START_DASH=43]="COMMENT_START_DASH",t[t.COMMENT=44]="COMMENT",t[t.COMMENT_LESS_THAN_SIGN=45]="COMMENT_LESS_THAN_SIGN",t[t.COMMENT_LESS_THAN_SIGN_BANG=46]="COMMENT_LESS_THAN_SIGN_BANG",t[t.COMMENT_LESS_THAN_SIGN_BANG_DASH=47]="COMMENT_LESS_THAN_SIGN_BANG_DASH",t[t.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH=48]="COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH",t[t.COMMENT_END_DASH=49]="COMMENT_END_DASH",t[t.COMMENT_END=50]="COMMENT_END",t[t.COMMENT_END_BANG=51]="COMMENT_END_BANG",t[t.DOCTYPE=52]="DOCTYPE",t[t.BEFORE_DOCTYPE_NAME=53]="BEFORE_DOCTYPE_NAME",t[t.DOCTYPE_NAME=54]="DOCTYPE_NAME",t[t.AFTER_DOCTYPE_NAME=55]="AFTER_DOCTYPE_NAME",t[t.AFTER_DOCTYPE_PUBLIC_KEYWORD=56]="AFTER_DOCTYPE_PUBLIC_KEYWORD",t[t.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER=57]="BEFORE_DOCTYPE_PUBLIC_IDENTIFIER",t[t.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED=58]="DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED",t[t.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED=59]="DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED",t[t.AFTER_DOCTYPE_PUBLIC_IDENTIFIER=60]="AFTER_DOCTYPE_PUBLIC_IDENTIFIER",t[t.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS=61]="BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS",t[t.AFTER_DOCTYPE_SYSTEM_KEYWORD=62]="AFTER_DOCTYPE_SYSTEM_KEYWORD",t[t.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER=63]="BEFORE_DOCTYPE_SYSTEM_IDENTIFIER",t[t.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED=64]="DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED",t[t.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED=65]="DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED",t[t.AFTER_DOCTYPE_SYSTEM_IDENTIFIER=66]="AFTER_DOCTYPE_SYSTEM_IDENTIFIER",t[t.BOGUS_DOCTYPE=67]="BOGUS_DOCTYPE",t[t.CDATA_SECTION=68]="CDATA_SECTION",t[t.CDATA_SECTION_BRACKET=69]="CDATA_SECTION_BRACKET",t[t.CDATA_SECTION_END=70]="CDATA_SECTION_END",t[t.CHARACTER_REFERENCE=71]="CHARACTER_REFERENCE",t[t.AMBIGUOUS_AMPERSAND=72]="AMBIGUOUS_AMPERSAND"})(B||(B={}));const _n={DATA:B.DATA,RCDATA:B.RCDATA,RAWTEXT:B.RAWTEXT,SCRIPT_DATA:B.SCRIPT_DATA,PLAINTEXT:B.PLAINTEXT,CDATA_SECTION:B.CDATA_SECTION};function w$(t){return t>=L.DIGIT_0&&t<=L.DIGIT_9}function Uu(t){return t>=L.LATIN_CAPITAL_A&&t<=L.LATIN_CAPITAL_Z}function T$(t){return t>=L.LATIN_SMALL_A&&t<=L.LATIN_SMALL_Z}function Js(t){return T$(t)||Uu(t)}function xT(t){return Js(t)||w$(t)}function bf(t){return t+32}function PN(t){return t===L.SPACE||t===L.LINE_FEED||t===L.TABULATION||t===L.FORM_FEED}function vT(t){return PN(t)||t===L.SOLIDUS||t===L.GREATER_THAN_SIGN}function S$(t){return t===L.NULL?fe.nullCharacterReference:t>1114111?fe.characterReferenceOutsideUnicodeRange:ON(t)?fe.surrogateCharacterReference:DN(t)?fe.noncharacterCharacterReference:MN(t)||t===L.CARRIAGE_RETURN?fe.controlCharacterReference:null}class _${constructor(e,n){this.options=e,this.handler=n,this.paused=!1,this.inLoop=!1,this.inForeignNode=!1,this.lastStartTagName="",this.active=!1,this.state=B.DATA,this.returnState=B.DATA,this.entityStartPos=0,this.consumedAfterSnapshot=-1,this.currentCharacterToken=null,this.currentToken=null,this.currentAttr={name:"",value:""},this.preprocessor=new c$(n),this.currentLocation=this.getCurrentLocation(-1),this.entityDecoder=new E$(d$,(r,i)=>{this.preprocessor.pos=this.entityStartPos+i-1,this._flushCodePointConsumedAsCharacterReference(r)},n.onParseError?{missingSemicolonAfterCharacterReference:()=>{this._err(fe.missingSemicolonAfterCharacterReference,1)},absenceOfDigitsInNumericCharacterReference:r=>{this._err(fe.absenceOfDigitsInNumericCharacterReference,this.entityStartPos-this.preprocessor.pos+r)},validateNumericCharacterReference:r=>{const i=S$(r);i&&this._err(i,1)}}:void 0)}_err(e,n=0){var r,i;(i=(r=this.handler).onParseError)===null||i===void 0||i.call(r,this.preprocessor.getError(e,n))}getCurrentLocation(e){return this.options.sourceCodeLocationInfo?{startLine:this.preprocessor.line,startCol:this.preprocessor.col-e,startOffset:this.preprocessor.offset-e,endLine:-1,endCol:-1,endOffset:-1}:null}_runParsingLoop(){if(!this.inLoop){for(this.inLoop=!0;this.active&&!this.paused;){this.consumedAfterSnapshot=0;const e=this._consume();this._ensureHibernation()||this._callState(e)}this.inLoop=!1}}pause(){this.paused=!0}resume(e){if(!this.paused)throw new Error("Parser was already resumed");this.paused=!1,!this.inLoop&&(this._runParsingLoop(),this.paused||e?.())}write(e,n,r){this.active=!0,this.preprocessor.write(e,n),this._runParsingLoop(),this.paused||r?.()}insertHtmlAtCurrentPos(e){this.active=!0,this.preprocessor.insertHtmlAtCurrentPos(e),this._runParsingLoop()}_ensureHibernation(){return this.preprocessor.endOfChunkHit?(this.preprocessor.retreat(this.consumedAfterSnapshot),this.consumedAfterSnapshot=0,this.active=!1,!0):!1}_consume(){return this.consumedAfterSnapshot++,this.preprocessor.advance()}_advanceBy(e){this.consumedAfterSnapshot+=e;for(let n=0;n0&&this._err(fe.endTagWithAttributes),e.selfClosing&&this._err(fe.endTagWithTrailingSolidus),this.handler.onEndTag(e)),this.preprocessor.dropParsedChunk()}emitCurrentComment(e){this.prepareToken(e),this.handler.onComment(e),this.preprocessor.dropParsedChunk()}emitCurrentDoctype(e){this.prepareToken(e),this.handler.onDoctype(e),this.preprocessor.dropParsedChunk()}_emitCurrentCharacterToken(e){if(this.currentCharacterToken){switch(e&&this.currentCharacterToken.location&&(this.currentCharacterToken.location.endLine=e.startLine,this.currentCharacterToken.location.endCol=e.startCol,this.currentCharacterToken.location.endOffset=e.startOffset),this.currentCharacterToken.type){case yt.CHARACTER:{this.handler.onCharacter(this.currentCharacterToken);break}case yt.NULL_CHARACTER:{this.handler.onNullCharacter(this.currentCharacterToken);break}case yt.WHITESPACE_CHARACTER:{this.handler.onWhitespaceCharacter(this.currentCharacterToken);break}}this.currentCharacterToken=null}}_emitEOFToken(){const e=this.getCurrentLocation(0);e&&(e.endLine=e.startLine,e.endCol=e.startCol,e.endOffset=e.startOffset),this._emitCurrentCharacterToken(e),this.handler.onEof({type:yt.EOF,location:e}),this.active=!1}_appendCharToCurrentCharacterToken(e,n){if(this.currentCharacterToken)if(this.currentCharacterToken.type===e){this.currentCharacterToken.chars+=n;return}else this.currentLocation=this.getCurrentLocation(0),this._emitCurrentCharacterToken(this.currentLocation),this.preprocessor.dropParsedChunk();this._createCharacterToken(e,n)}_emitCodePoint(e){const n=PN(e)?yt.WHITESPACE_CHARACTER:e===L.NULL?yt.NULL_CHARACTER:yt.CHARACTER;this._appendCharToCurrentCharacterToken(n,String.fromCodePoint(e))}_emitChars(e){this._appendCharToCurrentCharacterToken(yt.CHARACTER,e)}_startCharacterReference(){this.returnState=this.state,this.state=B.CHARACTER_REFERENCE,this.entityStartPos=this.preprocessor.pos,this.entityDecoder.startEntity(this._isCharacterReferenceInAttribute()?hs.Attribute:hs.Legacy)}_isCharacterReferenceInAttribute(){return this.returnState===B.ATTRIBUTE_VALUE_DOUBLE_QUOTED||this.returnState===B.ATTRIBUTE_VALUE_SINGLE_QUOTED||this.returnState===B.ATTRIBUTE_VALUE_UNQUOTED}_flushCodePointConsumedAsCharacterReference(e){this._isCharacterReferenceInAttribute()?this.currentAttr.value+=String.fromCodePoint(e):this._emitCodePoint(e)}_callState(e){switch(this.state){case B.DATA:{this._stateData(e);break}case B.RCDATA:{this._stateRcdata(e);break}case B.RAWTEXT:{this._stateRawtext(e);break}case B.SCRIPT_DATA:{this._stateScriptData(e);break}case B.PLAINTEXT:{this._statePlaintext(e);break}case B.TAG_OPEN:{this._stateTagOpen(e);break}case B.END_TAG_OPEN:{this._stateEndTagOpen(e);break}case B.TAG_NAME:{this._stateTagName(e);break}case B.RCDATA_LESS_THAN_SIGN:{this._stateRcdataLessThanSign(e);break}case B.RCDATA_END_TAG_OPEN:{this._stateRcdataEndTagOpen(e);break}case B.RCDATA_END_TAG_NAME:{this._stateRcdataEndTagName(e);break}case B.RAWTEXT_LESS_THAN_SIGN:{this._stateRawtextLessThanSign(e);break}case B.RAWTEXT_END_TAG_OPEN:{this._stateRawtextEndTagOpen(e);break}case B.RAWTEXT_END_TAG_NAME:{this._stateRawtextEndTagName(e);break}case B.SCRIPT_DATA_LESS_THAN_SIGN:{this._stateScriptDataLessThanSign(e);break}case B.SCRIPT_DATA_END_TAG_OPEN:{this._stateScriptDataEndTagOpen(e);break}case B.SCRIPT_DATA_END_TAG_NAME:{this._stateScriptDataEndTagName(e);break}case B.SCRIPT_DATA_ESCAPE_START:{this._stateScriptDataEscapeStart(e);break}case B.SCRIPT_DATA_ESCAPE_START_DASH:{this._stateScriptDataEscapeStartDash(e);break}case B.SCRIPT_DATA_ESCAPED:{this._stateScriptDataEscaped(e);break}case B.SCRIPT_DATA_ESCAPED_DASH:{this._stateScriptDataEscapedDash(e);break}case B.SCRIPT_DATA_ESCAPED_DASH_DASH:{this._stateScriptDataEscapedDashDash(e);break}case B.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN:{this._stateScriptDataEscapedLessThanSign(e);break}case B.SCRIPT_DATA_ESCAPED_END_TAG_OPEN:{this._stateScriptDataEscapedEndTagOpen(e);break}case B.SCRIPT_DATA_ESCAPED_END_TAG_NAME:{this._stateScriptDataEscapedEndTagName(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPE_START:{this._stateScriptDataDoubleEscapeStart(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPED:{this._stateScriptDataDoubleEscaped(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPED_DASH:{this._stateScriptDataDoubleEscapedDash(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH:{this._stateScriptDataDoubleEscapedDashDash(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN:{this._stateScriptDataDoubleEscapedLessThanSign(e);break}case B.SCRIPT_DATA_DOUBLE_ESCAPE_END:{this._stateScriptDataDoubleEscapeEnd(e);break}case B.BEFORE_ATTRIBUTE_NAME:{this._stateBeforeAttributeName(e);break}case B.ATTRIBUTE_NAME:{this._stateAttributeName(e);break}case B.AFTER_ATTRIBUTE_NAME:{this._stateAfterAttributeName(e);break}case B.BEFORE_ATTRIBUTE_VALUE:{this._stateBeforeAttributeValue(e);break}case B.ATTRIBUTE_VALUE_DOUBLE_QUOTED:{this._stateAttributeValueDoubleQuoted(e);break}case B.ATTRIBUTE_VALUE_SINGLE_QUOTED:{this._stateAttributeValueSingleQuoted(e);break}case B.ATTRIBUTE_VALUE_UNQUOTED:{this._stateAttributeValueUnquoted(e);break}case B.AFTER_ATTRIBUTE_VALUE_QUOTED:{this._stateAfterAttributeValueQuoted(e);break}case B.SELF_CLOSING_START_TAG:{this._stateSelfClosingStartTag(e);break}case B.BOGUS_COMMENT:{this._stateBogusComment(e);break}case B.MARKUP_DECLARATION_OPEN:{this._stateMarkupDeclarationOpen(e);break}case B.COMMENT_START:{this._stateCommentStart(e);break}case B.COMMENT_START_DASH:{this._stateCommentStartDash(e);break}case B.COMMENT:{this._stateComment(e);break}case B.COMMENT_LESS_THAN_SIGN:{this._stateCommentLessThanSign(e);break}case B.COMMENT_LESS_THAN_SIGN_BANG:{this._stateCommentLessThanSignBang(e);break}case B.COMMENT_LESS_THAN_SIGN_BANG_DASH:{this._stateCommentLessThanSignBangDash(e);break}case B.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH:{this._stateCommentLessThanSignBangDashDash(e);break}case B.COMMENT_END_DASH:{this._stateCommentEndDash(e);break}case B.COMMENT_END:{this._stateCommentEnd(e);break}case B.COMMENT_END_BANG:{this._stateCommentEndBang(e);break}case B.DOCTYPE:{this._stateDoctype(e);break}case B.BEFORE_DOCTYPE_NAME:{this._stateBeforeDoctypeName(e);break}case B.DOCTYPE_NAME:{this._stateDoctypeName(e);break}case B.AFTER_DOCTYPE_NAME:{this._stateAfterDoctypeName(e);break}case B.AFTER_DOCTYPE_PUBLIC_KEYWORD:{this._stateAfterDoctypePublicKeyword(e);break}case B.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:{this._stateBeforeDoctypePublicIdentifier(e);break}case B.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:{this._stateDoctypePublicIdentifierDoubleQuoted(e);break}case B.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:{this._stateDoctypePublicIdentifierSingleQuoted(e);break}case B.AFTER_DOCTYPE_PUBLIC_IDENTIFIER:{this._stateAfterDoctypePublicIdentifier(e);break}case B.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:{this._stateBetweenDoctypePublicAndSystemIdentifiers(e);break}case B.AFTER_DOCTYPE_SYSTEM_KEYWORD:{this._stateAfterDoctypeSystemKeyword(e);break}case B.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:{this._stateBeforeDoctypeSystemIdentifier(e);break}case B.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:{this._stateDoctypeSystemIdentifierDoubleQuoted(e);break}case B.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:{this._stateDoctypeSystemIdentifierSingleQuoted(e);break}case B.AFTER_DOCTYPE_SYSTEM_IDENTIFIER:{this._stateAfterDoctypeSystemIdentifier(e);break}case B.BOGUS_DOCTYPE:{this._stateBogusDoctype(e);break}case B.CDATA_SECTION:{this._stateCdataSection(e);break}case B.CDATA_SECTION_BRACKET:{this._stateCdataSectionBracket(e);break}case B.CDATA_SECTION_END:{this._stateCdataSectionEnd(e);break}case B.CHARACTER_REFERENCE:{this._stateCharacterReference();break}case B.AMBIGUOUS_AMPERSAND:{this._stateAmbiguousAmpersand(e);break}default:throw new Error("Unknown state")}}_stateData(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.TAG_OPEN;break}case L.AMPERSAND:{this._startCharacterReference();break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this._emitCodePoint(e);break}case L.EOF:{this._emitEOFToken();break}default:this._emitCodePoint(e)}}_stateRcdata(e){switch(e){case L.AMPERSAND:{this._startCharacterReference();break}case L.LESS_THAN_SIGN:{this.state=B.RCDATA_LESS_THAN_SIGN;break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this._emitChars(cn);break}case L.EOF:{this._emitEOFToken();break}default:this._emitCodePoint(e)}}_stateRawtext(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.RAWTEXT_LESS_THAN_SIGN;break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this._emitChars(cn);break}case L.EOF:{this._emitEOFToken();break}default:this._emitCodePoint(e)}}_stateScriptData(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.SCRIPT_DATA_LESS_THAN_SIGN;break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this._emitChars(cn);break}case L.EOF:{this._emitEOFToken();break}default:this._emitCodePoint(e)}}_statePlaintext(e){switch(e){case L.NULL:{this._err(fe.unexpectedNullCharacter),this._emitChars(cn);break}case L.EOF:{this._emitEOFToken();break}default:this._emitCodePoint(e)}}_stateTagOpen(e){if(Js(e))this._createStartTagToken(),this.state=B.TAG_NAME,this._stateTagName(e);else switch(e){case L.EXCLAMATION_MARK:{this.state=B.MARKUP_DECLARATION_OPEN;break}case L.SOLIDUS:{this.state=B.END_TAG_OPEN;break}case L.QUESTION_MARK:{this._err(fe.unexpectedQuestionMarkInsteadOfTagName),this._createCommentToken(1),this.state=B.BOGUS_COMMENT,this._stateBogusComment(e);break}case L.EOF:{this._err(fe.eofBeforeTagName),this._emitChars("<"),this._emitEOFToken();break}default:this._err(fe.invalidFirstCharacterOfTagName),this._emitChars("<"),this.state=B.DATA,this._stateData(e)}}_stateEndTagOpen(e){if(Js(e))this._createEndTagToken(),this.state=B.TAG_NAME,this._stateTagName(e);else switch(e){case L.GREATER_THAN_SIGN:{this._err(fe.missingEndTagName),this.state=B.DATA;break}case L.EOF:{this._err(fe.eofBeforeTagName),this._emitChars("");break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this.state=B.SCRIPT_DATA_ESCAPED,this._emitChars(cn);break}case L.EOF:{this._err(fe.eofInScriptHtmlCommentLikeText),this._emitEOFToken();break}default:this.state=B.SCRIPT_DATA_ESCAPED,this._emitCodePoint(e)}}_stateScriptDataEscapedLessThanSign(e){e===L.SOLIDUS?this.state=B.SCRIPT_DATA_ESCAPED_END_TAG_OPEN:Js(e)?(this._emitChars("<"),this.state=B.SCRIPT_DATA_DOUBLE_ESCAPE_START,this._stateScriptDataDoubleEscapeStart(e)):(this._emitChars("<"),this.state=B.SCRIPT_DATA_ESCAPED,this._stateScriptDataEscaped(e))}_stateScriptDataEscapedEndTagOpen(e){Js(e)?(this.state=B.SCRIPT_DATA_ESCAPED_END_TAG_NAME,this._stateScriptDataEscapedEndTagName(e)):(this._emitChars("");break}case L.NULL:{this._err(fe.unexpectedNullCharacter),this.state=B.SCRIPT_DATA_DOUBLE_ESCAPED,this._emitChars(cn);break}case L.EOF:{this._err(fe.eofInScriptHtmlCommentLikeText),this._emitEOFToken();break}default:this.state=B.SCRIPT_DATA_DOUBLE_ESCAPED,this._emitCodePoint(e)}}_stateScriptDataDoubleEscapedLessThanSign(e){e===L.SOLIDUS?(this.state=B.SCRIPT_DATA_DOUBLE_ESCAPE_END,this._emitChars("/")):(this.state=B.SCRIPT_DATA_DOUBLE_ESCAPED,this._stateScriptDataDoubleEscaped(e))}_stateScriptDataDoubleEscapeEnd(e){if(this.preprocessor.startsWith(Ar.SCRIPT,!1)&&vT(this.preprocessor.peek(Ar.SCRIPT.length))){this._emitCodePoint(e);for(let n=0;n0&&this._isInTemplate()&&this.tmplCount--,this.stackTop--,this._updateCurrentElement(),this.handler.onItemPop(e,!0)}replace(e,n){const r=this._indexOf(e);this.items[r]=n,r===this.stackTop&&(this.current=n)}insertAfter(e,n,r){const i=this._indexOf(e)+1;this.items.splice(i,0,n),this.tagIDs.splice(i,0,r),this.stackTop++,i===this.stackTop&&this._updateCurrentElement(),this.current&&this.currentTagId!==void 0&&this.handler.onItemPush(this.current,this.currentTagId,i===this.stackTop)}popUntilTagNamePopped(e){let n=this.stackTop+1;do n=this.tagIDs.lastIndexOf(e,n-1);while(n>0&&this.treeAdapter.getNamespaceURI(this.items[n])!==be.HTML);this.shortenToLength(Math.max(n,0))}shortenToLength(e){for(;this.stackTop>=e;){const n=this.current;this.tmplCount>0&&this._isInTemplate()&&(this.tmplCount-=1),this.stackTop--,this._updateCurrentElement(),this.handler.onItemPop(n,this.stackTop=0;r--)if(e.has(this.tagIDs[r])&&this.treeAdapter.getNamespaceURI(this.items[r])===n)return r;return-1}clearBackTo(e,n){const r=this._indexOfTagNames(e,n);this.shortenToLength(r+1)}clearBackToTableContext(){this.clearBackTo(R$,be.HTML)}clearBackToTableBodyContext(){this.clearBackTo(N$,be.HTML)}clearBackToTableRowContext(){this.clearBackTo(k$,be.HTML)}remove(e){const n=this._indexOf(e);n>=0&&(n===this.stackTop?this.pop():(this.items.splice(n,1),this.tagIDs.splice(n,1),this.stackTop--,this._updateCurrentElement(),this.handler.onItemPop(e,!1)))}tryPeekProperlyNestedBodyElement(){return this.stackTop>=1&&this.tagIDs[1]===E.BODY?this.items[1]:null}contains(e){return this._indexOf(e)>-1}getCommonAncestor(e){const n=this._indexOf(e)-1;return n>=0?this.items[n]:null}isRootHtmlElementCurrent(){return this.stackTop===0&&this.tagIDs[0]===E.HTML}hasInDynamicScope(e,n){for(let r=this.stackTop;r>=0;r--){const i=this.tagIDs[r];switch(this.treeAdapter.getNamespaceURI(this.items[r])){case be.HTML:{if(i===e)return!0;if(n.has(i))return!1;break}case be.SVG:{if(ST.has(i))return!1;break}case be.MATHML:{if(TT.has(i))return!1;break}}}return!0}hasInScope(e){return this.hasInDynamicScope(e,ph)}hasInListItemScope(e){return this.hasInDynamicScope(e,C$)}hasInButtonScope(e){return this.hasInDynamicScope(e,A$)}hasNumberedHeaderInScope(){for(let e=this.stackTop;e>=0;e--){const n=this.tagIDs[e];switch(this.treeAdapter.getNamespaceURI(this.items[e])){case be.HTML:{if(ab.has(n))return!0;if(ph.has(n))return!1;break}case be.SVG:{if(ST.has(n))return!1;break}case be.MATHML:{if(TT.has(n))return!1;break}}}return!0}hasInTableScope(e){for(let n=this.stackTop;n>=0;n--)if(this.treeAdapter.getNamespaceURI(this.items[n])===be.HTML)switch(this.tagIDs[n]){case e:return!0;case E.TABLE:case E.HTML:return!1}return!0}hasTableBodyContextInTableScope(){for(let e=this.stackTop;e>=0;e--)if(this.treeAdapter.getNamespaceURI(this.items[e])===be.HTML)switch(this.tagIDs[e]){case E.TBODY:case E.THEAD:case E.TFOOT:return!0;case E.TABLE:case E.HTML:return!1}return!0}hasInSelectScope(e){for(let n=this.stackTop;n>=0;n--)if(this.treeAdapter.getNamespaceURI(this.items[n])===be.HTML)switch(this.tagIDs[n]){case e:return!0;case E.OPTION:case E.OPTGROUP:break;default:return!1}return!0}generateImpliedEndTags(){for(;this.currentTagId!==void 0&&FN.has(this.currentTagId);)this.pop()}generateImpliedEndTagsThoroughly(){for(;this.currentTagId!==void 0&&wT.has(this.currentTagId);)this.pop()}generateImpliedEndTagsWithExclusion(e){for(;this.currentTagId!==void 0&&this.currentTagId!==e&&wT.has(this.currentTagId);)this.pop()}}const r0=3;var zi;(function(t){t[t.Marker=0]="Marker",t[t.Element=1]="Element"})(zi||(zi={}));const _T={type:zi.Marker};class M${constructor(e){this.treeAdapter=e,this.entries=[],this.bookmark=null}_getNoahArkConditionCandidates(e,n){const r=[],i=n.length,s=this.treeAdapter.getTagName(e),o=this.treeAdapter.getNamespaceURI(e);for(let l=0;l[o.name,o.value]));let s=0;for(let o=0;oi.get(c.name)===c.value)&&(s+=1,s>=r0&&this.entries.splice(l.idx,1))}}insertMarker(){this.entries.unshift(_T)}pushElement(e,n){this._ensureNoahArkCondition(e),this.entries.unshift({type:zi.Element,element:e,token:n})}insertElementAfterBookmark(e,n){const r=this.entries.indexOf(this.bookmark);this.entries.splice(r,0,{type:zi.Element,element:e,token:n})}removeEntry(e){const n=this.entries.indexOf(e);n!==-1&&this.entries.splice(n,1)}clearToLastMarker(){const e=this.entries.indexOf(_T);e===-1?this.entries.length=0:this.entries.splice(0,e+1)}getElementEntryInScopeWithTagName(e){const n=this.entries.find(r=>r.type===zi.Marker||this.treeAdapter.getTagName(r.element)===e);return n&&n.type===zi.Element?n:null}getElementEntry(e){return this.entries.find(n=>n.type===zi.Element&&n.element===e)}}const eo={createDocument(){return{nodeName:"#document",mode:ni.NO_QUIRKS,childNodes:[]}},createDocumentFragment(){return{nodeName:"#document-fragment",childNodes:[]}},createElement(t,e,n){return{nodeName:t,tagName:t,attrs:n,namespaceURI:e,childNodes:[],parentNode:null}},createCommentNode(t){return{nodeName:"#comment",data:t,parentNode:null}},createTextNode(t){return{nodeName:"#text",value:t,parentNode:null}},appendChild(t,e){t.childNodes.push(e),e.parentNode=t},insertBefore(t,e,n){const r=t.childNodes.indexOf(n);t.childNodes.splice(r,0,e),e.parentNode=t},setTemplateContent(t,e){t.content=e},getTemplateContent(t){return t.content},setDocumentType(t,e,n,r){const i=t.childNodes.find(s=>s.nodeName==="#documentType");if(i)i.name=e,i.publicId=n,i.systemId=r;else{const s={nodeName:"#documentType",name:e,publicId:n,systemId:r,parentNode:null};eo.appendChild(t,s)}},setDocumentMode(t,e){t.mode=e},getDocumentMode(t){return t.mode},detachNode(t){if(t.parentNode){const e=t.parentNode.childNodes.indexOf(t);t.parentNode.childNodes.splice(e,1),t.parentNode=null}},insertText(t,e){if(t.childNodes.length>0){const n=t.childNodes[t.childNodes.length-1];if(eo.isTextNode(n)){n.value+=e;return}}eo.appendChild(t,eo.createTextNode(e))},insertTextBefore(t,e,n){const r=t.childNodes[t.childNodes.indexOf(n)-1];r&&eo.isTextNode(r)?r.value+=e:eo.insertBefore(t,eo.createTextNode(e),n)},adoptAttributes(t,e){const n=new Set(t.attrs.map(r=>r.name));for(let r=0;rt.startsWith(n))}function U$(t){return t.name===BN&&t.publicId===null&&(t.systemId===null||t.systemId===D$)}function H$(t){if(t.name!==BN)return ni.QUIRKS;const{systemId:e}=t;if(e&&e.toLowerCase()===L$)return ni.QUIRKS;let{publicId:n}=t;if(n!==null){if(n=n.toLowerCase(),F$.has(n))return ni.QUIRKS;let r=e===null?P$:UN;if(CT(n,r))return ni.QUIRKS;if(r=e===null?HN:B$,CT(n,r))return ni.LIMITED_QUIRKS}return ni.NO_QUIRKS}const AT={TEXT_HTML:"text/html",APPLICATION_XML:"application/xhtml+xml"},z$="definitionurl",j$="definitionURL",$$=new Map(["attributeName","attributeType","baseFrequency","baseProfile","calcMode","clipPathUnits","diffuseConstant","edgeMode","filterUnits","glyphRef","gradientTransform","gradientUnits","kernelMatrix","kernelUnitLength","keyPoints","keySplines","keyTimes","lengthAdjust","limitingConeAngle","markerHeight","markerUnits","markerWidth","maskContentUnits","maskUnits","numOctaves","pathLength","patternContentUnits","patternTransform","patternUnits","pointsAtX","pointsAtY","pointsAtZ","preserveAlpha","preserveAspectRatio","primitiveUnits","refX","refY","repeatCount","repeatDur","requiredExtensions","requiredFeatures","specularConstant","specularExponent","spreadMethod","startOffset","stdDeviation","stitchTiles","surfaceScale","systemLanguage","tableValues","targetX","targetY","textLength","viewBox","viewTarget","xChannelSelector","yChannelSelector","zoomAndPan"].map(t=>[t.toLowerCase(),t])),W$=new Map([["xlink:actuate",{prefix:"xlink",name:"actuate",namespace:be.XLINK}],["xlink:arcrole",{prefix:"xlink",name:"arcrole",namespace:be.XLINK}],["xlink:href",{prefix:"xlink",name:"href",namespace:be.XLINK}],["xlink:role",{prefix:"xlink",name:"role",namespace:be.XLINK}],["xlink:show",{prefix:"xlink",name:"show",namespace:be.XLINK}],["xlink:title",{prefix:"xlink",name:"title",namespace:be.XLINK}],["xlink:type",{prefix:"xlink",name:"type",namespace:be.XLINK}],["xml:lang",{prefix:"xml",name:"lang",namespace:be.XML}],["xml:space",{prefix:"xml",name:"space",namespace:be.XML}],["xmlns",{prefix:"",name:"xmlns",namespace:be.XMLNS}],["xmlns:xlink",{prefix:"xmlns",name:"xlink",namespace:be.XMLNS}]]),V$=new Map(["altGlyph","altGlyphDef","altGlyphItem","animateColor","animateMotion","animateTransform","clipPath","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","foreignObject","glyphRef","linearGradient","radialGradient","textPath"].map(t=>[t.toLowerCase(),t])),G$=new Set([E.B,E.BIG,E.BLOCKQUOTE,E.BODY,E.BR,E.CENTER,E.CODE,E.DD,E.DIV,E.DL,E.DT,E.EM,E.EMBED,E.H1,E.H2,E.H3,E.H4,E.H5,E.H6,E.HEAD,E.HR,E.I,E.IMG,E.LI,E.LISTING,E.MENU,E.META,E.NOBR,E.OL,E.P,E.PRE,E.RUBY,E.S,E.SMALL,E.SPAN,E.STRONG,E.STRIKE,E.SUB,E.SUP,E.TABLE,E.TT,E.U,E.UL,E.VAR]);function K$(t){const e=t.tagID;return e===E.FONT&&t.attrs.some(({name:r})=>r===Wo.COLOR||r===Wo.SIZE||r===Wo.FACE)||G$.has(e)}function zN(t){for(let e=0;e0&&this._setContextModes(e,n)}onItemPop(e,n){var r,i;if(this.options.sourceCodeLocationInfo&&this._setEndLocation(e,this.currentToken),(i=(r=this.treeAdapter).onItemPop)===null||i===void 0||i.call(r,e,this.openElements.current),n){let s,o;this.openElements.stackTop===0&&this.fragmentContext?(s=this.fragmentContext,o=this.fragmentContextID):{current:s,currentTagId:o}=this.openElements,this._setContextModes(s,o)}}_setContextModes(e,n){const r=e===this.document||e&&this.treeAdapter.getNamespaceURI(e)===be.HTML;this.currentNotInHTML=!r,this.tokenizer.inForeignNode=!r&&e!==void 0&&n!==void 0&&!this._isIntegrationPoint(n,e)}_switchToTextParsing(e,n){this._insertElement(e,be.HTML),this.tokenizer.state=n,this.originalInsertionMode=this.insertionMode,this.insertionMode=$.TEXT}switchToPlaintextParsing(){this.insertionMode=$.TEXT,this.originalInsertionMode=$.IN_BODY,this.tokenizer.state=_n.PLAINTEXT}_getAdjustedCurrentElement(){return this.openElements.stackTop===0&&this.fragmentContext?this.fragmentContext:this.openElements.current}_findFormInFragmentContext(){let e=this.fragmentContext;for(;e;){if(this.treeAdapter.getTagName(e)===re.FORM){this.formElement=e;break}e=this.treeAdapter.getParentNode(e)}}_initTokenizerForFragmentParsing(){if(!(!this.fragmentContext||this.treeAdapter.getNamespaceURI(this.fragmentContext)!==be.HTML))switch(this.fragmentContextID){case E.TITLE:case E.TEXTAREA:{this.tokenizer.state=_n.RCDATA;break}case E.STYLE:case E.XMP:case E.IFRAME:case E.NOEMBED:case E.NOFRAMES:case E.NOSCRIPT:{this.tokenizer.state=_n.RAWTEXT;break}case E.SCRIPT:{this.tokenizer.state=_n.SCRIPT_DATA;break}case E.PLAINTEXT:{this.tokenizer.state=_n.PLAINTEXT;break}}}_setDocumentType(e){const n=e.name||"",r=e.publicId||"",i=e.systemId||"";if(this.treeAdapter.setDocumentType(this.document,n,r,i),e.location){const o=this.treeAdapter.getChildNodes(this.document).find(l=>this.treeAdapter.isDocumentTypeNode(l));o&&this.treeAdapter.setNodeSourceCodeLocation(o,e.location)}}_attachElementToTree(e,n){if(this.options.sourceCodeLocationInfo){const r=n&&{...n,startTag:n};this.treeAdapter.setNodeSourceCodeLocation(e,r)}if(this._shouldFosterParentOnInsertion())this._fosterParentElement(e);else{const r=this.openElements.currentTmplContentOrNode;this.treeAdapter.appendChild(r??this.document,e)}}_appendElement(e,n){const r=this.treeAdapter.createElement(e.tagName,n,e.attrs);this._attachElementToTree(r,e.location)}_insertElement(e,n){const r=this.treeAdapter.createElement(e.tagName,n,e.attrs);this._attachElementToTree(r,e.location),this.openElements.push(r,e.tagID)}_insertFakeElement(e,n){const r=this.treeAdapter.createElement(e,be.HTML,[]);this._attachElementToTree(r,null),this.openElements.push(r,n)}_insertTemplate(e){const n=this.treeAdapter.createElement(e.tagName,be.HTML,e.attrs),r=this.treeAdapter.createDocumentFragment();this.treeAdapter.setTemplateContent(n,r),this._attachElementToTree(n,e.location),this.openElements.push(n,e.tagID),this.options.sourceCodeLocationInfo&&this.treeAdapter.setNodeSourceCodeLocation(r,null)}_insertFakeRootElement(){const e=this.treeAdapter.createElement(re.HTML,be.HTML,[]);this.options.sourceCodeLocationInfo&&this.treeAdapter.setNodeSourceCodeLocation(e,null),this.treeAdapter.appendChild(this.openElements.current,e),this.openElements.push(e,E.HTML)}_appendCommentNode(e,n){const r=this.treeAdapter.createCommentNode(e.data);this.treeAdapter.appendChild(n,r),this.options.sourceCodeLocationInfo&&this.treeAdapter.setNodeSourceCodeLocation(r,e.location)}_insertCharacters(e){let n,r;if(this._shouldFosterParentOnInsertion()?({parent:n,beforeElement:r}=this._findFosterParentingLocation(),r?this.treeAdapter.insertTextBefore(n,e.chars,r):this.treeAdapter.insertText(n,e.chars)):(n=this.openElements.currentTmplContentOrNode,this.treeAdapter.insertText(n,e.chars)),!e.location)return;const i=this.treeAdapter.getChildNodes(n),s=r?i.lastIndexOf(r):i.length,o=i[s-1];if(this.treeAdapter.getNodeSourceCodeLocation(o)){const{endLine:c,endCol:d,endOffset:f}=e.location;this.treeAdapter.updateNodeSourceCodeLocation(o,{endLine:c,endCol:d,endOffset:f})}else this.options.sourceCodeLocationInfo&&this.treeAdapter.setNodeSourceCodeLocation(o,e.location)}_adoptNodes(e,n){for(let r=this.treeAdapter.getFirstChild(e);r;r=this.treeAdapter.getFirstChild(e))this.treeAdapter.detachNode(r),this.treeAdapter.appendChild(n,r)}_setEndLocation(e,n){if(this.treeAdapter.getNodeSourceCodeLocation(e)&&n.location){const r=n.location,i=this.treeAdapter.getTagName(e),s=n.type===yt.END_TAG&&i===n.tagName?{endTag:{...r},endLine:r.endLine,endCol:r.endCol,endOffset:r.endOffset}:{endLine:r.startLine,endCol:r.startCol,endOffset:r.startOffset};this.treeAdapter.updateNodeSourceCodeLocation(e,s)}}shouldProcessStartTagTokenInForeignContent(e){if(!this.currentNotInHTML)return!1;let n,r;return this.openElements.stackTop===0&&this.fragmentContext?(n=this.fragmentContext,r=this.fragmentContextID):{current:n,currentTagId:r}=this.openElements,e.tagID===E.SVG&&this.treeAdapter.getTagName(n)===re.ANNOTATION_XML&&this.treeAdapter.getNamespaceURI(n)===be.MATHML?!1:this.tokenizer.inForeignNode||(e.tagID===E.MGLYPH||e.tagID===E.MALIGNMARK)&&r!==void 0&&!this._isIntegrationPoint(r,n,be.HTML)}_processToken(e){switch(e.type){case yt.CHARACTER:{this.onCharacter(e);break}case yt.NULL_CHARACTER:{this.onNullCharacter(e);break}case yt.COMMENT:{this.onComment(e);break}case yt.DOCTYPE:{this.onDoctype(e);break}case yt.START_TAG:{this._processStartTag(e);break}case yt.END_TAG:{this.onEndTag(e);break}case yt.EOF:{this.onEof(e);break}case yt.WHITESPACE_CHARACTER:{this.onWhitespaceCharacter(e);break}}}_isIntegrationPoint(e,n,r){const i=this.treeAdapter.getNamespaceURI(n),s=this.treeAdapter.getAttrList(n);return Q$(e,i,s,r)}_reconstructActiveFormattingElements(){const e=this.activeFormattingElements.entries.length;if(e){const n=this.activeFormattingElements.entries.findIndex(i=>i.type===zi.Marker||this.openElements.contains(i.element)),r=n===-1?e-1:n-1;for(let i=r;i>=0;i--){const s=this.activeFormattingElements.entries[i];this._insertElement(s.token,this.treeAdapter.getNamespaceURI(s.element)),s.element=this.openElements.current}}}_closeTableCell(){this.openElements.generateImpliedEndTags(),this.openElements.popUntilTableCellPopped(),this.activeFormattingElements.clearToLastMarker(),this.insertionMode=$.IN_ROW}_closePElement(){this.openElements.generateImpliedEndTagsWithExclusion(E.P),this.openElements.popUntilTagNamePopped(E.P)}_resetInsertionMode(){for(let e=this.openElements.stackTop;e>=0;e--)switch(e===0&&this.fragmentContext?this.fragmentContextID:this.openElements.tagIDs[e]){case E.TR:{this.insertionMode=$.IN_ROW;return}case E.TBODY:case E.THEAD:case E.TFOOT:{this.insertionMode=$.IN_TABLE_BODY;return}case E.CAPTION:{this.insertionMode=$.IN_CAPTION;return}case E.COLGROUP:{this.insertionMode=$.IN_COLUMN_GROUP;return}case E.TABLE:{this.insertionMode=$.IN_TABLE;return}case E.BODY:{this.insertionMode=$.IN_BODY;return}case E.FRAMESET:{this.insertionMode=$.IN_FRAMESET;return}case E.SELECT:{this._resetInsertionModeForSelect(e);return}case E.TEMPLATE:{this.insertionMode=this.tmplInsertionModeStack[0];return}case E.HTML:{this.insertionMode=this.headElement?$.AFTER_HEAD:$.BEFORE_HEAD;return}case E.TD:case E.TH:{if(e>0){this.insertionMode=$.IN_CELL;return}break}case E.HEAD:{if(e>0){this.insertionMode=$.IN_HEAD;return}break}}this.insertionMode=$.IN_BODY}_resetInsertionModeForSelect(e){if(e>0)for(let n=e-1;n>0;n--){const r=this.openElements.tagIDs[n];if(r===E.TEMPLATE)break;if(r===E.TABLE){this.insertionMode=$.IN_SELECT_IN_TABLE;return}}this.insertionMode=$.IN_SELECT}_isElementCausesFosterParenting(e){return $N.has(e)}_shouldFosterParentOnInsertion(){return this.fosterParentingEnabled&&this.openElements.currentTagId!==void 0&&this._isElementCausesFosterParenting(this.openElements.currentTagId)}_findFosterParentingLocation(){for(let e=this.openElements.stackTop;e>=0;e--){const n=this.openElements.items[e];switch(this.openElements.tagIDs[e]){case E.TEMPLATE:{if(this.treeAdapter.getNamespaceURI(n)===be.HTML)return{parent:this.treeAdapter.getTemplateContent(n),beforeElement:null};break}case E.TABLE:{const r=this.treeAdapter.getParentNode(n);return r?{parent:r,beforeElement:n}:{parent:this.openElements.items[e-1],beforeElement:null}}}}return{parent:this.openElements.items[0],beforeElement:null}}_fosterParentElement(e){const n=this._findFosterParentingLocation();n.beforeElement?this.treeAdapter.insertBefore(n.parent,e,n.beforeElement):this.treeAdapter.appendChild(n.parent,e)}_isSpecialElement(e,n){const r=this.treeAdapter.getNamespaceURI(e);return v$[r].has(n)}onCharacter(e){if(this.skipNextNewLine=!1,this.tokenizer.inForeignNode){IV(this,e);return}switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}case $.BEFORE_HTML:{qu(this,e);break}case $.BEFORE_HEAD:{Xu(this,e);break}case $.IN_HEAD:{Qu(this,e);break}case $.IN_HEAD_NO_SCRIPT:{Zu(this,e);break}case $.AFTER_HEAD:{Ju(this,e);break}case $.IN_BODY:case $.IN_CAPTION:case $.IN_CELL:case $.IN_TEMPLATE:{VN(this,e);break}case $.TEXT:case $.IN_SELECT:case $.IN_SELECT_IN_TABLE:{this._insertCharacters(e);break}case $.IN_TABLE:case $.IN_TABLE_BODY:case $.IN_ROW:{i0(this,e);break}case $.IN_TABLE_TEXT:{QN(this,e);break}case $.IN_COLUMN_GROUP:{mh(this,e);break}case $.AFTER_BODY:{gh(this,e);break}case $.AFTER_AFTER_BODY:{Hf(this,e);break}}}onNullCharacter(e){if(this.skipNextNewLine=!1,this.tokenizer.inForeignNode){RV(this,e);return}switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}case $.BEFORE_HTML:{qu(this,e);break}case $.BEFORE_HEAD:{Xu(this,e);break}case $.IN_HEAD:{Qu(this,e);break}case $.IN_HEAD_NO_SCRIPT:{Zu(this,e);break}case $.AFTER_HEAD:{Ju(this,e);break}case $.TEXT:{this._insertCharacters(e);break}case $.IN_TABLE:case $.IN_TABLE_BODY:case $.IN_ROW:{i0(this,e);break}case $.IN_COLUMN_GROUP:{mh(this,e);break}case $.AFTER_BODY:{gh(this,e);break}case $.AFTER_AFTER_BODY:{Hf(this,e);break}}}onComment(e){if(this.skipNextNewLine=!1,this.currentNotInHTML){lb(this,e);return}switch(this.insertionMode){case $.INITIAL:case $.BEFORE_HTML:case $.BEFORE_HEAD:case $.IN_HEAD:case $.IN_HEAD_NO_SCRIPT:case $.AFTER_HEAD:case $.IN_BODY:case $.IN_TABLE:case $.IN_CAPTION:case $.IN_COLUMN_GROUP:case $.IN_TABLE_BODY:case $.IN_ROW:case $.IN_CELL:case $.IN_SELECT:case $.IN_SELECT_IN_TABLE:case $.IN_TEMPLATE:case $.IN_FRAMESET:case $.AFTER_FRAMESET:{lb(this,e);break}case $.IN_TABLE_TEXT:{Du(this,e);break}case $.AFTER_BODY:{lW(this,e);break}case $.AFTER_AFTER_BODY:case $.AFTER_AFTER_FRAMESET:{uW(this,e);break}}}onDoctype(e){switch(this.skipNextNewLine=!1,this.insertionMode){case $.INITIAL:{cW(this,e);break}case $.BEFORE_HEAD:case $.IN_HEAD:case $.IN_HEAD_NO_SCRIPT:case $.AFTER_HEAD:{this._err(e,fe.misplacedDoctype);break}case $.IN_TABLE_TEXT:{Du(this,e);break}}}onStartTag(e){this.skipNextNewLine=!1,this.currentToken=e,this._processStartTag(e),e.selfClosing&&!e.ackSelfClosing&&this._err(e,fe.nonVoidHtmlElementStartTagWithTrailingSolidus)}_processStartTag(e){this.shouldProcessStartTagTokenInForeignContent(e)?OV(this,e):this._startTagOutsideForeignContent(e)}_startTagOutsideForeignContent(e){switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}case $.BEFORE_HTML:{dW(this,e);break}case $.BEFORE_HEAD:{hW(this,e);break}case $.IN_HEAD:{Ni(this,e);break}case $.IN_HEAD_NO_SCRIPT:{gW(this,e);break}case $.AFTER_HEAD:{EW(this,e);break}case $.IN_BODY:{cr(this,e);break}case $.IN_TABLE:{yl(this,e);break}case $.IN_TABLE_TEXT:{Du(this,e);break}case $.IN_CAPTION:{pV(this,e);break}case $.IN_COLUMN_GROUP:{f1(this,e);break}case $.IN_TABLE_BODY:{hp(this,e);break}case $.IN_ROW:{pp(this,e);break}case $.IN_CELL:{bV(this,e);break}case $.IN_SELECT:{e2(this,e);break}case $.IN_SELECT_IN_TABLE:{yV(this,e);break}case $.IN_TEMPLATE:{vV(this,e);break}case $.AFTER_BODY:{TV(this,e);break}case $.IN_FRAMESET:{SV(this,e);break}case $.AFTER_FRAMESET:{CV(this,e);break}case $.AFTER_AFTER_BODY:{kV(this,e);break}case $.AFTER_AFTER_FRAMESET:{NV(this,e);break}}}onEndTag(e){this.skipNextNewLine=!1,this.currentToken=e,this.currentNotInHTML?MV(this,e):this._endTagOutsideForeignContent(e)}_endTagOutsideForeignContent(e){switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}case $.BEFORE_HTML:{fW(this,e);break}case $.BEFORE_HEAD:{pW(this,e);break}case $.IN_HEAD:{mW(this,e);break}case $.IN_HEAD_NO_SCRIPT:{bW(this,e);break}case $.AFTER_HEAD:{yW(this,e);break}case $.IN_BODY:{fp(this,e);break}case $.TEXT:{iV(this,e);break}case $.IN_TABLE:{mc(this,e);break}case $.IN_TABLE_TEXT:{Du(this,e);break}case $.IN_CAPTION:{mV(this,e);break}case $.IN_COLUMN_GROUP:{gV(this,e);break}case $.IN_TABLE_BODY:{ub(this,e);break}case $.IN_ROW:{JN(this,e);break}case $.IN_CELL:{EV(this,e);break}case $.IN_SELECT:{t2(this,e);break}case $.IN_SELECT_IN_TABLE:{xV(this,e);break}case $.IN_TEMPLATE:{wV(this,e);break}case $.AFTER_BODY:{r2(this,e);break}case $.IN_FRAMESET:{_V(this,e);break}case $.AFTER_FRAMESET:{AV(this,e);break}case $.AFTER_AFTER_BODY:{Hf(this,e);break}}}onEof(e){switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}case $.BEFORE_HTML:{qu(this,e);break}case $.BEFORE_HEAD:{Xu(this,e);break}case $.IN_HEAD:{Qu(this,e);break}case $.IN_HEAD_NO_SCRIPT:{Zu(this,e);break}case $.AFTER_HEAD:{Ju(this,e);break}case $.IN_BODY:case $.IN_TABLE:case $.IN_CAPTION:case $.IN_COLUMN_GROUP:case $.IN_TABLE_BODY:case $.IN_ROW:case $.IN_CELL:case $.IN_SELECT:case $.IN_SELECT_IN_TABLE:{qN(this,e);break}case $.TEXT:{sV(this,e);break}case $.IN_TABLE_TEXT:{Du(this,e);break}case $.IN_TEMPLATE:{n2(this,e);break}case $.AFTER_BODY:case $.IN_FRAMESET:case $.AFTER_FRAMESET:case $.AFTER_AFTER_BODY:case $.AFTER_AFTER_FRAMESET:{d1(this,e);break}}}onWhitespaceCharacter(e){if(this.skipNextNewLine&&(this.skipNextNewLine=!1,e.chars.charCodeAt(0)===L.LINE_FEED)){if(e.chars.length===1)return;e.chars=e.chars.substr(1)}if(this.tokenizer.inForeignNode){this._insertCharacters(e);return}switch(this.insertionMode){case $.IN_HEAD:case $.IN_HEAD_NO_SCRIPT:case $.AFTER_HEAD:case $.TEXT:case $.IN_COLUMN_GROUP:case $.IN_SELECT:case $.IN_SELECT_IN_TABLE:case $.IN_FRAMESET:case $.AFTER_FRAMESET:{this._insertCharacters(e);break}case $.IN_BODY:case $.IN_CAPTION:case $.IN_CELL:case $.IN_TEMPLATE:case $.AFTER_BODY:case $.AFTER_AFTER_BODY:case $.AFTER_AFTER_FRAMESET:{WN(this,e);break}case $.IN_TABLE:case $.IN_TABLE_BODY:case $.IN_ROW:{i0(this,e);break}case $.IN_TABLE_TEXT:{XN(this,e);break}}}}function nW(t,e){let n=t.activeFormattingElements.getElementEntryInScopeWithTagName(e.tagName);return n?t.openElements.contains(n.element)?t.openElements.hasInScope(e.tagID)||(n=null):(t.activeFormattingElements.removeEntry(n),n=null):YN(t,e),n}function rW(t,e){let n=null,r=t.openElements.stackTop;for(;r>=0;r--){const i=t.openElements.items[r];if(i===e.element)break;t._isSpecialElement(i,t.openElements.tagIDs[r])&&(n=i)}return n||(t.openElements.shortenToLength(Math.max(r,0)),t.activeFormattingElements.removeEntry(e)),n}function iW(t,e,n){let r=e,i=t.openElements.getCommonAncestor(e);for(let s=0,o=i;o!==n;s++,o=i){i=t.openElements.getCommonAncestor(o);const l=t.activeFormattingElements.getElementEntry(o),c=l&&s>=eW;!l||c?(c&&t.activeFormattingElements.removeEntry(l),t.openElements.remove(o)):(o=sW(t,l),r===e&&(t.activeFormattingElements.bookmark=l),t.treeAdapter.detachNode(r),t.treeAdapter.appendChild(o,r),r=o)}return r}function sW(t,e){const n=t.treeAdapter.getNamespaceURI(e.element),r=t.treeAdapter.createElement(e.token.tagName,n,e.token.attrs);return t.openElements.replace(e.element,r),e.element=r,r}function oW(t,e,n){const r=t.treeAdapter.getTagName(e),i=Fl(r);if(t._isElementCausesFosterParenting(i))t._fosterParentElement(n);else{const s=t.treeAdapter.getNamespaceURI(e);i===E.TEMPLATE&&s===be.HTML&&(e=t.treeAdapter.getTemplateContent(e)),t.treeAdapter.appendChild(e,n)}}function aW(t,e,n){const r=t.treeAdapter.getNamespaceURI(n.element),{token:i}=n,s=t.treeAdapter.createElement(i.tagName,r,i.attrs);t._adoptNodes(e,s),t.treeAdapter.appendChild(e,s),t.activeFormattingElements.insertElementAfterBookmark(s,i),t.activeFormattingElements.removeEntry(n),t.openElements.remove(n.element),t.openElements.insertAfter(e,s,i.tagID)}function c1(t,e){for(let n=0;n=n;r--)t._setEndLocation(t.openElements.items[r],e);if(!t.fragmentContext&&t.openElements.stackTop>=0){const r=t.openElements.items[0],i=t.treeAdapter.getNodeSourceCodeLocation(r);if(i&&!i.endTag&&(t._setEndLocation(r,e),t.openElements.stackTop>=1)){const s=t.openElements.items[1],o=t.treeAdapter.getNodeSourceCodeLocation(s);o&&!o.endTag&&t._setEndLocation(s,e)}}}}function cW(t,e){t._setDocumentType(e);const n=e.forceQuirks?ni.QUIRKS:H$(e);U$(e)||t._err(e,fe.nonConformingDoctype),t.treeAdapter.setDocumentMode(t.document,n),t.insertionMode=$.BEFORE_HTML}function Mu(t,e){t._err(e,fe.missingDoctype,!0),t.treeAdapter.setDocumentMode(t.document,ni.QUIRKS),t.insertionMode=$.BEFORE_HTML,t._processToken(e)}function dW(t,e){e.tagID===E.HTML?(t._insertElement(e,be.HTML),t.insertionMode=$.BEFORE_HEAD):qu(t,e)}function fW(t,e){const n=e.tagID;(n===E.HTML||n===E.HEAD||n===E.BODY||n===E.BR)&&qu(t,e)}function qu(t,e){t._insertFakeRootElement(),t.insertionMode=$.BEFORE_HEAD,t._processToken(e)}function hW(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.HEAD:{t._insertElement(e,be.HTML),t.headElement=t.openElements.current,t.insertionMode=$.IN_HEAD;break}default:Xu(t,e)}}function pW(t,e){const n=e.tagID;n===E.HEAD||n===E.BODY||n===E.HTML||n===E.BR?Xu(t,e):t._err(e,fe.endTagWithoutMatchingOpenElement)}function Xu(t,e){t._insertFakeElement(re.HEAD,E.HEAD),t.headElement=t.openElements.current,t.insertionMode=$.IN_HEAD,t._processToken(e)}function Ni(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.BASE:case E.BASEFONT:case E.BGSOUND:case E.LINK:case E.META:{t._appendElement(e,be.HTML),e.ackSelfClosing=!0;break}case E.TITLE:{t._switchToTextParsing(e,_n.RCDATA);break}case E.NOSCRIPT:{t.options.scriptingEnabled?t._switchToTextParsing(e,_n.RAWTEXT):(t._insertElement(e,be.HTML),t.insertionMode=$.IN_HEAD_NO_SCRIPT);break}case E.NOFRAMES:case E.STYLE:{t._switchToTextParsing(e,_n.RAWTEXT);break}case E.SCRIPT:{t._switchToTextParsing(e,_n.SCRIPT_DATA);break}case E.TEMPLATE:{t._insertTemplate(e),t.activeFormattingElements.insertMarker(),t.framesetOk=!1,t.insertionMode=$.IN_TEMPLATE,t.tmplInsertionModeStack.unshift($.IN_TEMPLATE);break}case E.HEAD:{t._err(e,fe.misplacedStartTagForHeadElement);break}default:Qu(t,e)}}function mW(t,e){switch(e.tagID){case E.HEAD:{t.openElements.pop(),t.insertionMode=$.AFTER_HEAD;break}case E.BODY:case E.BR:case E.HTML:{Qu(t,e);break}case E.TEMPLATE:{ca(t,e);break}default:t._err(e,fe.endTagWithoutMatchingOpenElement)}}function ca(t,e){t.openElements.tmplCount>0?(t.openElements.generateImpliedEndTagsThoroughly(),t.openElements.currentTagId!==E.TEMPLATE&&t._err(e,fe.closingOfElementWithOpenChildElements),t.openElements.popUntilTagNamePopped(E.TEMPLATE),t.activeFormattingElements.clearToLastMarker(),t.tmplInsertionModeStack.shift(),t._resetInsertionMode()):t._err(e,fe.endTagWithoutMatchingOpenElement)}function Qu(t,e){t.openElements.pop(),t.insertionMode=$.AFTER_HEAD,t._processToken(e)}function gW(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.BASEFONT:case E.BGSOUND:case E.HEAD:case E.LINK:case E.META:case E.NOFRAMES:case E.STYLE:{Ni(t,e);break}case E.NOSCRIPT:{t._err(e,fe.nestedNoscriptInHead);break}default:Zu(t,e)}}function bW(t,e){switch(e.tagID){case E.NOSCRIPT:{t.openElements.pop(),t.insertionMode=$.IN_HEAD;break}case E.BR:{Zu(t,e);break}default:t._err(e,fe.endTagWithoutMatchingOpenElement)}}function Zu(t,e){const n=e.type===yt.EOF?fe.openElementsLeftAfterEof:fe.disallowedContentInNoscriptInHead;t._err(e,n),t.openElements.pop(),t.insertionMode=$.IN_HEAD,t._processToken(e)}function EW(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.BODY:{t._insertElement(e,be.HTML),t.framesetOk=!1,t.insertionMode=$.IN_BODY;break}case E.FRAMESET:{t._insertElement(e,be.HTML),t.insertionMode=$.IN_FRAMESET;break}case E.BASE:case E.BASEFONT:case E.BGSOUND:case E.LINK:case E.META:case E.NOFRAMES:case E.SCRIPT:case E.STYLE:case E.TEMPLATE:case E.TITLE:{t._err(e,fe.abandonedHeadElementChild),t.openElements.push(t.headElement,E.HEAD),Ni(t,e),t.openElements.remove(t.headElement);break}case E.HEAD:{t._err(e,fe.misplacedStartTagForHeadElement);break}default:Ju(t,e)}}function yW(t,e){switch(e.tagID){case E.BODY:case E.HTML:case E.BR:{Ju(t,e);break}case E.TEMPLATE:{ca(t,e);break}default:t._err(e,fe.endTagWithoutMatchingOpenElement)}}function Ju(t,e){t._insertFakeElement(re.BODY,E.BODY),t.insertionMode=$.IN_BODY,dp(t,e)}function dp(t,e){switch(e.type){case yt.CHARACTER:{VN(t,e);break}case yt.WHITESPACE_CHARACTER:{WN(t,e);break}case yt.COMMENT:{lb(t,e);break}case yt.START_TAG:{cr(t,e);break}case yt.END_TAG:{fp(t,e);break}case yt.EOF:{qN(t,e);break}}}function WN(t,e){t._reconstructActiveFormattingElements(),t._insertCharacters(e)}function VN(t,e){t._reconstructActiveFormattingElements(),t._insertCharacters(e),t.framesetOk=!1}function xW(t,e){t.openElements.tmplCount===0&&t.treeAdapter.adoptAttributes(t.openElements.items[0],e.attrs)}function vW(t,e){const n=t.openElements.tryPeekProperlyNestedBodyElement();n&&t.openElements.tmplCount===0&&(t.framesetOk=!1,t.treeAdapter.adoptAttributes(n,e.attrs))}function wW(t,e){const n=t.openElements.tryPeekProperlyNestedBodyElement();t.framesetOk&&n&&(t.treeAdapter.detachNode(n),t.openElements.popAllUpToHtmlElement(),t._insertElement(e,be.HTML),t.insertionMode=$.IN_FRAMESET)}function TW(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML)}function SW(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t.openElements.currentTagId!==void 0&&ab.has(t.openElements.currentTagId)&&t.openElements.pop(),t._insertElement(e,be.HTML)}function _W(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML),t.skipNextNewLine=!0,t.framesetOk=!1}function CW(t,e){const n=t.openElements.tmplCount>0;(!t.formElement||n)&&(t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML),n||(t.formElement=t.openElements.current))}function AW(t,e){t.framesetOk=!1;const n=e.tagID;for(let r=t.openElements.stackTop;r>=0;r--){const i=t.openElements.tagIDs[r];if(n===E.LI&&i===E.LI||(n===E.DD||n===E.DT)&&(i===E.DD||i===E.DT)){t.openElements.generateImpliedEndTagsWithExclusion(i),t.openElements.popUntilTagNamePopped(i);break}if(i!==E.ADDRESS&&i!==E.DIV&&i!==E.P&&t._isSpecialElement(t.openElements.items[r],i))break}t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML)}function kW(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML),t.tokenizer.state=_n.PLAINTEXT}function NW(t,e){t.openElements.hasInScope(E.BUTTON)&&(t.openElements.generateImpliedEndTags(),t.openElements.popUntilTagNamePopped(E.BUTTON)),t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML),t.framesetOk=!1}function RW(t,e){const n=t.activeFormattingElements.getElementEntryInScopeWithTagName(re.A);n&&(c1(t,e),t.openElements.remove(n.element),t.activeFormattingElements.removeEntry(n)),t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML),t.activeFormattingElements.pushElement(t.openElements.current,e)}function IW(t,e){t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML),t.activeFormattingElements.pushElement(t.openElements.current,e)}function OW(t,e){t._reconstructActiveFormattingElements(),t.openElements.hasInScope(E.NOBR)&&(c1(t,e),t._reconstructActiveFormattingElements()),t._insertElement(e,be.HTML),t.activeFormattingElements.pushElement(t.openElements.current,e)}function MW(t,e){t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML),t.activeFormattingElements.insertMarker(),t.framesetOk=!1}function DW(t,e){t.treeAdapter.getDocumentMode(t.document)!==ni.QUIRKS&&t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._insertElement(e,be.HTML),t.framesetOk=!1,t.insertionMode=$.IN_TABLE}function GN(t,e){t._reconstructActiveFormattingElements(),t._appendElement(e,be.HTML),t.framesetOk=!1,e.ackSelfClosing=!0}function KN(t){const e=LN(t,Wo.TYPE);return e!=null&&e.toLowerCase()===Z$}function LW(t,e){t._reconstructActiveFormattingElements(),t._appendElement(e,be.HTML),KN(e)||(t.framesetOk=!1),e.ackSelfClosing=!0}function PW(t,e){t._appendElement(e,be.HTML),e.ackSelfClosing=!0}function FW(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._appendElement(e,be.HTML),t.framesetOk=!1,e.ackSelfClosing=!0}function BW(t,e){e.tagName=re.IMG,e.tagID=E.IMG,GN(t,e)}function UW(t,e){t._insertElement(e,be.HTML),t.skipNextNewLine=!0,t.tokenizer.state=_n.RCDATA,t.originalInsertionMode=t.insertionMode,t.framesetOk=!1,t.insertionMode=$.TEXT}function HW(t,e){t.openElements.hasInButtonScope(E.P)&&t._closePElement(),t._reconstructActiveFormattingElements(),t.framesetOk=!1,t._switchToTextParsing(e,_n.RAWTEXT)}function zW(t,e){t.framesetOk=!1,t._switchToTextParsing(e,_n.RAWTEXT)}function RT(t,e){t._switchToTextParsing(e,_n.RAWTEXT)}function jW(t,e){t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML),t.framesetOk=!1,t.insertionMode=t.insertionMode===$.IN_TABLE||t.insertionMode===$.IN_CAPTION||t.insertionMode===$.IN_TABLE_BODY||t.insertionMode===$.IN_ROW||t.insertionMode===$.IN_CELL?$.IN_SELECT_IN_TABLE:$.IN_SELECT}function $W(t,e){t.openElements.currentTagId===E.OPTION&&t.openElements.pop(),t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML)}function WW(t,e){t.openElements.hasInScope(E.RUBY)&&t.openElements.generateImpliedEndTags(),t._insertElement(e,be.HTML)}function VW(t,e){t.openElements.hasInScope(E.RUBY)&&t.openElements.generateImpliedEndTagsWithExclusion(E.RTC),t._insertElement(e,be.HTML)}function GW(t,e){t._reconstructActiveFormattingElements(),zN(e),u1(e),e.selfClosing?t._appendElement(e,be.MATHML):t._insertElement(e,be.MATHML),e.ackSelfClosing=!0}function KW(t,e){t._reconstructActiveFormattingElements(),jN(e),u1(e),e.selfClosing?t._appendElement(e,be.SVG):t._insertElement(e,be.SVG),e.ackSelfClosing=!0}function IT(t,e){t._reconstructActiveFormattingElements(),t._insertElement(e,be.HTML)}function cr(t,e){switch(e.tagID){case E.I:case E.S:case E.B:case E.U:case E.EM:case E.TT:case E.BIG:case E.CODE:case E.FONT:case E.SMALL:case E.STRIKE:case E.STRONG:{IW(t,e);break}case E.A:{RW(t,e);break}case E.H1:case E.H2:case E.H3:case E.H4:case E.H5:case E.H6:{SW(t,e);break}case E.P:case E.DL:case E.OL:case E.UL:case E.DIV:case E.DIR:case E.NAV:case E.MAIN:case E.MENU:case E.ASIDE:case E.CENTER:case E.FIGURE:case E.FOOTER:case E.HEADER:case E.HGROUP:case E.DIALOG:case E.DETAILS:case E.ADDRESS:case E.ARTICLE:case E.SEARCH:case E.SECTION:case E.SUMMARY:case E.FIELDSET:case E.BLOCKQUOTE:case E.FIGCAPTION:{TW(t,e);break}case E.LI:case E.DD:case E.DT:{AW(t,e);break}case E.BR:case E.IMG:case E.WBR:case E.AREA:case E.EMBED:case E.KEYGEN:{GN(t,e);break}case E.HR:{FW(t,e);break}case E.RB:case E.RTC:{WW(t,e);break}case E.RT:case E.RP:{VW(t,e);break}case E.PRE:case E.LISTING:{_W(t,e);break}case E.XMP:{HW(t,e);break}case E.SVG:{KW(t,e);break}case E.HTML:{xW(t,e);break}case E.BASE:case E.LINK:case E.META:case E.STYLE:case E.TITLE:case E.SCRIPT:case E.BGSOUND:case E.BASEFONT:case E.TEMPLATE:{Ni(t,e);break}case E.BODY:{vW(t,e);break}case E.FORM:{CW(t,e);break}case E.NOBR:{OW(t,e);break}case E.MATH:{GW(t,e);break}case E.TABLE:{DW(t,e);break}case E.INPUT:{LW(t,e);break}case E.PARAM:case E.TRACK:case E.SOURCE:{PW(t,e);break}case E.IMAGE:{BW(t,e);break}case E.BUTTON:{NW(t,e);break}case E.APPLET:case E.OBJECT:case E.MARQUEE:{MW(t,e);break}case E.IFRAME:{zW(t,e);break}case E.SELECT:{jW(t,e);break}case E.OPTION:case E.OPTGROUP:{$W(t,e);break}case E.NOEMBED:case E.NOFRAMES:{RT(t,e);break}case E.FRAMESET:{wW(t,e);break}case E.TEXTAREA:{UW(t,e);break}case E.NOSCRIPT:{t.options.scriptingEnabled?RT(t,e):IT(t,e);break}case E.PLAINTEXT:{kW(t,e);break}case E.COL:case E.TH:case E.TD:case E.TR:case E.HEAD:case E.FRAME:case E.TBODY:case E.TFOOT:case E.THEAD:case E.CAPTION:case E.COLGROUP:break;default:IT(t,e)}}function YW(t,e){if(t.openElements.hasInScope(E.BODY)&&(t.insertionMode=$.AFTER_BODY,t.options.sourceCodeLocationInfo)){const n=t.openElements.tryPeekProperlyNestedBodyElement();n&&t._setEndLocation(n,e)}}function qW(t,e){t.openElements.hasInScope(E.BODY)&&(t.insertionMode=$.AFTER_BODY,r2(t,e))}function XW(t,e){const n=e.tagID;t.openElements.hasInScope(n)&&(t.openElements.generateImpliedEndTags(),t.openElements.popUntilTagNamePopped(n))}function QW(t){const e=t.openElements.tmplCount>0,{formElement:n}=t;e||(t.formElement=null),(n||e)&&t.openElements.hasInScope(E.FORM)&&(t.openElements.generateImpliedEndTags(),e?t.openElements.popUntilTagNamePopped(E.FORM):n&&t.openElements.remove(n))}function ZW(t){t.openElements.hasInButtonScope(E.P)||t._insertFakeElement(re.P,E.P),t._closePElement()}function JW(t){t.openElements.hasInListItemScope(E.LI)&&(t.openElements.generateImpliedEndTagsWithExclusion(E.LI),t.openElements.popUntilTagNamePopped(E.LI))}function eV(t,e){const n=e.tagID;t.openElements.hasInScope(n)&&(t.openElements.generateImpliedEndTagsWithExclusion(n),t.openElements.popUntilTagNamePopped(n))}function tV(t){t.openElements.hasNumberedHeaderInScope()&&(t.openElements.generateImpliedEndTags(),t.openElements.popUntilNumberedHeaderPopped())}function nV(t,e){const n=e.tagID;t.openElements.hasInScope(n)&&(t.openElements.generateImpliedEndTags(),t.openElements.popUntilTagNamePopped(n),t.activeFormattingElements.clearToLastMarker())}function rV(t){t._reconstructActiveFormattingElements(),t._insertFakeElement(re.BR,E.BR),t.openElements.pop(),t.framesetOk=!1}function YN(t,e){const n=e.tagName,r=e.tagID;for(let i=t.openElements.stackTop;i>0;i--){const s=t.openElements.items[i],o=t.openElements.tagIDs[i];if(r===o&&(r!==E.UNKNOWN||t.treeAdapter.getTagName(s)===n)){t.openElements.generateImpliedEndTagsWithExclusion(r),t.openElements.stackTop>=i&&t.openElements.shortenToLength(i);break}if(t._isSpecialElement(s,o))break}}function fp(t,e){switch(e.tagID){case E.A:case E.B:case E.I:case E.S:case E.U:case E.EM:case E.TT:case E.BIG:case E.CODE:case E.FONT:case E.NOBR:case E.SMALL:case E.STRIKE:case E.STRONG:{c1(t,e);break}case E.P:{ZW(t);break}case E.DL:case E.UL:case E.OL:case E.DIR:case E.DIV:case E.NAV:case E.PRE:case E.MAIN:case E.MENU:case E.ASIDE:case E.BUTTON:case E.CENTER:case E.FIGURE:case E.FOOTER:case E.HEADER:case E.HGROUP:case E.DIALOG:case E.ADDRESS:case E.ARTICLE:case E.DETAILS:case E.SEARCH:case E.SECTION:case E.SUMMARY:case E.LISTING:case E.FIELDSET:case E.BLOCKQUOTE:case E.FIGCAPTION:{XW(t,e);break}case E.LI:{JW(t);break}case E.DD:case E.DT:{eV(t,e);break}case E.H1:case E.H2:case E.H3:case E.H4:case E.H5:case E.H6:{tV(t);break}case E.BR:{rV(t);break}case E.BODY:{YW(t,e);break}case E.HTML:{qW(t,e);break}case E.FORM:{QW(t);break}case E.APPLET:case E.OBJECT:case E.MARQUEE:{nV(t,e);break}case E.TEMPLATE:{ca(t,e);break}default:YN(t,e)}}function qN(t,e){t.tmplInsertionModeStack.length>0?n2(t,e):d1(t,e)}function iV(t,e){var n;e.tagID===E.SCRIPT&&((n=t.scriptHandler)===null||n===void 0||n.call(t,t.openElements.current)),t.openElements.pop(),t.insertionMode=t.originalInsertionMode}function sV(t,e){t._err(e,fe.eofInElementThatCanContainOnlyText),t.openElements.pop(),t.insertionMode=t.originalInsertionMode,t.onEof(e)}function i0(t,e){if(t.openElements.currentTagId!==void 0&&$N.has(t.openElements.currentTagId))switch(t.pendingCharacterTokens.length=0,t.hasNonWhitespacePendingCharacterToken=!1,t.originalInsertionMode=t.insertionMode,t.insertionMode=$.IN_TABLE_TEXT,e.type){case yt.CHARACTER:{QN(t,e);break}case yt.WHITESPACE_CHARACTER:{XN(t,e);break}}else Uc(t,e)}function oV(t,e){t.openElements.clearBackToTableContext(),t.activeFormattingElements.insertMarker(),t._insertElement(e,be.HTML),t.insertionMode=$.IN_CAPTION}function aV(t,e){t.openElements.clearBackToTableContext(),t._insertElement(e,be.HTML),t.insertionMode=$.IN_COLUMN_GROUP}function lV(t,e){t.openElements.clearBackToTableContext(),t._insertFakeElement(re.COLGROUP,E.COLGROUP),t.insertionMode=$.IN_COLUMN_GROUP,f1(t,e)}function uV(t,e){t.openElements.clearBackToTableContext(),t._insertElement(e,be.HTML),t.insertionMode=$.IN_TABLE_BODY}function cV(t,e){t.openElements.clearBackToTableContext(),t._insertFakeElement(re.TBODY,E.TBODY),t.insertionMode=$.IN_TABLE_BODY,hp(t,e)}function dV(t,e){t.openElements.hasInTableScope(E.TABLE)&&(t.openElements.popUntilTagNamePopped(E.TABLE),t._resetInsertionMode(),t._processStartTag(e))}function fV(t,e){KN(e)?t._appendElement(e,be.HTML):Uc(t,e),e.ackSelfClosing=!0}function hV(t,e){!t.formElement&&t.openElements.tmplCount===0&&(t._insertElement(e,be.HTML),t.formElement=t.openElements.current,t.openElements.pop())}function yl(t,e){switch(e.tagID){case E.TD:case E.TH:case E.TR:{cV(t,e);break}case E.STYLE:case E.SCRIPT:case E.TEMPLATE:{Ni(t,e);break}case E.COL:{lV(t,e);break}case E.FORM:{hV(t,e);break}case E.TABLE:{dV(t,e);break}case E.TBODY:case E.TFOOT:case E.THEAD:{uV(t,e);break}case E.INPUT:{fV(t,e);break}case E.CAPTION:{oV(t,e);break}case E.COLGROUP:{aV(t,e);break}default:Uc(t,e)}}function mc(t,e){switch(e.tagID){case E.TABLE:{t.openElements.hasInTableScope(E.TABLE)&&(t.openElements.popUntilTagNamePopped(E.TABLE),t._resetInsertionMode());break}case E.TEMPLATE:{ca(t,e);break}case E.BODY:case E.CAPTION:case E.COL:case E.COLGROUP:case E.HTML:case E.TBODY:case E.TD:case E.TFOOT:case E.TH:case E.THEAD:case E.TR:break;default:Uc(t,e)}}function Uc(t,e){const n=t.fosterParentingEnabled;t.fosterParentingEnabled=!0,dp(t,e),t.fosterParentingEnabled=n}function XN(t,e){t.pendingCharacterTokens.push(e)}function QN(t,e){t.pendingCharacterTokens.push(e),t.hasNonWhitespacePendingCharacterToken=!0}function Du(t,e){let n=0;if(t.hasNonWhitespacePendingCharacterToken)for(;n0&&t.openElements.currentTagId===E.OPTION&&t.openElements.tagIDs[t.openElements.stackTop-1]===E.OPTGROUP&&t.openElements.pop(),t.openElements.currentTagId===E.OPTGROUP&&t.openElements.pop();break}case E.OPTION:{t.openElements.currentTagId===E.OPTION&&t.openElements.pop();break}case E.SELECT:{t.openElements.hasInSelectScope(E.SELECT)&&(t.openElements.popUntilTagNamePopped(E.SELECT),t._resetInsertionMode());break}case E.TEMPLATE:{ca(t,e);break}}}function yV(t,e){const n=e.tagID;n===E.CAPTION||n===E.TABLE||n===E.TBODY||n===E.TFOOT||n===E.THEAD||n===E.TR||n===E.TD||n===E.TH?(t.openElements.popUntilTagNamePopped(E.SELECT),t._resetInsertionMode(),t._processStartTag(e)):e2(t,e)}function xV(t,e){const n=e.tagID;n===E.CAPTION||n===E.TABLE||n===E.TBODY||n===E.TFOOT||n===E.THEAD||n===E.TR||n===E.TD||n===E.TH?t.openElements.hasInTableScope(n)&&(t.openElements.popUntilTagNamePopped(E.SELECT),t._resetInsertionMode(),t.onEndTag(e)):t2(t,e)}function vV(t,e){switch(e.tagID){case E.BASE:case E.BASEFONT:case E.BGSOUND:case E.LINK:case E.META:case E.NOFRAMES:case E.SCRIPT:case E.STYLE:case E.TEMPLATE:case E.TITLE:{Ni(t,e);break}case E.CAPTION:case E.COLGROUP:case E.TBODY:case E.TFOOT:case E.THEAD:{t.tmplInsertionModeStack[0]=$.IN_TABLE,t.insertionMode=$.IN_TABLE,yl(t,e);break}case E.COL:{t.tmplInsertionModeStack[0]=$.IN_COLUMN_GROUP,t.insertionMode=$.IN_COLUMN_GROUP,f1(t,e);break}case E.TR:{t.tmplInsertionModeStack[0]=$.IN_TABLE_BODY,t.insertionMode=$.IN_TABLE_BODY,hp(t,e);break}case E.TD:case E.TH:{t.tmplInsertionModeStack[0]=$.IN_ROW,t.insertionMode=$.IN_ROW,pp(t,e);break}default:t.tmplInsertionModeStack[0]=$.IN_BODY,t.insertionMode=$.IN_BODY,cr(t,e)}}function wV(t,e){e.tagID===E.TEMPLATE&&ca(t,e)}function n2(t,e){t.openElements.tmplCount>0?(t.openElements.popUntilTagNamePopped(E.TEMPLATE),t.activeFormattingElements.clearToLastMarker(),t.tmplInsertionModeStack.shift(),t._resetInsertionMode(),t.onEof(e)):d1(t,e)}function TV(t,e){e.tagID===E.HTML?cr(t,e):gh(t,e)}function r2(t,e){var n;if(e.tagID===E.HTML){if(t.fragmentContext||(t.insertionMode=$.AFTER_AFTER_BODY),t.options.sourceCodeLocationInfo&&t.openElements.tagIDs[0]===E.HTML){t._setEndLocation(t.openElements.items[0],e);const r=t.openElements.items[1];r&&!(!((n=t.treeAdapter.getNodeSourceCodeLocation(r))===null||n===void 0)&&n.endTag)&&t._setEndLocation(r,e)}}else gh(t,e)}function gh(t,e){t.insertionMode=$.IN_BODY,dp(t,e)}function SV(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.FRAMESET:{t._insertElement(e,be.HTML);break}case E.FRAME:{t._appendElement(e,be.HTML),e.ackSelfClosing=!0;break}case E.NOFRAMES:{Ni(t,e);break}}}function _V(t,e){e.tagID===E.FRAMESET&&!t.openElements.isRootHtmlElementCurrent()&&(t.openElements.pop(),!t.fragmentContext&&t.openElements.currentTagId!==E.FRAMESET&&(t.insertionMode=$.AFTER_FRAMESET))}function CV(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.NOFRAMES:{Ni(t,e);break}}}function AV(t,e){e.tagID===E.HTML&&(t.insertionMode=$.AFTER_AFTER_FRAMESET)}function kV(t,e){e.tagID===E.HTML?cr(t,e):Hf(t,e)}function Hf(t,e){t.insertionMode=$.IN_BODY,dp(t,e)}function NV(t,e){switch(e.tagID){case E.HTML:{cr(t,e);break}case E.NOFRAMES:{Ni(t,e);break}}}function RV(t,e){e.chars=cn,t._insertCharacters(e)}function IV(t,e){t._insertCharacters(e),t.framesetOk=!1}function i2(t){for(;t.treeAdapter.getNamespaceURI(t.openElements.current)!==be.HTML&&t.openElements.currentTagId!==void 0&&!t._isIntegrationPoint(t.openElements.currentTagId,t.openElements.current);)t.openElements.pop()}function OV(t,e){if(K$(e))i2(t),t._startTagOutsideForeignContent(e);else{const n=t._getAdjustedCurrentElement(),r=t.treeAdapter.getNamespaceURI(n);r===be.MATHML?zN(e):r===be.SVG&&(Y$(e),jN(e)),u1(e),e.selfClosing?t._appendElement(e,r):t._insertElement(e,r),e.ackSelfClosing=!0}}function MV(t,e){if(e.tagID===E.P||e.tagID===E.BR){i2(t),t._endTagOutsideForeignContent(e);return}for(let n=t.openElements.stackTop;n>0;n--){const r=t.openElements.items[n];if(t.treeAdapter.getNamespaceURI(r)===be.HTML){t._endTagOutsideForeignContent(e);break}const i=t.treeAdapter.getTagName(r);if(i.toLowerCase()===e.tagName){e.tagName=i,t.openElements.shortenToLength(n);break}}}re.AREA,re.BASE,re.BASEFONT,re.BGSOUND,re.BR,re.COL,re.EMBED,re.FRAME,re.HR,re.IMG,re.INPUT,re.KEYGEN,re.LINK,re.META,re.PARAM,re.SOURCE,re.TRACK,re.WBR;const DV=/<(\/?)(iframe|noembed|noframes|plaintext|script|style|textarea|title|xmp)(?=[\t\n\f\r />])/gi,LV=new Set(["mdxFlowExpression","mdxJsxFlowElement","mdxJsxTextElement","mdxTextExpression","mdxjsEsm"]),OT={sourceCodeLocationInfo:!0,scriptingEnabled:!1};function s2(t,e){const n=VV(t),r=Ok("type",{handlers:{root:PV,element:FV,text:BV,comment:a2,doctype:UV,raw:zV},unknown:jV}),i={parser:n?new NT(OT):NT.getFragmentParser(void 0,OT),handle(l){r(l,i)},stitches:!1,options:e||{}};r(t,i),Bl(i,Ji());const s=n?i.parser.document:i.parser.getFragment(),o=Pj(s,{file:i.options.file});return i.stitches&&Pc(o,"comment",function(l,c,d){const f=l;if(f.value.stitch&&d&&c!==void 0){const p=d.children;return p[c]=f.value.stitch,c}}),o.type==="root"&&o.children.length===1&&o.children[0].type===t.type?o.children[0]:o}function o2(t,e){let n=-1;if(t)for(;++n4&&(e.parser.tokenizer.state=0);const n={type:yt.CHARACTER,chars:t.value,location:Hc(t)};Bl(e,Ji(t)),e.parser.currentToken=n,e.parser._processToken(e.parser.currentToken)}function UV(t,e){const n={type:yt.DOCTYPE,name:"html",forceQuirks:!1,publicId:"",systemId:"",location:Hc(t)};Bl(e,Ji(t)),e.parser.currentToken=n,e.parser._processToken(e.parser.currentToken)}function HV(t,e){e.stitches=!0;const n=GV(t);if("children"in t&&"children"in n){const r=s2({type:"root",children:t.children},e.options);n.children=r.children}a2({type:"comment",value:{stitch:n}},e)}function a2(t,e){const n=t.value,r={type:yt.COMMENT,data:n,location:Hc(t)};Bl(e,Ji(t)),e.parser.currentToken=r,e.parser._processToken(e.parser.currentToken)}function zV(t,e){if(e.parser.tokenizer.preprocessor.html="",e.parser.tokenizer.preprocessor.pos=-1,e.parser.tokenizer.preprocessor.lastGapPos=-2,e.parser.tokenizer.preprocessor.gapStack=[],e.parser.tokenizer.preprocessor.skipNextNewLine=!1,e.parser.tokenizer.preprocessor.lastChunkWritten=!1,e.parser.tokenizer.preprocessor.endOfChunkHit=!1,e.parser.tokenizer.preprocessor.isEol=!1,l2(e,Ji(t)),e.parser.tokenizer.write(e.options.tagfilter?t.value.replace(DV,"<$1$2"):t.value,!1),e.parser.tokenizer._runParsingLoop(),e.parser.tokenizer.state===72||e.parser.tokenizer.state===78){e.parser.tokenizer.preprocessor.lastChunkWritten=!0;const n=e.parser.tokenizer._consume();e.parser.tokenizer._callState(n)}}function jV(t,e){const n=t;if(e.options.passThrough&&e.options.passThrough.includes(n.type))HV(n,e);else{let r="";throw LV.has(n.type)&&(r=". It looks like you are using MDX nodes with `hast-util-raw` (or `rehype-raw`). If you use this because you are using remark or rehype plugins that inject `'html'` nodes, then please raise an issue with that plugin, as its a bad and slow idea. If you use this because you are using markdown syntax, then you have to configure this utility (or plugin) to pass through these nodes (see `passThrough` in docs), but you can also migrate to use the MDX syntax"),new Error("Cannot compile `"+n.type+"` node"+r)}}function Bl(t,e){l2(t,e);const n=t.parser.tokenizer.currentCharacterToken;n&&n.location&&(n.location.endLine=t.parser.tokenizer.preprocessor.line,n.location.endCol=t.parser.tokenizer.preprocessor.col+1,n.location.endOffset=t.parser.tokenizer.preprocessor.offset+1,t.parser.currentToken=n,t.parser._processToken(t.parser.currentToken)),t.parser.tokenizer.paused=!1,t.parser.tokenizer.inLoop=!1,t.parser.tokenizer.active=!1,t.parser.tokenizer.returnState=_n.DATA,t.parser.tokenizer.charRefCode=-1,t.parser.tokenizer.consumedAfterSnapshot=-1,t.parser.tokenizer.currentLocation=null,t.parser.tokenizer.currentCharacterToken=null,t.parser.tokenizer.currentToken=null,t.parser.tokenizer.currentAttr={name:"",value:""}}function l2(t,e){if(e&&e.offset!==void 0){const n={startLine:e.line,startCol:e.column,startOffset:e.offset,endLine:-1,endCol:-1,endOffset:-1};t.parser.tokenizer.preprocessor.lineStartPos=-e.column+1,t.parser.tokenizer.preprocessor.droppedBufferSize=e.offset,t.parser.tokenizer.preprocessor.line=e.line,t.parser.tokenizer.currentLocation=n}}function $V(t,e){const n=t.tagName.toLowerCase();if(e.parser.tokenizer.state===_n.PLAINTEXT)return;Bl(e,Ji(t));const r=e.parser.openElements.current;let i="namespaceURI"in r?r.namespaceURI:Ho.html;i===Ho.html&&n==="svg"&&(i=Ho.svg);const s=Qj({...t,children:[]},{space:i===Ho.svg?"svg":"html"}),o={type:yt.START_TAG,tagName:n,tagID:Fl(n),selfClosing:!1,ackSelfClosing:!1,attrs:"attrs"in s?s.attrs:[],location:Hc(t)};e.parser.currentToken=o,e.parser._processToken(e.parser.currentToken),e.parser.tokenizer.lastStartTagName=n}function WV(t,e){const n=t.tagName.toLowerCase();if(!e.parser.tokenizer.inForeignNode&&s$.includes(n)||e.parser.tokenizer.state===_n.PLAINTEXT)return;Bl(e,op(t));const r={type:yt.END_TAG,tagName:n,tagID:Fl(n),selfClosing:!1,ackSelfClosing:!1,attrs:[],location:Hc(t)};e.parser.currentToken=r,e.parser._processToken(e.parser.currentToken),n===e.parser.tokenizer.lastStartTagName&&(e.parser.tokenizer.state===_n.RCDATA||e.parser.tokenizer.state===_n.RAWTEXT||e.parser.tokenizer.state===_n.SCRIPT_DATA)&&(e.parser.tokenizer.state=_n.DATA)}function VV(t){const e=t.type==="root"?t.children[0]:t;return!!(e&&(e.type==="doctype"||e.type==="element"&&e.tagName.toLowerCase()==="html"))}function Hc(t){const e=Ji(t)||{line:void 0,column:void 0,offset:void 0},n=op(t)||{line:void 0,column:void 0,offset:void 0};return{startLine:e.line,startCol:e.column,startOffset:e.offset,endLine:n.line,endCol:n.column,endOffset:n.offset}}function GV(t){return"children"in t?El({...t,children:[]}):El(t)}function KV(t){return function(e,n){return s2(e,{...t,file:n})}}const YV="_markdown_n2mv1_5",qV={markdown:YV};function XV(t){return t?.replace?.(/\\n/g,` +`)?.replace(/\n(?!-)/g,"
")||t}const u2=({children:t,className:e})=>w.jsx(TU,{components:{p:"div",img:({node:n,...r})=>w.jsx("img",{...r,loading:"lazy",alt:""})},rehypePlugins:[Sj,KV],remarkPlugins:[Pz],className:Xe("leading-[19px]",qV.markdown,e),children:XV(t)}),c2=({events:t,sessionId:e,existingFlagValue:n,onFlag:r})=>{const[i]=lt(ws),[s,o]=T.useState(n||""),l=t?.[0]?.trace_id,c=async()=>{await XD("Parlant-flags","message_flags",l,{sessionId:e,traceId:l,flagValue:s||"This message is flagged"},"update",{name:"sessionIndex",keyPath:"sessionId"}),r?.(s||""),i.closeDialog()},d=async()=>{await QD("Parlant-flags","message_flags",l),r?.(""),i.closeDialog()};return w.jsxs("div",{className:"px-[24px] pb-3 flex flex-col gap-3 h-full",children:[w.jsx("div",{children:w.jsx("p",{className:"text-[16px] text-[#959595]",children:"Feedback provided here will show up in the session's exported CSV file."})}),w.jsx("div",{className:"flex flex-col gap-1 mt-[26px] overflow-auto",children:t.map(f=>w.jsx("div",{className:"message-bubble [&>*]:w-full [&_*]:cursor-default",children:w.jsx("div",{className:"px-[22px] py-[20px] bg-[#F5F9F7] rounded-[22px] mb-[10px] !w-fit max-w-[90%]",children:f?.data?.message})}))}),w.jsx(ip,{autoFocus:!0,placeholder:"Enter your flag reason",value:s,onChange:f=>o(f.target.value),className:"!ring-0 !ring-offset-0 flex-1 !resize-none text-[16px] placeholder:text-[#959595]"}),w.jsxs("div",{className:"flex justify-end gap-3",children:[w.jsx(An,{variant:"outline",onClick:()=>i.closeDialog(),children:"Cancel"}),n&&w.jsx(An,{variant:"outline",onClick:d,children:"Unflag"}),w.jsx(An,{className:"bg-green-main hover:bg-[#005C3F]",onClick:c,children:"Save"})]})]})},QV=({draft:t="",open:e=!1})=>{const[n,r]=T.useState(!1);return T.useEffect(()=>{e&&r(!0)},[e]),w.jsxs("div",{className:Xe("group/main flex !origin-top min-w-full overflow-hidden",!e&&!n&&"h-0 opacity-0",e?"animate-slide-down":n?"animate-slide-up":""),children:[w.jsx("div",{className:"text-gray-400 relative px-[22px] peer/draft py-[20px] bg-[#F5F6F8] rounded-[22px] mb-[16px] max-w-[min(560px,calc(100%-30px))] min-w-[min(560px,100%)]",children:w.jsx(u2,{className:"leading-[26px]",children:t})}),w.jsx("div",{className:Xe("mx-[10px] self-stretch relative invisible items-center flex group-hover/main:visible peer-hover:visible hover:visible"),children:w.jsx(Xn,{value:"Copy",side:"top",children:w.jsx("div",{"data-testid":"copy-button",role:"button",onClick:()=>hl(t||""),className:"group cursor-pointer",children:w.jsx("img",{src:"icons/copy.svg",alt:"edit",className:"block opacity-50 rounded-[10px] group-hover:bg-[#EBECF0] size-[30px] p-[5px]"})})})})]})},ZV=({event:t,isFirstMessageInDate:e,showLogs:n,isContinual:r,showLogsForMessage:i,setIsEditing:s,flagged:o,flaggedChanged:l,sameTraceMessages:c})=>{const d=T.useRef(null),[f]=lt(oa),[p]=lt(np),m=T.useRef(null),[g,x]=T.useState(!1),[,v]=T.useState(1),[S]=lt(ws),[C]=lt(As),A=t?.data?.message||"",k=t?.data?.chunks,M=k!==void 0&&k.length>0&&k[k.length-1]===null,[F,I]=T.useState(M?A.length:0),[D,G]=T.useState(M?A.length:0),X=T.useRef(M?A.length:0),P=T.useRef(null);T.useEffect(()=>{if(!m?.current)return;const oe=Math.floor(m.current.offsetHeight/24);v(oe+1)},[m,g]),T.useEffect(()=>{if(A.length=A.length)return;const oe=30,pe=4,ue=setInterval(()=>{const J=X.current,he=A.length;if(J>=he){clearInterval(ue);return}const _e=Math.min(J+pe,he);X.current=_e,I(_e)},oe);return()=>clearInterval(ue)},[A]);const Y=T.useRef(0);Y.current=F,T.useEffect(()=>{if(FD&&!P.current&&(P.current=setTimeout(()=>{P.current=null,G(Y.current)},400))},[F,D]),T.useEffect(()=>()=>{P.current&&clearTimeout(P.current)},[]);const z=t.source==="customer"||t.source==="customer_ui",ie=t.serverStatus,Z=p?.id==="guest",ee=Z?"G":p?.name?.[0]?.toUpperCase(),ae=i&&i.id===t.id,de=U0((z?p?.id:f?.id)||"",z?"customer":"agent"),j=z?p?.name:f?.name,W=z&&Z?"Guest":j,O=c?.some(oe=>oe.serverStatus&&oe.serverStatus!=="ready"&&oe.serverStatus!=="error"),U=k!==void 0&&(k.length===0||k[k.length-1]!==null),Q=U||k!==void 0&&(F{const oe=d.current?.closest(".messages");if(!oe)return;const{scrollTop:pe,scrollHeight:ue,clientHeight:J}=oe,he=ue-pe-J<150;Q&&d.current&&he?d.current.scrollIntoView({behavior:"smooth",block:"end"}):R.current&&!Q&&he&&oe.scrollTo({top:oe.scrollHeight,behavior:"smooth"}),R.current=Q},[F,Q]),w.jsx(w.Fragment,{children:w.jsx("div",{className:Xe(z?"justify-end":"justify-start","flex-1 flex max-w-[min(1000px,100%)] items-end w-[calc(100%-412px)] max-[1440px]:w-[calc(100%-160px)] max-[900px]:w-[calc(100%-40px)]"),children:w.jsxs("div",{className:"relative max-w-[80%]",children:[(!r||e)&&w.jsxs("div",{className:On("flex items-center mb-[12px] mt-[46px] max-w-[min(560px,100%)]",z&&"justify-self-end",e&&"mt-[0]",z&&"flex-row-reverse"),children:[w.jsxs("div",{className:On("flex items-center contents",z&&"flex-row-reverse"),children:[w.jsx("div",{className:Xe("size-[26px] min-h-[26px] min-w-[26px] flex rounded-[6.5px] select-none items-center justify-center font-semibold",z?"ms-[8px]":"me-[8px]"),style:{color:z?"white":de.text,background:z?de.iconBackground:de?.background},children:(z?ee?.[0]:f?.name?.[0])?.toUpperCase()}),w.jsx("div",{className:"font-medium text-[14px] text-[#282828] truncate",children:W})]}),w.jsxs("div",{className:"flex items-center flex-1 justify-end",children:[!z&&c?.some(oe=>oe.data?.draft)&&w.jsx("div",{className:"flex items-center me-[6px] pe-[6px] border-e border-[#EBECF0]",children:w.jsx(Xn,{value:g?"Hide Draft":"Show Draft",side:"top",children:w.jsx(An,{"data-selected":g,variant:"ghost",className:"flex p-1 h-fit items-center gap-1",onClick:()=>x(!g),children:w.jsxs("div",{className:"text-[14px] text-[#777] font-normal px-[.25em] flex items-center gap-[6px]",children:[g?w.jsx(L4,{size:16,color:"#777"}):w.jsx(D4,{size:16,color:"#777"}),"Draft"]})})})}),o&&w.jsx("div",{className:"flex items-center gap-1 pe-[6px] me-[6px] border-e border-[#EBECF0]",children:w.jsx(Xn,{value:"View comment",side:"top",children:w.jsxs(An,{variant:"ghost",className:"flex p-1 h-fit items-center gap-1",onClick:()=>S.openDialog("Flag Response",w.jsx(c2,{existingFlagValue:o||"",events:c||[t],sessionId:C?.id,onFlag:l}),{width:"600px",height:"636px"}),children:[w.jsx(nA,{size:16,color:"#777"}),w.jsx("div",{className:"text-[14px] text-[#777] font-normal px-[.25em]",children:"Flagged"})]})})}),!z&&w.jsx(Xn,{value:"View message actions and logs",side:"top",children:w.jsxs(An,{"data-selected":ae,variant:"ghost",className:"flex p-1 h-fit items-center gap-1",onClick:()=>n(t),children:[w.jsx(B4,{size:16,color:"#777"}),w.jsx("div",{className:"text-[14px] text-[#777] font-normal px-[.25em]",children:"Inspect"})]})})]})]}),w.jsx(QV,{open:g,draft:c?.find(oe=>oe.data?.draft)?.data?.draft||""}),w.jsx("div",{className:"group/main relative",children:w.jsxs("div",{className:Xe("flex items-center max-w-full",z&&"flex-row-reverse"),children:[w.jsx("div",{className:"max-w-full",children:w.jsxs("div",{ref:d,tabIndex:0,"data-testid":"message",className:Xe("bg-green-light border-[2px] hover:bg-[#F5F9F3] text-black border-transparent",z&&ie==="error"&&"!bg-[#FDF2F1] hover:!bg-[#F5EFEF]","max-w-[min(560px,100%)] peer w-[560px] flex items-center relative",t?.serverStatus==="pending"&&"opacity-50","p-[20px_22px_24px_22px] rounded-[22px]"),children:[w.jsx("div",{className:Xe("markdown overflow-hidden relative min-w-[200px] max-w-[608px] [word-break:break-word] font-light text-[16px] pe-[38px]"),children:w.jsxs("span",{ref:m,children:[Q?w.jsxs(w.Fragment,{children:[w.jsx("span",{className:On("leading-[26px]"),children:A.slice(0,D)}),F>D&&w.jsx("span",{className:On("leading-[26px]","animate-fade-in-fast"),children:A.slice(D,F)},D)]}):w.jsx(u2,{className:On("leading-[26px]"),children:A}),U&&w.jsx("span",{className:"inline-block w-[2px] h-[1em] bg-current align-text-bottom ml-[1px] animate-pulse"})]})}),w.jsx("div",{className:Xe("flex h-full font-normal text-[11px] text-[#AEB4BB] pe-[20px] font-inter self-end items-end whitespace-nowrap leading-[14px]","")})]})}),w.jsxs("div",{className:Xe("mx-[10px] self-stretch relative invisible items-center flex group-hover/main:visible peer-hover:visible hover:visible"),children:[w.jsx(Xn,{value:"Copy",side:"top",children:w.jsx("div",{"data-testid":"copy-button",role:"button",onClick:()=>hl(t?.data?.message||""),className:"group cursor-pointer",children:w.jsx("img",{src:"icons/copy.svg",alt:"edit",className:"block opacity-50 rounded-[10px] group-hover:bg-[#EBECF0] size-[30px] p-[5px]"})})}),z&&!O&&w.jsx(Xn,{value:"Edit",side:"top",children:w.jsx("div",{"data-testid":"edit-button",role:"button",onClick:()=>s?.(!0),className:"group cursor-pointer",children:w.jsx("img",{src:"icons/edit-message.svg",alt:"edit",className:"block opacity-50 rounded-[10px] group-hover:bg-[#EBECF0] size-[30px] p-[5px]"})})})]})]})})]})})})},JV=({event:t,resendMessageFn:e,setIsEditing:n})=>{const r=T.useRef(null),i=T.useRef(null),[s,o]=T.useState(t?.data?.message||""),[l]=lt(As);return T.useEffect(()=>{i?.current?.select()},[i?.current]),T.useEffect(()=>{r?.current?.scrollIntoView({behavior:"smooth",block:"nearest"})},[r?.current]),w.jsxs("div",{ref:r,className:"w-full p-[16px] ps-[6px] pe-[6px] rounded-[16px] max-w-[min(560px,90%)] rounded-br-none border origin-bottom bg-[#f5f6f8] ",style:{transformOrigin:"bottom"},children:[w.jsx(ip,{ref:i,className:"[direction:ltr] resize-none h-[120px] pe-[108px] !ring-0 !ring-offset-0 border-none ps-[22px] bg-[#f5f6f8]",onChange:c=>o(c.target.value),defaultValue:s}),w.jsxs("div",{className:"pt-[10px] flex justify-end gap-[10px] pe-[12px] [direction:ltr]",children:[w.jsx(An,{variant:"ghost",onClick:()=>n?.(!1),className:"rounded-[10px] hover:bg-white",children:"Cancel"}),w.jsx(An,{disabled:!s?.trim()||s?.trim()===t?.data?.message,className:"rounded-[10px]",onClick:()=>{e?.(l?.id||"",s?.trim()),n?.(!1)},children:"Apply"})]})]})};function eG({event:t,isFirstMessageInDate:e,isContinual:n,showLogs:r,showLogsForMessage:i,resendMessageFn:s,flagged:o,flaggedChanged:l,sameTraceMessages:c}){const[d,f]=T.useState(!1);return w.jsx("div",{className:Xe(d&&"[direction:rtl] flex justify-center"),children:w.jsxs("div",{className:Xe("flex py-[3px] mx-0 mb-1 w-full justify-between animate-fade-in scrollbar",d&&"flex-1 flex justify-start max-w-[1000px] items-end w-[calc(100%-412px)] max-[2100px]:w-[calc(100%-200px)] self-end max-[1700px]:w-[calc(100%-40px)]"),children:[w.jsx(Qa,{}),d?w.jsx(JV,{resendMessageFn:s,setIsEditing:f,event:t,isContinual:n,showLogs:r,showLogsForMessage:i}):w.jsx(ZV,{isFirstMessageInDate:e,setIsEditing:f,event:t,isContinual:n,showLogs:r,showLogsForMessage:i,flagged:o,flaggedChanged:l,sameTraceMessages:c}),w.jsx(Qa,{})]})})}const tG=()=>{const[t]=lt(ws);return{openQuestionDialog:T.useCallback((n,r,i)=>{const s=()=>w.jsxs("div",{className:"h-full flex flex-col justify-between ms-[30px] me-[20px]",children:[w.jsx("p",{className:"mt-[10px]",children:r}),w.jsxs("div",{className:"h-[80px] flex items-center justify-end",children:[w.jsx(An,{"data-testid":"cancel",onClick:t.closeDialog,className:"hover:bg-[#EBE9F5] bg-[#F2F0FC] h-[46px] w-[96px] text-black rounded-[6px] py-[12px] px-[24px] me-[10px] text-[16px] font-normal",children:"Cancel"}),i.map(o=>o.isMainAction?w.jsx(An,{onClick:o.onClick,className:"h-[46px] w-[161px] bg-green-main hover:bg-[#005C3F] rounded-[6px] py-[10px] px-[29.5px] text-[15px] font-medium",children:o.text},o.text):w.jsx(An,{onClick:o.onClick,className:"hover:bg-[#EBE9F5] bg-[#F2F0FC] h-[46px] w-[96px] text-black rounded-[6px] py-[12px] px-[24px] me-[10px] text-[16px] font-normal",children:o.text},o.text))]})]});return t.openDialog(n,w.jsx(s,{}),{height:"230px",width:"480px"})},[t]),closeQuestionDialog:t.closeDialog}},MT=["CRITICAL","ERROR","WARNING","INFO","DEBUG","TRACE"],nG="Parlant",yi="logs",s0=2e3,DT=600*1e3;function mp(t=yi){return new Promise((e,n)=>{const r=indexedDB.open(nG,1);r.onupgradeneeded=()=>{const i=r.result;i.objectStoreNames.contains(t)||i.createObjectStore(t,{autoIncrement:!0}).createIndex("timestampIndex","timestamp",{unique:!1})},r.onsuccess=()=>e(r.result),r.onerror=()=>n(r.error)})}async function rG(t){const e=await mp();return new Promise((n,r)=>{const o=e.transaction(yi,"readonly").objectStore(yi).get(t);o.onsuccess=()=>n(o.result?.values||[]),o.onerror=()=>r(o.error)})}const iG=async t=>{if(YD())return;const r=(await mp()).transaction(yi,"readwrite").objectStore(yi),i=r.get(t.trace_id);i.onsuccess=()=>{const s=i.result,o=Date.now();s?.values?(s.values.push(t),r.put({timestamp:o,values:s.values},t.trace_id)):(!t.message?.trim().startsWith("HTTP")||t.message?.includes("/events"))&&r.put({timestamp:o,values:[t]},t.trace_id),window.dispatchEvent(new CustomEvent("new-log",{detail:{trace_id:t.trace_id}}))},i.onerror=()=>console.error(i.error)},cb=async t=>rG(t),sG=async(t,e)=>{const n=await cb(t),r=e?.content?.map(c=>c.replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1")),i=r?.map(c=>`\\[?${c}\\]?`).join(".*?"),s=e.level?MT.indexOf(e.level):null,o=e.level?new Set(MT.filter((c,d)=>d<=s)):null,l=e.types?.length?new Set(e.types):null;return n.filter(c=>{if(o&&!o.has(c.level)||i&&!r?.every(f=>new RegExp(`\\[?${f}\\]?`,"i").test(`[${c.level}]${c.message}`)))return!1;if(l){const d=[...c.message.matchAll(/\[([^\]]+)\]/g)].map(m=>m?.[1]),p=(d[0]?.startsWith("T+")?d[1]:d[0])||"General";return l.has(p)}return!0})};async function oG(){const t=await mp();return new Promise((e,n)=>{try{const o=t.transaction(yi,"readonly").objectStore(yi).index("timestampIndex").openCursor(),l=[];o.onsuccess=c=>{const d=c.target.result;d?(d.primaryKey?.includes("::")&&l.push(d.value),d.continue()):e(l)},o.onerror=()=>n(o.error)}catch(r){t.close(),n(r)}})}async function aG(t=0){if(!t||t<=0){console.log("No valid deletion timestamp provided, skipping cleanup");return}try{const e=await mp(),n=e.transaction(yi,"readonly"),r=n.objectStore(yi),i=r.getAllKeys(),s=r.getAll();return new Promise((o,l)=>{let c=[],d=[];i.onsuccess=()=>{c=i.result,d.length>0&&f()},s.onsuccess=()=>{d=s.result,c.length>0&&f()};const f=()=>{const p=[];for(const S in c)d[S].timestamp{const C=g.delete(S);C.onsuccess=()=>{x++,x+v===p.length&&v>0&&console.warn(`Completed with ${v} errors`)},C.onerror=A=>{v++,console.error(`Failed to delete key ${S}:`,A.target.error)}}),m.oncomplete=()=>{e.close(),console.log(`Successfully deleted ${x} records older than ${new Date(t).toISOString()}`),o()},m.onerror=S=>{e.close(),l(S.target.error)}};n.onerror=p=>{e.close(),l(p.target.error)}})}catch(e){throw console.error("Error in deleteOldestLogs:",e),e}}async function LT(){try{const t=await oG();if(t[s0]){const e=t[t.length-s0]?.timestamp||0;console.log(`Log count exceeds maximum (${s0}), deleting logs before ${new Date(e)?.toLocaleString()}`),await aG(e),console.log("Cleanup completed")}}catch(t){console.error("Error during log cleanup:",t)}}let PT=null;function lG(){LT(),PT||(PT=window.setInterval(LT,DT),console.log(`Log cleanup scheduled every ${DT/1e3/60} minutes`))}lG();const uG=30;function cG(t,e){const[n,r]=T.useState(()=>{try{const s=globalThis.localStorage?.getItem(t);return s?JSON.parse(s):e}catch(s){return console.error("Error reading from localStorage",s),e}}),i=()=>{try{Array.isArray(n)&&n?.length>uG&&n.shift(),localStorage.setItem(t,JSON.stringify(n))}catch(s){if(console.error("Error writing to localStorage",s),s instanceof DOMException&&s.name==="QuotaExceededError"){const o=JSON.parse(localStorage.logs||"{}");Object.keys(o)[0]&&(console.log("deleting first log"),delete o[Object.keys(o)[0]],localStorage.setItem("logs",JSON.stringify(o)),i())}}};return T.useEffect(()=>{i()},[t,n]),[n,r]}function d2(t){const e=T.useRef({value:t,previous:t});return T.useMemo(()=>(e.current.value!==t&&(e.current.previous=e.current.value,e.current.value=t),e.current.previous),[t])}var gp="Checkbox",[dG]=Cs(gp),[fG,h1]=dG(gp);function hG(t){const{__scopeCheckbox:e,checked:n,children:r,defaultChecked:i,disabled:s,form:o,name:l,onCheckedChange:c,required:d,value:f="on",internal_do_not_use_render:p}=t,[m,g]=Yo({prop:n,defaultProp:i??!1,onChange:c,caller:gp}),[x,v]=T.useState(null),[S,C]=T.useState(null),A=T.useRef(!1),k=x?!!o||!!x.closest("form"):!0,M={checked:m,disabled:s,setChecked:g,control:x,setControl:v,name:l,form:o,value:f,hasConsumerStoppedPropagationRef:A,required:d,defaultChecked:oo(i)?!1:i,isFormControl:k,bubbleInput:S,setBubbleInput:C};return w.jsx(fG,{scope:e,...M,children:pG(p)?p(M):r})}var f2="CheckboxTrigger",h2=T.forwardRef(({__scopeCheckbox:t,onKeyDown:e,onClick:n,...r},i)=>{const{control:s,value:o,disabled:l,checked:c,required:d,setControl:f,setChecked:p,hasConsumerStoppedPropagationRef:m,isFormControl:g,bubbleInput:x}=h1(f2,t),v=Pt(i,f),S=T.useRef(c);return T.useEffect(()=>{const C=s?.form;if(C){const A=()=>p(S.current);return C.addEventListener("reset",A),()=>C.removeEventListener("reset",A)}},[s,p]),w.jsx(xt.button,{type:"button",role:"checkbox","aria-checked":oo(c)?"mixed":c,"aria-required":d,"data-state":E2(c),"data-disabled":l?"":void 0,disabled:l,value:o,...r,ref:v,onKeyDown:je(e,C=>{C.key==="Enter"&&C.preventDefault()}),onClick:je(n,C=>{p(A=>oo(A)?!0:!A),x&&g&&(m.current=C.isPropagationStopped(),m.current||C.stopPropagation())})})});h2.displayName=f2;var p1=T.forwardRef((t,e)=>{const{__scopeCheckbox:n,name:r,checked:i,defaultChecked:s,required:o,disabled:l,value:c,onCheckedChange:d,form:f,...p}=t;return w.jsx(hG,{__scopeCheckbox:n,checked:i,defaultChecked:s,disabled:l,required:o,onCheckedChange:d,name:r,form:f,value:c,internal_do_not_use_render:({isFormControl:m})=>w.jsxs(w.Fragment,{children:[w.jsx(h2,{...p,ref:e,__scopeCheckbox:n}),m&&w.jsx(b2,{__scopeCheckbox:n})]})})});p1.displayName=gp;var p2="CheckboxIndicator",m2=T.forwardRef((t,e)=>{const{__scopeCheckbox:n,forceMount:r,...i}=t,s=h1(p2,n);return w.jsx(Zi,{present:r||oo(s.checked)||s.checked===!0,children:w.jsx(xt.span,{"data-state":E2(s.checked),"data-disabled":s.disabled?"":void 0,...i,ref:e,style:{pointerEvents:"none",...t.style}})})});m2.displayName=p2;var g2="CheckboxBubbleInput",b2=T.forwardRef(({__scopeCheckbox:t,...e},n)=>{const{control:r,hasConsumerStoppedPropagationRef:i,checked:s,defaultChecked:o,required:l,disabled:c,name:d,value:f,form:p,bubbleInput:m,setBubbleInput:g}=h1(g2,t),x=Pt(n,g),v=d2(s),S=S_(r);T.useEffect(()=>{const A=m;if(!A)return;const k=window.HTMLInputElement.prototype,F=Object.getOwnPropertyDescriptor(k,"checked").set,I=!i.current;if(v!==s&&F){const D=new Event("click",{bubbles:I});A.indeterminate=oo(s),F.call(A,oo(s)?!1:s),A.dispatchEvent(D)}},[m,v,s,i]);const C=T.useRef(oo(s)?!1:s);return w.jsx(xt.input,{type:"checkbox","aria-hidden":!0,defaultChecked:o??C.current,required:l,disabled:c,name:d,value:f,form:p,...e,tabIndex:-1,ref:x,style:{...e.style,...S,position:"absolute",pointerEvents:"none",opacity:0,margin:0,transform:"translateX(-100%)"}})});b2.displayName=g2;function pG(t){return typeof t=="function"}function oo(t){return t==="indeterminate"}function E2(t){return oo(t)?"indeterminate":t?"checked":"unchecked"}const y2=T.forwardRef(({className:t,...e},n)=>w.jsx(p1,{ref:n,className:Rt("peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",t),...e,children:w.jsx(m2,{className:Rt("flex items-center justify-center text-current"),children:w.jsx(CE,{className:"h-4 w-4",color:"black"})})}));y2.displayName=p1.displayName;function FT(t,[e,n]){return Math.min(n,Math.max(e,t))}var mG=[" ","Enter","ArrowUp","ArrowDown"],gG=[" ","Enter"],Qo="Select",[bp,Ep,bG]=mE(Qo),[Ul]=Cs(Qo,[bG,Il]),yp=Il(),[EG,mo]=Ul(Qo),[yG,xG]=Ul(Qo),x2=t=>{const{__scopeSelect:e,children:n,open:r,defaultOpen:i,onOpenChange:s,value:o,defaultValue:l,onValueChange:c,dir:d,name:f,autoComplete:p,disabled:m,required:g,form:x}=t,v=yp(e),[S,C]=T.useState(null),[A,k]=T.useState(null),[M,F]=T.useState(!1),I=gE(d),[D,G]=Yo({prop:r,defaultProp:i??!1,onChange:s,caller:Qo}),[X,P]=Yo({prop:o,defaultProp:l,onChange:c,caller:Qo}),Y=T.useRef(null),z=S?x||!!S.closest("form"):!0,[ie,Z]=T.useState(new Set),ee=Array.from(ie).map(ae=>ae.props.value).join(";");return w.jsx(cE,{...v,children:w.jsxs(EG,{required:g,scope:e,trigger:S,onTriggerChange:C,valueNode:A,onValueNodeChange:k,valueNodeHasChildren:M,onValueNodeHasChildrenChange:F,contentId:Gi(),value:X,onValueChange:P,open:D,onOpenChange:G,dir:I,triggerPointerDownPosRef:Y,disabled:m,children:[w.jsx(bp.Provider,{scope:e,children:w.jsx(yG,{scope:t.__scopeSelect,onNativeOptionAdd:T.useCallback(ae=>{Z(de=>new Set(de).add(ae))},[]),onNativeOptionRemove:T.useCallback(ae=>{Z(de=>{const j=new Set(de);return j.delete(ae),j})},[]),children:n})}),z?w.jsxs(V2,{"aria-hidden":!0,required:g,tabIndex:-1,name:f,autoComplete:p,value:X,onChange:ae=>P(ae.target.value),disabled:m,form:x,children:[X===void 0?w.jsx("option",{value:""}):null,Array.from(ie)]},ee):null]})})};x2.displayName=Qo;var v2="SelectTrigger",w2=T.forwardRef((t,e)=>{const{__scopeSelect:n,disabled:r=!1,...i}=t,s=yp(n),o=mo(v2,n),l=o.disabled||r,c=Pt(e,o.onTriggerChange),d=Ep(n),f=T.useRef("touch"),[p,m,g]=K2(v=>{const S=d().filter(k=>!k.disabled),C=S.find(k=>k.value===o.value),A=Y2(S,v,C);A!==void 0&&o.onValueChange(A.value)}),x=v=>{l||(o.onOpenChange(!0),g()),v&&(o.triggerPointerDownPosRef.current={x:Math.round(v.pageX),y:Math.round(v.pageY)})};return w.jsx(dE,{asChild:!0,...s,children:w.jsx(xt.button,{type:"button",role:"combobox","aria-controls":o.contentId,"aria-expanded":o.open,"aria-required":o.required,"aria-autocomplete":"none",dir:o.dir,"data-state":o.open?"open":"closed",disabled:l,"data-disabled":l?"":void 0,"data-placeholder":G2(o.value)?"":void 0,...i,ref:c,onClick:je(i.onClick,v=>{v.currentTarget.focus(),f.current!=="mouse"&&x(v)}),onPointerDown:je(i.onPointerDown,v=>{f.current=v.pointerType;const S=v.target;S.hasPointerCapture(v.pointerId)&&S.releasePointerCapture(v.pointerId),v.button===0&&v.ctrlKey===!1&&v.pointerType==="mouse"&&(x(v),v.preventDefault())}),onKeyDown:je(i.onKeyDown,v=>{const S=p.current!=="";!(v.ctrlKey||v.altKey||v.metaKey)&&v.key.length===1&&m(v.key),!(S&&v.key===" ")&&mG.includes(v.key)&&(x(),v.preventDefault())})})})});w2.displayName=v2;var T2="SelectValue",S2=T.forwardRef((t,e)=>{const{__scopeSelect:n,className:r,style:i,children:s,placeholder:o="",...l}=t,c=mo(T2,n),{onValueNodeHasChildrenChange:d}=c,f=s!==void 0,p=Pt(e,c.onValueNodeChange);return lr(()=>{d(f)},[d,f]),w.jsx(xt.span,{...l,ref:p,style:{pointerEvents:"none"},children:G2(c.value)?w.jsx(w.Fragment,{children:o}):s})});S2.displayName=T2;var vG="SelectIcon",_2=T.forwardRef((t,e)=>{const{__scopeSelect:n,children:r,...i}=t;return w.jsx(xt.span,{"aria-hidden":!0,...i,ref:e,children:r||"▼"})});_2.displayName=vG;var wG="SelectPortal",C2=t=>w.jsx(Hh,{asChild:!0,...t});C2.displayName=wG;var Zo="SelectContent",A2=T.forwardRef((t,e)=>{const n=mo(Zo,t.__scopeSelect),[r,i]=T.useState();if(lr(()=>{i(new DocumentFragment)},[]),!n.open){const s=r;return s?Ac.createPortal(w.jsx(k2,{scope:t.__scopeSelect,children:w.jsx(bp.Slot,{scope:t.__scopeSelect,children:w.jsx("div",{children:t.children})})}),s):null}return w.jsx(N2,{...t,ref:e})});A2.displayName=Zo;var bi=10,[k2,go]=Ul(Zo),TG="SelectContentImpl",SG=Go("SelectContent.RemoveScroll"),N2=T.forwardRef((t,e)=>{const{__scopeSelect:n,position:r="item-aligned",onCloseAutoFocus:i,onEscapeKeyDown:s,onPointerDownOutside:o,side:l,sideOffset:c,align:d,alignOffset:f,arrowPadding:p,collisionBoundary:m,collisionPadding:g,sticky:x,hideWhenDetached:v,avoidCollisions:S,...C}=t,A=mo(Zo,n),[k,M]=T.useState(null),[F,I]=T.useState(null),D=Pt(e,J=>M(J)),[G,X]=T.useState(null),[P,Y]=T.useState(null),z=Ep(n),[ie,Z]=T.useState(!1),ee=T.useRef(!1);T.useEffect(()=>{if(k)return EE(k)},[k]),bE();const ae=T.useCallback(J=>{const[he,..._e]=z().map(ot=>ot.ref.current),[ke]=_e.slice(-1),Ve=document.activeElement;for(const ot of J)if(ot===Ve||(ot?.scrollIntoView({block:"nearest"}),ot===he&&F&&(F.scrollTop=0),ot===ke&&F&&(F.scrollTop=F.scrollHeight),ot?.focus(),document.activeElement!==Ve))return},[z,F]),de=T.useCallback(()=>ae([G,k]),[ae,G,k]);T.useEffect(()=>{ie&&de()},[ie,de]);const{onOpenChange:j,triggerPointerDownPosRef:W}=A;T.useEffect(()=>{if(k){let J={x:0,y:0};const he=ke=>{J={x:Math.abs(Math.round(ke.pageX)-(W.current?.x??0)),y:Math.abs(Math.round(ke.pageY)-(W.current?.y??0))}},_e=ke=>{J.x<=10&&J.y<=10?ke.preventDefault():k.contains(ke.target)||j(!1),document.removeEventListener("pointermove",he),W.current=null};return W.current!==null&&(document.addEventListener("pointermove",he),document.addEventListener("pointerup",_e,{capture:!0,once:!0})),()=>{document.removeEventListener("pointermove",he),document.removeEventListener("pointerup",_e,{capture:!0})}}},[k,j,W]),T.useEffect(()=>{const J=()=>j(!1);return window.addEventListener("blur",J),window.addEventListener("resize",J),()=>{window.removeEventListener("blur",J),window.removeEventListener("resize",J)}},[j]);const[O,U]=K2(J=>{const he=z().filter(Ve=>!Ve.disabled),_e=he.find(Ve=>Ve.ref.current===document.activeElement),ke=Y2(he,J,_e);ke&&setTimeout(()=>ke.ref.current.focus())}),Q=T.useCallback((J,he,_e)=>{const ke=!ee.current&&!_e;(A.value!==void 0&&A.value===he||ke)&&(X(J),ke&&(ee.current=!0))},[A.value]),R=T.useCallback(()=>k?.focus(),[k]),oe=T.useCallback((J,he,_e)=>{const ke=!ee.current&&!_e;(A.value!==void 0&&A.value===he||ke)&&Y(J)},[A.value]),pe=r==="popper"?db:R2,ue=pe===db?{side:l,sideOffset:c,align:d,alignOffset:f,arrowPadding:p,collisionBoundary:m,collisionPadding:g,sticky:x,hideWhenDetached:v,avoidCollisions:S}:{};return w.jsx(k2,{scope:n,content:k,viewport:F,onViewportChange:I,itemRefCallback:Q,selectedItem:G,onItemLeave:R,itemTextRefCallback:oe,focusSelectedItem:de,selectedItemText:P,position:r,isPositioned:ie,searchRef:O,children:w.jsx(Gh,{as:SG,allowPinchZoom:!0,children:w.jsx(Wh,{asChild:!0,trapped:A.open,onMountAutoFocus:J=>{J.preventDefault()},onUnmountAutoFocus:je(i,J=>{A.trigger?.focus({preventScroll:!0}),J.preventDefault()}),children:w.jsx(kc,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:s,onPointerDownOutside:o,onFocusOutside:J=>J.preventDefault(),onDismiss:()=>A.onOpenChange(!1),children:w.jsx(pe,{role:"listbox",id:A.contentId,"data-state":A.open?"open":"closed",dir:A.dir,onContextMenu:J=>J.preventDefault(),...C,...ue,onPlaced:()=>Z(!0),ref:D,style:{display:"flex",flexDirection:"column",outline:"none",...C.style},onKeyDown:je(C.onKeyDown,J=>{const he=J.ctrlKey||J.altKey||J.metaKey;if(J.key==="Tab"&&J.preventDefault(),!he&&J.key.length===1&&U(J.key),["ArrowUp","ArrowDown","Home","End"].includes(J.key)){let ke=z().filter(Ve=>!Ve.disabled).map(Ve=>Ve.ref.current);if(["ArrowUp","End"].includes(J.key)&&(ke=ke.slice().reverse()),["ArrowUp","ArrowDown"].includes(J.key)){const Ve=J.target,ot=ke.indexOf(Ve);ke=ke.slice(ot+1)}setTimeout(()=>ae(ke)),J.preventDefault()}})})})})})})});N2.displayName=TG;var _G="SelectItemAlignedPosition",R2=T.forwardRef((t,e)=>{const{__scopeSelect:n,onPlaced:r,...i}=t,s=mo(Zo,n),o=go(Zo,n),[l,c]=T.useState(null),[d,f]=T.useState(null),p=Pt(e,D=>f(D)),m=Ep(n),g=T.useRef(!1),x=T.useRef(!0),{viewport:v,selectedItem:S,selectedItemText:C,focusSelectedItem:A}=o,k=T.useCallback(()=>{if(s.trigger&&s.valueNode&&l&&d&&v&&S&&C){const D=s.trigger.getBoundingClientRect(),G=d.getBoundingClientRect(),X=s.valueNode.getBoundingClientRect(),P=C.getBoundingClientRect();if(s.dir!=="rtl"){const Ve=P.left-G.left,ot=X.left-Ve,qe=D.left-ot,kt=D.width+qe,fn=Math.max(kt,G.width),nt=window.innerWidth-bi,Yt=FT(ot,[bi,Math.max(bi,nt-fn)]);l.style.minWidth=kt+"px",l.style.left=Yt+"px"}else{const Ve=G.right-P.right,ot=window.innerWidth-X.right-Ve,qe=window.innerWidth-D.right-ot,kt=D.width+qe,fn=Math.max(kt,G.width),nt=window.innerWidth-bi,Yt=FT(ot,[bi,Math.max(bi,nt-fn)]);l.style.minWidth=kt+"px",l.style.right=Yt+"px"}const Y=m(),z=window.innerHeight-bi*2,ie=v.scrollHeight,Z=window.getComputedStyle(d),ee=parseInt(Z.borderTopWidth,10),ae=parseInt(Z.paddingTop,10),de=parseInt(Z.borderBottomWidth,10),j=parseInt(Z.paddingBottom,10),W=ee+ae+ie+j+de,O=Math.min(S.offsetHeight*5,W),U=window.getComputedStyle(v),Q=parseInt(U.paddingTop,10),R=parseInt(U.paddingBottom,10),oe=D.top+D.height/2-bi,pe=z-oe,ue=S.offsetHeight/2,J=S.offsetTop+ue,he=ee+ae+J,_e=W-he;if(he<=oe){const Ve=Y.length>0&&S===Y[Y.length-1].ref.current;l.style.bottom="0px";const ot=d.clientHeight-v.offsetTop-v.offsetHeight,qe=Math.max(pe,ue+(Ve?R:0)+ot+de),kt=he+qe;l.style.height=kt+"px"}else{const Ve=Y.length>0&&S===Y[0].ref.current;l.style.top="0px";const qe=Math.max(oe,ee+v.offsetTop+(Ve?Q:0)+ue)+_e;l.style.height=qe+"px",v.scrollTop=he-oe+v.offsetTop}l.style.margin=`${bi}px 0`,l.style.minHeight=O+"px",l.style.maxHeight=z+"px",r?.(),requestAnimationFrame(()=>g.current=!0)}},[m,s.trigger,s.valueNode,l,d,v,S,C,s.dir,r]);lr(()=>k(),[k]);const[M,F]=T.useState();lr(()=>{d&&F(window.getComputedStyle(d).zIndex)},[d]);const I=T.useCallback(D=>{D&&x.current===!0&&(k(),A?.(),x.current=!1)},[k,A]);return w.jsx(AG,{scope:n,contentWrapper:l,shouldExpandOnScrollRef:g,onScrollButtonChange:I,children:w.jsx("div",{ref:c,style:{display:"flex",flexDirection:"column",position:"fixed",zIndex:M},children:w.jsx(xt.div,{...i,ref:p,style:{boxSizing:"border-box",maxHeight:"100%",...i.style}})})})});R2.displayName=_G;var CG="SelectPopperPosition",db=T.forwardRef((t,e)=>{const{__scopeSelect:n,align:r="start",collisionPadding:i=bi,...s}=t,o=yp(n);return w.jsx(fE,{...o,...s,ref:e,align:r,collisionPadding:i,style:{boxSizing:"border-box",...s.style,"--radix-select-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-select-content-available-width":"var(--radix-popper-available-width)","--radix-select-content-available-height":"var(--radix-popper-available-height)","--radix-select-trigger-width":"var(--radix-popper-anchor-width)","--radix-select-trigger-height":"var(--radix-popper-anchor-height)"}})});db.displayName=CG;var[AG,m1]=Ul(Zo,{}),fb="SelectViewport",I2=T.forwardRef((t,e)=>{const{__scopeSelect:n,nonce:r,...i}=t,s=go(fb,n),o=m1(fb,n),l=Pt(e,s.onViewportChange),c=T.useRef(0);return w.jsxs(w.Fragment,{children:[w.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}"},nonce:r}),w.jsx(bp.Slot,{scope:n,children:w.jsx(xt.div,{"data-radix-select-viewport":"",role:"presentation",...i,ref:l,style:{position:"relative",flex:1,overflow:"hidden auto",...i.style},onScroll:je(i.onScroll,d=>{const f=d.currentTarget,{contentWrapper:p,shouldExpandOnScrollRef:m}=o;if(m?.current&&p){const g=Math.abs(c.current-f.scrollTop);if(g>0){const x=window.innerHeight-bi*2,v=parseFloat(p.style.minHeight),S=parseFloat(p.style.height),C=Math.max(v,S);if(C0?M:0,p.style.justifyContent="flex-end")}}}c.current=f.scrollTop})})})]})});I2.displayName=fb;var O2="SelectGroup",[kG,NG]=Ul(O2),M2=T.forwardRef((t,e)=>{const{__scopeSelect:n,...r}=t,i=Gi();return w.jsx(kG,{scope:n,id:i,children:w.jsx(xt.div,{role:"group","aria-labelledby":i,...r,ref:e})})});M2.displayName=O2;var D2="SelectLabel",L2=T.forwardRef((t,e)=>{const{__scopeSelect:n,...r}=t,i=NG(D2,n);return w.jsx(xt.div,{id:i.id,...r,ref:e})});L2.displayName=D2;var bh="SelectItem",[RG,P2]=Ul(bh),F2=T.forwardRef((t,e)=>{const{__scopeSelect:n,value:r,disabled:i=!1,textValue:s,...o}=t,l=mo(bh,n),c=go(bh,n),d=l.value===r,[f,p]=T.useState(s??""),[m,g]=T.useState(!1),x=Pt(e,A=>c.itemRefCallback?.(A,r,i)),v=Gi(),S=T.useRef("touch"),C=()=>{i||(l.onValueChange(r),l.onOpenChange(!1))};if(r==="")throw new Error("A must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.");return w.jsx(RG,{scope:n,value:r,disabled:i,textId:v,isSelected:d,onItemTextChange:T.useCallback(A=>{p(k=>k||(A?.textContent??"").trim())},[]),children:w.jsx(bp.ItemSlot,{scope:n,value:r,disabled:i,textValue:f,children:w.jsx(xt.div,{role:"option","aria-labelledby":v,"data-highlighted":m?"":void 0,"aria-selected":d&&m,"data-state":d?"checked":"unchecked","aria-disabled":i||void 0,"data-disabled":i?"":void 0,tabIndex:i?void 0:-1,...o,ref:x,onFocus:je(o.onFocus,()=>g(!0)),onBlur:je(o.onBlur,()=>g(!1)),onClick:je(o.onClick,()=>{S.current!=="mouse"&&C()}),onPointerUp:je(o.onPointerUp,()=>{S.current==="mouse"&&C()}),onPointerDown:je(o.onPointerDown,A=>{S.current=A.pointerType}),onPointerMove:je(o.onPointerMove,A=>{S.current=A.pointerType,i?c.onItemLeave?.():S.current==="mouse"&&A.currentTarget.focus({preventScroll:!0})}),onPointerLeave:je(o.onPointerLeave,A=>{A.currentTarget===document.activeElement&&c.onItemLeave?.()}),onKeyDown:je(o.onKeyDown,A=>{c.searchRef?.current!==""&&A.key===" "||(gG.includes(A.key)&&C(),A.key===" "&&A.preventDefault())})})})})});F2.displayName=bh;var Hu="SelectItemText",B2=T.forwardRef((t,e)=>{const{__scopeSelect:n,className:r,style:i,...s}=t,o=mo(Hu,n),l=go(Hu,n),c=P2(Hu,n),d=xG(Hu,n),[f,p]=T.useState(null),m=Pt(e,C=>p(C),c.onItemTextChange,C=>l.itemTextRefCallback?.(C,c.value,c.disabled)),g=f?.textContent,x=T.useMemo(()=>w.jsx("option",{value:c.value,disabled:c.disabled,children:g},c.value),[c.disabled,c.value,g]),{onNativeOptionAdd:v,onNativeOptionRemove:S}=d;return lr(()=>(v(x),()=>S(x)),[v,S,x]),w.jsxs(w.Fragment,{children:[w.jsx(xt.span,{id:c.textId,...s,ref:m}),c.isSelected&&o.valueNode&&!o.valueNodeHasChildren?Ac.createPortal(s.children,o.valueNode):null]})});B2.displayName=Hu;var U2="SelectItemIndicator",H2=T.forwardRef((t,e)=>{const{__scopeSelect:n,...r}=t;return P2(U2,n).isSelected?w.jsx(xt.span,{"aria-hidden":!0,...r,ref:e}):null});H2.displayName=U2;var hb="SelectScrollUpButton",z2=T.forwardRef((t,e)=>{const n=go(hb,t.__scopeSelect),r=m1(hb,t.__scopeSelect),[i,s]=T.useState(!1),o=Pt(e,r.onScrollButtonChange);return lr(()=>{if(n.viewport&&n.isPositioned){let l=function(){const d=c.scrollTop>0;s(d)};const c=n.viewport;return l(),c.addEventListener("scroll",l),()=>c.removeEventListener("scroll",l)}},[n.viewport,n.isPositioned]),i?w.jsx($2,{...t,ref:o,onAutoScroll:()=>{const{viewport:l,selectedItem:c}=n;l&&c&&(l.scrollTop=l.scrollTop-c.offsetHeight)}}):null});z2.displayName=hb;var pb="SelectScrollDownButton",j2=T.forwardRef((t,e)=>{const n=go(pb,t.__scopeSelect),r=m1(pb,t.__scopeSelect),[i,s]=T.useState(!1),o=Pt(e,r.onScrollButtonChange);return lr(()=>{if(n.viewport&&n.isPositioned){let l=function(){const d=c.scrollHeight-c.clientHeight,f=Math.ceil(c.scrollTop)c.removeEventListener("scroll",l)}},[n.viewport,n.isPositioned]),i?w.jsx($2,{...t,ref:o,onAutoScroll:()=>{const{viewport:l,selectedItem:c}=n;l&&c&&(l.scrollTop=l.scrollTop+c.offsetHeight)}}):null});j2.displayName=pb;var $2=T.forwardRef((t,e)=>{const{__scopeSelect:n,onAutoScroll:r,...i}=t,s=go("SelectScrollButton",n),o=T.useRef(null),l=Ep(n),c=T.useCallback(()=>{o.current!==null&&(window.clearInterval(o.current),o.current=null)},[]);return T.useEffect(()=>()=>c(),[c]),lr(()=>{l().find(f=>f.ref.current===document.activeElement)?.ref.current?.scrollIntoView({block:"nearest"})},[l]),w.jsx(xt.div,{"aria-hidden":!0,...i,ref:e,style:{flexShrink:0,...i.style},onPointerDown:je(i.onPointerDown,()=>{o.current===null&&(o.current=window.setInterval(r,50))}),onPointerMove:je(i.onPointerMove,()=>{s.onItemLeave?.(),o.current===null&&(o.current=window.setInterval(r,50))}),onPointerLeave:je(i.onPointerLeave,()=>{c()})})}),IG="SelectSeparator",W2=T.forwardRef((t,e)=>{const{__scopeSelect:n,...r}=t;return w.jsx(xt.div,{"aria-hidden":!0,...r,ref:e})});W2.displayName=IG;var mb="SelectArrow",OG=T.forwardRef((t,e)=>{const{__scopeSelect:n,...r}=t,i=yp(n),s=mo(mb,n),o=go(mb,n);return s.open&&o.position==="popper"?w.jsx(hE,{...i,...r,ref:e}):null});OG.displayName=mb;var MG="SelectBubbleInput",V2=T.forwardRef(({__scopeSelect:t,value:e,...n},r)=>{const i=T.useRef(null),s=Pt(r,i),o=d2(e);return T.useEffect(()=>{const l=i.current;if(!l)return;const c=window.HTMLSelectElement.prototype,f=Object.getOwnPropertyDescriptor(c,"value").set;if(o!==e&&f){const p=new Event("change",{bubbles:!0});f.call(l,e),l.dispatchEvent(p)}},[o,e]),w.jsx(xt.select,{...n,style:{...D_,...n.style},ref:s,defaultValue:e})});V2.displayName=MG;function G2(t){return t===""||t===void 0}function K2(t){const e=Yi(t),n=T.useRef(""),r=T.useRef(0),i=T.useCallback(o=>{const l=n.current+o;e(l),(function c(d){n.current=d,window.clearTimeout(r.current),d!==""&&(r.current=window.setTimeout(()=>c(""),1e3))})(l)},[e]),s=T.useCallback(()=>{n.current="",window.clearTimeout(r.current)},[]);return T.useEffect(()=>()=>window.clearTimeout(r.current),[]),[n,i,s]}function Y2(t,e,n){const i=e.length>1&&Array.from(e).every(d=>d===e[0])?e[0]:e,s=n?t.indexOf(n):-1;let o=DG(t,Math.max(s,0));i.length===1&&(o=o.filter(d=>d!==n));const c=o.find(d=>d.textValue.toLowerCase().startsWith(i.toLowerCase()));return c!==n?c:void 0}function DG(t,e){return t.map((n,r)=>t[(e+r)%t.length])}var LG=x2,q2=w2,PG=S2,FG=_2,BG=C2,X2=A2,UG=I2,HG=M2,Q2=L2,Z2=F2,zG=B2,jG=H2,J2=z2,eR=j2,tR=W2;const $G=LG,WG=HG,VG=PG,nR=T.forwardRef(({className:t,children:e,...n},r)=>w.jsxs(q2,{ref:r,className:Rt("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",t),...n,children:[e,w.jsx(FG,{asChild:!0,children:w.jsx(tA,{className:"h-4 w-4 opacity-50"})})]}));nR.displayName=q2.displayName;const rR=T.forwardRef(({className:t,...e},n)=>w.jsx(J2,{ref:n,className:Rt("flex cursor-default items-center justify-center py-1",t),...e,children:w.jsx(O4,{className:"h-4 w-4"})}));rR.displayName=J2.displayName;const iR=T.forwardRef(({className:t,...e},n)=>w.jsx(eR,{ref:n,className:Rt("flex cursor-default items-center justify-center py-1",t),...e,children:w.jsx(tA,{className:"h-4 w-4"})}));iR.displayName=eR.displayName;const sR=T.forwardRef(({className:t,children:e,position:n="popper",...r},i)=>w.jsx(BG,{children:w.jsxs(X2,{ref:i,className:Rt("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",n==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",t),position:n,...r,children:[w.jsx(rR,{}),w.jsx(UG,{className:Rt("p-1",n==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:e}),w.jsx(iR,{})]})}));sR.displayName=X2.displayName;const GG=T.forwardRef(({className:t,...e},n)=>w.jsx(Q2,{ref:n,className:Rt("py-1.5 pl-8 pr-2 text-sm font-semibold",t),...e}));GG.displayName=Q2.displayName;const oR=T.forwardRef(({className:t,children:e,...n},r)=>w.jsxs(Z2,{ref:r,className:Rt("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),...n,children:[w.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:w.jsx(jG,{children:w.jsx(CE,{className:"h-4 w-4"})})}),w.jsx(zG,{children:e})]}));oR.displayName=Z2.displayName;const KG=T.forwardRef(({className:t,...e},n)=>w.jsx(tR,{ref:n,className:Rt("-mx-1 my-1 h-px bg-muted",t),...e}));KG.displayName=tR.displayName;const BT=["GuidelineMatcher","ToolCaller","MessageEventComposer"],fs=["CRITICAL","ERROR","WARNING","INFO","DEBUG","TRACE"],Ef={GuidelineMatcher:{label:"Guideline Matcher",icon:"icons/filters/guideline-matcher-color.svg",color:"#419480"},MessageEventComposer:{label:"Message Event Composer",icon:"icons/filters/message-composer-color.svg",color:"#7E3A89"},ToolCaller:{label:"Tool Caller",icon:"icons/filters/tool-caller-color.svg",color:"#CB7714"}},YG=({className:t})=>w.jsx("div",{className:Xe("group cursor-pointer bg-white border-[#eeeeee] hover:bg-[#F3F5F9] hover:border-[#E4E6EA] border h-[30px] rounded-[6px] flex items-center w-full shadow-main",t),children:w.jsxs("div",{className:"flex items-center justify-center rounded-[3px] leading-[16px] h-[calc(100%-4px)] w-[calc(100%-4px)] py-[5px] px-[8px] pe-[6px]",children:[w.jsx("img",{src:"icons/text.svg",alt:"",className:"me-[5px]"}),w.jsx("p",{className:"text-nowrap font-normal text-[14px]",children:"Add Content Filter"})]})}),qG=({contentChanged:t,defaultValue:e})=>{const[n,r]=T.useState(e||""),i=()=>{n.trim()&&t(n)};return w.jsxs("div",{className:"px-[39px] py-[42px] flex flex-col gap-[22px]",children:[w.jsx("h2",{className:"text-[20px] font-normal",children:"Filter by content"}),w.jsx("div",{className:"border rounded-[5px] h-[38px] flex items-center bg-[#FBFBFB] hover:bg-[#F5F6F8] focus-within:!bg-white",children:w.jsx(sc,{value:n,onChange:s=>r(s.target.value),name:"filter",className:"h-[36px] !ring-0 !ring-offset-0 border-none text-[16px] bg-[#FBFBFB] hover:bg-[#F5F6F8] focus:!bg-white"})}),w.jsxs("div",{className:"buttons flex items-center gap-[16px] justify-end text-[16px] font-normal font-inter",children:[w.jsx(Gv,{className:"h-[38px] w-[84px] !bg-white text-[#656565] hover:text-[#151515] rounded-[5px] border",children:"Cancel"}),w.jsx(Gv,{onClick:i,className:"bg-green-main text-white h-[38px] w-[79px] hover:bg-green-hover rounded-[5px]",children:"Apply"})]})]})},UT=({contentChanged:t,content:e,children:n,className:r})=>w.jsxs(TA,{children:[w.jsx(iF,{className:"w-full",children:n||w.jsx(YG,{className:r})}),w.jsx(DE,{"aria-hidden":!1,children:w.jsxs(LE,{"aria-hidden":!1,className:"p-0 [&>button]:hidden z-[99]",children:[w.jsx(FE,{className:"hidden",children:"Filter by content"}),w.jsx(BE,{className:"hidden",children:"Filter by content"}),w.jsx(qG,{contentChanged:t,defaultValue:e||""})]})})]}),XG=({applyFn:t,def:e,filterId:n,className:r,showDropdown:i,showTags:s,deleteFilterTab:o})=>{const[l,c]=T.useState(structuredClone(e?.types||[])),[d,f]=T.useState(structuredClone(e?.content||[])),[p,m]=T.useState(e?.level||fs[fs.length-1]),[g,x]=T.useState();T.useEffect(()=>{if(s&&n&&n!==g){const A=structuredClone(e?.types||BT),k=e?.level||fs[fs.length-1],M=e?.content||[];c(A),m(k),f(M),t(A,k,M),x(n)}},[n]),T.useEffect(()=>{c(e?.types||[]),m(e?.level||fs[fs.length-1]),f(e?.content||[])},[e]);const v=({type:A,className:k})=>w.jsxs("div",{className:Xe("group border cursor-default border-[#EEEEEE] h-[30px] flex items-center gap-[8px] pt-[6px] pb-[5px] ps-[6px] rounded-[5px] pe-[6px] hover:bg-white",k),children:[w.jsx("img",{src:Ef[A].icon,alt:A}),w.jsx("p",{className:"text-nowrap font-normal text-[14px]",children:Ef[A].label})]},A),S=({text:A,index:k,apply:M,deleted:F,wrapperClassName:I,className:D,deleteButtonClassName:G})=>w.jsx(Xn,{value:A,side:"top",delayDuration:1e3,children:w.jsx("div",{className:Xe("group px-[2px] cursor-default max-w-[320px] bg-white border-[#EEEEEE] border h-[30px] rounded-[5px] flex justify-center items-center w-fit",I),children:w.jsxs("div",{className:Xe("flex items-center w-full justify-between max-w-full rounded-[3px] h-[calc(100%-4px)] py-[5px] ps-[5px] pe-[6px] gap-[8px]",D),children:[w.jsxs("div",{className:Xe("flex items-center gap-[8px] leading-[16px] max-w-[-webkit-fill-available]",F&&"max-w-[calc(100%-25px)]"),children:[w.jsx("img",{src:"icons/text.svg",alt:""}),w.jsx("p",{className:"text-nowrap cursor-default max-w-full overflow-hidden text-ellipsis font-light text-[14px]",children:A})]}),F&&w.jsx(gl,{role:"button",className:Xe("invisible min-w-[18px] size-[18px] group-hover:visible rounded-[3px]",G),onClick:X=>{X.stopPropagation();const P=d?.filter((Y,z)=>z!==k);M&&(f(P),t(l,p,P)),F?.()}})]})},A)}),C=()=>{const[A,k]=T.useState(!1),[M,F]=T.useState(structuredClone(e?.types||[])),[I,D]=T.useState(structuredClone(e?.content||[])),[G,X]=T.useState(e?.level||fs[fs.length-1]),P=T.useRef(null),[Y,z]=T.useState(!1),ie=(ee,ae)=>{F(de=>(ae?de.push(ee):de=de.filter(W=>W!==ee),[...new Set(de)]))};T.useEffect(()=>{A||(F(structuredClone(e?.types||[])),D(structuredClone(e?.content||[])))},[A]),T.useEffect(()=>{P?.current&&(Y4(P.current)<218?z(!0):z(!1))},[P?.current?.scrollWidth,A]);const Z=()=>{k(!A),F(structuredClone(e?.types||[])),D(structuredClone(e?.content||[]))};return w.jsxs("div",{className:"wrapper relative flex items-center h-[30px]",ref:P,children:[w.jsx("div",{children:w.jsxs("div",{onClick:Z,role:"button",className:Xe("flex group bg-white rounded-[6px] items-center gap-[6px] max-h-[30px] h-[30px] w-[73px] min-w-max pe-[8px]",A&&"bg-white border-transparent"),children:[w.jsx("img",{src:"icons/funnel.svg",className:"[stroke-width:2px] size-[16px]"}),w.jsx("p",{className:"text-[14px] group-hover:underline font-medium select-none",children:"Edit Filters"})]})}),w.jsxs("div",{className:Xe("hidden border rounded-[7px] absolute top-[38px] left-0 w-[246px] z-50 bg-white",A&&"block",Y?"right-0 left-[unset]":""),children:[w.jsxs("div",{className:"flex justify-between items-center",children:[w.jsx("div",{className:"flex items-center gap-[6px] h-[35px] px-[14px]",children:w.jsx("p",{className:"text-[14px] font-normal",children:"Filter"})}),w.jsx("div",{role:"button",onClick:Z,className:"flex h-[24px] w-[24px] items-center me-[2px] justify-center",children:w.jsx("img",{src:"icons/close.svg",alt:"close"})})]}),w.jsx("hr",{className:"bg-[#EBECF0]"}),w.jsxs("div",{className:"flex gap-[6px] items-center px-[14px]",children:[w.jsx("p",{className:"text-[14px] font-normal",children:"Level:"}),w.jsxs($G,{value:G,onValueChange:ee=>X(ee),children:[w.jsx(nR,{className:"!ring-0 !ring-offset-0 h-[30px] m-auto my-[5px] capitalize border",children:w.jsx(VG,{placeholder:G?.toLowerCase()})}),w.jsx(sR,{className:"z-[999999]",children:w.jsx(WG,{children:fs.toReversed().map(ee=>w.jsx(oR,{value:ee,className:"capitalize",children:ee?.toLowerCase()},ee))})})]})]}),w.jsx("hr",{className:"bg-[#EBECF0]"}),w.jsx("div",{className:"flex flex-col gap-[4px] mt-[9px] pb-[11px] px-[8px]",children:BT.map(ee=>w.jsxs("div",{className:Xe("flex items-center rounded-[3px] h-[24px] py-[4px] ps-[4px] space-x-2 hover:bg-main",M.includes(ee)&&"!bg-gray-4"),children:[w.jsx(y2,{id:ee,checked:M?.includes(ee),className:"[&_svg]:[stroke:#006E53] border-black rounded-[2px] !bg-white",onCheckedChange:ae=>ie(ee,!!ae)}),w.jsxs("label",{className:"text-[14px] font-light w-full cursor-pointer flex gap-[8px] !ms-[12px]",htmlFor:ee,children:[w.jsx("img",{src:Ef[ee].icon,alt:ee}),Ef[ee].label]})]},ee))}),w.jsx("hr",{className:"bg-[#EBECF0]"}),w.jsx("div",{className:Xe("inputs flex flex-wrap gap-[6px] max-h-[200px] overflow-auto px-[14px] pb-[14px] pt-[11px]",!I?.length&&"h-0 p-0"),children:I?.map((ee,ae)=>w.jsx(UT,{content:ee,contentChanged:de=>{D(j=>(j[ae]=de,[...j]))},children:w.jsx(S,{text:ee,index:ae,apply:!1,deleted:()=>D(I.filter((de,j)=>j!==ae)),wrapperClassName:"w-full !border-0 bg-[#F5F6F8] hover:bg-[#EBECF0]",className:"justify-between !border-0 bg-[#F5F6F8] group-hover:bg-[#EBECF0]",deleteButtonClassName:"visible"})},ee))}),!!I?.length&&w.jsx("hr",{className:"bg-[#EBECF0] w-full"}),w.jsx("div",{className:"px-[14px] h-[54px] flex items-center",children:w.jsx(UT,{contentChanged:ee=>D(ae=>[...ae,ee])})}),w.jsx("hr",{className:"bg-[#EBECF0]"}),w.jsxs("div",{className:"buttons flex gap-[8px] items-center h-[47px] p-[6px]",children:[w.jsx(An,{onClick:()=>t([],"DEBUG",[]),variant:"ghost",className:"flex-1 text-[12px] bg-[#FAFAFA] hover:text-[#151515] hover:bg-[#F3F5F9] font-normal text-[#656565] h-[35px] w-[95px]",children:"Clear all"}),w.jsx(An,{variant:"ghost",onClick:()=>{t(M,G,I),k(!1)},className:"flex-1 ps-[12px] pe-[10px] text-[12px] font-normal !text-white bg-green-main hover:bg-[#005C3F] w-fit max-w-fit h-[35px]",children:"Apply"})]})]})]})};return w.jsxs("div",{className:"flex items-center justify-between pe-[14px] z-[1] bg-white",children:[w.jsx("div",{className:Xe("flex z-[1] pt-[10px] pb-[8px] pe-[12px] ps-[14px] gap-[8px] h-fit min-h-[58px]",(!!e?.types?.length||!!e?.content?.length)&&"min-h-[50px]",r),children:w.jsxs("div",{className:"filters-button flex items-start gap-[10px] flex-wrap",children:[s&&!!e?.types?.length&&e.types.map(A=>w.jsx(v,{type:A},A)),s&&e?.content?.map((A,k)=>w.jsx(S,{text:A,index:k,wrapperClassName:"cursor-auto"},A)),i&&w.jsx(C,{})]})}),o&&w.jsx(An,{onClick:()=>o(n),variant:"outline",className:"self-start mt-[10px] min-h-[28px] min-w-[28px] size-[28px] p-0 border border-[#EEEEEE] rounded-[6px] shadow-main",children:w.jsx(gl,{className:"size-[14px] min-h-[14px] min-w-[14px]"})})]})},HT=T.memo(XG),o0=({title:t,subTitle:e,wrapperClassName:n,className:r,imgClassName:i,imgUrl:s})=>w.jsx("div",{className:Xe("flex flex-col m-auto justify-center items-center w-full h-full",n),children:w.jsxs("div",{className:Xe("flex flex-col justify-center items-center -translate-y-[70px]",r),children:[w.jsx("img",{className:Xe("size-[330px] pointer-events-none rounded-full",i),src:s||"empty-state.svg",alt:""}),w.jsx("h2",{className:"text-[18px] font-normal font-inter text-[#656565] mt-[30px]",children:t}),e&&w.jsx("p",{className:"text-[15px] font-normal max-w-[378px] font-inter text-[#656565] text-center mt-[10px]",children:e})]})}),QG=({filterTabs:t,setCurrFilterTabs:e,setFilterTabs:n,currFilterTabs:r})=>{const[i,s]=T.useState(!1),[o,l]=T.useState(""),c=()=>{const m={id:Date.now(),name:"Logs",def:{level:"DEBUG",types:[]}},g=[...t,m];n(g),e(m.id)},d=(m,g)=>{m.stopPropagation(),s(!0),l(g.name);function x(){const v=document.createRange(),S=window.getSelection();m.target&&(v.selectNodeContents(m.target),S?.removeAllRanges(),S?.addRange(v))}x()},f=(m,g)=>{s(!1),m.target.textContent||(m.target.textContent=o||g.name),g.name=m.target.textContent,localStorage.setItem("filters",JSON.stringify(t)),m.target.blur(),window.getSelection()?.removeAllRanges()},p=(m,g)=>{s(!1),m.target.textContent=g.name,m.target.blur()};return w.jsxs("div",{className:Xe("ps-[10px] flex gap-[8px] bg-white items-center min-h-[42px] filter-tabs border-b border-[#EDEFF3] overflow-x-auto z-10 overflow-y-visible no-scrollbar",i&&"border-[#ebecf0]"),children:[t.map(m=>w.jsx("div",{className:On("bg-[#FAFAFA] hover:bg-[#F3F5F9] border border-transparent relative rounded-[6px] text-[#A9A9A9] hover:text-[#282828]",m.id===r&&"shadow-main-inset !bg-[#FAFAFA] !text-[#282828]",m.id===r&&i&&"!border-black !shadow-none"),role:"button",onClick:()=>{s(!1),e(m.id)},children:w.jsx("div",{className:On("group flex min-h-[28px] max-w-[200px] rounded-[6px] max-h-[28px] justify-center leading-[18px] text-[15px] border border-transparent items-center border-e w-fit",m.id===r&&i&&"h-full rounded-[5px]"),children:w.jsx("div",{className:Xe("flex items-center gap-[8px] relative max-w-full"),children:w.jsx("p",{tabIndex:-1,onClick:g=>m.id===r&&d(g,m),contentEditable:m.id===r&&i,suppressContentEditableWarning:!0,onKeyDown:g=>g.key==="Enter"?f(g,m):g.key==="Escape"&&p(g,m),onBlur:g=>f(g,m),className:Xe("text-[15px] flex-1 overflow-hidden whitespace-nowrap text-ellipsis h-[28px] px-[8px] outline-none items-center border border-transparent flex !justify-start",m.id===r&&!i&&"hover:cursor-text"),children:m.name})})})},m.id)),w.jsx("div",{className:"flex gap-[10px] items-center justify-center size-[28px] min-w-[28px] w-fit sticky right-0 text-[#151515] hover:text-[#151515] bg-white hover:bg-[#f3f5f9] rounded-[6px]",role:"button",onClick:c,children:w.jsx(F4,{size:16})})]})},ZG=({event:t,sameTraceMessages:e,regenerateMessageFn:n,resendMessageFn:r,closeLogs:i,className:s,flaggedChanged:o})=>{const[l]=lt(As),[c]=lt(ws),d=t?.source==="customer",[f,p]=T.useState(null),[m,g]=T.useState(!1);T.useEffect(()=>{const v=ZD("Parlant-flags","message_flags",t?.trace_id,{name:"sessionIndex",keyPath:"sessionId"});v&&v.then(S=>{p(S?.flagValue),o?.(!!S?.flagValue)})},[t,m]);const x=e?.some(v=>v.serverStatus&&v.serverStatus!=="ready"&&v.serverStatus!=="error");return w.jsx(PA,{className:Xe("static",!t&&"!border-transparent bg-[#f5f6f8]",s),children:t&&w.jsxs("div",{className:Xe("flex items-center justify-between w-full pe-[12px]"),children:[w.jsx("div",{className:"flex",children:w.jsx("div",{role:"button",className:"p-[5px] pe-[10px]",onClick:()=>i?.(),children:w.jsx(gl,{height:25,width:25})})}),w.jsxs("div",{className:"flex items-center gap-[12px] mb-[1px]",children:[!d&&w.jsxs(An,{className:Xe("gap-1",f&&"border-[#9B0360] !text-[#9B0360]"),variant:"outline",onClick:()=>c.openDialog("Flag Response",w.jsx(c2,{existingFlagValue:f||"",events:e||[t],sessionId:l?.id,onFlag:()=>g(!m)}),{width:"600px",height:"636px"}),children:[w.jsx(nA,{color:f?"#9B0360":"black",size:16}),w.jsx("div",{children:f?"View Comment":"Flag"})]}),w.jsxs("button",{className:On("group bg-[#006E53] [box-shadow:0px_2px_4px_0px_#00403029,0px_1px_5.5px_0px_#006E5329] hover:bg-[#005C3F] flex h-[38px] rounded-[5px] ms-[4px] items-center gap-[7px] py-[13px] px-[10px]",x&&"opacity-50 cursor-not-allowed"),role:"button",disabled:x,onClick:()=>t?.source==="customer"?r?.(l?.id):n?.(l?.id),children:[w.jsx("img",{src:"icons/regenerate.svg",alt:"regenerate",className:"block"}),w.jsx("div",{className:"text-white text-[14px] font-normal",children:d?"Resend":"Regenerate"})]})]})]})})},xp=T.createContext(null);xp.displayName="PanelGroupContext";const xn={group:"data-panel-group",groupDirection:"data-panel-group-direction",groupId:"data-panel-group-id",panel:"data-panel",panelCollapsible:"data-panel-collapsible",panelId:"data-panel-id",panelSize:"data-panel-size",resizeHandle:"data-resize-handle",resizeHandleActive:"data-resize-handle-active",resizeHandleEnabled:"data-panel-resize-handle-enabled",resizeHandleId:"data-panel-resize-handle-id",resizeHandleState:"data-resize-handle-state"},g1=10,Vo=T.useLayoutEffect,zT=Qb.useId,JG=typeof zT=="function"?zT:()=>null;let eK=0;function b1(t=null){const e=JG(),n=T.useRef(t||e||null);return n.current===null&&(n.current=""+eK++),t??n.current}function aR({children:t,className:e="",collapsedSize:n,collapsible:r,defaultSize:i,forwardedRef:s,id:o,maxSize:l,minSize:c,onCollapse:d,onExpand:f,onResize:p,order:m,style:g,tagName:x="div",...v}){const S=T.useContext(xp);if(S===null)throw Error("Panel components must be rendered within a PanelGroup container");const{collapsePanel:C,expandPanel:A,getPanelSize:k,getPanelStyle:M,groupId:F,isPanelCollapsed:I,reevaluatePanelConstraints:D,registerPanel:G,resizePanel:X,unregisterPanel:P}=S,Y=b1(o),z=T.useRef({callbacks:{onCollapse:d,onExpand:f,onResize:p},constraints:{collapsedSize:n,collapsible:r,defaultSize:i,maxSize:l,minSize:c},id:Y,idIsFromProps:o!==void 0,order:m});T.useRef({didLogMissingDefaultSizeWarning:!1}),Vo(()=>{const{callbacks:Z,constraints:ee}=z.current,ae={...ee};z.current.id=Y,z.current.idIsFromProps=o!==void 0,z.current.order=m,Z.onCollapse=d,Z.onExpand=f,Z.onResize=p,ee.collapsedSize=n,ee.collapsible=r,ee.defaultSize=i,ee.maxSize=l,ee.minSize=c,(ae.collapsedSize!==ee.collapsedSize||ae.collapsible!==ee.collapsible||ae.maxSize!==ee.maxSize||ae.minSize!==ee.minSize)&&D(z.current,ae)}),Vo(()=>{const Z=z.current;return G(Z),()=>{P(Z)}},[m,Y,G,P]),T.useImperativeHandle(s,()=>({collapse:()=>{C(z.current)},expand:Z=>{A(z.current,Z)},getId(){return Y},getSize(){return k(z.current)},isCollapsed(){return I(z.current)},isExpanded(){return!I(z.current)},resize:Z=>{X(z.current,Z)}}),[C,A,k,I,Y,X]);const ie=M(z.current,i);return T.createElement(x,{...v,children:t,className:e,id:Y,style:{...ie,...g},[xn.groupId]:F,[xn.panel]:"",[xn.panelCollapsible]:r||void 0,[xn.panelId]:Y,[xn.panelSize]:parseFloat(""+ie.flexGrow).toFixed(1)})}const lR=T.forwardRef((t,e)=>T.createElement(aR,{...t,forwardedRef:e}));aR.displayName="Panel";lR.displayName="forwardRef(Panel)";let gb=null,zf=-1,to=null;function tK(t,e){if(e){const n=(e&hR)!==0,r=(e&pR)!==0,i=(e&mR)!==0,s=(e&gR)!==0;if(n)return i?"se-resize":s?"ne-resize":"e-resize";if(r)return i?"sw-resize":s?"nw-resize":"w-resize";if(i)return"s-resize";if(s)return"n-resize"}switch(t){case"horizontal":return"ew-resize";case"intersection":return"move";case"vertical":return"ns-resize"}}function nK(){to!==null&&(document.head.removeChild(to),gb=null,to=null,zf=-1)}function a0(t,e){var n,r;const i=tK(t,e);if(gb!==i){if(gb=i,to===null&&(to=document.createElement("style"),document.head.appendChild(to)),zf>=0){var s;(s=to.sheet)===null||s===void 0||s.removeRule(zf)}zf=(n=(r=to.sheet)===null||r===void 0?void 0:r.insertRule(`*{cursor: ${i} !important;}`))!==null&&n!==void 0?n:-1}}function uR(t){return t.type==="keydown"}function cR(t){return t.type.startsWith("pointer")}function dR(t){return t.type.startsWith("mouse")}function vp(t){if(cR(t)){if(t.isPrimary)return{x:t.clientX,y:t.clientY}}else if(dR(t))return{x:t.clientX,y:t.clientY};return{x:1/0,y:1/0}}function rK(){if(typeof matchMedia=="function")return matchMedia("(pointer:coarse)").matches?"coarse":"fine"}function iK(t,e,n){return t.xe.x&&t.ye.y}function sK(t,e){if(t===e)throw new Error("Cannot compare node with itself");const n={a:WT(t),b:WT(e)};let r;for(;n.a.at(-1)===n.b.at(-1);)t=n.a.pop(),e=n.b.pop(),r=t;gt(r,"Stacking order can only be calculated for elements with a common ancestor");const i={a:$T(jT(n.a)),b:$T(jT(n.b))};if(i.a===i.b){const s=r.childNodes,o={a:n.a.at(-1),b:n.b.at(-1)};let l=s.length;for(;l--;){const c=s[l];if(c===o.a)return 1;if(c===o.b)return-1}}return Math.sign(i.a-i.b)}const oK=/\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/;function aK(t){var e;const n=getComputedStyle((e=fR(t))!==null&&e!==void 0?e:t).display;return n==="flex"||n==="inline-flex"}function lK(t){const e=getComputedStyle(t);return!!(e.position==="fixed"||e.zIndex!=="auto"&&(e.position!=="static"||aK(t))||+e.opacity<1||"transform"in e&&e.transform!=="none"||"webkitTransform"in e&&e.webkitTransform!=="none"||"mixBlendMode"in e&&e.mixBlendMode!=="normal"||"filter"in e&&e.filter!=="none"||"webkitFilter"in e&&e.webkitFilter!=="none"||"isolation"in e&&e.isolation==="isolate"||oK.test(e.willChange)||e.webkitOverflowScrolling==="touch")}function jT(t){let e=t.length;for(;e--;){const n=t[e];if(gt(n,"Missing node"),lK(n))return n}return null}function $T(t){return t&&Number(getComputedStyle(t).zIndex)||0}function WT(t){const e=[];for(;t;)e.push(t),t=fR(t);return e}function fR(t){const{parentNode:e}=t;return e&&e instanceof ShadowRoot?e.host:e}const hR=1,pR=2,mR=4,gR=8,uK=rK()==="coarse";let wi=[],ll=!1,Bo=new Map,wp=new Map;const gc=new Set;function cK(t,e,n,r,i){var s;const{ownerDocument:o}=e,l={direction:n,element:e,hitAreaMargins:r,setResizeHandlerState:i},c=(s=Bo.get(o))!==null&&s!==void 0?s:0;return Bo.set(o,c+1),gc.add(l),Eh(),function(){var f;wp.delete(t),gc.delete(l);const p=(f=Bo.get(o))!==null&&f!==void 0?f:1;if(Bo.set(o,p-1),Eh(),p===1&&Bo.delete(o),wi.includes(l)){const m=wi.indexOf(l);m>=0&&wi.splice(m,1),y1(),i("up",!0,null)}}}function dK(t){const{target:e}=t,{x:n,y:r}=vp(t);ll=!0,E1({target:e,x:n,y:r}),Eh(),wi.length>0&&(yh("down",t),t.preventDefault(),bR(e)||t.stopImmediatePropagation())}function l0(t){const{x:e,y:n}=vp(t);if(ll&&t.buttons===0&&(ll=!1,yh("up",t)),!ll){const{target:r}=t;E1({target:r,x:e,y:n})}yh("move",t),y1(),wi.length>0&&t.preventDefault()}function u0(t){const{target:e}=t,{x:n,y:r}=vp(t);wp.clear(),ll=!1,wi.length>0&&(t.preventDefault(),bR(e)||t.stopImmediatePropagation()),yh("up",t),E1({target:e,x:n,y:r}),y1(),Eh()}function bR(t){let e=t;for(;e;){if(e.hasAttribute(xn.resizeHandle))return!0;e=e.parentElement}return!1}function E1({target:t,x:e,y:n}){wi.splice(0);let r=null;(t instanceof HTMLElement||t instanceof SVGElement)&&(r=t),gc.forEach(i=>{const{element:s,hitAreaMargins:o}=i,l=s.getBoundingClientRect(),{bottom:c,left:d,right:f,top:p}=l,m=uK?o.coarse:o.fine;if(e>=d-m&&e<=f+m&&n>=p-m&&n<=c+m){if(r!==null&&document.contains(r)&&s!==r&&!s.contains(r)&&!r.contains(s)&&sK(r,s)>0){let x=r,v=!1;for(;x&&!x.contains(s);){if(iK(x.getBoundingClientRect(),l)){v=!0;break}x=x.parentElement}if(v)return}wi.push(i)}})}function c0(t,e){wp.set(t,e)}function y1(){let t=!1,e=!1;wi.forEach(r=>{const{direction:i}=r;i==="horizontal"?t=!0:e=!0});let n=0;wp.forEach(r=>{n|=r}),t&&e?a0("intersection",n):t?a0("horizontal",n):e?a0("vertical",n):nK()}let d0=new AbortController;function Eh(){d0.abort(),d0=new AbortController;const t={capture:!0,signal:d0.signal};gc.size&&(ll?(wi.length>0&&Bo.forEach((e,n)=>{const{body:r}=n;e>0&&(r.addEventListener("contextmenu",u0,t),r.addEventListener("pointerleave",l0,t),r.addEventListener("pointermove",l0,t))}),window.addEventListener("pointerup",u0,t),window.addEventListener("pointercancel",u0,t)):Bo.forEach((e,n)=>{const{body:r}=n;e>0&&(r.addEventListener("pointerdown",dK,t),r.addEventListener("pointermove",l0,t))}))}function yh(t,e){gc.forEach(n=>{const{setResizeHandlerState:r}=n,i=wi.includes(n);r(t,i,e)})}function fK(){const[t,e]=T.useState(0);return T.useCallback(()=>e(n=>n+1),[])}function gt(t,e){if(!t)throw console.error(e),Error(e)}function Jo(t,e,n=g1){return t.toFixed(n)===e.toFixed(n)?0:t>e?1:-1}function ps(t,e,n=g1){return Jo(t,e,n)===0}function zr(t,e,n){return Jo(t,e,n)===0}function hK(t,e,n){if(t.length!==e.length)return!1;for(let r=0;r0&&(t=t<0?0-C:C)}}}{const p=t<0?l:c,m=n[p];gt(m,`No panel constraints found for index ${p}`);const{collapsedSize:g=0,collapsible:x,minSize:v=0}=m;if(x){const S=e[p];if(gt(S!=null,`Previous layout not found for panel index ${p}`),zr(S,v)){const C=S-g;Jo(C,Math.abs(t))>0&&(t=t<0?0-C:C)}}}}{const p=t<0?1:-1;let m=t<0?c:l,g=0;for(;;){const v=e[m];gt(v!=null,`Previous layout not found for panel index ${m}`);const C=Ja({panelConstraints:n,panelIndex:m,size:100})-v;if(g+=C,m+=p,m<0||m>=n.length)break}const x=Math.min(Math.abs(t),Math.abs(g));t=t<0?0-x:x}{let m=t<0?l:c;for(;m>=0&&m=0))break;t<0?m--:m++}}if(hK(i,o))return i;{const p=t<0?c:l,m=e[p];gt(m!=null,`Previous layout not found for panel index ${p}`);const g=m+d,x=Ja({panelConstraints:n,panelIndex:p,size:g});if(o[p]=x,!zr(x,g)){let v=g-x,C=t<0?c:l;for(;C>=0&&C0?C--:C++}}}const f=o.reduce((p,m)=>m+p,0);return zr(f,100)?o:i}function pK({layout:t,panelsArray:e,pivotIndices:n}){let r=0,i=100,s=0,o=0;const l=n[0];gt(l!=null,"No pivot index found"),e.forEach((p,m)=>{const{constraints:g}=p,{maxSize:x=100,minSize:v=0}=g;m===l?(r=v,i=x):(s+=v,o+=x)});const c=Math.min(i,100-s),d=Math.max(r,100-o),f=t[l];return{valueMax:c,valueMin:d,valueNow:f}}function bc(t,e=document){return Array.from(e.querySelectorAll(`[${xn.resizeHandleId}][data-panel-group-id="${t}"]`))}function ER(t,e,n=document){const i=bc(t,n).findIndex(s=>s.getAttribute(xn.resizeHandleId)===e);return i??null}function yR(t,e,n){const r=ER(t,e,n);return r!=null?[r,r+1]:[-1,-1]}function xR(t,e=document){var n;if(e instanceof HTMLElement&&(e==null||(n=e.dataset)===null||n===void 0?void 0:n.panelGroupId)==t)return e;const r=e.querySelector(`[data-panel-group][data-panel-group-id="${t}"]`);return r||null}function Tp(t,e=document){const n=e.querySelector(`[${xn.resizeHandleId}="${t}"]`);return n||null}function mK(t,e,n,r=document){var i,s,o,l;const c=Tp(e,r),d=bc(t,r),f=c?d.indexOf(c):-1,p=(i=(s=n[f])===null||s===void 0?void 0:s.id)!==null&&i!==void 0?i:null,m=(o=(l=n[f+1])===null||l===void 0?void 0:l.id)!==null&&o!==void 0?o:null;return[p,m]}function gK({committedValuesRef:t,eagerValuesRef:e,groupId:n,layout:r,panelDataArray:i,panelGroupElement:s,setLayout:o}){T.useRef({didWarnAboutMissingResizeHandle:!1}),Vo(()=>{if(!s)return;const l=bc(n,s);for(let c=0;c{l.forEach((c,d)=>{c.removeAttribute("aria-controls"),c.removeAttribute("aria-valuemax"),c.removeAttribute("aria-valuemin"),c.removeAttribute("aria-valuenow")})}},[n,r,i,s]),T.useEffect(()=>{if(!s)return;const l=e.current;gt(l,"Eager values not found");const{panelDataArray:c}=l,d=xR(n,s);gt(d!=null,`No group found for id "${n}"`);const f=bc(n,s);gt(f,`No resize handles found for group id "${n}"`);const p=f.map(m=>{const g=m.getAttribute(xn.resizeHandleId);gt(g,"Resize handle element has no handle id attribute");const[x,v]=mK(n,g,c,s);if(x==null||v==null)return()=>{};const S=C=>{if(!C.defaultPrevented)switch(C.key){case"Enter":{C.preventDefault();const A=c.findIndex(k=>k.id===x);if(A>=0){const k=c[A];gt(k,`No panel data found for index ${A}`);const M=r[A],{collapsedSize:F=0,collapsible:I,minSize:D=0}=k.constraints;if(M!=null&&I){const G=zu({delta:zr(M,F)?D-F:F-M,initialLayout:r,panelConstraints:c.map(X=>X.constraints),pivotIndices:yR(n,g,s),prevLayout:r,trigger:"keyboard"});r!==G&&o(G)}}break}}};return m.addEventListener("keydown",S),()=>{m.removeEventListener("keydown",S)}});return()=>{p.forEach(m=>m())}},[s,t,e,n,r,i,o])}function VT(t,e){if(t.length!==e.length)return!1;for(let n=0;ns.constraints);let r=0,i=100;for(let s=0;s{const s=t[i];gt(s,`Panel data not found for index ${i}`);const{callbacks:o,constraints:l,id:c}=s,{collapsedSize:d=0,collapsible:f}=l,p=n[c];if(p==null||r!==p){n[c]=r;const{onCollapse:m,onExpand:g,onResize:x}=o;x&&x(r,p),f&&(m||g)&&(g&&(p==null||ps(p,d))&&!ps(r,d)&&g(),m&&(p==null||!ps(p,d))&&ps(r,d)&&m())}})}function yf(t,e){if(t.length!==e.length)return!1;for(let n=0;n{n!==null&&clearTimeout(n),n=setTimeout(()=>{t(...i)},e)}}function GT(t){try{if(typeof localStorage<"u")t.getItem=e=>localStorage.getItem(e),t.setItem=(e,n)=>{localStorage.setItem(e,n)};else throw new Error("localStorage not supported in this environment")}catch(e){console.error(e),t.getItem=()=>null,t.setItem=()=>{}}}function wR(t){return`react-resizable-panels:${t}`}function TR(t){return t.map(e=>{const{constraints:n,id:r,idIsFromProps:i,order:s}=e;return i?r:s?`${s}:${JSON.stringify(n)}`:JSON.stringify(n)}).sort((e,n)=>e.localeCompare(n)).join(",")}function SR(t,e){try{const n=wR(t),r=e.getItem(n);if(r){const i=JSON.parse(r);if(typeof i=="object"&&i!=null)return i}}catch{}return null}function wK(t,e,n){var r,i;const s=(r=SR(t,n))!==null&&r!==void 0?r:{},o=TR(e);return(i=s[o])!==null&&i!==void 0?i:null}function TK(t,e,n,r,i){var s;const o=wR(t),l=TR(e),c=(s=SR(t,i))!==null&&s!==void 0?s:{};c[l]={expandToSizes:Object.fromEntries(n.entries()),layout:r};try{i.setItem(o,JSON.stringify(c))}catch(d){console.error(d)}}function KT({layout:t,panelConstraints:e}){const n=[...t],r=n.reduce((s,o)=>s+o,0);if(n.length!==e.length)throw Error(`Invalid ${e.length} panel layout: ${n.map(s=>`${s}%`).join(", ")}`);if(!zr(r,100)&&n.length>0)for(let s=0;s(GT(ju),ju.getItem(t)),setItem:(t,e)=>{GT(ju),ju.setItem(t,e)}},YT={};function _R({autoSaveId:t=null,children:e,className:n="",direction:r,forwardedRef:i,id:s=null,onLayout:o=null,keyboardResizeBy:l=null,storage:c=ju,style:d,tagName:f="div",...p}){const m=b1(s),g=T.useRef(null),[x,v]=T.useState(null),[S,C]=T.useState([]),A=fK(),k=T.useRef({}),M=T.useRef(new Map),F=T.useRef(0),I=T.useRef({autoSaveId:t,direction:r,dragState:x,id:m,keyboardResizeBy:l,onLayout:o,storage:c}),D=T.useRef({layout:S,panelDataArray:[],panelDataArrayChanged:!1});T.useRef({didLogIdAndOrderWarning:!1,didLogPanelConstraintsWarning:!1,prevPanelIds:[]}),T.useImperativeHandle(i,()=>({getId:()=>I.current.id,getLayout:()=>{const{layout:R}=D.current;return R},setLayout:R=>{const{onLayout:oe}=I.current,{layout:pe,panelDataArray:ue}=D.current,J=KT({layout:R,panelConstraints:ue.map(he=>he.constraints)});VT(pe,J)||(C(J),D.current.layout=J,oe&&oe(J),$a(ue,J,k.current))}}),[]),Vo(()=>{I.current.autoSaveId=t,I.current.direction=r,I.current.dragState=x,I.current.id=m,I.current.onLayout=o,I.current.storage=c}),gK({committedValuesRef:I,eagerValuesRef:D,groupId:m,layout:S,panelDataArray:D.current.panelDataArray,setLayout:C,panelGroupElement:g.current}),T.useEffect(()=>{const{panelDataArray:R}=D.current;if(t){if(S.length===0||S.length!==R.length)return;let oe=YT[t];oe==null&&(oe=vK(TK,SK),YT[t]=oe);const pe=[...R],ue=new Map(M.current);oe(t,pe,ue,S,c)}},[t,S,c]),T.useEffect(()=>{});const G=T.useCallback(R=>{const{onLayout:oe}=I.current,{layout:pe,panelDataArray:ue}=D.current;if(R.constraints.collapsible){const J=ue.map(Ve=>Ve.constraints),{collapsedSize:he=0,panelSize:_e,pivotIndices:ke}=Fo(ue,R,pe);if(gt(_e!=null,`Panel size not found for panel "${R.id}"`),!ps(_e,he)){M.current.set(R.id,_e);const ot=Ya(ue,R)===ue.length-1?_e-he:he-_e,qe=zu({delta:ot,initialLayout:pe,panelConstraints:J,pivotIndices:ke,prevLayout:pe,trigger:"imperative-api"});yf(pe,qe)||(C(qe),D.current.layout=qe,oe&&oe(qe),$a(ue,qe,k.current))}}},[]),X=T.useCallback((R,oe)=>{const{onLayout:pe}=I.current,{layout:ue,panelDataArray:J}=D.current;if(R.constraints.collapsible){const he=J.map(kt=>kt.constraints),{collapsedSize:_e=0,panelSize:ke=0,minSize:Ve=0,pivotIndices:ot}=Fo(J,R,ue),qe=oe??Ve;if(ps(ke,_e)){const kt=M.current.get(R.id),fn=kt!=null&&kt>=qe?kt:qe,Yt=Ya(J,R)===J.length-1?ke-fn:fn-ke,Ct=zu({delta:Yt,initialLayout:ue,panelConstraints:he,pivotIndices:ot,prevLayout:ue,trigger:"imperative-api"});yf(ue,Ct)||(C(Ct),D.current.layout=Ct,pe&&pe(Ct),$a(J,Ct,k.current))}}},[]),P=T.useCallback(R=>{const{layout:oe,panelDataArray:pe}=D.current,{panelSize:ue}=Fo(pe,R,oe);return gt(ue!=null,`Panel size not found for panel "${R.id}"`),ue},[]),Y=T.useCallback((R,oe)=>{const{panelDataArray:pe}=D.current,ue=Ya(pe,R);return xK({defaultSize:oe,dragState:x,layout:S,panelData:pe,panelIndex:ue})},[x,S]),z=T.useCallback(R=>{const{layout:oe,panelDataArray:pe}=D.current,{collapsedSize:ue=0,collapsible:J,panelSize:he}=Fo(pe,R,oe);return gt(he!=null,`Panel size not found for panel "${R.id}"`),J===!0&&ps(he,ue)},[]),ie=T.useCallback(R=>{const{layout:oe,panelDataArray:pe}=D.current,{collapsedSize:ue=0,collapsible:J,panelSize:he}=Fo(pe,R,oe);return gt(he!=null,`Panel size not found for panel "${R.id}"`),!J||Jo(he,ue)>0},[]),Z=T.useCallback(R=>{const{panelDataArray:oe}=D.current;oe.push(R),oe.sort((pe,ue)=>{const J=pe.order,he=ue.order;return J==null&&he==null?0:J==null?-1:he==null?1:J-he}),D.current.panelDataArrayChanged=!0,A()},[A]);Vo(()=>{if(D.current.panelDataArrayChanged){D.current.panelDataArrayChanged=!1;const{autoSaveId:R,onLayout:oe,storage:pe}=I.current,{layout:ue,panelDataArray:J}=D.current;let he=null;if(R){const ke=wK(R,J,pe);ke&&(M.current=new Map(Object.entries(ke.expandToSizes)),he=ke.layout)}he==null&&(he=yK({panelDataArray:J}));const _e=KT({layout:he,panelConstraints:J.map(ke=>ke.constraints)});VT(ue,_e)||(C(_e),D.current.layout=_e,oe&&oe(_e),$a(J,_e,k.current))}}),Vo(()=>{const R=D.current;return()=>{R.layout=[]}},[]);const ee=T.useCallback(R=>{let oe=!1;const pe=g.current;return pe&&window.getComputedStyle(pe,null).getPropertyValue("direction")==="rtl"&&(oe=!0),function(J){J.preventDefault();const he=g.current;if(!he)return()=>null;const{direction:_e,dragState:ke,id:Ve,keyboardResizeBy:ot,onLayout:qe}=I.current,{layout:kt,panelDataArray:fn}=D.current,{initialLayout:nt}=ke??{},Yt=yR(Ve,R,he);let Ct=EK(J,R,_e,ke,ot,he);const Pn=_e==="horizontal";Pn&&oe&&(Ct=-Ct);const Fn=fn.map(Mn=>Mn.constraints),on=zu({delta:Ct,initialLayout:nt??kt,panelConstraints:Fn,pivotIndices:Yt,prevLayout:kt,trigger:uR(J)?"keyboard":"mouse-or-touch"}),dr=!yf(kt,on);(cR(J)||dR(J))&&F.current!=Ct&&(F.current=Ct,!dr&&Ct!==0?Pn?c0(R,Ct<0?hR:pR):c0(R,Ct<0?mR:gR):c0(R,0)),dr&&(C(on),D.current.layout=on,qe&&qe(on),$a(fn,on,k.current))}},[]),ae=T.useCallback((R,oe)=>{const{onLayout:pe}=I.current,{layout:ue,panelDataArray:J}=D.current,he=J.map(kt=>kt.constraints),{panelSize:_e,pivotIndices:ke}=Fo(J,R,ue);gt(_e!=null,`Panel size not found for panel "${R.id}"`);const ot=Ya(J,R)===J.length-1?_e-oe:oe-_e,qe=zu({delta:ot,initialLayout:ue,panelConstraints:he,pivotIndices:ke,prevLayout:ue,trigger:"imperative-api"});yf(ue,qe)||(C(qe),D.current.layout=qe,pe&&pe(qe),$a(J,qe,k.current))},[]),de=T.useCallback((R,oe)=>{const{layout:pe,panelDataArray:ue}=D.current,{collapsedSize:J=0,collapsible:he}=oe,{collapsedSize:_e=0,collapsible:ke,maxSize:Ve=100,minSize:ot=0}=R.constraints,{panelSize:qe}=Fo(ue,R,pe);qe!=null&&(he&&ke&&ps(qe,J)?ps(J,_e)||ae(R,_e):qeVe&&ae(R,Ve))},[ae]),j=T.useCallback((R,oe)=>{const{direction:pe}=I.current,{layout:ue}=D.current;if(!g.current)return;const J=Tp(R,g.current);gt(J,`Drag handle element not found for id "${R}"`);const he=vR(pe,oe);v({dragHandleId:R,dragHandleRect:J.getBoundingClientRect(),initialCursorPosition:he,initialLayout:ue})},[]),W=T.useCallback(()=>{v(null)},[]),O=T.useCallback(R=>{const{panelDataArray:oe}=D.current,pe=Ya(oe,R);pe>=0&&(oe.splice(pe,1),delete k.current[R.id],D.current.panelDataArrayChanged=!0,A())},[A]),U=T.useMemo(()=>({collapsePanel:G,direction:r,dragState:x,expandPanel:X,getPanelSize:P,getPanelStyle:Y,groupId:m,isPanelCollapsed:z,isPanelExpanded:ie,reevaluatePanelConstraints:de,registerPanel:Z,registerResizeHandle:ee,resizePanel:ae,startDragging:j,stopDragging:W,unregisterPanel:O,panelGroupElement:g.current}),[G,x,r,X,P,Y,m,z,ie,de,Z,ee,ae,j,W,O]),Q={display:"flex",flexDirection:r==="horizontal"?"row":"column",height:"100%",overflow:"hidden",width:"100%"};return T.createElement(xp.Provider,{value:U},T.createElement(f,{...p,children:e,className:n,id:s,ref:g,style:{...Q,...d},[xn.group]:"",[xn.groupDirection]:r,[xn.groupId]:m}))}const CR=T.forwardRef((t,e)=>T.createElement(_R,{...t,forwardedRef:e}));_R.displayName="PanelGroup";CR.displayName="forwardRef(PanelGroup)";function Ya(t,e){return t.findIndex(n=>n===e||n.id===e.id)}function Fo(t,e,n){const r=Ya(t,e),s=r===t.length-1?[r-1,r]:[r,r+1],o=n[r];return{...e.constraints,panelSize:o,pivotIndices:s}}function _K({disabled:t,handleId:e,resizeHandler:n,panelGroupElement:r}){T.useEffect(()=>{if(t||n==null||r==null)return;const i=Tp(e,r);if(i==null)return;const s=o=>{if(!o.defaultPrevented)switch(o.key){case"ArrowDown":case"ArrowLeft":case"ArrowRight":case"ArrowUp":case"End":case"Home":{o.preventDefault(),n(o);break}case"F6":{o.preventDefault();const l=i.getAttribute(xn.groupId);gt(l,`No group element found for id "${l}"`);const c=bc(l,r),d=ER(l,e,r);gt(d!==null,`No resize element found for id "${e}"`);const f=o.shiftKey?d>0?d-1:c.length-1:d+1{i.removeEventListener("keydown",s)}},[r,t,e,n])}function AR({children:t=null,className:e="",disabled:n=!1,hitAreaMargins:r,id:i,onBlur:s,onClick:o,onDragging:l,onFocus:c,onPointerDown:d,onPointerUp:f,style:p={},tabIndex:m=0,tagName:g="div",...x}){var v,S;const C=T.useRef(null),A=T.useRef({onClick:o,onDragging:l,onPointerDown:d,onPointerUp:f});T.useEffect(()=>{A.current.onClick=o,A.current.onDragging=l,A.current.onPointerDown=d,A.current.onPointerUp=f});const k=T.useContext(xp);if(k===null)throw Error("PanelResizeHandle components must be rendered within a PanelGroup container");const{direction:M,groupId:F,registerResizeHandle:I,startDragging:D,stopDragging:G,panelGroupElement:X}=k,P=b1(i),[Y,z]=T.useState("inactive"),[ie,Z]=T.useState(!1),[ee,ae]=T.useState(null),de=T.useRef({state:Y});Vo(()=>{de.current.state=Y}),T.useEffect(()=>{if(n)ae(null);else{const U=I(P);ae(()=>U)}},[n,P,I]);const j=(v=r?.coarse)!==null&&v!==void 0?v:15,W=(S=r?.fine)!==null&&S!==void 0?S:5;T.useEffect(()=>{if(n||ee==null)return;const U=C.current;gt(U,"Element ref not attached");let Q=!1;return cK(P,U,M,{coarse:j,fine:W},(oe,pe,ue)=>{if(!pe){z("inactive");return}switch(oe){case"down":{z("drag"),Q=!1,gt(ue,'Expected event to be defined for "down" action'),D(P,ue);const{onDragging:J,onPointerDown:he}=A.current;J?.(!0),he?.();break}case"move":{const{state:J}=de.current;Q=!0,J!=="drag"&&z("hover"),gt(ue,'Expected event to be defined for "move" action'),ee(ue);break}case"up":{z("hover"),G();const{onClick:J,onDragging:he,onPointerUp:_e}=A.current;he?.(!1),_e?.(),Q||J?.();break}}})},[j,M,n,W,I,P,ee,D,G]),_K({disabled:n,handleId:P,resizeHandler:ee,panelGroupElement:X});const O={touchAction:"none",userSelect:"none"};return T.createElement(g,{...x,children:t,className:e,id:i,onBlur:()=>{Z(!1),s?.()},onFocus:()=>{Z(!0),c?.()},ref:C,role:"separator",style:{...O,...p},tabIndex:m,[xn.groupDirection]:M,[xn.groupId]:F,[xn.resizeHandle]:"",[xn.resizeHandleActive]:Y==="drag"?"pointer":ie?"keyboard":void 0,[xn.resizeHandleEnabled]:!n,[xn.resizeHandleId]:P,[xn.resizeHandleState]:Y})}AR.displayName="PanelResizeHandle";const CK=({className:t,...e})=>w.jsx(CR,{className:Rt("flex h-full w-full data-[panel-group-direction=vertical]:flex-col",t),...e}),qT=lR,AK=({withHandle:t,className:e,...n})=>w.jsx(AR,{className:Rt("relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",e),...n,children:t&&w.jsx("div",{className:"z-10 flex h-4 w-3 items-center justify-center rounded-sm",children:w.jsx("img",{src:"icons/resize.svg",className:"rotate-90 max-w-[unset]",alt:""})})});let bb=[],kR=[];(()=>{let t="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(e=>e?parseInt(e,36):1);for(let e=0,n=0;e>1;if(t=kR[r])e=r+1;else return!0;if(e==n)return!1}}function XT(t){return t>=127462&&t<=127487}const QT=8205;function NK(t,e,n=!0,r=!0){return(n?NR:RK)(t,e,r)}function NR(t,e,n){if(e==t.length)return e;e&&RR(t.charCodeAt(e))&&IR(t.charCodeAt(e-1))&&e--;let r=f0(t,e);for(e+=ZT(r);e=0&&XT(f0(t,o));)s++,o-=2;if(s%2==0)break;e+=2}else break}return e}function RK(t,e,n){for(;e>0;){let r=NR(t,e-2,n);if(r=56320&&t<57344}function IR(t){return t>=55296&&t<56320}function ZT(t){return t<65536?1:2}class Lt{lineAt(e){if(e<0||e>this.length)throw new RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw new RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,n,r){[e,n]=xl(this,e,n);let i=[];return this.decompose(0,e,i,2),r.length&&r.decompose(0,r.length,i,3),this.decompose(n,this.length,i,1),$i.from(i,this.length-(n-e)+r.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,n=this.length){[e,n]=xl(this,e,n);let r=[];return this.decompose(e,n,r,0),$i.from(r,n-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let n=this.scanIdentical(e,1),r=this.length-this.scanIdentical(e,-1),i=new ec(this),s=new ec(e);for(let o=n,l=n;;){if(i.next(o),s.next(o),o=0,i.lineBreak!=s.lineBreak||i.done!=s.done||i.value!=s.value)return!1;if(l+=i.value.length,i.done||l>=r)return!0}}iter(e=1){return new ec(this,e)}iterRange(e,n=this.length){return new OR(this,e,n)}iterLines(e,n){let r;if(e==null)r=this.iter();else{n==null&&(n=this.lines+1);let i=this.line(e).from;r=this.iterRange(i,Math.max(i,n==this.lines+1?this.length:n<=1?0:this.line(n-1).to))}return new MR(r)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(e){if(e.length==0)throw new RangeError("A document must have at least one line");return e.length==1&&!e[0]?Lt.empty:e.length<=32?new Sn(e):$i.from(Sn.split(e,[]))}}class Sn extends Lt{constructor(e,n=IK(e)){super(),this.text=e,this.length=n}get lines(){return this.text.length}get children(){return null}lineInner(e,n,r,i){for(let s=0;;s++){let o=this.text[s],l=i+o.length;if((n?r:l)>=e)return new OK(i,l,r,o);i=l+1,r++}}decompose(e,n,r,i){let s=e<=0&&n>=this.length?this:new Sn(JT(this.text,e,n),Math.min(n,this.length)-Math.max(0,e));if(i&1){let o=r.pop(),l=jf(s.text,o.text.slice(),0,s.length);if(l.length<=32)r.push(new Sn(l,o.length+s.length));else{let c=l.length>>1;r.push(new Sn(l.slice(0,c)),new Sn(l.slice(c)))}}else r.push(s)}replace(e,n,r){if(!(r instanceof Sn))return super.replace(e,n,r);[e,n]=xl(this,e,n);let i=jf(this.text,jf(r.text,JT(this.text,0,e)),n),s=this.length+r.length-(n-e);return i.length<=32?new Sn(i,s):$i.from(Sn.split(i,[]),s)}sliceString(e,n=this.length,r=` +`){[e,n]=xl(this,e,n);let i="";for(let s=0,o=0;s<=n&&oe&&o&&(i+=r),es&&(i+=l.slice(Math.max(0,e-s),n-s)),s=c+1}return i}flatten(e){for(let n of this.text)e.push(n)}scanIdentical(){return 0}static split(e,n){let r=[],i=-1;for(let s of e)r.push(s),i+=s.length+1,r.length==32&&(n.push(new Sn(r,i)),r=[],i=-1);return i>-1&&n.push(new Sn(r,i)),n}}class $i extends Lt{constructor(e,n){super(),this.children=e,this.length=n,this.lines=0;for(let r of e)this.lines+=r.lines}lineInner(e,n,r,i){for(let s=0;;s++){let o=this.children[s],l=i+o.length,c=r+o.lines-1;if((n?c:l)>=e)return o.lineInner(e,n,r,i);i=l+1,r=c+1}}decompose(e,n,r,i){for(let s=0,o=0;o<=n&&s=o){let d=i&((o<=e?1:0)|(c>=n?2:0));o>=e&&c<=n&&!d?r.push(l):l.decompose(e-o,n-o,r,d)}o=c+1}}replace(e,n,r){if([e,n]=xl(this,e,n),r.lines=s&&n<=l){let c=o.replace(e-s,n-s,r),d=this.lines-o.lines+c.lines;if(c.lines>4&&c.lines>d>>6){let f=this.children.slice();return f[i]=c,new $i(f,this.length-(n-e)+r.length)}return super.replace(s,l,c)}s=l+1}return super.replace(e,n,r)}sliceString(e,n=this.length,r=` +`){[e,n]=xl(this,e,n);let i="";for(let s=0,o=0;se&&s&&(i+=r),eo&&(i+=l.sliceString(e-o,n-o,r)),o=c+1}return i}flatten(e){for(let n of this.children)n.flatten(e)}scanIdentical(e,n){if(!(e instanceof $i))return 0;let r=0,[i,s,o,l]=n>0?[0,0,this.children.length,e.children.length]:[this.children.length-1,e.children.length-1,-1,-1];for(;;i+=n,s+=n){if(i==o||s==l)return r;let c=this.children[i],d=e.children[s];if(c!=d)return r+c.scanIdentical(d,n);r+=c.length+1}}static from(e,n=e.reduce((r,i)=>r+i.length+1,-1)){let r=0;for(let g of e)r+=g.lines;if(r<32){let g=[];for(let x of e)x.flatten(g);return new Sn(g,n)}let i=Math.max(32,r>>5),s=i<<1,o=i>>1,l=[],c=0,d=-1,f=[];function p(g){let x;if(g.lines>s&&g instanceof $i)for(let v of g.children)p(v);else g.lines>o&&(c>o||!c)?(m(),l.push(g)):g instanceof Sn&&c&&(x=f[f.length-1])instanceof Sn&&g.lines+x.lines<=32?(c+=g.lines,d+=g.length+1,f[f.length-1]=new Sn(x.text.concat(g.text),x.length+1+g.length)):(c+g.lines>i&&m(),c+=g.lines,d+=g.length+1,f.push(g))}function m(){c!=0&&(l.push(f.length==1?f[0]:$i.from(f,d)),d=-1,c=f.length=0)}for(let g of e)p(g);return m(),l.length==1?l[0]:new $i(l,n)}}Lt.empty=new Sn([""],0);function IK(t){let e=-1;for(let n of t)e+=n.length+1;return e}function jf(t,e,n=0,r=1e9){for(let i=0,s=0,o=!0;s=n&&(c>r&&(l=l.slice(0,r-i)),i0?1:(e instanceof Sn?e.text.length:e.children.length)<<1]}nextInner(e,n){for(this.done=this.lineBreak=!1;;){let r=this.nodes.length-1,i=this.nodes[r],s=this.offsets[r],o=s>>1,l=i instanceof Sn?i.text.length:i.children.length;if(o==(n>0?l:0)){if(r==0)return this.done=!0,this.value="",this;n>0&&this.offsets[r-1]++,this.nodes.pop(),this.offsets.pop()}else if((s&1)==(n>0?0:1)){if(this.offsets[r]+=n,e==0)return this.lineBreak=!0,this.value=` +`,this;e--}else if(i instanceof Sn){let c=i.text[o+(n<0?-1:0)];if(this.offsets[r]+=n,c.length>Math.max(0,e))return this.value=e==0?c:n>0?c.slice(e):c.slice(0,c.length-e),this;e-=c.length}else{let c=i.children[o+(n<0?-1:0)];e>c.length?(e-=c.length,this.offsets[r]+=n):(n<0&&this.offsets[r]--,this.nodes.push(c),this.offsets.push(n>0?1:(c instanceof Sn?c.text.length:c.children.length)<<1))}}}next(e=0){return e<0&&(this.nextInner(-e,-this.dir),e=this.value.length),this.nextInner(e,this.dir)}}class OR{constructor(e,n,r){this.value="",this.done=!1,this.cursor=new ec(e,n>r?-1:1),this.pos=n>r?e.length:0,this.from=Math.min(n,r),this.to=Math.max(n,r)}nextInner(e,n){if(n<0?this.pos<=this.from:this.pos>=this.to)return this.value="",this.done=!0,this;e+=Math.max(0,n<0?this.pos-this.to:this.from-this.pos);let r=n<0?this.pos-this.from:this.to-this.pos;e>r&&(e=r),r-=e;let{value:i}=this.cursor.next(e);return this.pos+=(i.length+e)*n,this.value=i.length<=r?i:n<0?i.slice(i.length-r):i.slice(0,r),this.done=!this.value,this}next(e=0){return e<0?e=Math.max(e,this.from-this.pos):e>0&&(e=Math.min(e,this.to-this.pos)),this.nextInner(e,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=""}}class MR{constructor(e){this.inner=e,this.afterBreak=!0,this.value="",this.done=!1}next(e=0){let{done:n,lineBreak:r,value:i}=this.inner.next(e);return n&&this.afterBreak?(this.value="",this.afterBreak=!1):n?(this.done=!0,this.value=""):r?this.afterBreak?this.value="":(this.afterBreak=!0,this.next()):(this.value=i,this.afterBreak=!1),this}get lineBreak(){return!1}}typeof Symbol<"u"&&(Lt.prototype[Symbol.iterator]=function(){return this.iter()},ec.prototype[Symbol.iterator]=OR.prototype[Symbol.iterator]=MR.prototype[Symbol.iterator]=function(){return this});class OK{constructor(e,n,r,i){this.from=e,this.to=n,this.number=r,this.text=i}get length(){return this.to-this.from}}function xl(t,e,n){return e=Math.max(0,Math.min(t.length,e)),[e,Math.max(e,Math.min(t.length,n))]}function xi(t,e,n=!0,r=!0){return NK(t,e,n,r)}function MK(t){return t>=56320&&t<57344}function DK(t){return t>=55296&&t<56320}function DR(t,e){let n=t.charCodeAt(e);if(!DK(n)||e+1==t.length)return n;let r=t.charCodeAt(e+1);return MK(r)?(n-55296<<10)+(r-56320)+65536:n}function LK(t){return t<=65535?String.fromCharCode(t):(t-=65536,String.fromCharCode((t>>10)+55296,(t&1023)+56320))}function LR(t){return t<65536?1:2}const Eb=/\r\n?|\n/;var Wr=(function(t){return t[t.Simple=0]="Simple",t[t.TrackDel=1]="TrackDel",t[t.TrackBefore=2]="TrackBefore",t[t.TrackAfter=3]="TrackAfter",t})(Wr||(Wr={}));class bs{constructor(e){this.sections=e}get length(){let e=0;for(let n=0;ne)return s+(e-i);s+=l}else{if(r!=Wr.Simple&&d>=e&&(r==Wr.TrackDel&&ie||r==Wr.TrackBefore&&ie))return null;if(d>e||d==e&&n<0&&!l)return e==i||n<0?s:s+c;s+=c}i=d}if(e>i)throw new RangeError(`Position ${e} is out of range for changeset of length ${i}`);return s}touchesRange(e,n=e){for(let r=0,i=0;r=0&&i<=n&&l>=e)return in?"cover":!0;i=l}return!1}toString(){let e="";for(let n=0;n=0?":"+i:"")}return e}toJSON(){return this.sections}static fromJSON(e){if(!Array.isArray(e)||e.length%2||e.some(n=>typeof n!="number"))throw new RangeError("Invalid JSON representation of ChangeDesc");return new bs(e)}static create(e){return new bs(e)}}class $n extends bs{constructor(e,n){super(e),this.inserted=n}apply(e){if(this.length!=e.length)throw new RangeError("Applying change set to a document with the wrong length");return yb(this,(n,r,i,s,o)=>e=e.replace(i,i+(r-n),o),!1),e}mapDesc(e,n=!1){return xb(this,e,n,!0)}invert(e){let n=this.sections.slice(),r=[];for(let i=0,s=0;i=0){n[i]=l,n[i+1]=o;let c=i>>1;for(;r.length0&&io(r,n,s.text),s.forward(f),l+=f}let d=e[o++];for(;l>1].toJSON()))}return e}static of(e,n,r){let i=[],s=[],o=0,l=null;function c(f=!1){if(!f&&!i.length)return;om||p<0||m>n)throw new RangeError(`Invalid change range ${p} to ${m} (in doc of length ${n})`);let x=g?typeof g=="string"?Lt.of(g.split(r||Eb)):g:Lt.empty,v=x.length;if(p==m&&v==0)return;po&&rr(i,p-o,-1),rr(i,m-p,v),io(s,i,x),o=m}}return d(e),c(!l),l}static empty(e){return new $n(e?[e,-1]:[],[])}static fromJSON(e){if(!Array.isArray(e))throw new RangeError("Invalid JSON representation of ChangeSet");let n=[],r=[];for(let i=0;il&&typeof o!="string"))throw new RangeError("Invalid JSON representation of ChangeSet");if(s.length==1)n.push(s[0],0);else{for(;r.length=0&&n<=0&&n==t[i+1]?t[i]+=e:i>=0&&e==0&&t[i]==0?t[i+1]+=n:r?(t[i]+=e,t[i+1]+=n):t.push(e,n)}function io(t,e,n){if(n.length==0)return;let r=e.length-2>>1;if(r>1])),!(n||o==t.sections.length||t.sections[o+1]<0);)l=t.sections[o++],c=t.sections[o++];e(i,d,s,f,p),i=d,s=f}}}function xb(t,e,n,r=!1){let i=[],s=r?[]:null,o=new Ec(t),l=new Ec(e);for(let c=-1;;){if(o.done&&l.len||l.done&&o.len)throw new Error("Mismatched change set lengths");if(o.ins==-1&&l.ins==-1){let d=Math.min(o.len,l.len);rr(i,d,-1),o.forward(d),l.forward(d)}else if(l.ins>=0&&(o.ins<0||c==o.i||o.off==0&&(l.len=0&&c=0){let d=0,f=o.len;for(;f;)if(l.ins==-1){let p=Math.min(f,l.len);d+=p,f-=p,l.forward(p)}else if(l.ins==0&&l.lenc||o.ins>=0&&o.len>c)&&(l||r.length>d),s.forward2(c),o.forward(c)}}}}class Ec{constructor(e){this.set=e,this.i=0,this.next()}next(){let{sections:e}=this.set;this.i>1;return n>=e.length?Lt.empty:e[n]}textBit(e){let{inserted:n}=this.set,r=this.i-2>>1;return r>=n.length&&!e?Lt.empty:n[r].slice(this.off,e==null?void 0:this.off+e)}forward(e){e==this.len?this.next():(this.len-=e,this.off+=e)}forward2(e){this.ins==-1?this.forward(e):e==this.ins?this.next():(this.ins-=e,this.off+=e)}}class zo{constructor(e,n,r){this.from=e,this.to=n,this.flags=r}get anchor(){return this.flags&32?this.to:this.from}get head(){return this.flags&32?this.from:this.to}get empty(){return this.from==this.to}get assoc(){return this.flags&8?-1:this.flags&16?1:0}get bidiLevel(){let e=this.flags&7;return e==7?null:e}get goalColumn(){let e=this.flags>>6;return e==16777215?void 0:e}map(e,n=-1){let r,i;return this.empty?r=i=e.mapPos(this.from,n):(r=e.mapPos(this.from,1),i=e.mapPos(this.to,-1)),r==this.from&&i==this.to?this:new zo(r,i,this.flags)}extend(e,n=e){if(e<=this.anchor&&n>=this.anchor)return Pe.range(e,n);let r=Math.abs(e-this.anchor)>Math.abs(n-this.anchor)?e:n;return Pe.range(this.anchor,r)}eq(e,n=!1){return this.anchor==e.anchor&&this.head==e.head&&(!n||!this.empty||this.assoc==e.assoc)}toJSON(){return{anchor:this.anchor,head:this.head}}static fromJSON(e){if(!e||typeof e.anchor!="number"||typeof e.head!="number")throw new RangeError("Invalid JSON representation for SelectionRange");return Pe.range(e.anchor,e.head)}static create(e,n,r){return new zo(e,n,r)}}class Pe{constructor(e,n){this.ranges=e,this.mainIndex=n}map(e,n=-1){return e.empty?this:Pe.create(this.ranges.map(r=>r.map(e,n)),this.mainIndex)}eq(e,n=!1){if(this.ranges.length!=e.ranges.length||this.mainIndex!=e.mainIndex)return!1;for(let r=0;re.toJSON()),main:this.mainIndex}}static fromJSON(e){if(!e||!Array.isArray(e.ranges)||typeof e.main!="number"||e.main>=e.ranges.length)throw new RangeError("Invalid JSON representation for EditorSelection");return new Pe(e.ranges.map(n=>zo.fromJSON(n)),e.main)}static single(e,n=e){return new Pe([Pe.range(e,n)],0)}static create(e,n=0){if(e.length==0)throw new RangeError("A selection needs at least one range");for(let r=0,i=0;ie?8:0)|s)}static normalized(e,n=0){let r=e[n];e.sort((i,s)=>i.from-s.from),n=e.indexOf(r);for(let i=1;is.head?Pe.range(c,l):Pe.range(l,c))}}return new Pe(e,n)}}function FR(t,e){for(let n of t.ranges)if(n.to>e)throw new RangeError("Selection points outside of document")}let x1=0;class tt{constructor(e,n,r,i,s){this.combine=e,this.compareInput=n,this.compare=r,this.isStatic=i,this.id=x1++,this.default=e([]),this.extensions=typeof s=="function"?s(this):s}get reader(){return this}static define(e={}){return new tt(e.combine||(n=>n),e.compareInput||((n,r)=>n===r),e.compare||(e.combine?(n,r)=>n===r:v1),!!e.static,e.enables)}of(e){return new $f([],this,0,e)}compute(e,n){if(this.isStatic)throw new Error("Can't compute a static facet");return new $f(e,this,1,n)}computeN(e,n){if(this.isStatic)throw new Error("Can't compute a static facet");return new $f(e,this,2,n)}from(e,n){return n||(n=r=>r),this.compute([e],r=>n(r.field(e)))}}function v1(t,e){return t==e||t.length==e.length&&t.every((n,r)=>n===e[r])}class $f{constructor(e,n,r,i){this.dependencies=e,this.facet=n,this.type=r,this.value=i,this.id=x1++}dynamicSlot(e){var n;let r=this.value,i=this.facet.compareInput,s=this.id,o=e[s]>>1,l=this.type==2,c=!1,d=!1,f=[];for(let p of this.dependencies)p=="doc"?c=!0:p=="selection"?d=!0:(((n=e[p.id])!==null&&n!==void 0?n:1)&1)==0&&f.push(e[p.id]);return{create(p){return p.values[o]=r(p),1},update(p,m){if(c&&m.docChanged||d&&(m.docChanged||m.selection)||vb(p,f)){let g=r(p);if(l?!eS(g,p.values[o],i):!i(g,p.values[o]))return p.values[o]=g,1}return 0},reconfigure:(p,m)=>{let g,x=m.config.address[s];if(x!=null){let v=vh(m,x);if(this.dependencies.every(S=>S instanceof tt?m.facet(S)===p.facet(S):S instanceof bo?m.field(S,!1)==p.field(S,!1):!0)||(l?eS(g=r(p),v,i):i(g=r(p),v)))return p.values[o]=v,0}else g=r(p);return p.values[o]=g,1}}}}function eS(t,e,n){if(t.length!=e.length)return!1;for(let r=0;rt[c.id]),i=n.map(c=>c.type),s=r.filter(c=>!(c&1)),o=t[e.id]>>1;function l(c){let d=[];for(let f=0;fr===i),e);return e.provide&&(n.provides=e.provide(n)),n}create(e){let n=e.facet(xf).find(r=>r.field==this);return(n?.create||this.createF)(e)}slot(e){let n=e[this.id]>>1;return{create:r=>(r.values[n]=this.create(r),1),update:(r,i)=>{let s=r.values[n],o=this.updateF(s,i);return this.compareF(s,o)?0:(r.values[n]=o,1)},reconfigure:(r,i)=>{let s=r.facet(xf),o=i.facet(xf),l;return(l=s.find(c=>c.field==this))&&l!=o.find(c=>c.field==this)?(r.values[n]=l.create(r),1):i.config.address[this.id]!=null?(r.values[n]=i.field(this),0):(r.values[n]=this.create(r),1)}}}init(e){return[this,xf.of({field:this,create:e})]}get extension(){return this}}const Uo={lowest:4,low:3,default:2,high:1,highest:0};function Lu(t){return e=>new BR(e,t)}const w1={highest:Lu(Uo.highest),high:Lu(Uo.high),default:Lu(Uo.default),low:Lu(Uo.low),lowest:Lu(Uo.lowest)};class BR{constructor(e,n){this.inner=e,this.prec=n}}class Sp{of(e){return new wb(this,e)}reconfigure(e){return Sp.reconfigure.of({compartment:this,extension:e})}get(e){return e.config.compartments.get(this)}}class wb{constructor(e,n){this.compartment=e,this.inner=n}}class xh{constructor(e,n,r,i,s,o){for(this.base=e,this.compartments=n,this.dynamicSlots=r,this.address=i,this.staticValues=s,this.facets=o,this.statusTemplate=[];this.statusTemplate.length>1]}static resolve(e,n,r){let i=[],s=Object.create(null),o=new Map;for(let m of FK(e,n,o))m instanceof bo?i.push(m):(s[m.facet.id]||(s[m.facet.id]=[])).push(m);let l=Object.create(null),c=[],d=[];for(let m of i)l[m.id]=d.length<<1,d.push(g=>m.slot(g));let f=r?.config.facets;for(let m in s){let g=s[m],x=g[0].facet,v=f&&f[m]||[];if(g.every(S=>S.type==0))if(l[x.id]=c.length<<1|1,v1(v,g))c.push(r.facet(x));else{let S=x.combine(g.map(C=>C.value));c.push(r&&x.compare(S,r.facet(x))?r.facet(x):S)}else{for(let S of g)S.type==0?(l[S.id]=c.length<<1|1,c.push(S.value)):(l[S.id]=d.length<<1,d.push(C=>S.dynamicSlot(C)));l[x.id]=d.length<<1,d.push(S=>PK(S,x,g))}}let p=d.map(m=>m(l));return new xh(e,o,p,l,c,s)}}function FK(t,e,n){let r=[[],[],[],[],[]],i=new Map;function s(o,l){let c=i.get(o);if(c!=null){if(c<=l)return;let d=r[c].indexOf(o);d>-1&&r[c].splice(d,1),o instanceof wb&&n.delete(o.compartment)}if(i.set(o,l),Array.isArray(o))for(let d of o)s(d,l);else if(o instanceof wb){if(n.has(o.compartment))throw new RangeError("Duplicate use of compartment in extensions");let d=e.get(o.compartment)||o.inner;n.set(o.compartment,d),s(d,l)}else if(o instanceof BR)s(o.inner,o.prec);else if(o instanceof bo)r[l].push(o),o.provides&&s(o.provides,l);else if(o instanceof $f)r[l].push(o),o.facet.extensions&&s(o.facet.extensions,Uo.default);else{let d=o.extension;if(!d)throw new Error(`Unrecognized extension value in extension set (${o}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);s(d,l)}}return s(t,Uo.default),r.reduce((o,l)=>o.concat(l))}function tc(t,e){if(e&1)return 2;let n=e>>1,r=t.status[n];if(r==4)throw new Error("Cyclic dependency between fields and/or facets");if(r&2)return r;t.status[n]=4;let i=t.computeSlot(t,t.config.dynamicSlots[n]);return t.status[n]=2|i}function vh(t,e){return e&1?t.config.staticValues[e>>1]:t.values[e>>1]}const UR=tt.define(),Tb=tt.define({combine:t=>t.some(e=>e),static:!0}),HR=tt.define({combine:t=>t.length?t[0]:void 0,static:!0}),zR=tt.define(),jR=tt.define(),$R=tt.define(),WR=tt.define({combine:t=>t.length?t[0]:!1});class Hl{constructor(e,n){this.type=e,this.value=n}static define(){return new BK}}class BK{of(e){return new Hl(this,e)}}class UK{constructor(e){this.map=e}of(e){return new bn(this,e)}}class bn{constructor(e,n){this.type=e,this.value=n}map(e){let n=this.type.map(this.value,e);return n===void 0?void 0:n==this.value?this:new bn(this.type,n)}is(e){return this.type==e}static define(e={}){return new UK(e.map||(n=>n))}static mapEffects(e,n){if(!e.length)return e;let r=[];for(let i of e){let s=i.map(n);s&&r.push(s)}return r}}bn.reconfigure=bn.define();bn.appendConfig=bn.define();class or{constructor(e,n,r,i,s,o){this.startState=e,this.changes=n,this.selection=r,this.effects=i,this.annotations=s,this.scrollIntoView=o,this._doc=null,this._state=null,r&&FR(r,n.newLength),s.some(l=>l.type==or.time)||(this.annotations=s.concat(or.time.of(Date.now())))}static create(e,n,r,i,s,o){return new or(e,n,r,i,s,o)}get newDoc(){return this._doc||(this._doc=this.changes.apply(this.startState.doc))}get newSelection(){return this.selection||this.startState.selection.map(this.changes)}get state(){return this._state||this.startState.applyTransaction(this),this._state}annotation(e){for(let n of this.annotations)if(n.type==e)return n.value}get docChanged(){return!this.changes.empty}get reconfigured(){return this.startState.config!=this.state.config}isUserEvent(e){let n=this.annotation(or.userEvent);return!!(n&&(n==e||n.length>e.length&&n.slice(0,e.length)==e&&n[e.length]=="."))}}or.time=Hl.define();or.userEvent=Hl.define();or.addToHistory=Hl.define();or.remote=Hl.define();function HK(t,e){let n=[];for(let r=0,i=0;;){let s,o;if(r=t[r]))s=t[r++],o=t[r++];else if(i=0;i--){let s=r[i](t);s instanceof or?t=s:Array.isArray(s)&&s.length==1&&s[0]instanceof or?t=s[0]:t=GR(e,ul(s),!1)}return t}function jK(t){let e=t.startState,n=e.facet($R),r=t;for(let i=n.length-1;i>=0;i--){let s=n[i](t);s&&Object.keys(s).length&&(r=VR(r,Sb(e,s,t.changes.newLength),!0))}return r==t?t:or.create(e,t.changes,t.selection,r.effects,r.annotations,r.scrollIntoView)}const $K=[];function ul(t){return t==null?$K:Array.isArray(t)?t:[t]}var Cn=(function(t){return t[t.Word=0]="Word",t[t.Space=1]="Space",t[t.Other=2]="Other",t})(Cn||(Cn={}));const WK=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;let _b;try{_b=new RegExp("[\\p{Alphabetic}\\p{Number}_]","u")}catch{}function VK(t){if(_b)return _b.test(t);for(let e=0;e"€"&&(n.toUpperCase()!=n.toLowerCase()||WK.test(n)))return!0}return!1}function GK(t){return e=>{if(!/\S/.test(e))return Cn.Space;if(VK(e))return Cn.Word;for(let n=0;n-1)return Cn.Word;return Cn.Other}}class Wt{constructor(e,n,r,i,s,o){this.config=e,this.doc=n,this.selection=r,this.values=i,this.status=e.statusTemplate.slice(),this.computeSlot=s,o&&(o._state=this);for(let l=0;li.set(d,c)),n=null),i.set(l.value.compartment,l.value.extension)):l.is(bn.reconfigure)?(n=null,r=l.value):l.is(bn.appendConfig)&&(n=null,r=ul(r).concat(l.value));let s;n?s=e.startState.values.slice():(n=xh.resolve(r,i,this),s=new Wt(n,this.doc,this.selection,n.dynamicSlots.map(()=>null),(c,d)=>d.reconfigure(c,this),null).values);let o=e.startState.facet(Tb)?e.newSelection:e.newSelection.asSingle();new Wt(n,e.newDoc,o,s,(l,c)=>c.update(l,e),e)}replaceSelection(e){return typeof e=="string"&&(e=this.toText(e)),this.changeByRange(n=>({changes:{from:n.from,to:n.to,insert:e},range:Pe.cursor(n.from+e.length)}))}changeByRange(e){let n=this.selection,r=e(n.ranges[0]),i=this.changes(r.changes),s=[r.range],o=ul(r.effects);for(let l=1;lo.spec.fromJSON(l,c)))}}return Wt.create({doc:e.doc,selection:Pe.fromJSON(e.selection),extensions:n.extensions?i.concat([n.extensions]):i})}static create(e={}){let n=xh.resolve(e.extensions||[],new Map),r=e.doc instanceof Lt?e.doc:Lt.of((e.doc||"").split(n.staticFacet(Wt.lineSeparator)||Eb)),i=e.selection?e.selection instanceof Pe?e.selection:Pe.single(e.selection.anchor,e.selection.head):Pe.single(0);return FR(i,r.length),n.staticFacet(Tb)||(i=i.asSingle()),new Wt(n,r,i,n.dynamicSlots.map(()=>null),(s,o)=>o.create(s),null)}get tabSize(){return this.facet(Wt.tabSize)}get lineBreak(){return this.facet(Wt.lineSeparator)||` +`}get readOnly(){return this.facet(WR)}phrase(e,...n){for(let r of this.facet(Wt.phrases))if(Object.prototype.hasOwnProperty.call(r,e)){e=r[e];break}return n.length&&(e=e.replace(/\$(\$|\d*)/g,(r,i)=>{if(i=="$")return"$";let s=+(i||1);return!s||s>n.length?r:n[s-1]})),e}languageDataAt(e,n,r=-1){let i=[];for(let s of this.facet(UR))for(let o of s(this,n,r))Object.prototype.hasOwnProperty.call(o,e)&&i.push(o[e]);return i}charCategorizer(e){return GK(this.languageDataAt("wordChars",e).join(""))}wordAt(e){let{text:n,from:r,length:i}=this.doc.lineAt(e),s=this.charCategorizer(e),o=e-r,l=e-r;for(;o>0;){let c=xi(n,o,!1);if(s(n.slice(c,o))!=Cn.Word)break;o=c}for(;lt.length?t[0]:4});Wt.lineSeparator=HR;Wt.readOnly=WR;Wt.phrases=tt.define({compare(t,e){let n=Object.keys(t),r=Object.keys(e);return n.length==r.length&&n.every(i=>t[i]==e[i])}});Wt.languageData=UR;Wt.changeFilter=zR;Wt.transactionFilter=jR;Wt.transactionExtender=$R;Sp.reconfigure=bn.define();function T1(t,e,n={}){let r={};for(let i of t)for(let s of Object.keys(i)){let o=i[s],l=r[s];if(l===void 0)r[s]=o;else if(!(l===o||o===void 0))if(Object.hasOwnProperty.call(n,s))r[s]=n[s](l,o);else throw new Error("Config merge conflict for field "+s)}for(let i in e)r[i]===void 0&&(r[i]=e[i]);return r}class vl{eq(e){return this==e}range(e,n=e){return yc.create(e,n,this)}}vl.prototype.startSide=vl.prototype.endSide=0;vl.prototype.point=!1;vl.prototype.mapMode=Wr.TrackDel;class yc{constructor(e,n,r){this.from=e,this.to=n,this.value=r}static create(e,n,r){return new yc(e,n,r)}}function Cb(t,e){return t.from-e.from||t.value.startSide-e.value.startSide}class S1{constructor(e,n,r,i){this.from=e,this.to=n,this.value=r,this.maxPoint=i}get length(){return this.to[this.to.length-1]}findIndex(e,n,r,i=0){let s=r?this.to:this.from;for(let o=i,l=s.length;;){if(o==l)return o;let c=o+l>>1,d=s[c]-e||(r?this.value[c].endSide:this.value[c].startSide)-n;if(c==o)return d>=0?o:l;d>=0?l=c:o=c+1}}between(e,n,r,i){for(let s=this.findIndex(n,-1e9,!0),o=this.findIndex(r,1e9,!1,s);sg||m==g&&d.startSide>0&&d.endSide<=0)continue;(g-m||d.endSide-d.startSide)<0||(o<0&&(o=m),d.point&&(l=Math.max(l,g-m)),r.push(d),i.push(m-o),s.push(g-o))}return{mapped:r.length?new S1(i,s,r,l):null,pos:o}}}class Ht{constructor(e,n,r,i){this.chunkPos=e,this.chunk=n,this.nextLayer=r,this.maxPoint=i}static create(e,n,r,i){return new Ht(e,n,r,i)}get length(){let e=this.chunk.length-1;return e<0?0:Math.max(this.chunkEnd(e),this.nextLayer.length)}get size(){if(this.isEmpty)return 0;let e=this.nextLayer.size;for(let n of this.chunk)e+=n.value.length;return e}chunkEnd(e){return this.chunkPos[e]+this.chunk[e].length}update(e){let{add:n=[],sort:r=!1,filterFrom:i=0,filterTo:s=this.length}=e,o=e.filter;if(n.length==0&&!o)return this;if(r&&(n=n.slice().sort(Cb)),this.isEmpty)return n.length?Ht.of(n):this;let l=new KR(this,null,-1).goto(0),c=0,d=[],f=new xc;for(;l.value||c=0){let p=n[c++];f.addInner(p.from,p.to,p.value)||d.push(p)}else l.rangeIndex==1&&l.chunkIndexthis.chunkEnd(l.chunkIndex)||sl.to||s=s&&e<=s+o.length&&o.between(s,e-s,n-s,r)===!1)return}this.nextLayer.between(e,n,r)}}iter(e=0){return vc.from([this]).goto(e)}get isEmpty(){return this.nextLayer==this}static iter(e,n=0){return vc.from(e).goto(n)}static compare(e,n,r,i,s=-1){let o=e.filter(p=>p.maxPoint>0||!p.isEmpty&&p.maxPoint>=s),l=n.filter(p=>p.maxPoint>0||!p.isEmpty&&p.maxPoint>=s),c=tS(o,l,r),d=new Pu(o,c,s),f=new Pu(l,c,s);r.iterGaps((p,m,g)=>nS(d,p,f,m,g,i)),r.empty&&r.length==0&&nS(d,0,f,0,0,i)}static eq(e,n,r=0,i){i==null&&(i=999999999);let s=e.filter(f=>!f.isEmpty&&n.indexOf(f)<0),o=n.filter(f=>!f.isEmpty&&e.indexOf(f)<0);if(s.length!=o.length)return!1;if(!s.length)return!0;let l=tS(s,o),c=new Pu(s,l,0).goto(r),d=new Pu(o,l,0).goto(r);for(;;){if(c.to!=d.to||!Ab(c.active,d.active)||c.point&&(!d.point||!c.point.eq(d.point)))return!1;if(c.to>i)return!0;c.next(),d.next()}}static spans(e,n,r,i,s=-1){let o=new Pu(e,null,s).goto(n),l=n,c=o.openStart;for(;;){let d=Math.min(o.to,r);if(o.point){let f=o.activeForPoint(o.to),p=o.pointFroml&&(i.span(l,d,o.active,c),c=o.openEnd(d));if(o.to>r)return c+(o.point&&o.to>r?1:0);l=o.to,o.next()}}static of(e,n=!1){let r=new xc;for(let i of e instanceof yc?[e]:n?KK(e):e)r.add(i.from,i.to,i.value);return r.finish()}static join(e){if(!e.length)return Ht.empty;let n=e[e.length-1];for(let r=e.length-2;r>=0;r--)for(let i=e[r];i!=Ht.empty;i=i.nextLayer)n=new Ht(i.chunkPos,i.chunk,n,Math.max(i.maxPoint,n.maxPoint));return n}}Ht.empty=new Ht([],[],null,-1);function KK(t){if(t.length>1)for(let e=t[0],n=1;n0)return t.slice().sort(Cb);e=r}return t}Ht.empty.nextLayer=Ht.empty;class xc{finishChunk(e){this.chunks.push(new S1(this.from,this.to,this.value,this.maxPoint)),this.chunkPos.push(this.chunkStart),this.chunkStart=-1,this.setMaxPoint=Math.max(this.setMaxPoint,this.maxPoint),this.maxPoint=-1,e&&(this.from=[],this.to=[],this.value=[])}constructor(){this.chunks=[],this.chunkPos=[],this.chunkStart=-1,this.last=null,this.lastFrom=-1e9,this.lastTo=-1e9,this.from=[],this.to=[],this.value=[],this.maxPoint=-1,this.setMaxPoint=-1,this.nextLayer=null}add(e,n,r){this.addInner(e,n,r)||(this.nextLayer||(this.nextLayer=new xc)).add(e,n,r)}addInner(e,n,r){let i=e-this.lastTo||r.startSide-this.last.endSide;if(i<=0&&(e-this.lastFrom||r.startSide-this.last.startSide)<0)throw new Error("Ranges must be added sorted by `from` position and `startSide`");return i<0?!1:(this.from.length==250&&this.finishChunk(!0),this.chunkStart<0&&(this.chunkStart=e),this.from.push(e-this.chunkStart),this.to.push(n-this.chunkStart),this.last=r,this.lastFrom=e,this.lastTo=n,this.value.push(r),r.point&&(this.maxPoint=Math.max(this.maxPoint,n-e)),!0)}addChunk(e,n){if((e-this.lastTo||n.value[0].startSide-this.last.endSide)<0)return!1;this.from.length&&this.finishChunk(!0),this.setMaxPoint=Math.max(this.setMaxPoint,n.maxPoint),this.chunks.push(n),this.chunkPos.push(e);let r=n.value.length-1;return this.last=n.value[r],this.lastFrom=n.from[r]+e,this.lastTo=n.to[r]+e,!0}finish(){return this.finishInner(Ht.empty)}finishInner(e){if(this.from.length&&this.finishChunk(!1),this.chunks.length==0)return e;let n=Ht.create(this.chunkPos,this.chunks,this.nextLayer?this.nextLayer.finishInner(e):e,this.setMaxPoint);return this.from=null,n}}function tS(t,e,n){let r=new Map;for(let s of t)for(let o=0;o=this.minPoint)break}}setRangeIndex(e){if(e==this.layer.chunk[this.chunkIndex].value.length){if(this.chunkIndex++,this.skip)for(;this.chunkIndex=r&&i.push(new KR(o,n,r,s));return i.length==1?i[0]:new vc(i)}get startSide(){return this.value?this.value.startSide:0}goto(e,n=-1e9){for(let r of this.heap)r.goto(e,n);for(let r=this.heap.length>>1;r>=0;r--)h0(this.heap,r);return this.next(),this}forward(e,n){for(let r of this.heap)r.forward(e,n);for(let r=this.heap.length>>1;r>=0;r--)h0(this.heap,r);(this.to-e||this.value.endSide-n)<0&&this.next()}next(){if(this.heap.length==0)this.from=this.to=1e9,this.value=null,this.rank=-1;else{let e=this.heap[0];this.from=e.from,this.to=e.to,this.value=e.value,this.rank=e.rank,e.value&&e.next(),h0(this.heap,0)}}}function h0(t,e){for(let n=t[e];;){let r=(e<<1)+1;if(r>=t.length)break;let i=t[r];if(r+1=0&&(i=t[r+1],r++),n.compare(i)<0)break;t[r]=n,t[e]=i,e=r}}class Pu{constructor(e,n,r){this.minPoint=r,this.active=[],this.activeTo=[],this.activeRank=[],this.minActive=-1,this.point=null,this.pointFrom=0,this.pointRank=0,this.to=-1e9,this.endSide=0,this.openStart=-1,this.cursor=vc.from(e,n,r)}goto(e,n=-1e9){return this.cursor.goto(e,n),this.active.length=this.activeTo.length=this.activeRank.length=0,this.minActive=-1,this.to=e,this.endSide=n,this.openStart=-1,this.next(),this}forward(e,n){for(;this.minActive>-1&&(this.activeTo[this.minActive]-e||this.active[this.minActive].endSide-n)<0;)this.removeActive(this.minActive);this.cursor.forward(e,n)}removeActive(e){vf(this.active,e),vf(this.activeTo,e),vf(this.activeRank,e),this.minActive=rS(this.active,this.activeTo)}addActive(e){let n=0,{value:r,to:i,rank:s}=this.cursor;for(;n0;)n++;wf(this.active,n,r),wf(this.activeTo,n,i),wf(this.activeRank,n,s),e&&wf(e,n,this.cursor.from),this.minActive=rS(this.active,this.activeTo)}next(){let e=this.to,n=this.point;this.point=null;let r=this.openStart<0?[]:null;for(;;){let i=this.minActive;if(i>-1&&(this.activeTo[i]-this.cursor.from||this.active[i].endSide-this.cursor.startSide)<0){if(this.activeTo[i]>e){this.to=this.activeTo[i],this.endSide=this.active[i].endSide;break}this.removeActive(i),r&&vf(r,i)}else if(this.cursor.value)if(this.cursor.from>e){this.to=this.cursor.from,this.endSide=this.cursor.startSide;break}else{let s=this.cursor.value;if(!s.point)this.addActive(r),this.cursor.next();else if(n&&this.cursor.to==this.to&&this.cursor.from=0&&r[i]=0&&!(this.activeRank[r]e||this.activeTo[r]==e&&this.active[r].endSide>=this.point.endSide)&&n.push(this.active[r]);return n.reverse()}openEnd(e){let n=0;for(let r=this.activeTo.length-1;r>=0&&this.activeTo[r]>e;r--)n++;return n}}function nS(t,e,n,r,i,s){t.goto(e),n.goto(r);let o=r+i,l=r,c=r-e;for(;;){let d=t.to+c-n.to,f=d||t.endSide-n.endSide,p=f<0?t.to+c:n.to,m=Math.min(p,o);if(t.point||n.point?t.point&&n.point&&(t.point==n.point||t.point.eq(n.point))&&Ab(t.activeForPoint(t.to),n.activeForPoint(n.to))||s.comparePoint(l,m,t.point,n.point):m>l&&!Ab(t.active,n.active)&&s.compareRange(l,m,t.active,n.active),p>o)break;(d||t.openEnd!=n.openEnd)&&s.boundChange&&s.boundChange(p),l=p,f<=0&&t.next(),f>=0&&n.next()}}function Ab(t,e){if(t.length!=e.length)return!1;for(let n=0;n=e;r--)t[r+1]=t[r];t[e]=n}function rS(t,e){let n=-1,r=1e9;for(let i=0;i=e)return i;if(i==t.length)break;s+=t.charCodeAt(i)==9?n-s%n:1,i=xi(t,i)}return t.length}const kb="ͼ",iS=typeof Symbol>"u"?"__"+kb:Symbol.for(kb),Nb=typeof Symbol>"u"?"__styleSet"+Math.floor(Math.random()*1e8):Symbol("styleSet"),sS=typeof globalThis<"u"?globalThis:typeof window<"u"?window:{};class wl{constructor(e,n){this.rules=[];let{finish:r}=n||{};function i(o){return/^@/.test(o)?[o]:o.split(/,\s*/)}function s(o,l,c,d){let f=[],p=/^@(\w+)\b/.exec(o[0]),m=p&&p[1]=="keyframes";if(p&&l==null)return c.push(o[0]+";");for(let g in l){let x=l[g];if(/&/.test(g))s(g.split(/,\s*/).map(v=>o.map(S=>v.replace(/&/,S))).reduce((v,S)=>v.concat(S)),x,c);else if(x&&typeof x=="object"){if(!p)throw new RangeError("The value of a property ("+g+") should be a primitive value.");s(i(g),x,f,m)}else x!=null&&f.push(g.replace(/_.*/,"").replace(/[A-Z]/g,v=>"-"+v.toLowerCase())+": "+x+";")}(f.length||m)&&c.push((r&&!p&&!d?o.map(r):o).join(", ")+" {"+f.join(" ")+"}")}for(let o in e)s(i(o),e[o],this.rules)}getRules(){return this.rules.join(` +`)}static newName(){let e=sS[iS]||1;return sS[iS]=e+1,kb+e.toString(36)}static mount(e,n,r){let i=e[Nb],s=r&&r.nonce;i?s&&i.setNonce(s):i=new qK(e,s),i.mount(Array.isArray(n)?n:[n],e)}}let oS=new Map;class qK{constructor(e,n){let r=e.ownerDocument||e,i=r.defaultView;if(!e.head&&e.adoptedStyleSheets&&i.CSSStyleSheet){let s=oS.get(r);if(s)return e[Nb]=s;this.sheet=new i.CSSStyleSheet,oS.set(r,this)}else this.styleTag=r.createElement("style"),n&&this.styleTag.setAttribute("nonce",n);this.modules=[],e[Nb]=this}mount(e,n){let r=this.sheet,i=0,s=0;for(let o=0;o-1&&(this.modules.splice(c,1),s--,c=-1),c==-1){if(this.modules.splice(s++,0,l),r)for(let d=0;d",191:"?",192:"~",219:"{",220:"|",221:"}",222:'"'},XK=typeof navigator<"u"&&/Mac/.test(navigator.platform),QK=typeof navigator<"u"&&/MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);for(var qn=0;qn<10;qn++)fo[48+qn]=fo[96+qn]=String(qn);for(var qn=1;qn<=24;qn++)fo[qn+111]="F"+qn;for(var qn=65;qn<=90;qn++)fo[qn]=String.fromCharCode(qn+32),wc[qn]=String.fromCharCode(qn);for(var p0 in fo)wc.hasOwnProperty(p0)||(wc[p0]=fo[p0]);function ZK(t){var e=XK&&t.metaKey&&t.shiftKey&&!t.ctrlKey&&!t.altKey||QK&&t.shiftKey&&t.key&&t.key.length==1||t.key=="Unidentified",n=!e&&t.key||(t.shiftKey?wc:fo)[t.keyCode]||t.key||"Unidentified";return n=="Esc"&&(n="Escape"),n=="Del"&&(n="Delete"),n=="Left"&&(n="ArrowLeft"),n=="Up"&&(n="ArrowUp"),n=="Right"&&(n="ArrowRight"),n=="Down"&&(n="ArrowDown"),n}function Kn(){var t=arguments[0];typeof t=="string"&&(t=document.createElement(t));var e=1,n=arguments[1];if(n&&typeof n=="object"&&n.nodeType==null&&!Array.isArray(n)){for(var r in n)if(Object.prototype.hasOwnProperty.call(n,r)){var i=n[r];typeof i=="string"?t.setAttribute(r,i):i!=null&&(t[r]=i)}e++}for(;e.995&&n<1.005||!isFinite(n)||Math.abs(e.width-t.offsetWidth)<1)&&(n=1),(r>.995&&r<1.005||!isFinite(r)||Math.abs(e.height-t.offsetHeight)<1)&&(r=1),{scaleX:n,scaleY:r}}function eY(t,e,n,r,i,s,o,l){let c=t.ownerDocument,d=c.defaultView||window;for(let f=t,p=!1;f&&!p;)if(f.nodeType==1){let m,g=f==c.body,x=1,v=1;if(g)m=JK(d);else{if(/^(fixed|sticky)$/.test(getComputedStyle(f).position)&&(p=!0),f.scrollHeight<=f.clientHeight&&f.scrollWidth<=f.clientWidth){f=f.assignedSlot||f.parentNode;continue}let A=f.getBoundingClientRect();({scaleX:x,scaleY:v}=qR(f,A)),m={left:A.left,right:A.left+f.clientWidth*x,top:A.top,bottom:A.top+f.clientHeight*v}}let S=0,C=0;if(i=="nearest")e.top0&&e.bottom>m.bottom+C&&(C=e.bottom-m.bottom+o)):e.bottom>m.bottom&&(C=e.bottom-m.bottom+o,n<0&&e.top-C0&&e.right>m.right+S&&(S=e.right-m.right+s)):e.right>m.right&&(S=e.right-m.right+s,n<0&&e.leftm.bottom||e.leftm.right)&&(e={left:Math.max(e.left,m.left),right:Math.min(e.right,m.right),top:Math.max(e.top,m.top),bottom:Math.min(e.bottom,m.bottom)}),f=f.assignedSlot||f.parentNode}else if(f.nodeType==11)f=f.host;else break}function tY(t){let e=t.ownerDocument,n,r;for(let i=t.parentNode;i&&!(i==e.body||n&&r);)if(i.nodeType==1)!r&&i.scrollHeight>i.clientHeight&&(r=i),!n&&i.scrollWidth>i.clientWidth&&(n=i),i=i.assignedSlot||i.parentNode;else if(i.nodeType==11)i=i.host;else break;return{x:n,y:r}}class nY{constructor(){this.anchorNode=null,this.anchorOffset=0,this.focusNode=null,this.focusOffset=0}eq(e){return this.anchorNode==e.anchorNode&&this.anchorOffset==e.anchorOffset&&this.focusNode==e.focusNode&&this.focusOffset==e.focusOffset}setRange(e){let{anchorNode:n,focusNode:r}=e;this.set(n,Math.min(e.anchorOffset,n?Xi(n):0),r,Math.min(e.focusOffset,r?Xi(r):0))}set(e,n,r,i){this.anchorNode=e,this.anchorOffset=n,this.focusNode=r,this.focusOffset=i}}let Wa=null;function XR(t){if(t.setActive)return t.setActive();if(Wa)return t.focus(Wa);let e=[];for(let n=t;n&&(e.push(n,n.scrollTop,n.scrollLeft),n!=n.ownerDocument);n=n.parentNode);if(t.focus(Wa==null?{get preventScroll(){return Wa={preventScroll:!0},!0}}:void 0),!Wa){Wa=!1;for(let n=0;nMath.max(1,t.scrollHeight-t.clientHeight-4)}function JR(t,e){for(let n=t,r=e;;){if(n.nodeType==3&&r>0)return{node:n,offset:r};if(n.nodeType==1&&r>0){if(n.contentEditable=="false")return null;n=n.childNodes[r-1],r=Xi(n)}else if(n.parentNode&&!wh(n))r=ea(n),n=n.parentNode;else return null}}function eI(t,e){for(let n=t,r=e;;){if(n.nodeType==3&&rn)return p.domBoundsAround(e,n,d);if(m>=e&&i==-1&&(i=c,s=d),d>n&&p.dom.parentNode==this.dom){o=c,l=f;break}f=m,d=m+p.breakAfter}return{from:s,to:l<0?r+this.length:l,startDOM:(i?this.children[i-1].dom.nextSibling:null)||this.dom.firstChild,endDOM:o=0?this.children[o].dom:null}}markDirty(e=!1){this.flags|=2,this.markParentsDirty(e)}markParentsDirty(e){for(let n=this.parent;n;n=n.parent){if(e&&(n.flags|=2),n.flags&1)return;n.flags|=1,e=!1}}setParent(e){this.parent!=e&&(this.parent=e,this.flags&7&&this.markParentsDirty(!0))}setDOM(e){this.dom!=e&&(this.dom&&(this.dom.cmView=null),this.dom=e,e.cmView=this)}get rootView(){for(let e=this;;){let n=e.parent;if(!n)return e;e=n}}replaceChildren(e,n,r=_1){this.markDirty();for(let i=e;ithis.pos||e==this.pos&&(n>0||this.i==0||this.children[this.i-1].breakAfter))return this.off=e-this.pos,this;let r=this.children[--this.i];this.pos-=r.length+r.breakAfter}}}function nI(t,e,n,r,i,s,o,l,c){let{children:d}=t,f=d.length?d[e]:null,p=s.length?s[s.length-1]:null,m=p?p.breakAfter:o;if(!(e==r&&f&&!o&&!m&&s.length<2&&f.merge(n,i,s.length?p:null,n==0,l,c))){if(r0&&(!o&&s.length&&f.merge(n,f.length,s[0],!1,l,0)?f.breakAfter=s.shift().breakAfter:(n2);var Fe={mac:dS||/Mac/.test(Or.platform),windows:/Win/.test(Or.platform),linux:/Linux|X11/.test(Or.platform),ie:Cp,ie_version:iI?Ib.documentMode||6:Mb?+Mb[1]:Ob?+Ob[1]:0,gecko:cS,gecko_version:cS?+(/Firefox\/(\d+)/.exec(Or.userAgent)||[0,0])[1]:0,chrome:!!m0,chrome_version:m0?+m0[1]:0,ios:dS,android:/Android\b/.test(Or.userAgent),safari:sI,webkit_version:sY?+(/\bAppleWebKit\/(\d+)/.exec(Or.userAgent)||[0,0])[1]:0,tabSize:Ib.documentElement.style.tabSize!=null?"tab-size":"-moz-tab-size"};const oY=256;class _i extends Gt{constructor(e){super(),this.text=e}get length(){return this.text.length}createDOM(e){this.setDOM(e||document.createTextNode(this.text))}sync(e,n){this.dom||this.createDOM(),this.dom.nodeValue!=this.text&&(n&&n.node==this.dom&&(n.written=!0),this.dom.nodeValue=this.text)}reuseDOM(e){e.nodeType==3&&this.createDOM(e)}merge(e,n,r){return this.flags&8||r&&(!(r instanceof _i)||this.length-(n-e)+r.length>oY||r.flags&8)?!1:(this.text=this.text.slice(0,e)+(r?r.text:"")+this.text.slice(n),this.markDirty(),!0)}split(e){let n=new _i(this.text.slice(e));return this.text=this.text.slice(0,e),this.markDirty(),n.flags|=this.flags&8,n}localPosFromDOM(e,n){return e==this.dom?n:n?this.text.length:0}domAtPos(e){return new ir(this.dom,e)}domBoundsAround(e,n,r){return{from:r,to:r+this.length,startDOM:this.dom,endDOM:this.dom.nextSibling}}coordsAt(e,n){return aY(this.dom,e,n)}}class Ts extends Gt{constructor(e,n=[],r=0){super(),this.mark=e,this.children=n,this.length=r;for(let i of n)i.setParent(this)}setAttrs(e){if(QR(e),this.mark.class&&(e.className=this.mark.class),this.mark.attrs)for(let n in this.mark.attrs)e.setAttribute(n,this.mark.attrs[n]);return e}canReuseDOM(e){return super.canReuseDOM(e)&&!((this.flags|e.flags)&8)}reuseDOM(e){e.nodeName==this.mark.tagName.toUpperCase()&&(this.setDOM(e),this.flags|=6)}sync(e,n){this.dom?this.flags&4&&this.setAttrs(this.dom):this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))),super.sync(e,n)}merge(e,n,r,i,s,o){return r&&(!(r instanceof Ts&&r.mark.eq(this.mark))||e&&s<=0||ne&&n.push(r=e&&(i=s),r=c,s++}let o=this.length-e;return this.length=e,i>-1&&(this.children.length=i,this.markDirty()),new Ts(this.mark,n,o)}domAtPos(e){return oI(this,e)}coordsAt(e,n){return lI(this,e,n)}}function aY(t,e,n){let r=t.nodeValue.length;e>r&&(e=r);let i=e,s=e,o=0;e==0&&n<0||e==r&&n>=0?Fe.chrome||Fe.gecko||(e?(i--,o=1):s=0)?0:l.length-1];return Fe.safari&&!o&&c.width==0&&(c=Array.prototype.find.call(l,d=>d.width)||c),o?_p(c,o<0):c||null}class jo extends Gt{static create(e,n,r){return new jo(e,n,r)}constructor(e,n,r){super(),this.widget=e,this.length=n,this.side=r,this.prevWidget=null}split(e){let n=jo.create(this.widget,this.length-e,this.side);return this.length-=e,n}sync(e){(!this.dom||!this.widget.updateDOM(this.dom,e))&&(this.dom&&this.prevWidget&&this.prevWidget.destroy(this.dom),this.prevWidget=null,this.setDOM(this.widget.toDOM(e)),this.widget.editable||(this.dom.contentEditable="false"))}getSide(){return this.side}merge(e,n,r,i,s,o){return r&&(!(r instanceof jo)||!this.widget.compare(r.widget)||e>0&&s<=0||n0)?ir.before(this.dom):ir.after(this.dom,e==this.length)}domBoundsAround(){return null}coordsAt(e,n){let r=this.widget.coordsAt(this.dom,e,n);if(r)return r;let i=this.dom.getClientRects(),s=null;if(!i.length)return null;let o=this.side?this.side<0:e>0;for(let l=o?i.length-1:0;s=i[l],!(e>0?l==0:l==i.length-1||s.top0?ir.before(this.dom):ir.after(this.dom)}localPosFromDOM(){return 0}domBoundsAround(){return null}coordsAt(e){return this.dom.getBoundingClientRect()}get overrideDOMText(){return Lt.empty}get isHidden(){return!0}}_i.prototype.children=jo.prototype.children=Tl.prototype.children=_1;function oI(t,e){let n=t.dom,{children:r}=t,i=0;for(let s=0;is&&e0;s--){let o=r[s-1];if(o.dom.parentNode==n)return o.domAtPos(o.length)}for(let s=i;s0&&e instanceof Ts&&i.length&&(r=i[i.length-1])instanceof Ts&&r.mark.eq(e.mark)?aI(r,e.children[0],n-1):(i.push(e),e.setParent(t)),t.length+=e.length}function lI(t,e,n){let r=null,i=-1,s=null,o=-1;function l(d,f){for(let p=0,m=0;p=f&&(g.children.length?l(g,f-m):(!s||s.isHidden&&(n>0||uY(s,g)))&&(x>f||m==x&&g.getSide()>0)?(s=g,o=f-m):(m-1?1:0)!=i.length-(n&&i.indexOf(n)>-1?1:0))return!1;for(let s of r)if(s!=n&&(i.indexOf(s)==-1||t[s]!==e[s]))return!1;return!0}function Lb(t,e,n){let r=!1;if(e)for(let i in e)n&&i in n||(r=!0,i=="style"?t.style.cssText="":t.removeAttribute(i));if(n)for(let i in n)e&&e[i]==n[i]||(r=!0,i=="style"?t.style.cssText=n[i]:t.setAttribute(i,n[i]));return r}function cY(t){let e=Object.create(null);for(let n=0;n0?3e8:-4e8:n>0?1e8:-1e8,new ho(e,n,n,r,e.widget||null,!1)}static replace(e){let n=!!e.block,r,i;if(e.isBlockGap)r=-5e8,i=4e8;else{let{start:s,end:o}=uI(e,n);r=(s?n?-3e8:-1:5e8)-1,i=(o?n?2e8:1:-6e8)+1}return new ho(e,r,i,n,e.widget||null,!0)}static line(e){return new jc(e)}static set(e,n=!1){return Ht.of(e,n)}hasHeight(){return this.widget?this.widget.estimatedHeight>-1:!1}}en.none=Ht.empty;class zc extends en{constructor(e){let{start:n,end:r}=uI(e);super(n?-1:5e8,r?1:-6e8,null,e),this.tagName=e.tagName||"span",this.class=e.class||"",this.attrs=e.attributes||null}eq(e){var n,r;return this==e||e instanceof zc&&this.tagName==e.tagName&&(this.class||((n=this.attrs)===null||n===void 0?void 0:n.class))==(e.class||((r=e.attrs)===null||r===void 0?void 0:r.class))&&Th(this.attrs,e.attrs,"class")}range(e,n=e){if(e>=n)throw new RangeError("Mark decorations may not be empty");return super.range(e,n)}}zc.prototype.point=!1;class jc extends en{constructor(e){super(-2e8,-2e8,null,e)}eq(e){return e instanceof jc&&this.spec.class==e.spec.class&&Th(this.spec.attributes,e.spec.attributes)}range(e,n=e){if(n!=e)throw new RangeError("Line decoration ranges must be zero-length");return super.range(e,n)}}jc.prototype.mapMode=Wr.TrackBefore;jc.prototype.point=!0;class ho extends en{constructor(e,n,r,i,s,o){super(n,r,s,e),this.block=i,this.isReplace=o,this.mapMode=i?n<=0?Wr.TrackBefore:Wr.TrackAfter:Wr.TrackDel}get type(){return this.startSide!=this.endSide?ii.WidgetRange:this.startSide<=0?ii.WidgetBefore:ii.WidgetAfter}get heightRelevant(){return this.block||!!this.widget&&(this.widget.estimatedHeight>=5||this.widget.lineBreaks>0)}eq(e){return e instanceof ho&&dY(this.widget,e.widget)&&this.block==e.block&&this.startSide==e.startSide&&this.endSide==e.endSide}range(e,n=e){if(this.isReplace&&(e>n||e==n&&this.startSide>0&&this.endSide<=0))throw new RangeError("Invalid range for replacement decoration");if(!this.isReplace&&n!=e)throw new RangeError("Widget decorations can only have zero-length ranges");return super.range(e,n)}}ho.prototype.point=!0;function uI(t,e=!1){let{inclusiveStart:n,inclusiveEnd:r}=t;return n==null&&(n=t.inclusive),r==null&&(r=t.inclusive),{start:n??e,end:r??e}}function dY(t,e){return t==e||!!(t&&e&&t.compare(e))}function Vf(t,e,n,r=0){let i=n.length-1;i>=0&&n[i]+r>=t?n[i]=Math.max(n[i],e):n.push(t,e)}class In extends Gt{constructor(){super(...arguments),this.children=[],this.length=0,this.prevAttrs=void 0,this.attrs=null,this.breakAfter=0}merge(e,n,r,i,s,o){if(r){if(!(r instanceof In))return!1;this.dom||r.transferDOM(this)}return i&&this.setDeco(r?r.attrs:null),rI(this,e,n,r?r.children.slice():[],s,o),!0}split(e){let n=new In;if(n.breakAfter=this.breakAfter,this.length==0)return n;let{i:r,off:i}=this.childPos(e);i&&(n.append(this.children[r].split(i),0),this.children[r].merge(i,this.children[r].length,null,!1,0,0),r++);for(let s=r;s0&&this.children[r-1].length==0;)this.children[--r].destroy();return this.children.length=r,this.markDirty(),this.length=e,n}transferDOM(e){this.dom&&(this.markDirty(),e.setDOM(this.dom),e.prevAttrs=this.prevAttrs===void 0?this.attrs:this.prevAttrs,this.prevAttrs=void 0,this.dom=null)}setDeco(e){Th(this.attrs,e)||(this.dom&&(this.prevAttrs=this.attrs,this.markDirty()),this.attrs=e)}append(e,n){aI(this,e,n)}addLineDeco(e){let n=e.spec.attributes,r=e.spec.class;n&&(this.attrs=Db(n,this.attrs||{})),r&&(this.attrs=Db({class:r},this.attrs||{}))}domAtPos(e){return oI(this,e)}reuseDOM(e){e.nodeName=="DIV"&&(this.setDOM(e),this.flags|=6)}sync(e,n){var r;this.dom?this.flags&4&&(QR(this.dom),this.dom.className="cm-line",this.prevAttrs=this.attrs?null:void 0):(this.setDOM(document.createElement("div")),this.dom.className="cm-line",this.prevAttrs=this.attrs?null:void 0),this.prevAttrs!==void 0&&(Lb(this.dom,this.prevAttrs,this.attrs),this.dom.classList.add("cm-line"),this.prevAttrs=void 0),super.sync(e,n);let i=this.dom.lastChild;for(;i&&Gt.get(i)instanceof Ts;)i=i.lastChild;if(!i||!this.length||i.nodeName!="BR"&&((r=Gt.get(i))===null||r===void 0?void 0:r.isEditable)==!1&&(!Fe.ios||!this.children.some(s=>s instanceof _i))){let s=document.createElement("BR");s.cmIgnore=!0,this.dom.appendChild(s)}}measureTextSize(){if(this.children.length==0||this.length>20)return null;let e=0,n;for(let r of this.children){if(!(r instanceof _i)||/[^ -~]/.test(r.text))return null;let i=Sc(r.dom);if(i.length!=1)return null;e+=i[0].width,n=i[0].height}return e?{lineHeight:this.dom.getBoundingClientRect().height,charWidth:e/this.length,textHeight:n}:null}coordsAt(e,n){let r=lI(this,e,n);if(!this.children.length&&r&&this.parent){let{heightOracle:i}=this.parent.view.viewState,s=r.bottom-r.top;if(Math.abs(s-i.lineHeight)<2&&i.textHeight=n){if(s instanceof In)return s;if(o>n)break}i=o+s.breakAfter}return null}}class Es extends Gt{constructor(e,n,r){super(),this.widget=e,this.length=n,this.deco=r,this.breakAfter=0,this.prevWidget=null}merge(e,n,r,i,s,o){return r&&(!(r instanceof Es)||!this.widget.compare(r.widget)||e>0&&s<=0||n0}}class Pb extends C1{constructor(e){super(),this.height=e}toDOM(){let e=document.createElement("div");return e.className="cm-gap",this.updateDOM(e),e}eq(e){return e.height==this.height}updateDOM(e){return e.style.height=this.height+"px",!0}get editable(){return!0}get estimatedHeight(){return this.height}ignoreEvent(){return!1}}class rc{constructor(e,n,r,i){this.doc=e,this.pos=n,this.end=r,this.disallowBlockEffectsFor=i,this.content=[],this.curLine=null,this.breakAtStart=0,this.pendingBuffer=0,this.bufferMarks=[],this.atCursorPos=!0,this.openStart=-1,this.openEnd=-1,this.text="",this.textOff=0,this.cursor=e.iter(),this.skip=n}posCovered(){if(this.content.length==0)return!this.breakAtStart&&this.doc.lineAt(this.pos).from!=this.pos;let e=this.content[this.content.length-1];return!(e.breakAfter||e instanceof Es&&e.deco.endSide<0)}getLine(){return this.curLine||(this.content.push(this.curLine=new In),this.atCursorPos=!0),this.curLine}flushBuffer(e=this.bufferMarks){this.pendingBuffer&&(this.curLine.append(Tf(new Tl(-1),e),e.length),this.pendingBuffer=0)}addBlockWidget(e){this.flushBuffer(),this.curLine=null,this.content.push(e)}finish(e){this.pendingBuffer&&e<=this.bufferMarks.length?this.flushBuffer():this.pendingBuffer=0,!this.posCovered()&&!(e&&this.content.length&&this.content[this.content.length-1]instanceof Es)&&this.getLine()}buildText(e,n,r){for(;e>0;){if(this.textOff==this.text.length){let{value:s,lineBreak:o,done:l}=this.cursor.next(this.skip);if(this.skip=0,l)throw new Error("Ran out of text content when drawing inline views");if(o){this.posCovered()||this.getLine(),this.content.length?this.content[this.content.length-1].breakAfter=1:this.breakAtStart=1,this.flushBuffer(),this.curLine=null,this.atCursorPos=!0,e--;continue}else this.text=s,this.textOff=0}let i=Math.min(this.text.length-this.textOff,e,512);this.flushBuffer(n.slice(n.length-r)),this.getLine().append(Tf(new _i(this.text.slice(this.textOff,this.textOff+i)),n),r),this.atCursorPos=!0,this.textOff+=i,e-=i,r=0}}span(e,n,r,i){this.buildText(n-e,r,i),this.pos=n,this.openStart<0&&(this.openStart=i)}point(e,n,r,i,s,o){if(this.disallowBlockEffectsFor[o]&&r instanceof ho){if(r.block)throw new RangeError("Block decorations may not be specified via plugins");if(n>this.doc.lineAt(this.pos).to)throw new RangeError("Decorations that replace line breaks may not be specified via plugins")}let l=n-e;if(r instanceof ho)if(r.block)r.startSide>0&&!this.posCovered()&&this.getLine(),this.addBlockWidget(new Es(r.widget||Sl.block,l,r));else{let c=jo.create(r.widget||Sl.inline,l,l?0:r.startSide),d=this.atCursorPos&&!c.isEditable&&s<=i.length&&(e0),f=!c.isEditable&&(ei.length||r.startSide<=0),p=this.getLine();this.pendingBuffer==2&&!d&&!c.isEditable&&(this.pendingBuffer=0),this.flushBuffer(i),d&&(p.append(Tf(new Tl(1),i),s),s=i.length+Math.max(0,s-i.length)),p.append(Tf(c,i),s),this.atCursorPos=f,this.pendingBuffer=f?ei.length?1:2:0,this.pendingBuffer&&(this.bufferMarks=i.slice())}else this.doc.lineAt(this.pos).from==this.pos&&this.getLine().addLineDeco(r);l&&(this.textOff+l<=this.text.length?this.textOff+=l:(this.skip+=l-(this.text.length-this.textOff),this.text="",this.textOff=0),this.pos=n),this.openStart<0&&(this.openStart=s)}static build(e,n,r,i,s){let o=new rc(e,n,r,s);return o.openEnd=Ht.spans(i,n,r,o),o.openStart<0&&(o.openStart=o.openEnd),o.finish(o.openEnd),o}}function Tf(t,e){for(let n of e)t=new Ts(n,[t],t.length);return t}class Sl extends C1{constructor(e){super(),this.tag=e}eq(e){return e.tag==this.tag}toDOM(){return document.createElement(this.tag)}updateDOM(e){return e.nodeName.toLowerCase()==this.tag}get isHidden(){return!0}}Sl.inline=new Sl("span");Sl.block=new Sl("div");var ar=(function(t){return t[t.LTR=0]="LTR",t[t.RTL=1]="RTL",t})(ar||(ar={}));const na=ar.LTR,A1=ar.RTL;function cI(t){let e=[];for(let n=0;n=n){if(l.level==r)return o;(s<0||(i!=0?i<0?l.fromn:e[s].level>l.level))&&(s=o)}}if(s<0)throw new RangeError("Index out of range");return s}}function fI(t,e){if(t.length!=e.length)return!1;for(let n=0;n=0;v-=3)if(Fi[v+1]==-g){let S=Fi[v+2],C=S&2?i:S&4?S&1?s:i:0;C&&(Vt[p]=Vt[Fi[v]]=C),l=v;break}}else{if(Fi.length==189)break;Fi[l++]=p,Fi[l++]=m,Fi[l++]=c}else if((x=Vt[p])==2||x==1){let v=x==i;c=v?0:1;for(let S=l-3;S>=0;S-=3){let C=Fi[S+2];if(C&2)break;if(v)Fi[S+2]|=2;else{if(C&4)break;Fi[S+2]|=4}}}}}function bY(t,e,n,r){for(let i=0,s=r;i<=n.length;i++){let o=i?n[i-1].to:t,l=ic;)x==S&&(x=n[--v].from,S=v?n[v-1].to:t),Vt[--x]=g;c=f}else s=d,c++}}}function Bb(t,e,n,r,i,s,o){let l=r%2?2:1;if(r%2==i%2)for(let c=e,d=0;cc&&o.push(new so(c,v.from,g));let S=v.direction==na!=!(g%2);Ub(t,S?r+1:r,i,v.inner,v.from,v.to,o),c=v.to}x=v.to}else{if(x==n||(f?Vt[x]!=l:Vt[x]==l))break;x++}m?Bb(t,c,x,r+1,i,m,o):ce;){let f=!0,p=!1;if(!d||c>s[d-1].to){let v=Vt[c-1];v!=l&&(f=!1,p=v==16)}let m=!f&&l==1?[]:null,g=f?r:r+1,x=c;e:for(;;)if(d&&x==s[d-1].to){if(p)break e;let v=s[--d];if(!f)for(let S=v.from,C=d;;){if(S==e)break e;if(C&&s[C-1].to==S)S=s[--C].from;else{if(Vt[S-1]==l)break e;break}}if(m)m.push(v);else{v.toVt.length;)Vt[Vt.length]=256;let r=[],i=e==na?0:1;return Ub(t,i,i,n,0,t.length,r),r}function hI(t){return[new so(0,t,0)]}let pI="";function yY(t,e,n,r,i){var s;let o=r.head-t.from,l=so.find(e,o,(s=r.bidiLevel)!==null&&s!==void 0?s:-1,r.assoc),c=e[l],d=c.side(i,n);if(o==d){let m=l+=i?1:-1;if(m<0||m>=e.length)return null;c=e[l=m],o=c.side(!i,n),d=c.side(i,n)}let f=xi(t.text,o,c.forward(i,n));(fc.to)&&(f=d),pI=t.text.slice(Math.min(o,f),Math.max(o,f));let p=l==(i?e.length-1:0)?null:e[l+(i?1:-1)];return p&&f==d&&p.level+(i?0:1)t.some(e=>e)}),vY=tt.define({combine:t=>t.some(e=>e)}),wI=tt.define();class dl{constructor(e,n="nearest",r="nearest",i=5,s=5,o=!1){this.range=e,this.y=n,this.x=r,this.yMargin=i,this.xMargin=s,this.isSnapshot=o}map(e){return e.empty?this:new dl(this.range.map(e),this.y,this.x,this.yMargin,this.xMargin,this.isSnapshot)}clip(e){return this.range.to<=e.doc.length?this:new dl(Pe.cursor(e.doc.length),this.y,this.x,this.yMargin,this.xMargin,this.isSnapshot)}}const Sf=bn.define({map:(t,e)=>t.map(e)}),TI=bn.define();function gs(t,e,n){let r=t.facet(EI);r.length?r[0](e):window.onerror&&window.onerror(String(e),n,void 0,void 0,e)||(n?console.error(n+":",e):console.error(e))}const ms=tt.define({combine:t=>t.length?t[0]:!0});let wY=0;const el=tt.define({combine(t){return t.filter((e,n)=>{for(let r=0;r{let c=[];return o&&c.push(_c.of(d=>{let f=d.plugin(l);return f?o(f):en.none})),s&&c.push(s(l)),c})}static fromClass(e,n){return Ss.define((r,i)=>new e(r,i),n)}}class g0{constructor(e){this.spec=e,this.mustUpdate=null,this.value=null}get plugin(){return this.spec&&this.spec.plugin}update(e){if(this.value){if(this.mustUpdate){let n=this.mustUpdate;if(this.mustUpdate=null,this.value.update)try{this.value.update(n)}catch(r){if(gs(n.state,r,"CodeMirror plugin crashed"),this.value.destroy)try{this.value.destroy()}catch{}this.deactivate()}}}else if(this.spec)try{this.value=this.spec.plugin.create(e,this.spec.arg)}catch(n){gs(e.state,n,"CodeMirror plugin crashed"),this.deactivate()}return this}destroy(e){var n;if(!((n=this.value)===null||n===void 0)&&n.destroy)try{this.value.destroy()}catch(r){gs(e.state,r,"CodeMirror plugin crashed")}}deactivate(){this.spec=this.value=null}}const SI=tt.define(),R1=tt.define(),_c=tt.define(),_I=tt.define(),I1=tt.define(),CI=tt.define();function hS(t,e){let n=t.state.facet(CI);if(!n.length)return n;let r=n.map(s=>s instanceof Function?s(t):s),i=[];return Ht.spans(r,e.from,e.to,{point(){},span(s,o,l,c){let d=s-e.from,f=o-e.from,p=i;for(let m=l.length-1;m>=0;m--,c--){let g=l[m].spec.bidiIsolate,x;if(g==null&&(g=xY(e.text,d,f)),c>0&&p.length&&(x=p[p.length-1]).to==d&&x.direction==g)x.to=f,p=x.inner;else{let v={from:d,to:f,direction:g,inner:[]};p.push(v),p=v.inner}}}}),i}const AI=tt.define();function kI(t){let e=0,n=0,r=0,i=0;for(let s of t.state.facet(AI)){let o=s(t);o&&(o.left!=null&&(e=Math.max(e,o.left)),o.right!=null&&(n=Math.max(n,o.right)),o.top!=null&&(r=Math.max(r,o.top)),o.bottom!=null&&(i=Math.max(i,o.bottom)))}return{left:e,right:n,top:r,bottom:i}}const $u=tt.define();class si{constructor(e,n,r,i){this.fromA=e,this.toA=n,this.fromB=r,this.toB=i}join(e){return new si(Math.min(this.fromA,e.fromA),Math.max(this.toA,e.toA),Math.min(this.fromB,e.fromB),Math.max(this.toB,e.toB))}addToSet(e){let n=e.length,r=this;for(;n>0;n--){let i=e[n-1];if(!(i.fromA>r.toA)){if(i.toAf)break;s+=2}if(!c)return r;new si(c.fromA,c.toA,c.fromB,c.toB).addToSet(r),o=c.toA,l=c.toB}}}class Sh{constructor(e,n,r){this.view=e,this.state=n,this.transactions=r,this.flags=0,this.startState=e.state,this.changes=$n.empty(this.startState.doc.length);for(let s of r)this.changes=this.changes.compose(s.changes);let i=[];this.changes.iterChangedRanges((s,o,l,c)=>i.push(new si(s,o,l,c))),this.changedRanges=i}static create(e,n,r){return new Sh(e,n,r)}get viewportChanged(){return(this.flags&4)>0}get viewportMoved(){return(this.flags&8)>0}get heightChanged(){return(this.flags&2)>0}get geometryChanged(){return this.docChanged||(this.flags&18)>0}get focusChanged(){return(this.flags&1)>0}get docChanged(){return!this.changes.empty}get selectionSet(){return this.transactions.some(e=>e.selection)}get empty(){return this.flags==0&&this.transactions.length==0}}class pS extends Gt{get length(){return this.view.state.doc.length}constructor(e){super(),this.view=e,this.decorations=[],this.dynamicDecorationMap=[!1],this.domChanged=null,this.hasComposition=null,this.markedForComposition=new Set,this.editContextFormatting=en.none,this.lastCompositionAfterCursor=!1,this.minWidth=0,this.minWidthFrom=0,this.minWidthTo=0,this.impreciseAnchor=null,this.impreciseHead=null,this.forceSelection=!1,this.lastUpdate=Date.now(),this.setDOM(e.contentDOM),this.children=[new In],this.children[0].setParent(this),this.updateDeco(),this.updateInner([new si(0,0,0,e.state.doc.length)],0,null)}update(e){var n;let r=e.changedRanges;this.minWidth>0&&r.length&&(r.every(({fromA:d,toA:f})=>fthis.minWidthTo)?(this.minWidthFrom=e.changes.mapPos(this.minWidthFrom,1),this.minWidthTo=e.changes.mapPos(this.minWidthTo,1)):this.minWidth=this.minWidthFrom=this.minWidthTo=0),this.updateEditContextFormatting(e);let i=-1;this.view.inputState.composing>=0&&!this.view.observer.editContext&&(!((n=this.domChanged)===null||n===void 0)&&n.newSel?i=this.domChanged.newSel.head:!NY(e.changes,this.hasComposition)&&!e.selectionSet&&(i=e.state.selection.main.head));let s=i>-1?SY(this.view,e.changes,i):null;if(this.domChanged=null,this.hasComposition){this.markedForComposition.clear();let{from:d,to:f}=this.hasComposition;r=new si(d,f,e.changes.mapPos(d,-1),e.changes.mapPos(f,1)).addToSet(r.slice())}this.hasComposition=s?{from:s.range.fromB,to:s.range.toB}:null,(Fe.ie||Fe.chrome)&&!s&&e&&e.state.doc.lines!=e.startState.doc.lines&&(this.forceSelection=!0);let o=this.decorations,l=this.updateDeco(),c=AY(o,l,e.changes);return r=si.extendWithRanges(r,c),!(this.flags&7)&&r.length==0?!1:(this.updateInner(r,e.startState.doc.length,s),e.transactions.length&&(this.lastUpdate=Date.now()),!0)}updateInner(e,n,r){this.view.viewState.mustMeasureContent=!0,this.updateChildren(e,n,r);let{observer:i}=this.view;i.ignore(()=>{this.dom.style.height=this.view.viewState.contentHeight/this.view.scaleY+"px",this.dom.style.flexBasis=this.minWidth?this.minWidth+"px":"";let o=Fe.chrome||Fe.ios?{node:i.selectionRange.focusNode,written:!1}:void 0;this.sync(this.view,o),this.flags&=-8,o&&(o.written||i.selectionRange.focusNode!=o.node)&&(this.forceSelection=!0),this.dom.style.height=""}),this.markedForComposition.forEach(o=>o.flags&=-9);let s=[];if(this.view.viewport.from||this.view.viewport.to=0?i[o]:null;if(!l)break;let{fromA:c,toA:d,fromB:f,toB:p}=l,m,g,x,v;if(r&&r.range.fromBf){let M=rc.build(this.view.state.doc,f,r.range.fromB,this.decorations,this.dynamicDecorationMap),F=rc.build(this.view.state.doc,r.range.toB,p,this.decorations,this.dynamicDecorationMap);g=M.breakAtStart,x=M.openStart,v=F.openEnd;let I=this.compositionView(r);F.breakAtStart?I.breakAfter=1:F.content.length&&I.merge(I.length,I.length,F.content[0],!1,F.openStart,0)&&(I.breakAfter=F.content[0].breakAfter,F.content.shift()),M.content.length&&I.merge(0,0,M.content[M.content.length-1],!0,0,M.openEnd)&&M.content.pop(),m=M.content.concat(I).concat(F.content)}else({content:m,breakAtStart:g,openStart:x,openEnd:v}=rc.build(this.view.state.doc,f,p,this.decorations,this.dynamicDecorationMap));let{i:S,off:C}=s.findPos(d,1),{i:A,off:k}=s.findPos(c,-1);nI(this,A,k,S,C,m,g,x,v)}r&&this.fixCompositionDOM(r)}updateEditContextFormatting(e){this.editContextFormatting=this.editContextFormatting.map(e.changes);for(let n of e.transactions)for(let r of n.effects)r.is(TI)&&(this.editContextFormatting=r.value)}compositionView(e){let n=new _i(e.text.nodeValue);n.flags|=8;for(let{deco:i}of e.marks)n=new Ts(i,[n],n.length);let r=new In;return r.append(n,0),r}fixCompositionDOM(e){let n=(s,o)=>{o.flags|=8|(o.children.some(c=>c.flags&7)?1:0),this.markedForComposition.add(o);let l=Gt.get(s);l&&l!=o&&(l.dom=null),o.setDOM(s)},r=this.childPos(e.range.fromB,1),i=this.children[r.i];n(e.line,i);for(let s=e.marks.length-1;s>=-1;s--)r=i.childPos(r.off,1),i=i.children[r.i],n(s>=0?e.marks[s].node:e.text,i)}updateSelection(e=!1,n=!1){(e||!this.view.observer.selectionRange.focusNode)&&this.view.observer.readSelectionRange();let r=this.view.root.activeElement,i=r==this.dom,s=!i&&!(this.view.state.facet(ms)||this.dom.tabIndex>-1)&&Wf(this.dom,this.view.observer.selectionRange)&&!(r&&this.dom.contains(r));if(!(i||n||s))return;let o=this.forceSelection;this.forceSelection=!1;let l=this.view.state.selection.main,c=this.moveToLine(this.domAtPos(l.anchor)),d=l.empty?c:this.moveToLine(this.domAtPos(l.head));if(Fe.gecko&&l.empty&&!this.hasComposition&&TY(c)){let p=document.createTextNode("");this.view.observer.ignore(()=>c.node.insertBefore(p,c.node.childNodes[c.offset]||null)),c=d=new ir(p,0),o=!0}let f=this.view.observer.selectionRange;(o||!f.focusNode||(!nc(c.node,c.offset,f.anchorNode,f.anchorOffset)||!nc(d.node,d.offset,f.focusNode,f.focusOffset))&&!this.suppressWidgetCursorChange(f,l))&&(this.view.observer.ignore(()=>{Fe.android&&Fe.chrome&&this.dom.contains(f.focusNode)&&kY(f.focusNode,this.dom)&&(this.dom.blur(),this.dom.focus({preventScroll:!0}));let p=Tc(this.view.root);if(p)if(l.empty){if(Fe.gecko){let m=_Y(c.node,c.offset);if(m&&m!=3){let g=(m==1?JR:eI)(c.node,c.offset);g&&(c=new ir(g.node,g.offset))}}p.collapse(c.node,c.offset),l.bidiLevel!=null&&p.caretBidiLevel!==void 0&&(p.caretBidiLevel=l.bidiLevel)}else if(p.extend){p.collapse(c.node,c.offset);try{p.extend(d.node,d.offset)}catch{}}else{let m=document.createRange();l.anchor>l.head&&([c,d]=[d,c]),m.setEnd(d.node,d.offset),m.setStart(c.node,c.offset),p.removeAllRanges(),p.addRange(m)}s&&this.view.root.activeElement==this.dom&&(this.dom.blur(),r&&r.focus())}),this.view.observer.setSelectionRange(c,d)),this.impreciseAnchor=c.precise?null:new ir(f.anchorNode,f.anchorOffset),this.impreciseHead=d.precise?null:new ir(f.focusNode,f.focusOffset)}suppressWidgetCursorChange(e,n){return this.hasComposition&&n.empty&&nc(e.focusNode,e.focusOffset,e.anchorNode,e.anchorOffset)&&this.posFromDOM(e.focusNode,e.focusOffset)==n.head}enforceCursorAssoc(){if(this.hasComposition)return;let{view:e}=this,n=e.state.selection.main,r=Tc(e.root),{anchorNode:i,anchorOffset:s}=e.observer.selectionRange;if(!r||!n.empty||!n.assoc||!r.modify)return;let o=In.find(this,n.head);if(!o)return;let l=o.posAtStart;if(n.head==l||n.head==l+o.length)return;let c=this.coordsAt(n.head,-1),d=this.coordsAt(n.head,1);if(!c||!d||c.bottom>d.top)return;let f=this.domAtPos(n.head+n.assoc);r.collapse(f.node,f.offset),r.modify("move",n.assoc<0?"forward":"backward","lineboundary"),e.observer.readSelectionRange();let p=e.observer.selectionRange;e.docView.posFromDOM(p.anchorNode,p.anchorOffset)!=n.from&&r.collapse(i,s)}moveToLine(e){let n=this.dom,r;if(e.node!=n)return e;for(let i=e.offset;!r&&i=0;i--){let s=Gt.get(n.childNodes[i]);s instanceof In&&(r=s.domAtPos(s.length))}return r?new ir(r.node,r.offset,!0):e}nearest(e){for(let n=e;n;){let r=Gt.get(n);if(r&&r.rootView==this)return r;n=n.parentNode}return null}posFromDOM(e,n){let r=this.nearest(e);if(!r)throw new RangeError("Trying to find position for a DOM position outside of the document");return r.localPosFromDOM(e,n)+r.posAtStart}domAtPos(e){let{i:n,off:r}=this.childCursor().findPos(e,-1);for(;n=0;o--){let l=this.children[o],c=s-l.breakAfter,d=c-l.length;if(ce||l.covers(1))&&(!r||l instanceof In&&!(r instanceof In&&n>=0)))r=l,i=d;else if(r&&d==e&&c==e&&l instanceof Es&&Math.abs(n)<2){if(l.deco.startSide<0)break;o&&(r=null)}s=d}return r?r.coordsAt(e-i,n):null}coordsForChar(e){let{i:n,off:r}=this.childPos(e,1),i=this.children[n];if(!(i instanceof In))return null;for(;i.children.length;){let{i:l,off:c}=i.childPos(r,1);for(;;l++){if(l==i.children.length)return null;if((i=i.children[l]).length)break}r=c}if(!(i instanceof _i))return null;let s=xi(i.text,r);if(s==r)return null;let o=ta(i.dom,r,s).getClientRects();for(let l=0;lMath.max(this.view.scrollDOM.clientWidth,this.minWidth)+1,l=-1,c=this.view.textDirection==ar.LTR;for(let d=0,f=0;fi)break;if(d>=r){let g=p.dom.getBoundingClientRect();if(n.push(g.height),o){let x=p.dom.lastChild,v=x?Sc(x):[];if(v.length){let S=v[v.length-1],C=c?S.right-g.left:g.right-S.left;C>l&&(l=C,this.minWidth=s,this.minWidthFrom=d,this.minWidthTo=m)}}}d=m+p.breakAfter}return n}textDirectionAt(e){let{i:n}=this.childPos(e,1);return getComputedStyle(this.children[n].dom).direction=="rtl"?ar.RTL:ar.LTR}measureTextSize(){for(let s of this.children)if(s instanceof In){let o=s.measureTextSize();if(o)return o}let e=document.createElement("div"),n,r,i;return e.className="cm-line",e.style.width="99999px",e.style.position="absolute",e.textContent="abc def ghi jkl mno pqr stu",this.view.observer.ignore(()=>{this.dom.appendChild(e);let s=Sc(e.firstChild)[0];n=e.getBoundingClientRect().height,r=s?s.width/27:7,i=s?s.height:n,e.remove()}),{lineHeight:n,charWidth:r,textHeight:i}}childCursor(e=this.length){let n=this.children.length;return n&&(e-=this.children[--n].length),new tI(this.children,e,n)}computeBlockGapDeco(){let e=[],n=this.view.viewState;for(let r=0,i=0;;i++){let s=i==n.viewports.length?null:n.viewports[i],o=s?s.from-1:this.length;if(o>r){let l=(n.lineBlockAt(o).bottom-n.lineBlockAt(r).top)/this.view.scaleY;e.push(en.replace({widget:new Pb(l),block:!0,inclusive:!0,isBlockGap:!0}).range(r,o))}if(!s)break;r=s.to+1}return en.set(e)}updateDeco(){let e=1,n=this.view.state.facet(_c).map(s=>(this.dynamicDecorationMap[e++]=typeof s=="function")?s(this.view):s),r=!1,i=this.view.state.facet(_I).map((s,o)=>{let l=typeof s=="function";return l&&(r=!0),l?s(this.view):s});for(i.length&&(this.dynamicDecorationMap[e++]=r,n.push(Ht.join(i))),this.decorations=[this.editContextFormatting,...n,this.computeBlockGapDeco(),this.view.viewState.lineGapDeco];en.anchor?-1:1),i;if(!r)return;!n.empty&&(i=this.coordsAt(n.anchor,n.anchor>n.head?-1:1))&&(r={left:Math.min(r.left,i.left),top:Math.min(r.top,i.top),right:Math.max(r.right,i.right),bottom:Math.max(r.bottom,i.bottom)});let s=kI(this.view),o={left:r.left-s.left,top:r.top-s.top,right:r.right+s.right,bottom:r.bottom+s.bottom},{offsetWidth:l,offsetHeight:c}=this.view.scrollDOM;eY(this.view.scrollDOM,o,n.head{re.from&&(n=!0)}),n}function RY(t,e,n=1){let r=t.charCategorizer(e),i=t.doc.lineAt(e),s=e-i.from;if(i.length==0)return Pe.cursor(e);s==0?n=1:s==i.length&&(n=-1);let o=s,l=s;n<0?o=xi(i.text,s,!1):l=xi(i.text,s);let c=r(i.text.slice(o,l));for(;o>0;){let d=xi(i.text,o,!1);if(r(i.text.slice(d,o))!=c)break;o=d}for(;lt?e.left-t:Math.max(0,t-e.right)}function OY(t,e){return e.top>t?e.top-t:Math.max(0,t-e.bottom)}function b0(t,e){return t.tope.top+1}function mS(t,e){return et.bottom?{top:t.top,left:t.left,right:t.right,bottom:e}:t}function zb(t,e,n){let r,i,s,o,l=!1,c,d,f,p;for(let x=t.firstChild;x;x=x.nextSibling){let v=Sc(x);for(let S=0;Sk||o==k&&s>A)&&(r=x,i=C,s=A,o=k,l=A?e0:SC.bottom&&(!f||f.bottomC.top)&&(d=x,p=C):f&&b0(f,C)?f=gS(f,C.bottom):p&&b0(p,C)&&(p=mS(p,C.top))}}if(f&&f.bottom>=n?(r=c,i=f):p&&p.top<=n&&(r=d,i=p),!r)return{node:t,offset:0};let m=Math.max(i.left,Math.min(i.right,e));if(r.nodeType==3)return bS(r,m,n);if(l&&r.contentEditable!="false")return zb(r,m,n);let g=Array.prototype.indexOf.call(t.childNodes,r)+(e>=(i.left+i.right)/2?1:0);return{node:t,offset:g}}function bS(t,e,n){let r=t.nodeValue.length,i=-1,s=1e9,o=0;for(let l=0;ln?f.top-n:n-f.bottom)-1;if(f.left-1<=e&&f.right+1>=e&&p=(f.left+f.right)/2,g=m;if((Fe.chrome||Fe.gecko)&&ta(t,l).getBoundingClientRect().left==f.right&&(g=!m),p<=0)return{node:t,offset:l+(g?1:0)};i=l+(g?1:0),s=p}}}return{node:t,offset:i>-1?i:o>0?t.nodeValue.length:0}}function RI(t,e,n,r=-1){var i,s;let o=t.contentDOM.getBoundingClientRect(),l=o.top+t.viewState.paddingTop,c,{docHeight:d}=t.viewState,{x:f,y:p}=e,m=p-l;if(m<0)return 0;if(m>d)return t.state.doc.length;for(let M=t.viewState.heightOracle.textHeight/2,F=!1;c=t.elementAtHeight(m),c.type!=ii.Text;)for(;m=r>0?c.bottom+M:c.top-M,!(m>=0&&m<=d);){if(F)return n?null:0;F=!0,r=-r}p=l+m;let g=c.from;if(gt.viewport.to)return t.viewport.to==t.state.doc.length?t.state.doc.length:n?null:ES(t,o,c,f,p);let x=t.dom.ownerDocument,v=t.root.elementFromPoint?t.root:x,S=v.elementFromPoint(f,p);S&&!t.contentDOM.contains(S)&&(S=null),S||(f=Math.max(o.left+1,Math.min(o.right-1,f)),S=v.elementFromPoint(f,p),S&&!t.contentDOM.contains(S)&&(S=null));let C,A=-1;if(S&&((i=t.docView.nearest(S))===null||i===void 0?void 0:i.isEditable)!=!1){if(x.caretPositionFromPoint){let M=x.caretPositionFromPoint(f,p);M&&({offsetNode:C,offset:A}=M)}else if(x.caretRangeFromPoint){let M=x.caretRangeFromPoint(f,p);M&&({startContainer:C,startOffset:A}=M,(!t.contentDOM.contains(C)||Fe.safari&&MY(C,A,f)||Fe.chrome&&DY(C,A,f))&&(C=void 0))}C&&(A=Math.min(Xi(C),A))}if(!C||!t.docView.dom.contains(C)){let M=In.find(t.docView,g);if(!M)return m>c.top+c.height/2?c.to:c.from;({node:C,offset:A}=zb(M.dom,f,p))}let k=t.docView.nearest(C);if(!k)return null;if(k.isWidget&&((s=k.dom)===null||s===void 0?void 0:s.nodeType)==1){let M=k.dom.getBoundingClientRect();return e.yt.defaultLineHeight*1.5){let l=t.viewState.heightOracle.textHeight,c=Math.floor((i-n.top-(t.defaultLineHeight-l)*.5)/l);s+=c*t.viewState.heightOracle.lineLength}let o=t.state.sliceDoc(n.from,n.to);return n.from+YK(o,s,t.state.tabSize)}function MY(t,e,n){let r,i=t;if(t.nodeType!=3||e!=(r=t.nodeValue.length))return!1;for(;;){let s=i.nextSibling;if(s){if(s.nodeName=="BR")break;return!1}else{let o=i.parentNode;if(!o||o.nodeName=="DIV")break;i=o}}return ta(t,r-1,r).getBoundingClientRect().right>n}function DY(t,e,n){if(e!=0)return!1;for(let i=t;;){let s=i.parentNode;if(!s||s.nodeType!=1||s.firstChild!=i)return!1;if(s.classList.contains("cm-line"))break;i=s}let r=t.nodeType==1?t.getBoundingClientRect():ta(t,0,Math.max(t.nodeValue.length,1)).getBoundingClientRect();return n-r.left>5}function LY(t,e,n){let r=t.lineBlockAt(e);if(Array.isArray(r.type)){let i;for(let s of r.type){if(s.from>e)break;if(!(s.toe)return s;(!i||s.type==ii.Text&&(i.type!=s.type||(n<0?s.frome)))&&(i=s)}}return i||r}return r}function PY(t,e,n,r){let i=LY(t,e.head,e.assoc||-1),s=!r||i.type!=ii.Text||!(t.lineWrapping||i.widgetLineBreaks)?null:t.coordsAtPos(e.assoc<0&&e.head>i.from?e.head-1:e.head);if(s){let o=t.dom.getBoundingClientRect(),l=t.textDirectionAt(i.from),c=t.posAtCoords({x:n==(l==ar.LTR)?o.right-1:o.left+1,y:(s.top+s.bottom)/2});if(c!=null)return Pe.cursor(c,n?-1:1)}return Pe.cursor(n?i.to:i.from,n?-1:1)}function yS(t,e,n,r){let i=t.state.doc.lineAt(e.head),s=t.bidiSpans(i),o=t.textDirectionAt(i.from);for(let l=e,c=null;;){let d=yY(i,s,o,l,n),f=pI;if(!d){if(i.number==(n?t.state.doc.lines:1))return l;f=` +`,i=t.state.doc.line(i.number+(n?1:-1)),s=t.bidiSpans(i),d=t.visualLineSide(i,!n)}if(c){if(!c(f))return l}else{if(!r)return d;c=r(f)}l=d}}function FY(t,e,n){let r=t.state.charCategorizer(e),i=r(n);return s=>{let o=r(s);return i==Cn.Space&&(i=o),i==o}}function BY(t,e,n,r){let i=e.head,s=n?1:-1;if(i==(n?t.state.doc.length:0))return Pe.cursor(i,e.assoc);let o=e.goalColumn,l,c=t.contentDOM.getBoundingClientRect(),d=t.coordsAtPos(i,e.assoc||-1),f=t.documentTop;if(d)o==null&&(o=d.left-c.left),l=s<0?d.top:d.bottom;else{let g=t.viewState.lineBlockAt(i);o==null&&(o=Math.min(c.right-c.left,t.defaultCharacterWidth*(i-g.from))),l=(s<0?g.top:g.bottom)+f}let p=c.left+o,m=r??t.viewState.heightOracle.textHeight>>1;for(let g=0;;g+=10){let x=l+(m+g)*s,v=RI(t,{x:p,y:x},!1,s);if(xc.bottom||(s<0?vi)){let S=t.docView.coordsForChar(v),C=!S||x{if(e>s&&ei(t)),n.from,e.head>n.from?-1:1);return r==n.from?n:Pe.cursor(r,rs)&&this.lineBreak(),i=o}return this.findPointBefore(r,n),this}readTextNode(e){let n=e.nodeValue;for(let r of this.points)r.node==e&&(r.pos=this.text.length+Math.min(r.offset,n.length));for(let r=0,i=this.lineSeparator?null:/\r\n?|\n/g;;){let s=-1,o=1,l;if(this.lineSeparator?(s=n.indexOf(this.lineSeparator,r),o=this.lineSeparator.length):(l=i.exec(n))&&(s=l.index,o=l[0].length),this.append(n.slice(r,s<0?n.length:s)),s<0)break;if(this.lineBreak(),o>1)for(let c of this.points)c.node==e&&c.pos>this.text.length&&(c.pos-=o-1);r=s+o}}readNode(e){if(e.cmIgnore)return;let n=Gt.get(e),r=n&&n.overrideDOMText;if(r!=null){this.findPointInside(e,r.length);for(let i=r.iter();!i.next().done;)i.lineBreak?this.lineBreak():this.append(i.value)}else e.nodeType==3?this.readTextNode(e):e.nodeName=="BR"?e.nextSibling&&this.lineBreak():e.nodeType==1&&this.readRange(e.firstChild,null)}findPointBefore(e,n){for(let r of this.points)r.node==e&&e.childNodes[r.offset]==n&&(r.pos=this.text.length)}findPointInside(e,n){for(let r of this.points)(e.nodeType==3?r.node==e:e.contains(r.node))&&(r.pos=this.text.length+(HY(e,r.node,r.offset)?n:0))}}function HY(t,e,n){for(;;){if(!e||n-1;let{impreciseHead:s,impreciseAnchor:o}=e.docView;if(e.state.readOnly&&n>-1)this.newSel=null;else if(n>-1&&(this.bounds=e.docView.domBoundsAround(n,r,0))){let l=s||o?[]:WY(e),c=new UY(l,e.state);c.readRange(this.bounds.startDOM,this.bounds.endDOM),this.text=c.text,this.newSel=VY(l,this.bounds.from)}else{let l=e.observer.selectionRange,c=s&&s.node==l.focusNode&&s.offset==l.focusOffset||!Rb(e.contentDOM,l.focusNode)?e.state.selection.main.head:e.docView.posFromDOM(l.focusNode,l.focusOffset),d=o&&o.node==l.anchorNode&&o.offset==l.anchorOffset||!Rb(e.contentDOM,l.anchorNode)?e.state.selection.main.anchor:e.docView.posFromDOM(l.anchorNode,l.anchorOffset),f=e.viewport;if((Fe.ios||Fe.chrome)&&e.state.selection.main.empty&&c!=d&&(f.from>0||f.toDate.now()-100?t.inputState.lastKeyCode:-1;if(e.bounds){let{from:o,to:l}=e.bounds,c=i.from,d=null;(s===8||Fe.android&&e.text.length=i.from&&n.to<=i.to&&(n.from!=i.from||n.to!=i.to)&&i.to-i.from-(n.to-n.from)<=4?n={from:i.from,to:i.to,insert:t.state.doc.slice(i.from,n.from).append(n.insert).append(t.state.doc.slice(n.to,i.to))}:Fe.chrome&&n&&n.from==n.to&&n.from==i.head&&n.insert.toString()==` + `&&t.lineWrapping&&(r&&(r=Pe.single(r.main.anchor-1,r.main.head-1)),n={from:i.from,to:i.to,insert:Lt.of([" "])}),n)return O1(t,n,r,s);if(r&&!r.main.eq(i)){let o=!1,l="select";return t.inputState.lastSelectionTime>Date.now()-50&&(t.inputState.lastSelectionOrigin=="select"&&(o=!0),l=t.inputState.lastSelectionOrigin),t.dispatch({selection:r,scrollIntoView:o,userEvent:l}),!0}else return!1}function O1(t,e,n,r=-1){if(Fe.ios&&t.inputState.flushIOSKey(e))return!0;let i=t.state.selection.main;if(Fe.android&&(e.to==i.to&&(e.from==i.from||e.from==i.from-1&&t.state.sliceDoc(e.from,i.from)==" ")&&e.insert.length==1&&e.insert.lines==2&&cl(t.contentDOM,"Enter",13)||(e.from==i.from-1&&e.to==i.to&&e.insert.length==0||r==8&&e.insert.lengthi.head)&&cl(t.contentDOM,"Backspace",8)||e.from==i.from&&e.to==i.to+1&&e.insert.length==0&&cl(t.contentDOM,"Delete",46)))return!0;let s=e.insert.toString();t.inputState.composing>=0&&t.inputState.composing++;let o,l=()=>o||(o=jY(t,e,n));return t.state.facet(yI).some(c=>c(t,e.from,e.to,s,l))||t.dispatch(l()),!0}function jY(t,e,n){let r,i=t.state,s=i.selection.main;if(e.from>=s.from&&e.to<=s.to&&e.to-e.from>=(s.to-s.from)/3&&(!n||n.main.empty&&n.main.from==e.from+e.insert.length)&&t.inputState.composing<0){let l=s.frome.to?i.sliceDoc(e.to,s.to):"";r=i.replaceSelection(t.state.toText(l+e.insert.sliceString(0,void 0,t.state.lineBreak)+c))}else{let l=i.changes(e),c=n&&n.main.to<=l.newLength?n.main:void 0;if(i.selection.ranges.length>1&&t.inputState.composing>=0&&e.to<=s.to&&e.to>=s.to-10){let d=t.state.sliceDoc(e.from,e.to),f,p=n&&NI(t,n.main.head);if(p){let x=e.insert.length-(e.to-e.from);f={from:p.from,to:p.to-x}}else f=t.state.doc.lineAt(s.head);let m=s.to-e.to,g=s.to-s.from;r=i.changeByRange(x=>{if(x.from==s.from&&x.to==s.to)return{changes:l,range:c||x.map(l)};let v=x.to-m,S=v-d.length;if(x.to-x.from!=g||t.state.sliceDoc(S,v)!=d||x.to>=f.from&&x.from<=f.to)return{range:x};let C=i.changes({from:S,to:v,insert:e.insert}),A=x.to-s.to;return{changes:C,range:c?Pe.range(Math.max(0,c.anchor+A),Math.max(0,c.head+A)):x.map(C)}})}else r={changes:l,selection:c&&i.selection.replaceRange(c)}}let o="input.type";return(t.composing||t.inputState.compositionPendingChange&&t.inputState.compositionEndedAt>Date.now()-50)&&(t.inputState.compositionPendingChange=!1,o+=".compose",t.inputState.compositionFirstChange&&(o+=".start",t.inputState.compositionFirstChange=!1)),i.update(r,{userEvent:o,scrollIntoView:!0})}function $Y(t,e,n,r){let i=Math.min(t.length,e.length),s=0;for(;s0&&l>0&&t.charCodeAt(o-1)==e.charCodeAt(l-1);)o--,l--;if(r=="end"){let c=Math.max(0,s-Math.min(o,l));n-=o+c-s}if(o=o?s-n:0;s-=c,l=s+(l-o),o=s}else if(l=l?s-n:0;s-=c,o=s+(o-l),l=s}return{from:s,toA:o,toB:l}}function WY(t){let e=[];if(t.root.activeElement!=t.contentDOM)return e;let{anchorNode:n,anchorOffset:r,focusNode:i,focusOffset:s}=t.observer.selectionRange;return n&&(e.push(new xS(n,r)),(i!=n||s!=r)&&e.push(new xS(i,s))),e}function VY(t,e){if(t.length==0)return null;let n=t[0].pos,r=t.length==2?t[1].pos:n;return n>-1&&r>-1?Pe.single(n+e,r+e):null}class GY{setSelectionOrigin(e){this.lastSelectionOrigin=e,this.lastSelectionTime=Date.now()}constructor(e){this.view=e,this.lastKeyCode=0,this.lastKeyTime=0,this.lastTouchTime=0,this.lastFocusTime=0,this.lastScrollTop=0,this.lastScrollLeft=0,this.pendingIOSKey=void 0,this.tabFocusMode=-1,this.lastSelectionOrigin=null,this.lastSelectionTime=0,this.lastContextMenu=0,this.scrollHandlers=[],this.handlers=Object.create(null),this.composing=-1,this.compositionFirstChange=null,this.compositionEndedAt=0,this.compositionPendingKey=!1,this.compositionPendingChange=!1,this.mouseSelection=null,this.draggedContent=null,this.handleEvent=this.handleEvent.bind(this),this.notifiedFocused=e.hasFocus,Fe.safari&&e.contentDOM.addEventListener("input",()=>null),Fe.gecko&&lq(e.contentDOM.ownerDocument)}handleEvent(e){!eq(this.view,e)||this.ignoreDuringComposition(e)||e.type=="keydown"&&this.keydown(e)||(this.view.updateState!=0?Promise.resolve().then(()=>this.runHandlers(e.type,e)):this.runHandlers(e.type,e))}runHandlers(e,n){let r=this.handlers[e];if(r){for(let i of r.observers)i(this.view,n);for(let i of r.handlers){if(n.defaultPrevented)break;if(i(this.view,n)){n.preventDefault();break}}}}ensureHandlers(e){let n=KY(e),r=this.handlers,i=this.view.contentDOM;for(let s in n)if(s!="scroll"){let o=!n[s].handlers.length,l=r[s];l&&o!=!l.handlers.length&&(i.removeEventListener(s,this.handleEvent),l=null),l||i.addEventListener(s,this.handleEvent,{passive:o})}for(let s in r)s!="scroll"&&!n[s]&&i.removeEventListener(s,this.handleEvent);this.handlers=n}keydown(e){if(this.lastKeyCode=e.keyCode,this.lastKeyTime=Date.now(),e.keyCode==9&&this.tabFocusMode>-1&&(!this.tabFocusMode||Date.now()<=this.tabFocusMode))return!0;if(this.tabFocusMode>0&&e.keyCode!=27&&MI.indexOf(e.keyCode)<0&&(this.tabFocusMode=-1),Fe.android&&Fe.chrome&&!e.synthetic&&(e.keyCode==13||e.keyCode==8))return this.view.observer.delayAndroidKey(e.key,e.keyCode),!0;let n;return Fe.ios&&!e.synthetic&&!e.altKey&&!e.metaKey&&((n=OI.find(r=>r.keyCode==e.keyCode))&&!e.ctrlKey||YY.indexOf(e.key)>-1&&e.ctrlKey&&!e.shiftKey)?(this.pendingIOSKey=n||e,setTimeout(()=>this.flushIOSKey(),250),!0):(e.keyCode!=229&&this.view.observer.forceFlush(),!1)}flushIOSKey(e){let n=this.pendingIOSKey;return!n||n.key=="Enter"&&e&&e.from0?!0:Fe.safari&&!Fe.ios&&this.compositionPendingKey&&Date.now()-this.compositionEndedAt<100?(this.compositionPendingKey=!1,!0):!1:!1}startMouseSelection(e){this.mouseSelection&&this.mouseSelection.destroy(),this.mouseSelection=e}update(e){this.view.observer.update(e),this.mouseSelection&&this.mouseSelection.update(e),this.draggedContent&&e.docChanged&&(this.draggedContent=this.draggedContent.map(e.changes)),e.transactions.length&&(this.lastKeyCode=this.lastSelectionTime=0)}destroy(){this.mouseSelection&&this.mouseSelection.destroy()}}function vS(t,e){return(n,r)=>{try{return e.call(t,r,n)}catch(i){gs(n.state,i)}}}function KY(t){let e=Object.create(null);function n(r){return e[r]||(e[r]={observers:[],handlers:[]})}for(let r of t){let i=r.spec,s=i&&i.plugin.domEventHandlers,o=i&&i.plugin.domEventObservers;if(s)for(let l in s){let c=s[l];c&&n(l).handlers.push(vS(r.value,c))}if(o)for(let l in o){let c=o[l];c&&n(l).observers.push(vS(r.value,c))}}for(let r in Ci)n(r).handlers.push(Ci[r]);for(let r in oi)n(r).observers.push(oi[r]);return e}const OI=[{key:"Backspace",keyCode:8,inputType:"deleteContentBackward"},{key:"Enter",keyCode:13,inputType:"insertParagraph"},{key:"Enter",keyCode:13,inputType:"insertLineBreak"},{key:"Delete",keyCode:46,inputType:"deleteContentForward"}],YY="dthko",MI=[16,17,18,20,91,92,224,225],_f=6;function Cf(t){return Math.max(0,t)*.7+8}function qY(t,e){return Math.max(Math.abs(t.clientX-e.clientX),Math.abs(t.clientY-e.clientY))}class XY{constructor(e,n,r,i){this.view=e,this.startEvent=n,this.style=r,this.mustSelect=i,this.scrollSpeed={x:0,y:0},this.scrolling=-1,this.lastEvent=n,this.scrollParents=tY(e.contentDOM),this.atoms=e.state.facet(I1).map(o=>o(e));let s=e.contentDOM.ownerDocument;s.addEventListener("mousemove",this.move=this.move.bind(this)),s.addEventListener("mouseup",this.up=this.up.bind(this)),this.extend=n.shiftKey,this.multiple=e.state.facet(Wt.allowMultipleSelections)&&QY(e,n),this.dragging=JY(e,n)&&PI(n)==1?null:!1}start(e){this.dragging===!1&&this.select(e)}move(e){if(e.buttons==0)return this.destroy();if(this.dragging||this.dragging==null&&qY(this.startEvent,e)<10)return;this.select(this.lastEvent=e);let n=0,r=0,i=0,s=0,o=this.view.win.innerWidth,l=this.view.win.innerHeight;this.scrollParents.x&&({left:i,right:o}=this.scrollParents.x.getBoundingClientRect()),this.scrollParents.y&&({top:s,bottom:l}=this.scrollParents.y.getBoundingClientRect());let c=kI(this.view);e.clientX-c.left<=i+_f?n=-Cf(i-e.clientX):e.clientX+c.right>=o-_f&&(n=Cf(e.clientX-o)),e.clientY-c.top<=s+_f?r=-Cf(s-e.clientY):e.clientY+c.bottom>=l-_f&&(r=Cf(e.clientY-l)),this.setScrollSpeed(n,r)}up(e){this.dragging==null&&this.select(this.lastEvent),this.dragging||e.preventDefault(),this.destroy()}destroy(){this.setScrollSpeed(0,0);let e=this.view.contentDOM.ownerDocument;e.removeEventListener("mousemove",this.move),e.removeEventListener("mouseup",this.up),this.view.inputState.mouseSelection=this.view.inputState.draggedContent=null}setScrollSpeed(e,n){this.scrollSpeed={x:e,y:n},e||n?this.scrolling<0&&(this.scrolling=setInterval(()=>this.scroll(),50)):this.scrolling>-1&&(clearInterval(this.scrolling),this.scrolling=-1)}scroll(){let{x:e,y:n}=this.scrollSpeed;e&&this.scrollParents.x&&(this.scrollParents.x.scrollLeft+=e,e=0),n&&this.scrollParents.y&&(this.scrollParents.y.scrollTop+=n,n=0),(e||n)&&this.view.win.scrollBy(e,n),this.dragging===!1&&this.select(this.lastEvent)}skipAtoms(e){let n=null;for(let r=0;rn.isUserEvent("input.type"))?this.destroy():this.style.update(e)&&setTimeout(()=>this.select(this.lastEvent),20)}}function QY(t,e){let n=t.state.facet(mI);return n.length?n[0](e):Fe.mac?e.metaKey:e.ctrlKey}function ZY(t,e){let n=t.state.facet(gI);return n.length?n[0](e):Fe.mac?!e.altKey:!e.ctrlKey}function JY(t,e){let{main:n}=t.state.selection;if(n.empty)return!1;let r=Tc(t.root);if(!r||r.rangeCount==0)return!0;let i=r.getRangeAt(0).getClientRects();for(let s=0;s=e.clientX&&o.top<=e.clientY&&o.bottom>=e.clientY)return!0}return!1}function eq(t,e){if(!e.bubbles)return!0;if(e.defaultPrevented)return!1;for(let n=e.target,r;n!=t.contentDOM;n=n.parentNode)if(!n||n.nodeType==11||(r=Gt.get(n))&&r.ignoreEvent(e))return!1;return!0}const Ci=Object.create(null),oi=Object.create(null),DI=Fe.ie&&Fe.ie_version<15||Fe.ios&&Fe.webkit_version<604;function tq(t){let e=t.dom.parentNode;if(!e)return;let n=e.appendChild(document.createElement("textarea"));n.style.cssText="position: fixed; left: -10000px; top: 10px",n.focus(),setTimeout(()=>{t.focus(),n.remove(),LI(t,n.value)},50)}function Ap(t,e,n){for(let r of t.facet(e))n=r(n,t);return n}function LI(t,e){e=Ap(t.state,k1,e);let{state:n}=t,r,i=1,s=n.toText(e),o=s.lines==n.selection.ranges.length;if(jb!=null&&n.selection.ranges.every(c=>c.empty)&&jb==s.toString()){let c=-1;r=n.changeByRange(d=>{let f=n.doc.lineAt(d.from);if(f.from==c)return{range:d};c=f.from;let p=n.toText((o?s.line(i++).text:e)+n.lineBreak);return{changes:{from:f.from,insert:p},range:Pe.cursor(d.from+p.length)}})}else o?r=n.changeByRange(c=>{let d=s.line(i++);return{changes:{from:c.from,to:c.to,insert:d.text},range:Pe.cursor(c.from+d.length)}}):r=n.replaceSelection(s);t.dispatch(r,{userEvent:"input.paste",scrollIntoView:!0})}oi.scroll=t=>{t.inputState.lastScrollTop=t.scrollDOM.scrollTop,t.inputState.lastScrollLeft=t.scrollDOM.scrollLeft};Ci.keydown=(t,e)=>(t.inputState.setSelectionOrigin("select"),e.keyCode==27&&t.inputState.tabFocusMode!=0&&(t.inputState.tabFocusMode=Date.now()+2e3),!1);oi.touchstart=(t,e)=>{t.inputState.lastTouchTime=Date.now(),t.inputState.setSelectionOrigin("select.pointer")};oi.touchmove=t=>{t.inputState.setSelectionOrigin("select.pointer")};Ci.mousedown=(t,e)=>{if(t.observer.flush(),t.inputState.lastTouchTime>Date.now()-2e3)return!1;let n=null;for(let r of t.state.facet(bI))if(n=r(t,e),n)break;if(!n&&e.button==0&&(n=iq(t,e)),n){let r=!t.hasFocus;t.inputState.startMouseSelection(new XY(t,e,n,r)),r&&t.observer.ignore(()=>{XR(t.contentDOM);let s=t.root.activeElement;s&&!s.contains(t.contentDOM)&&s.blur()});let i=t.inputState.mouseSelection;if(i)return i.start(e),i.dragging===!1}return!1};function wS(t,e,n,r){if(r==1)return Pe.cursor(e,n);if(r==2)return RY(t.state,e,n);{let i=In.find(t.docView,e),s=t.state.doc.lineAt(i?i.posAtEnd:e),o=i?i.posAtStart:s.from,l=i?i.posAtEnd:s.to;return le>=n.top&&e<=n.bottom&&t>=n.left&&t<=n.right;function nq(t,e,n,r){let i=In.find(t.docView,e);if(!i)return 1;let s=e-i.posAtStart;if(s==0)return 1;if(s==i.length)return-1;let o=i.coordsAt(s,-1);if(o&&TS(n,r,o))return-1;let l=i.coordsAt(s,1);return l&&TS(n,r,l)?1:o&&o.bottom>=r?-1:1}function SS(t,e){let n=t.posAtCoords({x:e.clientX,y:e.clientY},!1);return{pos:n,bias:nq(t,n,e.clientX,e.clientY)}}const rq=Fe.ie&&Fe.ie_version<=11;let _S=null,CS=0,AS=0;function PI(t){if(!rq)return t.detail;let e=_S,n=AS;return _S=t,AS=Date.now(),CS=!e||n>Date.now()-400&&Math.abs(e.clientX-t.clientX)<2&&Math.abs(e.clientY-t.clientY)<2?(CS+1)%3:1}function iq(t,e){let n=SS(t,e),r=PI(e),i=t.state.selection;return{update(s){s.docChanged&&(n.pos=s.changes.mapPos(n.pos),i=i.map(s.changes))},get(s,o,l){let c=SS(t,s),d,f=wS(t,c.pos,c.bias,r);if(n.pos!=c.pos&&!o){let p=wS(t,n.pos,n.bias,r),m=Math.min(p.from,f.from),g=Math.max(p.to,f.to);f=m1&&(d=sq(i,c.pos))?d:l?i.addRange(f):Pe.create([f])}}}function sq(t,e){for(let n=0;n=e)return Pe.create(t.ranges.slice(0,n).concat(t.ranges.slice(n+1)),t.mainIndex==n?0:t.mainIndex-(t.mainIndex>n?1:0))}return null}Ci.dragstart=(t,e)=>{let{selection:{main:n}}=t.state;if(e.target.draggable){let i=t.docView.nearest(e.target);if(i&&i.isWidget){let s=i.posAtStart,o=s+i.length;(s>=n.to||o<=n.from)&&(n=Pe.range(s,o))}}let{inputState:r}=t;return r.mouseSelection&&(r.mouseSelection.dragging=!0),r.draggedContent=n,e.dataTransfer&&(e.dataTransfer.setData("Text",Ap(t.state,N1,t.state.sliceDoc(n.from,n.to))),e.dataTransfer.effectAllowed="copyMove"),!1};Ci.dragend=t=>(t.inputState.draggedContent=null,!1);function kS(t,e,n,r){if(n=Ap(t.state,k1,n),!n)return;let i=t.posAtCoords({x:e.clientX,y:e.clientY},!1),{draggedContent:s}=t.inputState,o=r&&s&&ZY(t,e)?{from:s.from,to:s.to}:null,l={from:i,insert:n},c=t.state.changes(o?[o,l]:l);t.focus(),t.dispatch({changes:c,selection:{anchor:c.mapPos(i,-1),head:c.mapPos(i,1)},userEvent:o?"move.drop":"input.drop"}),t.inputState.draggedContent=null}Ci.drop=(t,e)=>{if(!e.dataTransfer)return!1;if(t.state.readOnly)return!0;let n=e.dataTransfer.files;if(n&&n.length){let r=Array(n.length),i=0,s=()=>{++i==n.length&&kS(t,e,r.filter(o=>o!=null).join(t.state.lineBreak),!1)};for(let o=0;o{/[\x00-\x08\x0e-\x1f]{2}/.test(l.result)||(r[o]=l.result),s()},l.readAsText(n[o])}return!0}else{let r=e.dataTransfer.getData("Text");if(r)return kS(t,e,r,!0),!0}return!1};Ci.paste=(t,e)=>{if(t.state.readOnly)return!0;t.observer.flush();let n=DI?null:e.clipboardData;return n?(LI(t,n.getData("text/plain")||n.getData("text/uri-list")),!0):(tq(t),!1)};function oq(t,e){let n=t.dom.parentNode;if(!n)return;let r=n.appendChild(document.createElement("textarea"));r.style.cssText="position: fixed; left: -10000px; top: 10px",r.value=e,r.focus(),r.selectionEnd=e.length,r.selectionStart=0,setTimeout(()=>{r.remove(),t.focus()},50)}function aq(t){let e=[],n=[],r=!1;for(let i of t.selection.ranges)i.empty||(e.push(t.sliceDoc(i.from,i.to)),n.push(i));if(!e.length){let i=-1;for(let{from:s}of t.selection.ranges){let o=t.doc.lineAt(s);o.number>i&&(e.push(o.text),n.push({from:o.from,to:Math.min(t.doc.length,o.to+1)})),i=o.number}r=!0}return{text:Ap(t,N1,e.join(t.lineBreak)),ranges:n,linewise:r}}let jb=null;Ci.copy=Ci.cut=(t,e)=>{let{text:n,ranges:r,linewise:i}=aq(t.state);if(!n&&!i)return!1;jb=i?n:null,e.type=="cut"&&!t.state.readOnly&&t.dispatch({changes:r,scrollIntoView:!0,userEvent:"delete.cut"});let s=DI?null:e.clipboardData;return s?(s.clearData(),s.setData("text/plain",n),!0):(oq(t,n),!1)};const FI=Hl.define();function BI(t,e){let n=[];for(let r of t.facet(xI)){let i=r(t,e);i&&n.push(i)}return n.length?t.update({effects:n,annotations:FI.of(!0)}):null}function UI(t){setTimeout(()=>{let e=t.hasFocus;if(e!=t.inputState.notifiedFocused){let n=BI(t.state,e);n?t.dispatch(n):t.update([])}},10)}oi.focus=t=>{t.inputState.lastFocusTime=Date.now(),!t.scrollDOM.scrollTop&&(t.inputState.lastScrollTop||t.inputState.lastScrollLeft)&&(t.scrollDOM.scrollTop=t.inputState.lastScrollTop,t.scrollDOM.scrollLeft=t.inputState.lastScrollLeft),UI(t)};oi.blur=t=>{t.observer.clearSelectionRange(),UI(t)};oi.compositionstart=oi.compositionupdate=t=>{t.observer.editContext||(t.inputState.compositionFirstChange==null&&(t.inputState.compositionFirstChange=!0),t.inputState.composing<0&&(t.inputState.composing=0))};oi.compositionend=t=>{t.observer.editContext||(t.inputState.composing=-1,t.inputState.compositionEndedAt=Date.now(),t.inputState.compositionPendingKey=!0,t.inputState.compositionPendingChange=t.observer.pendingRecords().length>0,t.inputState.compositionFirstChange=null,Fe.chrome&&Fe.android?t.observer.flushSoon():t.inputState.compositionPendingChange?Promise.resolve().then(()=>t.observer.flush()):setTimeout(()=>{t.inputState.composing<0&&t.docView.hasComposition&&t.update([])},50))};oi.contextmenu=t=>{t.inputState.lastContextMenu=Date.now()};Ci.beforeinput=(t,e)=>{var n,r;if(e.inputType=="insertReplacementText"&&t.observer.editContext){let s=(n=e.dataTransfer)===null||n===void 0?void 0:n.getData("text/plain"),o=e.getTargetRanges();if(s&&o.length){let l=o[0],c=t.posAtDOM(l.startContainer,l.startOffset),d=t.posAtDOM(l.endContainer,l.endOffset);return O1(t,{from:c,to:d,insert:t.state.toText(s)},null),!0}}let i;if(Fe.chrome&&Fe.android&&(i=OI.find(s=>s.inputType==e.inputType))&&(t.observer.delayAndroidKey(i.key,i.keyCode),i.key=="Backspace"||i.key=="Delete")){let s=((r=window.visualViewport)===null||r===void 0?void 0:r.height)||0;setTimeout(()=>{var o;(((o=window.visualViewport)===null||o===void 0?void 0:o.height)||0)>s+10&&t.hasFocus&&(t.contentDOM.blur(),t.focus())},100)}return Fe.ios&&e.inputType=="deleteContentForward"&&t.observer.flushSoon(),Fe.safari&&e.inputType=="insertText"&&t.inputState.composing>=0&&setTimeout(()=>oi.compositionend(t,e),20),!1};const NS=new Set;function lq(t){NS.has(t)||(NS.add(t),t.addEventListener("copy",()=>{}),t.addEventListener("cut",()=>{}))}const RS=["pre-wrap","normal","pre-line","break-spaces"];let _l=!1;function IS(){_l=!1}class uq{constructor(e){this.lineWrapping=e,this.doc=Lt.empty,this.heightSamples={},this.lineHeight=14,this.charWidth=7,this.textHeight=14,this.lineLength=30}heightForGap(e,n){let r=this.doc.lineAt(n).number-this.doc.lineAt(e).number+1;return this.lineWrapping&&(r+=Math.max(0,Math.ceil((n-e-r*this.lineLength*.5)/this.lineLength))),this.lineHeight*r}heightForLine(e){return this.lineWrapping?(1+Math.max(0,Math.ceil((e-this.lineLength)/Math.max(1,this.lineLength-5))))*this.lineHeight:this.lineHeight}setDoc(e){return this.doc=e,this}mustRefreshForWrapping(e){return RS.indexOf(e)>-1!=this.lineWrapping}mustRefreshForHeights(e){let n=!1;for(let r=0;r-1,c=Math.round(n)!=Math.round(this.lineHeight)||this.lineWrapping!=l;if(this.lineWrapping=l,this.lineHeight=n,this.charWidth=r,this.textHeight=i,this.lineLength=s,c){this.heightSamples={};for(let d=0;d0}set outdated(e){this.flags=(e?2:0)|this.flags&-3}setHeight(e){this.height!=e&&(Math.abs(this.height-e)>Kf&&(_l=!0),this.height=e)}replace(e,n,r){return yr.of(r)}decomposeLeft(e,n){n.push(this)}decomposeRight(e,n){n.push(this)}applyChanges(e,n,r,i){let s=this,o=r.doc;for(let l=i.length-1;l>=0;l--){let{fromA:c,toA:d,fromB:f,toB:p}=i[l],m=s.lineAt(c,sn.ByPosNoHeight,r.setDoc(n),0,0),g=m.to>=d?m:s.lineAt(d,sn.ByPosNoHeight,r,0,0);for(p+=g.to-d,d=g.to;l>0&&m.from<=i[l-1].toA;)c=i[l-1].fromA,f=i[l-1].fromB,l--,cs*2){let l=e[n-1];l.break?e.splice(--n,1,l.left,null,l.right):e.splice(--n,1,l.left,l.right),r+=1+l.break,i-=l.size}else if(s>i*2){let l=e[r];l.break?e.splice(r,1,l.left,null,l.right):e.splice(r,1,l.left,l.right),r+=2+l.break,s-=l.size}else break;else if(i=s&&o(this.blockAt(0,r,i,s))}updateHeight(e,n=0,r=!1,i){return i&&i.from<=n&&i.more&&this.setHeight(i.heights[i.index++]),this.outdated=!1,this}toString(){return`block(${this.length})`}}class jr extends HI{constructor(e,n){super(e,n,null),this.collapsed=0,this.widgetHeight=0,this.breaks=0}blockAt(e,n,r,i){return new Wi(i,this.length,r,this.height,this.breaks)}replace(e,n,r){let i=r[0];return r.length==1&&(i instanceof jr||i instanceof Yn&&i.flags&4)&&Math.abs(this.length-i.length)<10?(i instanceof Yn?i=new jr(i.length,this.height):i.height=this.height,this.outdated||(i.outdated=!1),i):yr.of(r)}updateHeight(e,n=0,r=!1,i){return i&&i.from<=n&&i.more?this.setHeight(i.heights[i.index++]):(r||this.outdated)&&this.setHeight(Math.max(this.widgetHeight,e.heightForLine(this.length-this.collapsed))+this.breaks*e.lineHeight),this.outdated=!1,this}toString(){return`line(${this.length}${this.collapsed?-this.collapsed:""}${this.widgetHeight?":"+this.widgetHeight:""})`}}class Yn extends yr{constructor(e){super(e,0)}heightMetrics(e,n){let r=e.doc.lineAt(n).number,i=e.doc.lineAt(n+this.length).number,s=i-r+1,o,l=0;if(e.lineWrapping){let c=Math.min(this.height,e.lineHeight*s);o=c/s,this.length>s+1&&(l=(this.height-c)/(this.length-s-1))}else o=this.height/s;return{firstLine:r,lastLine:i,perLine:o,perChar:l}}blockAt(e,n,r,i){let{firstLine:s,lastLine:o,perLine:l,perChar:c}=this.heightMetrics(n,i);if(n.lineWrapping){let d=i+(e0){let s=r[r.length-1];s instanceof Yn?r[r.length-1]=new Yn(s.length+i):r.push(null,new Yn(i-1))}if(e>0){let s=r[0];s instanceof Yn?r[0]=new Yn(e+s.length):r.unshift(new Yn(e-1),null)}return yr.of(r)}decomposeLeft(e,n){n.push(new Yn(e-1),null)}decomposeRight(e,n){n.push(null,new Yn(this.length-e-1))}updateHeight(e,n=0,r=!1,i){let s=n+this.length;if(i&&i.from<=n+this.length&&i.more){let o=[],l=Math.max(n,i.from),c=-1;for(i.from>n&&o.push(new Yn(i.from-n-1).updateHeight(e,n));l<=s&&i.more;){let f=e.doc.lineAt(l).length;o.length&&o.push(null);let p=i.heights[i.index++];c==-1?c=p:Math.abs(p-c)>=Kf&&(c=-2);let m=new jr(f,p);m.outdated=!1,o.push(m),l+=f+1}l<=s&&o.push(null,new Yn(s-l).updateHeight(e,l));let d=yr.of(o);return(c<0||Math.abs(d.height-this.height)>=Kf||Math.abs(c-this.heightMetrics(e,n).perLine)>=Kf)&&(_l=!0),_h(this,d)}else(r||this.outdated)&&(this.setHeight(e.heightForGap(n,n+this.length)),this.outdated=!1);return this}toString(){return`gap(${this.length})`}}class dq extends yr{constructor(e,n,r){super(e.length+n+r.length,e.height+r.height,n|(e.outdated||r.outdated?2:0)),this.left=e,this.right=r,this.size=e.size+r.size}get break(){return this.flags&1}blockAt(e,n,r,i){let s=r+this.left.height;return el))return d;let f=n==sn.ByPosNoHeight?sn.ByPosNoHeight:sn.ByPos;return c?d.join(this.right.lineAt(l,f,r,o,l)):this.left.lineAt(l,f,r,i,s).join(d)}forEachLine(e,n,r,i,s,o){let l=i+this.left.height,c=s+this.left.length+this.break;if(this.break)e=c&&this.right.forEachLine(e,n,r,l,c,o);else{let d=this.lineAt(c,sn.ByPos,r,i,s);e=e&&d.from<=n&&o(d),n>d.to&&this.right.forEachLine(d.to+1,n,r,l,c,o)}}replace(e,n,r){let i=this.left.length+this.break;if(nthis.left.length)return this.balanced(this.left,this.right.replace(e-i,n-i,r));let s=[];e>0&&this.decomposeLeft(e,s);let o=s.length;for(let l of r)s.push(l);if(e>0&&OS(s,o-1),n=r&&n.push(null)),e>r&&this.right.decomposeLeft(e-r,n)}decomposeRight(e,n){let r=this.left.length,i=r+this.break;if(e>=i)return this.right.decomposeRight(e-i,n);e2*n.size||n.size>2*e.size?yr.of(this.break?[e,null,n]:[e,n]):(this.left=_h(this.left,e),this.right=_h(this.right,n),this.setHeight(e.height+n.height),this.outdated=e.outdated||n.outdated,this.size=e.size+n.size,this.length=e.length+this.break+n.length,this)}updateHeight(e,n=0,r=!1,i){let{left:s,right:o}=this,l=n+s.length+this.break,c=null;return i&&i.from<=n+s.length&&i.more?c=s=s.updateHeight(e,n,r,i):s.updateHeight(e,n,r),i&&i.from<=l+o.length&&i.more?c=o=o.updateHeight(e,l,r,i):o.updateHeight(e,l,r),c?this.balanced(s,o):(this.height=this.left.height+this.right.height,this.outdated=!1,this)}toString(){return this.left+(this.break?" ":"-")+this.right}}function OS(t,e){let n,r;t[e]==null&&(n=t[e-1])instanceof Yn&&(r=t[e+1])instanceof Yn&&t.splice(e-1,3,new Yn(n.length+1+r.length))}const fq=5;class M1{constructor(e,n){this.pos=e,this.oracle=n,this.nodes=[],this.lineStart=-1,this.lineEnd=-1,this.covering=null,this.writtenTo=e}get isCovered(){return this.covering&&this.nodes[this.nodes.length-1]==this.covering}span(e,n){if(this.lineStart>-1){let r=Math.min(n,this.lineEnd),i=this.nodes[this.nodes.length-1];i instanceof jr?i.length+=r-this.pos:(r>this.pos||!this.isCovered)&&this.nodes.push(new jr(r-this.pos,-1)),this.writtenTo=r,n>r&&(this.nodes.push(null),this.writtenTo++,this.lineStart=-1)}this.pos=n}point(e,n,r){if(e=fq)&&this.addLineDeco(i,s,o)}else n>e&&this.span(e,n);this.lineEnd>-1&&this.lineEnd-1)return;let{from:e,to:n}=this.oracle.doc.lineAt(this.pos);this.lineStart=e,this.lineEnd=n,this.writtenToe&&this.nodes.push(new jr(this.pos-e,-1)),this.writtenTo=this.pos}blankContent(e,n){let r=new Yn(n-e);return this.oracle.doc.lineAt(e).to==n&&(r.flags|=4),r}ensureLine(){this.enterLine();let e=this.nodes.length?this.nodes[this.nodes.length-1]:null;if(e instanceof jr)return e;let n=new jr(0,-1);return this.nodes.push(n),n}addBlock(e){this.enterLine();let n=e.deco;n&&n.startSide>0&&!this.isCovered&&this.ensureLine(),this.nodes.push(e),this.writtenTo=this.pos=this.pos+e.length,n&&n.endSide>0&&(this.covering=e)}addLineDeco(e,n,r){let i=this.ensureLine();i.length+=r,i.collapsed+=r,i.widgetHeight=Math.max(i.widgetHeight,e),i.breaks+=n,this.writtenTo=this.pos=this.pos+r}finish(e){let n=this.nodes.length==0?null:this.nodes[this.nodes.length-1];this.lineStart>-1&&!(n instanceof jr)&&!this.isCovered?this.nodes.push(new jr(0,-1)):(this.writtenTof.clientHeight||f.scrollWidth>f.clientWidth)&&p.overflow!="visible"){let m=f.getBoundingClientRect();s=Math.max(s,m.left),o=Math.min(o,m.right),l=Math.max(l,m.top),c=Math.min(d==t.parentNode?i.innerHeight:c,m.bottom)}d=p.position=="absolute"||p.position=="fixed"?f.offsetParent:f.parentNode}else if(d.nodeType==11)d=d.host;else break;return{left:s-n.left,right:Math.max(s,o)-n.left,top:l-(n.top+e),bottom:Math.max(l,c)-(n.top+e)}}function gq(t){let e=t.getBoundingClientRect(),n=t.ownerDocument.defaultView||window;return e.left0&&e.top0}function bq(t,e){let n=t.getBoundingClientRect();return{left:0,right:n.right-n.left,top:e,bottom:n.bottom-(n.top+e)}}class y0{constructor(e,n,r,i){this.from=e,this.to=n,this.size=r,this.displaySize=i}static same(e,n){if(e.length!=n.length)return!1;for(let r=0;rtypeof r!="function"&&r.class=="cm-lineWrapping");this.heightOracle=new uq(n),this.stateDeco=e.facet(_c).filter(r=>typeof r!="function"),this.heightMap=yr.empty().applyChanges(this.stateDeco,Lt.empty,this.heightOracle.setDoc(e.doc),[new si(0,0,0,e.doc.length)]);for(let r=0;r<2&&(this.viewport=this.getViewport(0,null),!!this.updateForViewport());r++);this.updateViewportLines(),this.lineGaps=this.ensureLineGaps([]),this.lineGapDeco=en.set(this.lineGaps.map(r=>r.draw(this,!1))),this.computeVisibleRanges()}updateForViewport(){let e=[this.viewport],{main:n}=this.state.selection;for(let r=0;r<=1;r++){let i=r?n.head:n.anchor;if(!e.some(({from:s,to:o})=>i>=s&&i<=o)){let{from:s,to:o}=this.lineBlockAt(i);e.push(new Af(s,o))}}return this.viewports=e.sort((r,i)=>r.from-i.from),this.updateScaler()}updateScaler(){let e=this.scaler;return this.scaler=this.heightMap.height<=7e6?DS:new D1(this.heightOracle,this.heightMap,this.viewports),e.eq(this.scaler)?0:2}updateViewportLines(){this.viewportLines=[],this.heightMap.forEachLine(this.viewport.from,this.viewport.to,this.heightOracle.setDoc(this.state.doc),0,0,e=>{this.viewportLines.push(Vu(e,this.scaler))})}update(e,n=null){this.state=e.state;let r=this.stateDeco;this.stateDeco=this.state.facet(_c).filter(f=>typeof f!="function");let i=e.changedRanges,s=si.extendWithRanges(i,hq(r,this.stateDeco,e?e.changes:$n.empty(this.state.doc.length))),o=this.heightMap.height,l=this.scrolledToBottom?null:this.scrollAnchorAt(this.scrollTop);IS(),this.heightMap=this.heightMap.applyChanges(this.stateDeco,e.startState.doc,this.heightOracle.setDoc(this.state.doc),s),(this.heightMap.height!=o||_l)&&(e.flags|=2),l?(this.scrollAnchorPos=e.changes.mapPos(l.from,-1),this.scrollAnchorHeight=l.top):(this.scrollAnchorPos=-1,this.scrollAnchorHeight=o);let c=s.length?this.mapViewport(this.viewport,e.changes):this.viewport;(n&&(n.range.headc.to)||!this.viewportIsAppropriate(c))&&(c=this.getViewport(0,n));let d=c.from!=this.viewport.from||c.to!=this.viewport.to;this.viewport=c,e.flags|=this.updateForViewport(),(d||!e.changes.empty||e.flags&2)&&this.updateViewportLines(),(this.lineGaps.length||this.viewport.to-this.viewport.from>4e3)&&this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps,e.changes))),e.flags|=this.computeVisibleRanges(e.changes),n&&(this.scrollTarget=n),!this.mustEnforceCursorAssoc&&e.selectionSet&&e.view.lineWrapping&&e.state.selection.main.empty&&e.state.selection.main.assoc&&!e.state.facet(vY)&&(this.mustEnforceCursorAssoc=!0)}measure(e){let n=e.contentDOM,r=window.getComputedStyle(n),i=this.heightOracle,s=r.whiteSpace;this.defaultTextDirection=r.direction=="rtl"?ar.RTL:ar.LTR;let o=this.heightOracle.mustRefreshForWrapping(s),l=n.getBoundingClientRect(),c=o||this.mustMeasureContent||this.contentDOMHeight!=l.height;this.contentDOMHeight=l.height,this.mustMeasureContent=!1;let d=0,f=0;if(l.width&&l.height){let{scaleX:M,scaleY:F}=qR(n,l);(M>.005&&Math.abs(this.scaleX-M)>.005||F>.005&&Math.abs(this.scaleY-F)>.005)&&(this.scaleX=M,this.scaleY=F,d|=16,o=c=!0)}let p=(parseInt(r.paddingTop)||0)*this.scaleY,m=(parseInt(r.paddingBottom)||0)*this.scaleY;(this.paddingTop!=p||this.paddingBottom!=m)&&(this.paddingTop=p,this.paddingBottom=m,d|=18),this.editorWidth!=e.scrollDOM.clientWidth&&(i.lineWrapping&&(c=!0),this.editorWidth=e.scrollDOM.clientWidth,d|=16);let g=e.scrollDOM.scrollTop*this.scaleY;this.scrollTop!=g&&(this.scrollAnchorHeight=-1,this.scrollTop=g),this.scrolledToBottom=ZR(e.scrollDOM);let x=(this.printing?bq:mq)(n,this.paddingTop),v=x.top-this.pixelViewport.top,S=x.bottom-this.pixelViewport.bottom;this.pixelViewport=x;let C=this.pixelViewport.bottom>this.pixelViewport.top&&this.pixelViewport.right>this.pixelViewport.left;if(C!=this.inView&&(this.inView=C,C&&(c=!0)),!this.inView&&!this.scrollTarget&&!gq(e.dom))return 0;let A=l.width;if((this.contentDOMWidth!=A||this.editorHeight!=e.scrollDOM.clientHeight)&&(this.contentDOMWidth=l.width,this.editorHeight=e.scrollDOM.clientHeight,d|=16),c){let M=e.docView.measureVisibleLineHeights(this.viewport);if(i.mustRefreshForHeights(M)&&(o=!0),o||i.lineWrapping&&Math.abs(A-this.contentDOMWidth)>i.charWidth){let{lineHeight:F,charWidth:I,textHeight:D}=e.docView.measureTextSize();o=F>0&&i.refresh(s,F,I,D,Math.max(5,A/I),M),o&&(e.docView.minWidth=0,d|=16)}v>0&&S>0?f=Math.max(v,S):v<0&&S<0&&(f=Math.min(v,S)),IS();for(let F of this.viewports){let I=F.from==this.viewport.from?M:e.docView.measureVisibleLineHeights(F);this.heightMap=(o?yr.empty().applyChanges(this.stateDeco,Lt.empty,this.heightOracle,[new si(0,0,0,e.state.doc.length)]):this.heightMap).updateHeight(i,0,o,new cq(F.from,I))}_l&&(d|=2)}let k=!this.viewportIsAppropriate(this.viewport,f)||this.scrollTarget&&(this.scrollTarget.range.headthis.viewport.to);return k&&(d&2&&(d|=this.updateScaler()),this.viewport=this.getViewport(f,this.scrollTarget),d|=this.updateForViewport()),(d&2||k)&&this.updateViewportLines(),(this.lineGaps.length||this.viewport.to-this.viewport.from>4e3)&&this.updateLineGaps(this.ensureLineGaps(o?[]:this.lineGaps,e)),d|=this.computeVisibleRanges(),this.mustEnforceCursorAssoc&&(this.mustEnforceCursorAssoc=!1,e.docView.enforceCursorAssoc()),d}get visibleTop(){return this.scaler.fromDOM(this.pixelViewport.top)}get visibleBottom(){return this.scaler.fromDOM(this.pixelViewport.bottom)}getViewport(e,n){let r=.5-Math.max(-.5,Math.min(.5,e/1e3/2)),i=this.heightMap,s=this.heightOracle,{visibleTop:o,visibleBottom:l}=this,c=new Af(i.lineAt(o-r*1e3,sn.ByHeight,s,0,0).from,i.lineAt(l+(1-r)*1e3,sn.ByHeight,s,0,0).to);if(n){let{head:d}=n.range;if(dc.to){let f=Math.min(this.editorHeight,this.pixelViewport.bottom-this.pixelViewport.top),p=i.lineAt(d,sn.ByPos,s,0,0),m;n.y=="center"?m=(p.top+p.bottom)/2-f/2:n.y=="start"||n.y=="nearest"&&d=l+Math.max(10,Math.min(r,250)))&&i>o-2*1e3&&s>1,o=i<<1;if(this.defaultTextDirection!=ar.LTR&&!r)return[];let l=[],c=(f,p,m,g)=>{if(p-ff&&CC.from>=m.from&&C.to<=m.to&&Math.abs(C.from-f)C.fromA));if(!S){if(pk.from<=p&&k.to>=p)){let k=n.moveToLineBoundary(Pe.cursor(p),!1,!0).head;k>f&&(p=k)}let C=this.gapSize(m,f,p,g),A=r||C<2e6?C:2e6;S=new y0(f,p,C,A)}l.push(S)},d=f=>{if(f.length2e6)for(let I of e)I.from>=f.from&&I.fromf.from&&c(f.from,g,f,p),xn.draw(this,this.heightOracle.lineWrapping))))}computeVisibleRanges(e){let n=this.stateDeco;this.lineGaps.length&&(n=n.concat(this.lineGapDeco));let r=[];Ht.spans(n,this.viewport.from,this.viewport.to,{span(s,o){r.push({from:s,to:o})},point(){}},20);let i=0;if(r.length!=this.visibleRanges.length)i=12;else for(let s=0;s=this.viewport.from&&e<=this.viewport.to&&this.viewportLines.find(n=>n.from<=e&&n.to>=e)||Vu(this.heightMap.lineAt(e,sn.ByPos,this.heightOracle,0,0),this.scaler)}lineBlockAtHeight(e){return e>=this.viewportLines[0].top&&e<=this.viewportLines[this.viewportLines.length-1].bottom&&this.viewportLines.find(n=>n.top<=e&&n.bottom>=e)||Vu(this.heightMap.lineAt(this.scaler.fromDOM(e),sn.ByHeight,this.heightOracle,0,0),this.scaler)}scrollAnchorAt(e){let n=this.lineBlockAtHeight(e+8);return n.from>=this.viewport.from||this.viewportLines[0].top-e>200?n:this.viewportLines[0]}elementAtHeight(e){return Vu(this.heightMap.blockAt(this.scaler.fromDOM(e),this.heightOracle,0,0),this.scaler)}get docHeight(){return this.scaler.toDOM(this.heightMap.height)}get contentHeight(){return this.docHeight+this.paddingTop+this.paddingBottom}}class Af{constructor(e,n){this.from=e,this.to=n}}function yq(t,e,n){let r=[],i=t,s=0;return Ht.spans(n,t,e,{span(){},point(o,l){o>i&&(r.push({from:i,to:o}),s+=o-i),i=l}},20),i=1)return e[e.length-1].to;let r=Math.floor(t*n);for(let i=0;;i++){let{from:s,to:o}=e[i],l=o-s;if(r<=l)return s+r;r-=l}}function Nf(t,e){let n=0;for(let{from:r,to:i}of t.ranges){if(e<=i){n+=e-r;break}n+=i-r}return n/t.total}function xq(t,e){for(let n of t)if(e(n))return n}const DS={toDOM(t){return t},fromDOM(t){return t},scale:1,eq(t){return t==this}};class D1{constructor(e,n,r){let i=0,s=0,o=0;this.viewports=r.map(({from:l,to:c})=>{let d=n.lineAt(l,sn.ByPos,e,0,0).top,f=n.lineAt(c,sn.ByPos,e,0,0).bottom;return i+=f-d,{from:l,to:c,top:d,bottom:f,domTop:0,domBottom:0}}),this.scale=(7e6-i)/(n.height-i);for(let l of this.viewports)l.domTop=o+(l.top-s)*this.scale,o=l.domBottom=l.domTop+(l.bottom-l.top),s=l.bottom}toDOM(e){for(let n=0,r=0,i=0;;n++){let s=nn.from==e.viewports[r].from&&n.to==e.viewports[r].to):!1}}function Vu(t,e){if(e.scale==1)return t;let n=e.toDOM(t.top),r=e.toDOM(t.bottom);return new Wi(t.from,t.length,n,r-n,Array.isArray(t._content)?t._content.map(i=>Vu(i,e)):t._content)}const Rf=tt.define({combine:t=>t.join(" ")}),$b=tt.define({combine:t=>t.indexOf(!0)>-1}),Wb=wl.newName(),zI=wl.newName(),jI=wl.newName(),$I={"&light":"."+zI,"&dark":"."+jI};function Vb(t,e,n){return new wl(e,{finish(r){return/&/.test(r)?r.replace(/&\w*/,i=>{if(i=="&")return t;if(!n||!n[i])throw new RangeError(`Unsupported selector: ${i}`);return n[i]}):t+" "+r}})}const vq=Vb("."+Wb,{"&":{position:"relative !important",boxSizing:"border-box","&.cm-focused":{outline:"1px dotted #212121"},display:"flex !important",flexDirection:"column"},".cm-scroller":{display:"flex !important",alignItems:"flex-start !important",fontFamily:"monospace",lineHeight:1.4,height:"100%",overflowX:"auto",position:"relative",zIndex:0,overflowAnchor:"none"},".cm-content":{margin:0,flexGrow:2,flexShrink:0,display:"block",whiteSpace:"pre",wordWrap:"normal",boxSizing:"border-box",minHeight:"100%",padding:"4px 0",outline:"none","&[contenteditable=true]":{WebkitUserModify:"read-write-plaintext-only"}},".cm-lineWrapping":{whiteSpace_fallback:"pre-wrap",whiteSpace:"break-spaces",wordBreak:"break-word",overflowWrap:"anywhere",flexShrink:1},"&light .cm-content":{caretColor:"black"},"&dark .cm-content":{caretColor:"white"},".cm-line":{display:"block",padding:"0 2px 0 6px"},".cm-layer":{position:"absolute",left:0,top:0,contain:"size style","& > *":{position:"absolute"}},"&light .cm-selectionBackground":{background:"#d9d9d9"},"&dark .cm-selectionBackground":{background:"#222"},"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground":{background:"#d7d4f0"},"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground":{background:"#233"},".cm-cursorLayer":{pointerEvents:"none"},"&.cm-focused > .cm-scroller > .cm-cursorLayer":{animation:"steps(1) cm-blink 1.2s infinite"},"@keyframes cm-blink":{"0%":{},"50%":{opacity:0},"100%":{}},"@keyframes cm-blink2":{"0%":{},"50%":{opacity:0},"100%":{}},".cm-cursor, .cm-dropCursor":{borderLeft:"1.2px solid black",marginLeft:"-0.6px",pointerEvents:"none"},".cm-cursor":{display:"none"},"&dark .cm-cursor":{borderLeftColor:"#ddd"},".cm-dropCursor":{position:"absolute"},"&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor":{display:"block"},".cm-iso":{unicodeBidi:"isolate"},".cm-announced":{position:"fixed",top:"-10000px"},"@media print":{".cm-announced":{display:"none"}},"&light .cm-activeLine":{backgroundColor:"#cceeff44"},"&dark .cm-activeLine":{backgroundColor:"#99eeff33"},"&light .cm-specialChar":{color:"red"},"&dark .cm-specialChar":{color:"#f78"},".cm-gutters":{flexShrink:0,display:"flex",height:"100%",boxSizing:"border-box",zIndex:200},".cm-gutters-before":{insetInlineStart:0},".cm-gutters-after":{insetInlineEnd:0},"&light .cm-gutters":{backgroundColor:"#f5f5f5",color:"#6c6c6c",border:"0px solid #ddd","&.cm-gutters-before":{borderRightWidth:"1px"},"&.cm-gutters-after":{borderLeftWidth:"1px"}},"&dark .cm-gutters":{backgroundColor:"#333338",color:"#ccc"},".cm-gutter":{display:"flex !important",flexDirection:"column",flexShrink:0,boxSizing:"border-box",minHeight:"100%",overflow:"hidden"},".cm-gutterElement":{boxSizing:"border-box"},".cm-lineNumbers .cm-gutterElement":{padding:"0 3px 0 5px",minWidth:"20px",textAlign:"right",whiteSpace:"nowrap"},"&light .cm-activeLineGutter":{backgroundColor:"#e2f2ff"},"&dark .cm-activeLineGutter":{backgroundColor:"#222227"},".cm-panels":{boxSizing:"border-box",position:"sticky",left:0,right:0,zIndex:300},"&light .cm-panels":{backgroundColor:"#f5f5f5",color:"black"},"&light .cm-panels-top":{borderBottom:"1px solid #ddd"},"&light .cm-panels-bottom":{borderTop:"1px solid #ddd"},"&dark .cm-panels":{backgroundColor:"#333338",color:"white"},".cm-dialog":{padding:"2px 19px 4px 6px",position:"relative","& label":{fontSize:"80%"}},".cm-dialog-close":{position:"absolute",top:"3px",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",fontSize:"14px",padding:"0"},".cm-tab":{display:"inline-block",overflow:"hidden",verticalAlign:"bottom"},".cm-widgetBuffer":{verticalAlign:"text-top",height:"1em",width:0,display:"inline"},".cm-placeholder":{color:"#888",display:"inline-block",verticalAlign:"top",userSelect:"none"},".cm-highlightSpace":{backgroundImage:"radial-gradient(circle at 50% 55%, #aaa 20%, transparent 5%)",backgroundPosition:"center"},".cm-highlightTab":{backgroundImage:`url('data:image/svg+xml,')`,backgroundSize:"auto 100%",backgroundPosition:"right 90%",backgroundRepeat:"no-repeat"},".cm-trailingSpace":{backgroundColor:"#ff332255"},".cm-button":{verticalAlign:"middle",color:"inherit",fontSize:"70%",padding:".2em 1em",borderRadius:"1px"},"&light .cm-button":{backgroundImage:"linear-gradient(#eff1f5, #d9d9df)",border:"1px solid #888","&:active":{backgroundImage:"linear-gradient(#b4b4b4, #d0d3d6)"}},"&dark .cm-button":{backgroundImage:"linear-gradient(#393939, #111)",border:"1px solid #888","&:active":{backgroundImage:"linear-gradient(#111, #333)"}},".cm-textfield":{verticalAlign:"middle",color:"inherit",fontSize:"70%",border:"1px solid silver",padding:".2em .5em"},"&light .cm-textfield":{backgroundColor:"white"},"&dark .cm-textfield":{border:"1px solid #555",backgroundColor:"inherit"}},$I),wq={childList:!0,characterData:!0,subtree:!0,attributes:!0,characterDataOldValue:!0},x0=Fe.ie&&Fe.ie_version<=11;class Tq{constructor(e){this.view=e,this.active=!1,this.editContext=null,this.selectionRange=new nY,this.selectionChanged=!1,this.delayedFlush=-1,this.resizeTimeout=-1,this.queue=[],this.delayedAndroidKey=null,this.flushingAndroidKey=-1,this.lastChange=0,this.scrollTargets=[],this.intersection=null,this.resizeScroll=null,this.intersecting=!1,this.gapIntersection=null,this.gaps=[],this.printQuery=null,this.parentCheck=-1,this.dom=e.contentDOM,this.observer=new MutationObserver(n=>{for(let r of n)this.queue.push(r);(Fe.ie&&Fe.ie_version<=11||Fe.ios&&e.composing)&&n.some(r=>r.type=="childList"&&r.removedNodes.length||r.type=="characterData"&&r.oldValue.length>r.target.nodeValue.length)?this.flushSoon():this.flush()}),window.EditContext&&Fe.android&&e.constructor.EDIT_CONTEXT!==!1&&!(Fe.chrome&&Fe.chrome_version<126)&&(this.editContext=new _q(e),e.state.facet(ms)&&(e.contentDOM.editContext=this.editContext.editContext)),x0&&(this.onCharData=n=>{this.queue.push({target:n.target,type:"characterData",oldValue:n.prevValue}),this.flushSoon()}),this.onSelectionChange=this.onSelectionChange.bind(this),this.onResize=this.onResize.bind(this),this.onPrint=this.onPrint.bind(this),this.onScroll=this.onScroll.bind(this),window.matchMedia&&(this.printQuery=window.matchMedia("print")),typeof ResizeObserver=="function"&&(this.resizeScroll=new ResizeObserver(()=>{var n;((n=this.view.docView)===null||n===void 0?void 0:n.lastUpdate){this.parentCheck<0&&(this.parentCheck=setTimeout(this.listenForScroll.bind(this),1e3)),n.length>0&&n[n.length-1].intersectionRatio>0!=this.intersecting&&(this.intersecting=!this.intersecting,this.intersecting!=this.view.inView&&this.onScrollChanged(document.createEvent("Event")))},{threshold:[0,.001]}),this.intersection.observe(this.dom),this.gapIntersection=new IntersectionObserver(n=>{n.length>0&&n[n.length-1].intersectionRatio>0&&this.onScrollChanged(document.createEvent("Event"))},{})),this.listenForScroll(),this.readSelectionRange()}onScrollChanged(e){this.view.inputState.runHandlers("scroll",e),this.intersecting&&this.view.measure()}onScroll(e){this.intersecting&&this.flush(!1),this.editContext&&this.view.requestMeasure(this.editContext.measureReq),this.onScrollChanged(e)}onResize(){this.resizeTimeout<0&&(this.resizeTimeout=setTimeout(()=>{this.resizeTimeout=-1,this.view.requestMeasure()},50))}onPrint(e){(e.type=="change"||!e.type)&&!e.matches||(this.view.viewState.printing=!0,this.view.measure(),setTimeout(()=>{this.view.viewState.printing=!1,this.view.requestMeasure()},500))}updateGaps(e){if(this.gapIntersection&&(e.length!=this.gaps.length||this.gaps.some((n,r)=>n!=e[r]))){this.gapIntersection.disconnect();for(let n of e)this.gapIntersection.observe(n);this.gaps=e}}onSelectionChange(e){let n=this.selectionChanged;if(!this.readSelectionRange()||this.delayedAndroidKey)return;let{view:r}=this,i=this.selectionRange;if(r.state.facet(ms)?r.root.activeElement!=this.dom:!Wf(this.dom,i))return;let s=i.anchorNode&&r.docView.nearest(i.anchorNode);if(s&&s.ignoreEvent(e)){n||(this.selectionChanged=!1);return}(Fe.ie&&Fe.ie_version<=11||Fe.android&&Fe.chrome)&&!r.state.selection.main.empty&&i.focusNode&&nc(i.focusNode,i.focusOffset,i.anchorNode,i.anchorOffset)?this.flushSoon():this.flush(!1)}readSelectionRange(){let{view:e}=this,n=Tc(e.root);if(!n)return!1;let r=Fe.safari&&e.root.nodeType==11&&e.root.activeElement==this.dom&&Sq(this.view,n)||n;if(!r||this.selectionRange.eq(r))return!1;let i=Wf(this.dom,r);return i&&!this.selectionChanged&&e.inputState.lastFocusTime>Date.now()-200&&e.inputState.lastTouchTime{let s=this.delayedAndroidKey;s&&(this.clearDelayedAndroidKey(),this.view.inputState.lastKeyCode=s.keyCode,this.view.inputState.lastKeyTime=Date.now(),!this.flush()&&s.force&&cl(this.dom,s.key,s.keyCode))};this.flushingAndroidKey=this.view.win.requestAnimationFrame(i)}(!this.delayedAndroidKey||e=="Enter")&&(this.delayedAndroidKey={key:e,keyCode:n,force:this.lastChange{this.delayedFlush=-1,this.flush()}))}forceFlush(){this.delayedFlush>=0&&(this.view.win.cancelAnimationFrame(this.delayedFlush),this.delayedFlush=-1),this.flush()}pendingRecords(){for(let e of this.observer.takeRecords())this.queue.push(e);return this.queue}processRecords(){let e=this.pendingRecords();e.length&&(this.queue=[]);let n=-1,r=-1,i=!1;for(let s of e){let o=this.readMutation(s);o&&(o.typeOver&&(i=!0),n==-1?{from:n,to:r}=o:(n=Math.min(o.from,n),r=Math.max(o.to,r)))}return{from:n,to:r,typeOver:i}}readChange(){let{from:e,to:n,typeOver:r}=this.processRecords(),i=this.selectionChanged&&Wf(this.dom,this.selectionRange);if(e<0&&!i)return null;e>-1&&(this.lastChange=Date.now()),this.view.inputState.lastFocusTime=0,this.selectionChanged=!1;let s=new zY(this.view,e,n,r);return this.view.docView.domChanged={newSel:s.newSel?s.newSel.main:null},s}flush(e=!0){if(this.delayedFlush>=0||this.delayedAndroidKey)return!1;e&&this.readSelectionRange();let n=this.readChange();if(!n)return this.view.requestMeasure(),!1;let r=this.view.state,i=II(this.view,n);return this.view.state==r&&(n.domChanged||n.newSel&&!n.newSel.main.eq(this.view.state.selection.main))&&this.view.update([]),i}readMutation(e){let n=this.view.docView.nearest(e.target);if(!n||n.ignoreMutation(e))return null;if(n.markDirty(e.type=="attributes"),e.type=="attributes"&&(n.flags|=4),e.type=="childList"){let r=LS(n,e.previousSibling||e.target.previousSibling,-1),i=LS(n,e.nextSibling||e.target.nextSibling,1);return{from:r?n.posAfter(r):n.posAtStart,to:i?n.posBefore(i):n.posAtEnd,typeOver:!1}}else return e.type=="characterData"?{from:n.posAtStart,to:n.posAtEnd,typeOver:e.target.nodeValue==e.oldValue}:null}setWindow(e){e!=this.win&&(this.removeWindowListeners(this.win),this.win=e,this.addWindowListeners(this.win))}addWindowListeners(e){e.addEventListener("resize",this.onResize),this.printQuery?this.printQuery.addEventListener?this.printQuery.addEventListener("change",this.onPrint):this.printQuery.addListener(this.onPrint):e.addEventListener("beforeprint",this.onPrint),e.addEventListener("scroll",this.onScroll),e.document.addEventListener("selectionchange",this.onSelectionChange)}removeWindowListeners(e){e.removeEventListener("scroll",this.onScroll),e.removeEventListener("resize",this.onResize),this.printQuery?this.printQuery.removeEventListener?this.printQuery.removeEventListener("change",this.onPrint):this.printQuery.removeListener(this.onPrint):e.removeEventListener("beforeprint",this.onPrint),e.document.removeEventListener("selectionchange",this.onSelectionChange)}update(e){this.editContext&&(this.editContext.update(e),e.startState.facet(ms)!=e.state.facet(ms)&&(e.view.contentDOM.editContext=e.state.facet(ms)?this.editContext.editContext:null))}destroy(){var e,n,r;this.stop(),(e=this.intersection)===null||e===void 0||e.disconnect(),(n=this.gapIntersection)===null||n===void 0||n.disconnect(),(r=this.resizeScroll)===null||r===void 0||r.disconnect();for(let i of this.scrollTargets)i.removeEventListener("scroll",this.onScroll);this.removeWindowListeners(this.win),clearTimeout(this.parentCheck),clearTimeout(this.resizeTimeout),this.win.cancelAnimationFrame(this.delayedFlush),this.win.cancelAnimationFrame(this.flushingAndroidKey),this.editContext&&(this.view.contentDOM.editContext=null,this.editContext.destroy())}}function LS(t,e,n){for(;e;){let r=Gt.get(e);if(r&&r.parent==t)return r;let i=e.parentNode;e=i!=t.dom?i:n>0?e.nextSibling:e.previousSibling}return null}function PS(t,e){let n=e.startContainer,r=e.startOffset,i=e.endContainer,s=e.endOffset,o=t.docView.domAtPos(t.state.selection.main.anchor);return nc(o.node,o.offset,i,s)&&([n,r,i,s]=[i,s,n,r]),{anchorNode:n,anchorOffset:r,focusNode:i,focusOffset:s}}function Sq(t,e){if(e.getComposedRanges){let i=e.getComposedRanges(t.root)[0];if(i)return PS(t,i)}let n=null;function r(i){i.preventDefault(),i.stopImmediatePropagation(),n=i.getTargetRanges()[0]}return t.contentDOM.addEventListener("beforeinput",r,!0),t.dom.ownerDocument.execCommand("indent"),t.contentDOM.removeEventListener("beforeinput",r,!0),n?PS(t,n):null}class _q{constructor(e){this.from=0,this.to=0,this.pendingContextChange=null,this.handlers=Object.create(null),this.composing=null,this.resetRange(e.state);let n=this.editContext=new window.EditContext({text:e.state.doc.sliceString(this.from,this.to),selectionStart:this.toContextPos(Math.max(this.from,Math.min(this.to,e.state.selection.main.anchor))),selectionEnd:this.toContextPos(e.state.selection.main.head)});this.handlers.textupdate=r=>{let i=e.state.selection.main,{anchor:s,head:o}=i,l=this.toEditorPos(r.updateRangeStart),c=this.toEditorPos(r.updateRangeEnd);e.inputState.composing>=0&&!this.composing&&(this.composing={contextBase:r.updateRangeStart,editorBase:l,drifted:!1});let d={from:l,to:c,insert:Lt.of(r.text.split(` +`))};if(d.from==this.from&&sthis.to&&(d.to=s),d.from==d.to&&!d.insert.length){let f=Pe.single(this.toEditorPos(r.selectionStart),this.toEditorPos(r.selectionEnd));f.main.eq(i)||e.dispatch({selection:f,userEvent:"select"});return}if((Fe.mac||Fe.android)&&d.from==o-1&&/^\. ?$/.test(r.text)&&e.contentDOM.getAttribute("autocorrect")=="off"&&(d={from:l,to:c,insert:Lt.of([r.text.replace("."," ")])}),this.pendingContextChange=d,!e.state.readOnly){let f=this.to-this.from+(d.to-d.from+d.insert.length);O1(e,d,Pe.single(this.toEditorPos(r.selectionStart,f),this.toEditorPos(r.selectionEnd,f)))}this.pendingContextChange&&(this.revertPending(e.state),this.setSelection(e.state))},this.handlers.characterboundsupdate=r=>{let i=[],s=null;for(let o=this.toEditorPos(r.rangeStart),l=this.toEditorPos(r.rangeEnd);o{let i=[];for(let s of r.getTextFormats()){let o=s.underlineStyle,l=s.underlineThickness;if(o!="None"&&l!="None"){let c=this.toEditorPos(s.rangeStart),d=this.toEditorPos(s.rangeEnd);if(c{e.inputState.composing<0&&(e.inputState.composing=0,e.inputState.compositionFirstChange=!0)},this.handlers.compositionend=()=>{if(e.inputState.composing=-1,e.inputState.compositionFirstChange=null,this.composing){let{drifted:r}=this.composing;this.composing=null,r&&this.reset(e.state)}};for(let r in this.handlers)n.addEventListener(r,this.handlers[r]);this.measureReq={read:r=>{this.editContext.updateControlBounds(r.contentDOM.getBoundingClientRect());let i=Tc(r.root);i&&i.rangeCount&&this.editContext.updateSelectionBounds(i.getRangeAt(0).getBoundingClientRect())}}}applyEdits(e){let n=0,r=!1,i=this.pendingContextChange;return e.changes.iterChanges((s,o,l,c,d)=>{if(r)return;let f=d.length-(o-s);if(i&&o>=i.to)if(i.from==s&&i.to==o&&i.insert.eq(d)){i=this.pendingContextChange=null,n+=f,this.to+=f;return}else i=null,this.revertPending(e.state);if(s+=n,o+=n,o<=this.from)this.from+=f,this.to+=f;else if(sthis.to||this.to-this.from+d.length>3e4){r=!0;return}this.editContext.updateText(this.toContextPos(s),this.toContextPos(o),d.toString()),this.to+=f}n+=f}),i&&!r&&this.revertPending(e.state),!r}update(e){let n=this.pendingContextChange,r=e.startState.selection.main;this.composing&&(this.composing.drifted||!e.changes.touchesRange(r.from,r.to)&&e.transactions.some(i=>!i.isUserEvent("input.type")&&i.changes.touchesRange(this.from,this.to)))?(this.composing.drifted=!0,this.composing.editorBase=e.changes.mapPos(this.composing.editorBase)):!this.applyEdits(e)||!this.rangeIsValid(e.state)?(this.pendingContextChange=null,this.reset(e.state)):(e.docChanged||e.selectionSet||n)&&this.setSelection(e.state),(e.geometryChanged||e.docChanged||e.selectionSet)&&e.view.requestMeasure(this.measureReq)}resetRange(e){let{head:n}=e.selection.main;this.from=Math.max(0,n-1e4),this.to=Math.min(e.doc.length,n+1e4)}reset(e){this.resetRange(e),this.editContext.updateText(0,this.editContext.text.length,e.doc.sliceString(this.from,this.to)),this.setSelection(e)}revertPending(e){let n=this.pendingContextChange;this.pendingContextChange=null,this.editContext.updateText(this.toContextPos(n.from),this.toContextPos(n.from+n.insert.length),e.doc.sliceString(n.from,n.to))}setSelection(e){let{main:n}=e.selection,r=this.toContextPos(Math.max(this.from,Math.min(this.to,n.anchor))),i=this.toContextPos(n.head);(this.editContext.selectionStart!=r||this.editContext.selectionEnd!=i)&&this.editContext.updateSelection(r,i)}rangeIsValid(e){let{head:n}=e.selection.main;return!(this.from>0&&n-this.from<500||this.to1e4*3)}toEditorPos(e,n=this.to-this.from){e=Math.min(e,n);let r=this.composing;return r&&r.drifted?r.editorBase+(e-r.contextBase):e+this.from}toContextPos(e){let n=this.composing;return n&&n.drifted?n.contextBase+(e-n.editorBase):e-this.from}destroy(){for(let e in this.handlers)this.editContext.removeEventListener(e,this.handlers[e])}}class ft{get state(){return this.viewState.state}get viewport(){return this.viewState.viewport}get visibleRanges(){return this.viewState.visibleRanges}get inView(){return this.viewState.inView}get composing(){return!!this.inputState&&this.inputState.composing>0}get compositionStarted(){return!!this.inputState&&this.inputState.composing>=0}get root(){return this._root}get win(){return this.dom.ownerDocument.defaultView||window}constructor(e={}){var n;this.plugins=[],this.pluginMap=new Map,this.editorAttrs={},this.contentAttrs={},this.bidiCache=[],this.destroyed=!1,this.updateState=2,this.measureScheduled=-1,this.measureRequests=[],this.contentDOM=document.createElement("div"),this.scrollDOM=document.createElement("div"),this.scrollDOM.tabIndex=-1,this.scrollDOM.className="cm-scroller",this.scrollDOM.appendChild(this.contentDOM),this.announceDOM=document.createElement("div"),this.announceDOM.className="cm-announced",this.announceDOM.setAttribute("aria-live","polite"),this.dom=document.createElement("div"),this.dom.appendChild(this.announceDOM),this.dom.appendChild(this.scrollDOM),e.parent&&e.parent.appendChild(this.dom);let{dispatch:r}=e;this.dispatchTransactions=e.dispatchTransactions||r&&(i=>i.forEach(s=>r(s,this)))||(i=>this.update(i)),this.dispatch=this.dispatch.bind(this),this._root=e.root||rY(e.parent)||document,this.viewState=new MS(e.state||Wt.create(e)),e.scrollTo&&e.scrollTo.is(Sf)&&(this.viewState.scrollTarget=e.scrollTo.value.clip(this.viewState.state)),this.plugins=this.state.facet(el).map(i=>new g0(i));for(let i of this.plugins)i.update(this);this.observer=new Tq(this),this.inputState=new GY(this),this.inputState.ensureHandlers(this.plugins),this.docView=new pS(this),this.mountStyles(),this.updateAttrs(),this.updateState=0,this.requestMeasure(),!((n=document.fonts)===null||n===void 0)&&n.ready&&document.fonts.ready.then(()=>this.requestMeasure())}dispatch(...e){let n=e.length==1&&e[0]instanceof or?e:e.length==1&&Array.isArray(e[0])?e[0]:[this.state.update(...e)];this.dispatchTransactions(n,this)}update(e){if(this.updateState!=0)throw new Error("Calls to EditorView.update are not allowed while an update is in progress");let n=!1,r=!1,i,s=this.state;for(let m of e){if(m.startState!=s)throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");s=m.state}if(this.destroyed){this.viewState.state=s;return}let o=this.hasFocus,l=0,c=null;e.some(m=>m.annotation(FI))?(this.inputState.notifiedFocused=o,l=1):o!=this.inputState.notifiedFocused&&(this.inputState.notifiedFocused=o,c=BI(s,o),c||(l=1));let d=this.observer.delayedAndroidKey,f=null;if(d?(this.observer.clearDelayedAndroidKey(),f=this.observer.readChange(),(f&&!this.state.doc.eq(s.doc)||!this.state.selection.eq(s.selection))&&(f=null)):this.observer.clear(),s.facet(Wt.phrases)!=this.state.facet(Wt.phrases))return this.setState(s);i=Sh.create(this,s,e),i.flags|=l;let p=this.viewState.scrollTarget;try{this.updateState=2;for(let m of e){if(p&&(p=p.map(m.changes)),m.scrollIntoView){let{main:g}=m.state.selection;p=new dl(g.empty?g:Pe.cursor(g.head,g.head>g.anchor?-1:1))}for(let g of m.effects)g.is(Sf)&&(p=g.value.clip(this.state))}this.viewState.update(i,p),this.bidiCache=Ch.update(this.bidiCache,i.changes),i.empty||(this.updatePlugins(i),this.inputState.update(i)),n=this.docView.update(i),this.state.facet($u)!=this.styleModules&&this.mountStyles(),r=this.updateAttrs(),this.showAnnouncements(e),this.docView.updateSelection(n,e.some(m=>m.isUserEvent("select.pointer")))}finally{this.updateState=0}if(i.startState.facet(Rf)!=i.state.facet(Rf)&&(this.viewState.mustMeasureContent=!0),(n||r||p||this.viewState.mustEnforceCursorAssoc||this.viewState.mustMeasureContent)&&this.requestMeasure(),n&&this.docViewUpdate(),!i.empty)for(let m of this.state.facet(Hb))try{m(i)}catch(g){gs(this.state,g,"update listener")}(c||f)&&Promise.resolve().then(()=>{c&&this.state==c.startState&&this.dispatch(c),f&&!II(this,f)&&d.force&&cl(this.contentDOM,d.key,d.keyCode)})}setState(e){if(this.updateState!=0)throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");if(this.destroyed){this.viewState.state=e;return}this.updateState=2;let n=this.hasFocus;try{for(let r of this.plugins)r.destroy(this);this.viewState=new MS(e),this.plugins=e.facet(el).map(r=>new g0(r)),this.pluginMap.clear();for(let r of this.plugins)r.update(this);this.docView.destroy(),this.docView=new pS(this),this.inputState.ensureHandlers(this.plugins),this.mountStyles(),this.updateAttrs(),this.bidiCache=[]}finally{this.updateState=0}n&&this.focus(),this.requestMeasure()}updatePlugins(e){let n=e.startState.facet(el),r=e.state.facet(el);if(n!=r){let i=[];for(let s of r){let o=n.indexOf(s);if(o<0)i.push(new g0(s));else{let l=this.plugins[o];l.mustUpdate=e,i.push(l)}}for(let s of this.plugins)s.mustUpdate!=e&&s.destroy(this);this.plugins=i,this.pluginMap.clear()}else for(let i of this.plugins)i.mustUpdate=e;for(let i=0;i-1&&this.win.cancelAnimationFrame(this.measureScheduled),this.observer.delayedAndroidKey){this.measureScheduled=-1,this.requestMeasure();return}this.measureScheduled=0,e&&this.observer.forceFlush();let n=null,r=this.scrollDOM,i=r.scrollTop*this.scaleY,{scrollAnchorPos:s,scrollAnchorHeight:o}=this.viewState;Math.abs(i-this.viewState.scrollTop)>1&&(o=-1),this.viewState.scrollAnchorHeight=-1;try{for(let l=0;;l++){if(o<0)if(ZR(r))s=-1,o=this.viewState.heightMap.height;else{let g=this.viewState.scrollAnchorAt(i);s=g.from,o=g.top}this.updateState=1;let c=this.viewState.measure(this);if(!c&&!this.measureRequests.length&&this.viewState.scrollTarget==null)break;if(l>5){console.warn(this.measureRequests.length?"Measure loop restarted more than 5 times":"Viewport failed to stabilize");break}let d=[];c&4||([this.measureRequests,d]=[d,this.measureRequests]);let f=d.map(g=>{try{return g.read(this)}catch(x){return gs(this.state,x),FS}}),p=Sh.create(this,this.state,[]),m=!1;p.flags|=c,n?n.flags|=c:n=p,this.updateState=2,p.empty||(this.updatePlugins(p),this.inputState.update(p),this.updateAttrs(),m=this.docView.update(p),m&&this.docViewUpdate());for(let g=0;g1||x<-1){i=i+x,r.scrollTop=i/this.scaleY,o=-1;continue}}break}}}finally{this.updateState=0,this.measureScheduled=-1}if(n&&!n.empty)for(let l of this.state.facet(Hb))l(n)}get themeClasses(){return Wb+" "+(this.state.facet($b)?jI:zI)+" "+this.state.facet(Rf)}updateAttrs(){let e=BS(this,SI,{class:"cm-editor"+(this.hasFocus?" cm-focused ":" ")+this.themeClasses}),n={spellcheck:"false",autocorrect:"off",autocapitalize:"off",writingsuggestions:"false",translate:"no",contenteditable:this.state.facet(ms)?"true":"false",class:"cm-content",style:`${Fe.tabSize}: ${this.state.tabSize}`,role:"textbox","aria-multiline":"true"};this.state.readOnly&&(n["aria-readonly"]="true"),BS(this,R1,n);let r=this.observer.ignore(()=>{let i=Lb(this.contentDOM,this.contentAttrs,n),s=Lb(this.dom,this.editorAttrs,e);return i||s});return this.editorAttrs=e,this.contentAttrs=n,r}showAnnouncements(e){let n=!0;for(let r of e)for(let i of r.effects)if(i.is(ft.announce)){n&&(this.announceDOM.textContent=""),n=!1;let s=this.announceDOM.appendChild(document.createElement("div"));s.textContent=i.value}}mountStyles(){this.styleModules=this.state.facet($u);let e=this.state.facet(ft.cspNonce);wl.mount(this.root,this.styleModules.concat(vq).reverse(),e?{nonce:e}:void 0)}readMeasured(){if(this.updateState==2)throw new Error("Reading the editor layout isn't allowed during an update");this.updateState==0&&this.measureScheduled>-1&&this.measure(!1)}requestMeasure(e){if(this.measureScheduled<0&&(this.measureScheduled=this.win.requestAnimationFrame(()=>this.measure())),e){if(this.measureRequests.indexOf(e)>-1)return;if(e.key!=null){for(let n=0;nr.plugin==e)||null),n&&n.update(this).value}get documentTop(){return this.contentDOM.getBoundingClientRect().top+this.viewState.paddingTop}get documentPadding(){return{top:this.viewState.paddingTop,bottom:this.viewState.paddingBottom}}get scaleX(){return this.viewState.scaleX}get scaleY(){return this.viewState.scaleY}elementAtHeight(e){return this.readMeasured(),this.viewState.elementAtHeight(e)}lineBlockAtHeight(e){return this.readMeasured(),this.viewState.lineBlockAtHeight(e)}get viewportLineBlocks(){return this.viewState.viewportLines}lineBlockAt(e){return this.viewState.lineBlockAt(e)}get contentHeight(){return this.viewState.contentHeight}moveByChar(e,n,r){return E0(this,e,yS(this,e,n,r))}moveByGroup(e,n){return E0(this,e,yS(this,e,n,r=>FY(this,e.head,r)))}visualLineSide(e,n){let r=this.bidiSpans(e),i=this.textDirectionAt(e.from),s=r[n?r.length-1:0];return Pe.cursor(s.side(n,i)+e.from,s.forward(!n,i)?1:-1)}moveToLineBoundary(e,n,r=!0){return PY(this,e,n,r)}moveVertically(e,n,r){return E0(this,e,BY(this,e,n,r))}domAtPos(e){return this.docView.domAtPos(e)}posAtDOM(e,n=0){return this.docView.posFromDOM(e,n)}posAtCoords(e,n=!0){return this.readMeasured(),RI(this,e,n)}coordsAtPos(e,n=1){this.readMeasured();let r=this.docView.coordsAt(e,n);if(!r||r.left==r.right)return r;let i=this.state.doc.lineAt(e),s=this.bidiSpans(i),o=s[so.find(s,e-i.from,-1,n)];return _p(r,o.dir==ar.LTR==n>0)}coordsForChar(e){return this.readMeasured(),this.docView.coordsForChar(e)}get defaultCharacterWidth(){return this.viewState.heightOracle.charWidth}get defaultLineHeight(){return this.viewState.heightOracle.lineHeight}get textDirection(){return this.viewState.defaultTextDirection}textDirectionAt(e){return!this.state.facet(vI)||ethis.viewport.to?this.textDirection:(this.readMeasured(),this.docView.textDirectionAt(e))}get lineWrapping(){return this.viewState.heightOracle.lineWrapping}bidiSpans(e){if(e.length>Cq)return hI(e.length);let n=this.textDirectionAt(e.from),r;for(let s of this.bidiCache)if(s.from==e.from&&s.dir==n&&(s.fresh||fI(s.isolates,r=hS(this,e))))return s.order;r||(r=hS(this,e));let i=EY(e.text,n,r);return this.bidiCache.push(new Ch(e.from,e.to,n,r,!0,i)),i}get hasFocus(){var e;return(this.dom.ownerDocument.hasFocus()||Fe.safari&&((e=this.inputState)===null||e===void 0?void 0:e.lastContextMenu)>Date.now()-3e4)&&this.root.activeElement==this.contentDOM}focus(){this.observer.ignore(()=>{XR(this.contentDOM),this.docView.updateSelection()})}setRoot(e){this._root!=e&&(this._root=e,this.observer.setWindow((e.nodeType==9?e:e.ownerDocument).defaultView||window),this.mountStyles())}destroy(){this.root.activeElement==this.contentDOM&&this.contentDOM.blur();for(let e of this.plugins)e.destroy(this);this.plugins=[],this.inputState.destroy(),this.docView.destroy(),this.dom.remove(),this.observer.destroy(),this.measureScheduled>-1&&this.win.cancelAnimationFrame(this.measureScheduled),this.destroyed=!0}static scrollIntoView(e,n={}){return Sf.of(new dl(typeof e=="number"?Pe.cursor(e):e,n.y,n.x,n.yMargin,n.xMargin))}scrollSnapshot(){let{scrollTop:e,scrollLeft:n}=this.scrollDOM,r=this.viewState.scrollAnchorAt(e);return Sf.of(new dl(Pe.cursor(r.from),"start","start",r.top-e,n,!0))}setTabFocusMode(e){e==null?this.inputState.tabFocusMode=this.inputState.tabFocusMode<0?0:-1:typeof e=="boolean"?this.inputState.tabFocusMode=e?0:-1:this.inputState.tabFocusMode!=0&&(this.inputState.tabFocusMode=Date.now()+e)}static domEventHandlers(e){return Ss.define(()=>({}),{eventHandlers:e})}static domEventObservers(e){return Ss.define(()=>({}),{eventObservers:e})}static theme(e,n){let r=wl.newName(),i=[Rf.of(r),$u.of(Vb(`.${r}`,e))];return n&&n.dark&&i.push($b.of(!0)),i}static baseTheme(e){return w1.lowest($u.of(Vb("."+Wb,e,$I)))}static findFromDOM(e){var n;let r=e.querySelector(".cm-content"),i=r&&Gt.get(r)||Gt.get(e);return((n=i?.rootView)===null||n===void 0?void 0:n.view)||null}}ft.styleModule=$u;ft.inputHandler=yI;ft.clipboardInputFilter=k1;ft.clipboardOutputFilter=N1;ft.scrollHandler=wI;ft.focusChangeEffect=xI;ft.perLineTextDirection=vI;ft.exceptionSink=EI;ft.updateListener=Hb;ft.editable=ms;ft.mouseSelectionStyle=bI;ft.dragMovesSelection=gI;ft.clickAddsSelectionRange=mI;ft.decorations=_c;ft.outerDecorations=_I;ft.atomicRanges=I1;ft.bidiIsolatedRanges=CI;ft.scrollMargins=AI;ft.darkTheme=$b;ft.cspNonce=tt.define({combine:t=>t.length?t[0]:""});ft.contentAttributes=R1;ft.editorAttributes=SI;ft.lineWrapping=ft.contentAttributes.of({class:"cm-lineWrapping"});ft.announce=bn.define();const Cq=4096,FS={};class Ch{constructor(e,n,r,i,s,o){this.from=e,this.to=n,this.dir=r,this.isolates=i,this.fresh=s,this.order=o}static update(e,n){if(n.empty&&!e.some(s=>s.fresh))return e;let r=[],i=e.length?e[e.length-1].dir:ar.LTR;for(let s=Math.max(0,e.length-10);s=0;i--){let s=r[i],o=typeof s=="function"?s(t):s;o&&Db(o,n)}return n}const Aq=Fe.mac?"mac":Fe.windows?"win":Fe.linux?"linux":"key";function kq(t,e){const n=t.split(/-(?!$)/);let r=n[n.length-1];r=="Space"&&(r=" ");let i,s,o,l;for(let c=0;cr.concat(i),[]))),n}function Rq(t,e,n){return GI(VI(t.state),e,t,n)}let no=null;const Iq=4e3;function Oq(t,e=Aq){let n=Object.create(null),r=Object.create(null),i=(o,l)=>{let c=r[o];if(c==null)r[o]=l;else if(c!=l)throw new Error("Key binding "+o+" is used both as a regular binding and as a multi-stroke prefix")},s=(o,l,c,d,f)=>{var p,m;let g=n[o]||(n[o]=Object.create(null)),x=l.split(/ (?!$)/).map(C=>kq(C,e));for(let C=1;C{let M=no={view:k,prefix:A,scope:o};return setTimeout(()=>{no==M&&(no=null)},Iq),!0}]})}let v=x.join(" ");i(v,!1);let S=g[v]||(g[v]={preventDefault:!1,stopPropagation:!1,run:((m=(p=g._any)===null||p===void 0?void 0:p.run)===null||m===void 0?void 0:m.slice())||[]});c&&S.run.push(c),d&&(S.preventDefault=!0),f&&(S.stopPropagation=!0)};for(let o of t){let l=o.scope?o.scope.split(" "):["editor"];if(o.any)for(let d of l){let f=n[d]||(n[d]=Object.create(null));f._any||(f._any={preventDefault:!1,stopPropagation:!1,run:[]});let{any:p}=o;for(let m in f)f[m].run.push(g=>p(g,Gb))}let c=o[e]||o.key;if(c)for(let d of l)s(d,c,o.run,o.preventDefault,o.stopPropagation),o.shift&&s(d,"Shift-"+c,o.shift,o.preventDefault,o.stopPropagation)}return n}let Gb=null;function GI(t,e,n,r){Gb=e;let i=ZK(e),s=DR(i,0),o=LR(s)==i.length&&i!=" ",l="",c=!1,d=!1,f=!1;no&&no.view==n&&no.scope==r&&(l=no.prefix+" ",MI.indexOf(e.keyCode)<0&&(d=!0,no=null));let p=new Set,m=S=>{if(S){for(let C of S.run)if(!p.has(C)&&(p.add(C),C(n)))return S.stopPropagation&&(f=!0),!0;S.preventDefault&&(S.stopPropagation&&(f=!0),d=!0)}return!1},g=t[r],x,v;return g&&(m(g[l+If(i,e,!o)])?c=!0:o&&(e.altKey||e.metaKey||e.ctrlKey)&&!(Fe.windows&&e.ctrlKey&&e.altKey)&&!(Fe.mac&&e.altKey&&!e.ctrlKey)&&(x=fo[e.keyCode])&&x!=i?(m(g[l+If(x,e,!0)])||e.shiftKey&&(v=wc[e.keyCode])!=i&&v!=x&&m(g[l+If(v,e,!1)]))&&(c=!0):o&&e.shiftKey&&m(g[l+If(i,e,!0)])&&(c=!0),!c&&m(g._any)&&(c=!0)),d&&(c=!0),c&&f&&e.stopPropagation(),Gb=null,c}const HS=tt.define({combine(t){let e,n;for(let r of t)e=e||r.topContainer,n=n||r.bottomContainer;return{topContainer:e,bottomContainer:n}}});function Ah(t,e){let n=t.plugin(KI),r=n?n.specs.indexOf(e):-1;return r>-1?n.panels[r]:null}const KI=Ss.fromClass(class{constructor(t){this.input=t.state.facet(kh),this.specs=this.input.filter(n=>n),this.panels=this.specs.map(n=>n(t));let e=t.state.facet(HS);this.top=new Of(t,!0,e.topContainer),this.bottom=new Of(t,!1,e.bottomContainer),this.top.sync(this.panels.filter(n=>n.top)),this.bottom.sync(this.panels.filter(n=>!n.top));for(let n of this.panels)n.dom.classList.add("cm-panel"),n.mount&&n.mount()}update(t){let e=t.state.facet(HS);this.top.container!=e.topContainer&&(this.top.sync([]),this.top=new Of(t.view,!0,e.topContainer)),this.bottom.container!=e.bottomContainer&&(this.bottom.sync([]),this.bottom=new Of(t.view,!1,e.bottomContainer)),this.top.syncClasses(),this.bottom.syncClasses();let n=t.state.facet(kh);if(n!=this.input){let r=n.filter(c=>c),i=[],s=[],o=[],l=[];for(let c of r){let d=this.specs.indexOf(c),f;d<0?(f=c(t.view),l.push(f)):(f=this.panels[d],f.update&&f.update(t)),i.push(f),(f.top?s:o).push(f)}this.specs=r,this.panels=i,this.top.sync(s),this.bottom.sync(o);for(let c of l)c.dom.classList.add("cm-panel"),c.mount&&c.mount()}else for(let r of this.panels)r.update&&r.update(t)}destroy(){this.top.sync([]),this.bottom.sync([])}},{provide:t=>ft.scrollMargins.of(e=>{let n=e.plugin(t);return n&&{top:n.top.scrollMargin(),bottom:n.bottom.scrollMargin()}})});class Of{constructor(e,n,r){this.view=e,this.top=n,this.container=r,this.dom=void 0,this.classes="",this.panels=[],this.syncClasses()}sync(e){for(let n of this.panels)n.destroy&&e.indexOf(n)<0&&n.destroy();this.panels=e,this.syncDOM()}syncDOM(){if(this.panels.length==0){this.dom&&(this.dom.remove(),this.dom=void 0);return}if(!this.dom){this.dom=document.createElement("div"),this.dom.className=this.top?"cm-panels cm-panels-top":"cm-panels cm-panels-bottom",this.dom.style[this.top?"top":"bottom"]="0";let n=this.container||this.view.dom;n.insertBefore(this.dom,this.top?n.firstChild:null)}let e=this.dom.firstChild;for(let n of this.panels)if(n.dom.parentNode==this.dom){for(;e!=n.dom;)e=zS(e);e=e.nextSibling}else this.dom.insertBefore(n.dom,e);for(;e;)e=zS(e)}scrollMargin(){return!this.dom||this.container?0:Math.max(0,this.top?this.dom.getBoundingClientRect().bottom-Math.max(0,this.view.scrollDOM.getBoundingClientRect().top):Math.min(innerHeight,this.view.scrollDOM.getBoundingClientRect().bottom)-this.dom.getBoundingClientRect().top)}syncClasses(){if(!(!this.container||this.classes==this.view.themeClasses)){for(let e of this.classes.split(" "))e&&this.container.classList.remove(e);for(let e of(this.classes=this.view.themeClasses).split(" "))e&&this.container.classList.add(e)}}}function zS(t){let e=t.nextSibling;return t.remove(),e}const kh=tt.define({enables:KI});class ra extends vl{compare(e){return this==e||this.constructor==e.constructor&&this.eq(e)}eq(e){return!1}destroy(e){}}ra.prototype.elementClass="";ra.prototype.toDOM=void 0;ra.prototype.mapMode=Wr.TrackBefore;ra.prototype.startSide=ra.prototype.endSide=-1;ra.prototype.point=!0;const v0=tt.define(),Mq=tt.define(),Yf=tt.define(),jS=tt.define({combine:t=>t.some(e=>e)});function Dq(t){return[Lq]}const Lq=Ss.fromClass(class{constructor(t){this.view=t,this.domAfter=null,this.prevViewport=t.viewport,this.dom=document.createElement("div"),this.dom.className="cm-gutters cm-gutters-before",this.dom.setAttribute("aria-hidden","true"),this.dom.style.minHeight=this.view.contentHeight/this.view.scaleY+"px",this.gutters=t.state.facet(Yf).map(e=>new WS(t,e)),this.fixed=!t.state.facet(jS);for(let e of this.gutters)e.config.side=="after"?this.getDOMAfter().appendChild(e.dom):this.dom.appendChild(e.dom);this.fixed&&(this.dom.style.position="sticky"),this.syncGutters(!1),t.scrollDOM.insertBefore(this.dom,t.contentDOM)}getDOMAfter(){return this.domAfter||(this.domAfter=document.createElement("div"),this.domAfter.className="cm-gutters cm-gutters-after",this.domAfter.setAttribute("aria-hidden","true"),this.domAfter.style.minHeight=this.view.contentHeight/this.view.scaleY+"px",this.domAfter.style.position=this.fixed?"sticky":"",this.view.scrollDOM.appendChild(this.domAfter)),this.domAfter}update(t){if(this.updateGutters(t)){let e=this.prevViewport,n=t.view.viewport,r=Math.min(e.to,n.to)-Math.max(e.from,n.from);this.syncGutters(r<(n.to-n.from)*.8)}if(t.geometryChanged){let e=this.view.contentHeight/this.view.scaleY+"px";this.dom.style.minHeight=e,this.domAfter&&(this.domAfter.style.minHeight=e)}this.view.state.facet(jS)!=!this.fixed&&(this.fixed=!this.fixed,this.dom.style.position=this.fixed?"sticky":"",this.domAfter&&(this.domAfter.style.position=this.fixed?"sticky":"")),this.prevViewport=t.view.viewport}syncGutters(t){let e=this.dom.nextSibling;t&&(this.dom.remove(),this.domAfter&&this.domAfter.remove());let n=Ht.iter(this.view.state.facet(v0),this.view.viewport.from),r=[],i=this.gutters.map(s=>new Pq(s,this.view.viewport,-this.view.documentPadding.top));for(let s of this.view.viewportLineBlocks)if(r.length&&(r=[]),Array.isArray(s.type)){let o=!0;for(let l of s.type)if(l.type==ii.Text&&o){Kb(n,r,l.from);for(let c of i)c.line(this.view,l,r);o=!1}else if(l.widget)for(let c of i)c.widget(this.view,l)}else if(s.type==ii.Text){Kb(n,r,s.from);for(let o of i)o.line(this.view,s,r)}else if(s.widget)for(let o of i)o.widget(this.view,s);for(let s of i)s.finish();t&&(this.view.scrollDOM.insertBefore(this.dom,e),this.domAfter&&this.view.scrollDOM.appendChild(this.domAfter))}updateGutters(t){let e=t.startState.facet(Yf),n=t.state.facet(Yf),r=t.docChanged||t.heightChanged||t.viewportChanged||!Ht.eq(t.startState.facet(v0),t.state.facet(v0),t.view.viewport.from,t.view.viewport.to);if(e==n)for(let i of this.gutters)i.update(t)&&(r=!0);else{r=!0;let i=[];for(let s of n){let o=e.indexOf(s);o<0?i.push(new WS(this.view,s)):(this.gutters[o].update(t),i.push(this.gutters[o]))}for(let s of this.gutters)s.dom.remove(),i.indexOf(s)<0&&s.destroy();for(let s of i)s.config.side=="after"?this.getDOMAfter().appendChild(s.dom):this.dom.appendChild(s.dom);this.gutters=i}return r}destroy(){for(let t of this.gutters)t.destroy();this.dom.remove(),this.domAfter&&this.domAfter.remove()}},{provide:t=>ft.scrollMargins.of(e=>{let n=e.plugin(t);if(!n||n.gutters.length==0||!n.fixed)return null;let r=n.dom.offsetWidth*e.scaleX,i=n.domAfter?n.domAfter.offsetWidth*e.scaleX:0;return e.textDirection==ar.LTR?{left:r,right:i}:{right:r,left:i}})});function $S(t){return Array.isArray(t)?t:[t]}function Kb(t,e,n){for(;t.value&&t.from<=n;)t.from==n&&e.push(t.value),t.next()}class Pq{constructor(e,n,r){this.gutter=e,this.height=r,this.i=0,this.cursor=Ht.iter(e.markers,n.from)}addElement(e,n,r){let{gutter:i}=this,s=(n.top-this.height)/e.scaleY,o=n.height/e.scaleY;if(this.i==i.elements.length){let l=new YI(e,o,s,r);i.elements.push(l),i.dom.appendChild(l.dom)}else i.elements[this.i].update(e,o,s,r);this.height=n.bottom,this.i++}line(e,n,r){let i=[];Kb(this.cursor,i,n.from),r.length&&(i=i.concat(r));let s=this.gutter.config.lineMarker(e,n,i);s&&i.unshift(s);let o=this.gutter;i.length==0&&!o.config.renderEmptyElements||this.addElement(e,n,i)}widget(e,n){let r=this.gutter.config.widgetMarker(e,n.widget,n),i=r?[r]:null;for(let s of e.state.facet(Mq)){let o=s(e,n.widget,n);o&&(i||(i=[])).push(o)}i&&this.addElement(e,n,i)}finish(){let e=this.gutter;for(;e.elements.length>this.i;){let n=e.elements.pop();e.dom.removeChild(n.dom),n.destroy()}}}class WS{constructor(e,n){this.view=e,this.config=n,this.elements=[],this.spacer=null,this.dom=document.createElement("div"),this.dom.className="cm-gutter"+(this.config.class?" "+this.config.class:"");for(let r in n.domEventHandlers)this.dom.addEventListener(r,i=>{let s=i.target,o;if(s!=this.dom&&this.dom.contains(s)){for(;s.parentNode!=this.dom;)s=s.parentNode;let c=s.getBoundingClientRect();o=(c.top+c.bottom)/2}else o=i.clientY;let l=e.lineBlockAtHeight(o-e.documentTop);n.domEventHandlers[r](e,l,i)&&i.preventDefault()});this.markers=$S(n.markers(e)),n.initialSpacer&&(this.spacer=new YI(e,0,0,[n.initialSpacer(e)]),this.dom.appendChild(this.spacer.dom),this.spacer.dom.style.cssText+="visibility: hidden; pointer-events: none")}update(e){let n=this.markers;if(this.markers=$S(this.config.markers(e.view)),this.spacer&&this.config.updateSpacer){let i=this.config.updateSpacer(this.spacer.markers[0],e);i!=this.spacer.markers[0]&&this.spacer.update(e.view,0,0,[i])}let r=e.view.viewport;return!Ht.eq(this.markers,n,r.from,r.to)||(this.config.lineMarkerChange?this.config.lineMarkerChange(e):!1)}destroy(){for(let e of this.elements)e.destroy()}}class YI{constructor(e,n,r,i){this.height=-1,this.above=0,this.markers=[],this.dom=document.createElement("div"),this.dom.className="cm-gutterElement",this.update(e,n,r,i)}update(e,n,r,i){this.height!=n&&(this.height=n,this.dom.style.height=n+"px"),this.above!=r&&(this.dom.style.marginTop=(this.above=r)?r+"px":""),Fq(this.markers,i)||this.setMarkers(e,i)}setMarkers(e,n){let r="cm-gutterElement",i=this.dom.firstChild;for(let s=0,o=0;;){let l=o,c=ss(l,c,d)||o(l,c,d):o}return r}})}});class w0 extends ra{constructor(e){super(),this.number=e}eq(e){return this.number==e.number}toDOM(){return document.createTextNode(this.number)}}function T0(t,e){return t.state.facet(tl).formatNumber(e,t.state)}const Hq=Yf.compute([tl],t=>({class:"cm-lineNumbers",renderEmptyElements:!1,markers(e){return e.state.facet(Bq)},lineMarker(e,n,r){return r.some(i=>i.toDOM)?null:new w0(T0(e,e.state.doc.lineAt(n.from).number))},widgetMarker:(e,n,r)=>{for(let i of e.state.facet(Uq)){let s=i(e,n,r);if(s)return s}return null},lineMarkerChange:e=>e.startState.facet(tl)!=e.state.facet(tl),initialSpacer(e){return new w0(T0(e,VS(e.state.doc.lines)))},updateSpacer(e,n){let r=T0(n.view,VS(n.view.state.doc.lines));return r==e.number?e:new w0(r)},domEventHandlers:t.facet(tl).domEventHandlers,side:"before"}));function zq(t={}){return[tl.of(t),Dq(),Hq]}function VS(t){let e=9;for(;et.normalize("NFKD"):t=>t;class Cl{constructor(e,n,r=0,i=e.length,s,o){this.test=o,this.value={from:0,to:0},this.done=!1,this.matches=[],this.buffer="",this.bufferPos=0,this.iter=e.iterRange(r,i),this.bufferStart=r,this.normalize=s?l=>s(GS(l)):GS,this.query=this.normalize(n)}peek(){if(this.bufferPos==this.buffer.length){if(this.bufferStart+=this.buffer.length,this.iter.next(),this.iter.done)return-1;this.bufferPos=0,this.buffer=this.iter.value}return DR(this.buffer,this.bufferPos)}next(){for(;this.matches.length;)this.matches.pop();return this.nextOverlapping()}nextOverlapping(){for(;;){let e=this.peek();if(e<0)return this.done=!0,this;let n=LK(e),r=this.bufferStart+this.bufferPos;this.bufferPos+=LR(e);let i=this.normalize(n);if(i.length)for(let s=0,o=r;;s++){let l=i.charCodeAt(s),c=this.match(l,o,this.bufferPos+this.bufferStart);if(s==i.length-1){if(c)return this.value=c,this;break}o==r&&sthis.to&&(this.curLine=this.curLine.slice(0,this.to-this.curLineStart)),this.iter.next())}nextLine(){this.curLineStart=this.curLineStart+this.curLine.length+1,this.curLineStart>this.to?this.curLine="":this.getLine(0)}next(){for(let e=this.matchPos-this.curLineStart;;){this.re.lastIndex=e;let n=this.matchPos<=this.to&&this.re.exec(this.curLine);if(n){let r=this.curLineStart+n.index,i=r+n[0].length;if(this.matchPos=Nh(this.text,i+(r==i?1:0)),r==this.curLineStart+this.curLine.length&&this.nextLine(),(rthis.value.to)&&(!this.test||this.test(r,i,n)))return this.value={from:r,to:i,match:n},this;e=this.matchPos-this.curLineStart}else if(this.curLineStart+this.curLine.length=r||i.to<=n){let l=new fl(n,e.sliceString(n,r));return S0.set(e,l),l}if(i.from==n&&i.to==r)return i;let{text:s,from:o}=i;return o>n&&(s=e.sliceString(n,o)+s,o=n),i.to=this.to?this.to:this.text.lineAt(e).to}next(){for(;;){let e=this.re.lastIndex=this.matchPos-this.flat.from,n=this.re.exec(this.flat.text);if(n&&!n[0]&&n.index==e&&(this.re.lastIndex=e+1,n=this.re.exec(this.flat.text)),n){let r=this.flat.from+n.index,i=r+n[0].length;if((this.flat.to>=this.to||n.index+n[0].length<=this.flat.text.length-10)&&(!this.test||this.test(r,i,n)))return this.value={from:r,to:i,match:n},this.matchPos=Nh(this.text,i+(r==i?1:0)),this}if(this.flat.to==this.to)return this.done=!0,this;this.flat=fl.get(this.text,this.flat.from,this.chunkEnd(this.flat.from+this.flat.text.length*2))}}}typeof Symbol<"u"&&(XI.prototype[Symbol.iterator]=QI.prototype[Symbol.iterator]=function(){return this});function jq(t){try{return new RegExp(t,L1),!0}catch{return!1}}function Nh(t,e){if(e>=t.length)return e;let n=t.lineAt(e),r;for(;e=56320&&r<57344;)e++;return e}function Yb(t){let e=String(t.state.doc.lineAt(t.state.selection.main.head).number),n=Kn("input",{class:"cm-textfield",name:"line",value:e}),r=Kn("form",{class:"cm-gotoLine",onkeydown:s=>{s.keyCode==27?(s.preventDefault(),t.dispatch({effects:ic.of(!1)}),t.focus()):s.keyCode==13&&(s.preventDefault(),i())},onsubmit:s=>{s.preventDefault(),i()}},Kn("label",t.state.phrase("Go to line"),": ",n)," ",Kn("button",{class:"cm-button",type:"submit"},t.state.phrase("go")),Kn("button",{name:"close",onclick:()=>{t.dispatch({effects:ic.of(!1)}),t.focus()},"aria-label":t.state.phrase("close"),type:"button"},["×"]));function i(){let s=/^([+-])?(\d+)?(:\d+)?(%)?$/.exec(n.value);if(!s)return;let{state:o}=t,l=o.doc.lineAt(o.selection.main.head),[,c,d,f,p]=s,m=f?+f.slice(1):0,g=d?+d:l.number;if(d&&p){let S=g/100;c&&(S=S*(c=="-"?-1:1)+l.number/o.doc.lines),g=Math.round(o.doc.lines*S)}else d&&c&&(g=g*(c=="-"?-1:1)+l.number);let x=o.doc.line(Math.max(1,Math.min(o.doc.lines,g))),v=Pe.cursor(x.from+Math.max(0,Math.min(m,x.length)));t.dispatch({effects:[ic.of(!1),ft.scrollIntoView(v.from,{y:"center"})],selection:v}),t.focus()}return{dom:r}}const ic=bn.define(),KS=bo.define({create(){return!0},update(t,e){for(let n of e.effects)n.is(ic)&&(t=n.value);return t},provide:t=>kh.from(t,e=>e?Yb:null)}),$q=t=>{let e=Ah(t,Yb);if(!e){let n=[ic.of(!0)];t.state.field(KS,!1)==null&&n.push(bn.appendConfig.of([KS,Wq])),t.dispatch({effects:n}),e=Ah(t,Yb)}return e&&e.dom.querySelector("input").select(),!0},Wq=ft.baseTheme({".cm-panel.cm-gotoLine":{padding:"2px 6px 4px",position:"relative","& label":{fontSize:"80%"},"& [name=close]":{position:"absolute",top:"0",bottom:"0",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",padding:"0"}}}),Vq={highlightWordAroundCursor:!1,minSelectionLength:1,maxMatches:100,wholeWords:!1},Gq=tt.define({combine(t){return T1(t,Vq,{highlightWordAroundCursor:(e,n)=>e||n,minSelectionLength:Math.min,maxMatches:Math.min})}});function Kq(t){return[Zq,Qq]}const Yq=en.mark({class:"cm-selectionMatch"}),qq=en.mark({class:"cm-selectionMatch cm-selectionMatch-main"});function YS(t,e,n,r){return(n==0||t(e.sliceDoc(n-1,n))!=Cn.Word)&&(r==e.doc.length||t(e.sliceDoc(r,r+1))!=Cn.Word)}function Xq(t,e,n,r){return t(e.sliceDoc(n,n+1))==Cn.Word&&t(e.sliceDoc(r-1,r))==Cn.Word}const Qq=Ss.fromClass(class{constructor(t){this.decorations=this.getDeco(t)}update(t){(t.selectionSet||t.docChanged||t.viewportChanged)&&(this.decorations=this.getDeco(t.view))}getDeco(t){let e=t.state.facet(Gq),{state:n}=t,r=n.selection;if(r.ranges.length>1)return en.none;let i=r.main,s,o=null;if(i.empty){if(!e.highlightWordAroundCursor)return en.none;let c=n.wordAt(i.head);if(!c)return en.none;o=n.charCategorizer(i.head),s=n.sliceDoc(c.from,c.to)}else{let c=i.to-i.from;if(c200)return en.none;if(e.wholeWords){if(s=n.sliceDoc(i.from,i.to),o=n.charCategorizer(i.head),!(YS(o,n,i.from,i.to)&&Xq(o,n,i.from,i.to)))return en.none}else if(s=n.sliceDoc(i.from,i.to),!s)return en.none}let l=[];for(let c of t.visibleRanges){let d=new Cl(n.doc,s,c.from,c.to);for(;!d.next().done;){let{from:f,to:p}=d.value;if((!o||YS(o,n,f,p))&&(i.empty&&f<=i.from&&p>=i.to?l.push(qq.range(f,p)):(f>=i.to||p<=i.from)&&l.push(Yq.range(f,p)),l.length>e.maxMatches))return en.none}}return en.set(l)}},{decorations:t=>t.decorations}),Zq=ft.baseTheme({".cm-selectionMatch":{backgroundColor:"#99ff7780"},".cm-searchMatch .cm-selectionMatch":{backgroundColor:"transparent"}}),Jq=({state:t,dispatch:e})=>{let{selection:n}=t,r=Pe.create(n.ranges.map(i=>t.wordAt(i.head)||Pe.cursor(i.head)),n.mainIndex);return r.eq(n)?!1:(e(t.update({selection:r})),!0)};function eX(t,e){let{main:n,ranges:r}=t.selection,i=t.wordAt(n.head),s=i&&i.from==n.from&&i.to==n.to;for(let o=!1,l=new Cl(t.doc,e,r[r.length-1].to);;)if(l.next(),l.done){if(o)return null;l=new Cl(t.doc,e,0,Math.max(0,r[r.length-1].from-1)),o=!0}else{if(o&&r.some(c=>c.from==l.value.from))continue;if(s){let c=t.wordAt(l.value.from);if(!c||c.from!=l.value.from||c.to!=l.value.to)continue}return l.value}}const tX=({state:t,dispatch:e})=>{let{ranges:n}=t.selection;if(n.some(s=>s.from===s.to))return Jq({state:t,dispatch:e});let r=t.sliceDoc(n[0].from,n[0].to);if(t.selection.ranges.some(s=>t.sliceDoc(s.from,s.to)!=r))return!1;let i=eX(t,r);return i?(e(t.update({selection:t.selection.addRange(Pe.range(i.from,i.to),!1),effects:ft.scrollIntoView(i.to)})),!0):!1},da=tt.define({combine(t){return T1(t,{top:!1,caseSensitive:!1,literal:!1,regexp:!1,wholeWord:!1,createPanel:e=>new pX(e),scrollToMatch:e=>ft.scrollIntoView(e)})}});function nX(t){return t?[da.of(t),Xb]:Xb}class ZI{constructor(e){this.search=e.search,this.caseSensitive=!!e.caseSensitive,this.literal=!!e.literal,this.regexp=!!e.regexp,this.replace=e.replace||"",this.valid=!!this.search&&(!this.regexp||jq(this.search)),this.unquoted=this.unquote(this.search),this.wholeWord=!!e.wholeWord}unquote(e){return this.literal?e:e.replace(/\\([nrt\\])/g,(n,r)=>r=="n"?` +`:r=="r"?"\r":r=="t"?" ":"\\")}eq(e){return this.search==e.search&&this.replace==e.replace&&this.caseSensitive==e.caseSensitive&&this.regexp==e.regexp&&this.wholeWord==e.wholeWord}create(){return this.regexp?new oX(this):new iX(this)}getCursor(e,n=0,r){let i=e.doc?e:Wt.create({doc:e});return r==null&&(r=i.doc.length),this.regexp?Xa(this,i,n,r):qa(this,i,n,r)}}class JI{constructor(e){this.spec=e}}function qa(t,e,n,r){return new Cl(e.doc,t.unquoted,n,r,t.caseSensitive?void 0:i=>i.toLowerCase(),t.wholeWord?rX(e.doc,e.charCategorizer(e.selection.main.head)):void 0)}function rX(t,e){return(n,r,i,s)=>((s>n||s+i.length=n)return null;i.push(r.value)}return i}highlight(e,n,r,i){let s=qa(this.spec,e,Math.max(0,n-this.spec.unquoted.length),Math.min(r+this.spec.unquoted.length,e.doc.length));for(;!s.next().done;)i(s.value.from,s.value.to)}}function Xa(t,e,n,r){return new XI(e.doc,t.search,{ignoreCase:!t.caseSensitive,test:t.wholeWord?sX(e.charCategorizer(e.selection.main.head)):void 0},n,r)}function Rh(t,e){return t.slice(xi(t,e,!1),e)}function Ih(t,e){return t.slice(e,xi(t,e))}function sX(t){return(e,n,r)=>!r[0].length||(t(Rh(r.input,r.index))!=Cn.Word||t(Ih(r.input,r.index))!=Cn.Word)&&(t(Ih(r.input,r.index+r[0].length))!=Cn.Word||t(Rh(r.input,r.index+r[0].length))!=Cn.Word)}class oX extends JI{nextMatch(e,n,r){let i=Xa(this.spec,e,r,e.doc.length).next();return i.done&&(i=Xa(this.spec,e,0,n).next()),i.done?null:i.value}prevMatchInRange(e,n,r){for(let i=1;;i++){let s=Math.max(n,r-i*1e4),o=Xa(this.spec,e,s,r),l=null;for(;!o.next().done;)l=o.value;if(l&&(s==n||l.from>s+10))return l;if(s==n)return null}}prevMatch(e,n,r){return this.prevMatchInRange(e,0,n)||this.prevMatchInRange(e,r,e.doc.length)}getReplacement(e){return this.spec.unquote(this.spec.replace).replace(/\$([$&]|\d+)/g,(n,r)=>{if(r=="&")return e.match[0];if(r=="$")return"$";for(let i=r.length;i>0;i--){let s=+r.slice(0,i);if(s>0&&s=n)return null;i.push(r.value)}return i}highlight(e,n,r,i){let s=Xa(this.spec,e,Math.max(0,n-250),Math.min(r+250,e.doc.length));for(;!s.next().done;)i(s.value.from,s.value.to)}}const Cc=bn.define(),P1=bn.define(),ao=bo.define({create(t){return new _0(qb(t).create(),null)},update(t,e){for(let n of e.effects)n.is(Cc)?t=new _0(n.value.create(),t.panel):n.is(P1)&&(t=new _0(t.query,n.value?F1:null));return t},provide:t=>kh.from(t,e=>e.panel)});class _0{constructor(e,n){this.query=e,this.panel=n}}const aX=en.mark({class:"cm-searchMatch"}),lX=en.mark({class:"cm-searchMatch cm-searchMatch-selected"}),uX=Ss.fromClass(class{constructor(t){this.view=t,this.decorations=this.highlight(t.state.field(ao))}update(t){let e=t.state.field(ao);(e!=t.startState.field(ao)||t.docChanged||t.selectionSet||t.viewportChanged)&&(this.decorations=this.highlight(e))}highlight({query:t,panel:e}){if(!e||!t.spec.valid)return en.none;let{view:n}=this,r=new xc;for(let i=0,s=n.visibleRanges,o=s.length;is[i+1].from-500;)c=s[++i].to;t.highlight(n.state,l,c,(d,f)=>{let p=n.state.selection.ranges.some(m=>m.from==d&&m.to==f);r.add(d,f,p?lX:aX)})}return r.finish()}},{decorations:t=>t.decorations});function $c(t){return e=>{let n=e.state.field(ao,!1);return n&&n.query.spec.valid?t(e,n):B1(e)}}const Oh=$c((t,{query:e})=>{let{to:n}=t.state.selection.main,r=e.nextMatch(t.state,n,n);if(!r)return!1;let i=Pe.single(r.from,r.to),s=t.state.facet(da);return t.dispatch({selection:i,effects:[U1(t,r),s.scrollToMatch(i.main,t)],userEvent:"select.search"}),tO(t),!0}),Mh=$c((t,{query:e})=>{let{state:n}=t,{from:r}=n.selection.main,i=e.prevMatch(n,r,r);if(!i)return!1;let s=Pe.single(i.from,i.to),o=t.state.facet(da);return t.dispatch({selection:s,effects:[U1(t,i),o.scrollToMatch(s.main,t)],userEvent:"select.search"}),tO(t),!0}),cX=$c((t,{query:e})=>{let n=e.matchAll(t.state,1e3);return!n||!n.length?!1:(t.dispatch({selection:Pe.create(n.map(r=>Pe.range(r.from,r.to))),userEvent:"select.search.matches"}),!0)}),dX=({state:t,dispatch:e})=>{let n=t.selection;if(n.ranges.length>1||n.main.empty)return!1;let{from:r,to:i}=n.main,s=[],o=0;for(let l=new Cl(t.doc,t.sliceDoc(r,i));!l.next().done;){if(s.length>1e3)return!1;l.value.from==r&&(o=s.length),s.push(Pe.range(l.value.from,l.value.to))}return e(t.update({selection:Pe.create(s,o),userEvent:"select.search.matches"})),!0},qS=$c((t,{query:e})=>{let{state:n}=t,{from:r,to:i}=n.selection.main;if(n.readOnly)return!1;let s=e.nextMatch(n,r,r);if(!s)return!1;let o=s,l=[],c,d,f=[];o.from==r&&o.to==i&&(d=n.toText(e.getReplacement(o)),l.push({from:o.from,to:o.to,insert:d}),o=e.nextMatch(n,o.from,o.to),f.push(ft.announce.of(n.phrase("replaced match on line $",n.doc.lineAt(r).number)+".")));let p=t.state.changes(l);return o&&(c=Pe.single(o.from,o.to).map(p),f.push(U1(t,o)),f.push(n.facet(da).scrollToMatch(c.main,t))),t.dispatch({changes:p,selection:c,effects:f,userEvent:"input.replace"}),!0}),fX=$c((t,{query:e})=>{if(t.state.readOnly)return!1;let n=e.matchAll(t.state,1e9).map(i=>{let{from:s,to:o}=i;return{from:s,to:o,insert:e.getReplacement(i)}});if(!n.length)return!1;let r=t.state.phrase("replaced $ matches",n.length)+".";return t.dispatch({changes:n,effects:ft.announce.of(r),userEvent:"input.replace.all"}),!0});function F1(t){return t.state.facet(da).createPanel(t)}function qb(t,e){var n,r,i,s,o;let l=t.selection.main,c=l.empty||l.to>l.from+100?"":t.sliceDoc(l.from,l.to);if(e&&!c)return e;let d=t.facet(da);return new ZI({search:((n=e?.literal)!==null&&n!==void 0?n:d.literal)?c:c.replace(/\n/g,"\\n"),caseSensitive:(r=e?.caseSensitive)!==null&&r!==void 0?r:d.caseSensitive,literal:(i=e?.literal)!==null&&i!==void 0?i:d.literal,regexp:(s=e?.regexp)!==null&&s!==void 0?s:d.regexp,wholeWord:(o=e?.wholeWord)!==null&&o!==void 0?o:d.wholeWord})}function eO(t){let e=Ah(t,F1);return e&&e.dom.querySelector("[main-field]")}function tO(t){let e=eO(t);e&&e==t.root.activeElement&&e.select()}const B1=t=>{let e=t.state.field(ao,!1);if(e&&e.panel){let n=eO(t);if(n&&n!=t.root.activeElement){let r=qb(t.state,e.query.spec);r.valid&&t.dispatch({effects:Cc.of(r)}),n.focus(),n.select()}}else t.dispatch({effects:[P1.of(!0),e?Cc.of(qb(t.state,e.query.spec)):bn.appendConfig.of(Xb)]});return!0},nO=t=>{let e=t.state.field(ao,!1);if(!e||!e.panel)return!1;let n=Ah(t,F1);return n&&n.dom.contains(t.root.activeElement)&&t.focus(),t.dispatch({effects:P1.of(!1)}),!0},hX=[{key:"Mod-f",run:B1,scope:"editor search-panel"},{key:"F3",run:Oh,shift:Mh,scope:"editor search-panel",preventDefault:!0},{key:"Mod-g",run:Oh,shift:Mh,scope:"editor search-panel",preventDefault:!0},{key:"Escape",run:nO,scope:"editor search-panel"},{key:"Mod-Shift-l",run:dX},{key:"Mod-Alt-g",run:$q},{key:"Mod-d",run:tX,preventDefault:!0}];class pX{constructor(e){this.view=e;let n=this.query=e.state.field(ao).query.spec;this.commit=this.commit.bind(this),this.searchField=Kn("input",{value:n.search,placeholder:Br(e,"Find"),"aria-label":Br(e,"Find"),class:"cm-textfield",name:"search",form:"","main-field":"true",onchange:this.commit,onkeyup:this.commit}),this.replaceField=Kn("input",{value:n.replace,placeholder:Br(e,"Replace"),"aria-label":Br(e,"Replace"),class:"cm-textfield",name:"replace",form:"",onchange:this.commit,onkeyup:this.commit}),this.caseField=Kn("input",{type:"checkbox",name:"case",form:"",checked:n.caseSensitive,onchange:this.commit}),this.reField=Kn("input",{type:"checkbox",name:"re",form:"",checked:n.regexp,onchange:this.commit}),this.wordField=Kn("input",{type:"checkbox",name:"word",form:"",checked:n.wholeWord,onchange:this.commit});function r(i,s,o){return Kn("button",{class:"cm-button",name:i,onclick:s,type:"button"},o)}this.dom=Kn("div",{onkeydown:i=>this.keydown(i),class:"cm-search"},[this.searchField,r("next",()=>Oh(e),[Br(e,"next")]),r("prev",()=>Mh(e),[Br(e,"previous")]),r("select",()=>cX(e),[Br(e,"all")]),Kn("label",null,[this.caseField,Br(e,"match case")]),Kn("label",null,[this.reField,Br(e,"regexp")]),Kn("label",null,[this.wordField,Br(e,"by word")]),...e.state.readOnly?[]:[Kn("br"),this.replaceField,r("replace",()=>qS(e),[Br(e,"replace")]),r("replaceAll",()=>fX(e),[Br(e,"replace all")])],Kn("button",{name:"close",onclick:()=>nO(e),"aria-label":Br(e,"close"),type:"button"},["×"])])}commit(){let e=new ZI({search:this.searchField.value,caseSensitive:this.caseField.checked,regexp:this.reField.checked,wholeWord:this.wordField.checked,replace:this.replaceField.value});e.eq(this.query)||(this.query=e,this.view.dispatch({effects:Cc.of(e)}))}keydown(e){Rq(this.view,e,"search-panel")?e.preventDefault():e.keyCode==13&&e.target==this.searchField?(e.preventDefault(),(e.shiftKey?Mh:Oh)(this.view)):e.keyCode==13&&e.target==this.replaceField&&(e.preventDefault(),qS(this.view))}update(e){for(let n of e.transactions)for(let r of n.effects)r.is(Cc)&&!r.value.eq(this.query)&&this.setQuery(r.value)}setQuery(e){this.query=e,this.searchField.value=e.search,this.replaceField.value=e.replace,this.caseField.checked=e.caseSensitive,this.reField.checked=e.regexp,this.wordField.checked=e.wholeWord}mount(){this.searchField.select()}get pos(){return 80}get top(){return this.view.state.facet(da).top}}function Br(t,e){return t.state.phrase(e)}const Mf=30,Df=/[\s\.,:;?!]/;function U1(t,{from:e,to:n}){let r=t.state.doc.lineAt(e),i=t.state.doc.lineAt(n).to,s=Math.max(r.from,e-Mf),o=Math.min(i,n+Mf),l=t.state.sliceDoc(s,o);if(s!=r.from){for(let c=0;cl.length-Mf;c--)if(!Df.test(l[c-1])&&Df.test(l[c])){l=l.slice(0,c);break}}return ft.announce.of(`${t.state.phrase("current match")}. ${l} ${t.state.phrase("on line")} ${r.number}.`)}const mX=ft.baseTheme({".cm-panel.cm-search":{padding:"2px 6px 4px",position:"relative","& [name=close]":{position:"absolute",top:"0",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",padding:0,margin:0},"& input, & button, & label":{margin:".2em .6em .2em 0"},"& input[type=checkbox]":{marginRight:".2em"},"& label":{fontSize:"80%",whiteSpace:"pre"}},"&light .cm-searchMatch":{backgroundColor:"#ffff0054"},"&dark .cm-searchMatch":{backgroundColor:"#00ffff8a"},"&light .cm-searchMatch-selected":{backgroundColor:"#ff6a0054"},"&dark .cm-searchMatch-selected":{backgroundColor:"#ff00ff8a"}}),Xb=[ao,w1.low(uX),mX],gX=({text:t})=>{const e=T.useRef(null),n=T.useRef(null);return T.useEffect(()=>{if(e.current){const r=[zq(),ft.editable.of(!1),nX({top:!0}),Kq(),WI.of(hX)],i=Wt.create({doc:t,extensions:r}),s=new ft({state:i,parent:e.current});return n.current=s,()=>s.destroy()}},[t]),T.useEffect(()=>{n.current&&setTimeout(()=>B1(n.current),0)},[n.current]),w.jsx("div",{onKeyDownCapture:r=>r.key==="Escape"&&r.stopPropagation(),className:"[&_.cm-search_*]:hidden [&_.cm-gutters]:bg-white [&_.cm-gutters]:text-[#bbb] [&_.cm-gutters]:border-0 [&_.cm-gutters]:ps-[0.5em] [&_.cm-gutters]:pe-[1.2em] [&_.cm-search]:bg-white [&_.cm-scroller>div:nth-child(2)]:flex-1 [&_.cm-scroller>div:nth-child(2)]:[white-space:break-spaces] [&_.cm-panels]:border-none [&_.cm-search_input:first-child]:block [&_.cm-search_input:first-child]:rounded-[5px] [&_.cm-search_input:first-child]:w-[300px] [&_.cm-panels]:sticky [&_.cm-panels]:translate-y-0 [&_.cm-panels]:h-[39px] [&_.cm-panels]:bg-white [&_.cm-panels]:-translate-y-[100%] [&_.cm-panels]:pl-[20px]",children:w.jsx("div",{ref:e,className:"your-class-name"})})},bX=({log:t})=>{const{openDialog:e,DialogComponent:n,closeDialog:r}=zA(),i=T.useRef(null),s=o=>{e("",w.jsxs("pre",{ref:i,className:"group rounded-[12px] fixed-scroll font-light font-ibm-plex-mono border-y-[10px] border-white text-wrap text-[#333] relative overflow-auto h-[100%]",children:[w.jsx("div",{className:"invisble w-fit [justify-self:end] z-[999] group-hover:visible flex fixed top-[10px] right-[10px] justify-end",children:w.jsxs("div",{className:"flex justify-end bg-white p-[10px] gap-[20px] rounded-lg w-fit",children:[w.jsx(Xn,{value:"Copy",side:"top",children:w.jsx("img",{src:"icons/copy.svg",alt:"",onClick:()=>hl(o,i?.current||void 0),className:"cursor-pointer"})}),w.jsx(Xn,{value:"Close",side:"top",children:w.jsx(gl,{onClick:()=>r(),size:18,className:"cursor-pointer"})})]})}),w.jsx(gX,{text:o})]}),{height:"90vh",width:"min(90vw, 1200px)"})};return w.jsxs("div",{className:On("flex max-h-[200px] w-full overflow-hidden group relative font-ubuntu-mono gap-[5px] px-[20px] text-[14px] transition-all hover:bg-[#FAFAFA]"),children:[w.jsxs("div",{className:"absolute hidden z-10 group-hover:flex right-[10px] top-[10px] gap-[5px]",children:[w.jsx(Xn,{value:"Copy",side:"top",children:w.jsx("div",{onClick:()=>hl(t?.message||""),className:"cursor-pointer size-[28px] flex justify-center items-center bg-white hover:bg-[#F3F5F9] border border-[#EEEEEE] hover:border-[#E9EBEF] rounded-[6px]",children:w.jsx("img",{src:"icons/copy.svg",alt:""})})}),w.jsx(Xn,{value:"Expand",side:"top",children:w.jsx("div",{onClick:()=>s(t?.message||""),className:"cursor-pointer size-[28px] flex justify-center items-center bg-white hover:bg-[#F3F5F9] border border-[#EEEEEE] hover:border-[#E9EBEF] rounded-[6px]",children:w.jsx("img",{src:"icons/expand.svg",alt:""})})})]}),w.jsx("pre",{className:Al("max-w-[-webkit-fill-available] border-y-[10px] border-white group-hover:border-[#FAFAFA] font-light font-ibm-plex-mono pe-[10px] text-wrap"),children:t?.message?.trim()}),w.jsx(n,{})]})},EX=({messagesRef:t,filteredLogs:e})=>w.jsx("div",{className:"p-[6px] overflow-hidden h-[calc(100%-12px)] rounded-[6px]",children:w.jsxs("div",{className:"pt-0 flex-1 border bg-white h-full rounded-[3px]",children:[w.jsxs("div",{className:"flex items-center min-h-[48px] text-[14px] font-medium border-b border-[#EDEFF3]",children:[w.jsx("div",{className:"w-[86px] border-e border-[#EDEFF3] min-h-[48px] flex items-center ps-[10px]",children:"Level"}),w.jsx("div",{className:"flex-1 ps-[10px]",children:"Message"})]}),w.jsx("div",{ref:t,className:"rounded-[8px] h-[calc(100%-60px)] overflow-auto bg-white fixed-scroll text-[14px] font-normal",children:e.map((n,r)=>w.jsxs("div",{className:"flex group hover:bg-[#FAFAFA] min-h-[48px] border-t border-[#EDEFF3] font-ibm-plex-mono [&:last-child]:border-b [&:first-child]:border-[0px] items-stretch",children:[w.jsx("div",{className:"min-w-[86px] w-[86px] border-e border-[#EDEFF3] min-h-[48px] flex ps-[10px] pt-[10px] capitalize",children:n.level?.toLowerCase()}),w.jsx(bX,{log:n})]},r))})]})}),yX=({event:t})=>w.jsx("div",{className:"h-full group p-[20px] bg-[#ebecf0] text-[13px] text-[#ef5350] z-10",children:w.jsxs("pre",{className:Al("p-[10px] max-w-[-webkit-fill-available] pe-[10px] text-wrap break-words bg-white rounded-[8px] h-full overflow-auto group relative"),children:[w.jsx("div",{className:"sticky h-0 hidden z-10 group-hover:block [direction:rtl] top-[10px] right-[10px] gap-[10px]",children:w.jsx(Xn,{value:"Copy",side:"top",children:w.jsx("img",{src:"icons/copy.svg",sizes:"18",alt:"",onClick:()=>hl(t?.error||""),className:"cursor-pointer"})})}),t?.error]})}),xX=t=>t.find(e=>e.selected)?.id||t[0]?.id||null,vX=({event:t,closeLogs:e,regenerateMessageFn:n,resendMessageFn:r,flaggedChanged:i,sameTraceMessages:s})=>{const[o,l]=T.useState(null),[c,d]=cG("filters",[]),[f,p]=T.useState(xX(c)),[m,g]=T.useState(null),[x,v]=T.useState([]),S=T.useRef(null),C=T.useRef(null);T.useEffect(()=>{d(I=>I.map(G=>(G.selected=G.id===f,G)))},[f]),T.useEffect(()=>{t?.id&&C.current?.resize(50)},[t?.id]),T.useEffect(()=>{(async()=>{const D=Object.keys(o||{}).length;if(m&&o)if(!D&&o)v(m);else{const G=await sG(t?.trace_id,o);v(G),d(X=>{if(!X.length&&D){const Y={id:Date.now(),def:o,name:"Logs"};return p(Y.id),[Y]}const P=X.find(Y=>Y.id===f);return P?(P.def=o,[...X]):X})}!o&&m?.length&&l({})})()},[m,o]),T.useEffect(()=>{!t&&m&&(g(null),v([]))},[t]),T.useEffect(()=>{if(!t?.trace_id)return;(async()=>{const D=await cb(t.trace_id);g(D)})()},[t?.trace_id]),T.useEffect(()=>{if(!t?.trace_id)return;const I=D=>{D.detail.trace_id===t.trace_id&&cb(t.trace_id).then(g)};return window.addEventListener("new-log",I),()=>window.removeEventListener("new-log",I)},[t?.trace_id]);const A=I=>{const D=c.findIndex(X=>X.id===I);if(D===-1)return;const G=c.filter(X=>X.id!==I);if(d(G),f===I){const X=G?.[(D||1)-1]?.id||G?.[0]?.id||null;p(X)}G.length||l({})},k=t&&!!m?.length&&!!c?.length,M=!1;Object.entries(t?.data?.canned_responses||{}).map(([I,D])=>({id:I,value:D}));const F=t?.serverStatus==="error";return w.jsxs("div",{className:On("w-full h-full animate-fade-in duration-200 overflow-auto flex flex-col justify-start pt-0 pe-0 bg-[#FBFBFB]"),children:[w.jsx(ZG,{event:t||null,closeLogs:e,sameTraceMessages:s,resendMessageFn:r,regenerateMessageFn:n,className:On("shadow-main h-[60px] min-h-[60px]",Object.keys(o||{}).length?"border-[#F3F5F9]":""),flaggedChanged:i}),w.jsx("div",{className:"ps-[20px] pt-[10px] flex items-center gap-[3px] text-[14px] font-normal bg-white",children:w.jsx(BA,{textToCopy:t?.trace_id?.split("::")?.[0],preText:"Trace ID: ",text:`${t?.trace_id?.split("::")?.[0]}`,className:"whitespace-nowrap [&_span]:text-ellipsis [&_span]:overflow-hidden [&_span]:block"})}),w.jsxs(CK,{direction:"vertical",className:On("w-full h-full overflow-auto flex flex-col justify-start pt-0 pe-0 bg-[#FBFBFB]"),children:[w.jsx(qT,{ref:C,minSize:0,maxSize:F?99:0,defaultSize:F?50:0,children:F&&w.jsx(yX,{event:t})}),w.jsx(AK,{withHandle:!0,className:On(!F&&"hidden")}),w.jsxs(qT,{minSize:F?0:100,maxSize:F?99:100,defaultSize:F?50:100,className:"flex flex-col bg-white",children:[M,w.jsx("div",{className:Xe("flex justify-between bg-white z-[1] items-center min-h-[58px] h-[58px] p-[10px] pb-[4px] pe-0",k&&"min-h-0 h-0"),children:!k&&w.jsx(HT,{showDropdown:!0,filterId:f||void 0,def:structuredClone(c.find(I=>f===I.id)?.def||null),applyFn:(I,D,G)=>{setTimeout(()=>l({types:I,level:D,content:G}),0)}})}),k&&w.jsx(QG,{currFilterTabs:f,filterTabs:c,setFilterTabs:d,setCurrFilterTabs:p}),t&&!!m?.length&&k&&w.jsx(HT,{showTags:!0,showDropdown:!0,deleteFilterTab:A,className:Xe(!x?.length&&"",!m?.length&&"absolute"),filterId:f||void 0,def:structuredClone(c.find(I=>f===I.id)?.def||null),applyFn:(I,D,G)=>{setTimeout(()=>l({types:I,level:D,content:G}),0)}}),!t&&w.jsx(o0,{title:"Feeling curious?",subTitle:"Select a message for additional actions and information about its process."}),t&&m&&!m?.length&&w.jsx(o0,{imgClassName:"w-[68px] h-[48px]",imgUrl:"logo-muted.svg",title:"Whoopsie!",subTitle:"The logs for this message weren't found in cache. Try regenerating it to get fresh logs.",className:On(F&&"translate-y-[0px]")}),t&&!!m?.length&&!x.length&&w.jsx(o0,{title:"No logs for the current filters",className:On(F&&"translate-y-[0px]")}),t&&!!x.length&&w.jsx("div",{className:"ps-[10px] overflow-auto h-[-webkit-fill-available]",children:w.jsx(EX,{messagesRef:S,filteredLogs:x})})]})]})]})},wX=T.memo(vX,(t,e)=>t.event===e.event&&t.sameTraceMessages===e.sameTraceMessages),TX=({date:t,isFirst:e,bgColor:n})=>w.jsx("div",{className:"flex justify-center min-h-[30px] z-[1] bg-white h-[30px] pb-[4px] mb-[14px] pt-[4px] sticky -top-[1px]",children:w.jsxs("div",{className:Xe("text-center flex justify-center max-w-[min(1000px,100%)] min-w-[min(1000px,100%)]",e&&"pt-[1px] !mt-0",n),children:[w.jsx("div",{className:"[box-shadow:0_-0.6px_0px_0px_#F3F5F9] h-full -translate-y-[-50%] flex-1 "}),w.jsx("div",{className:"w-[130px] border-[0.6px] border-muted font-light text-[12px] bg-white text-[#656565] flex items-center justify-center rounded-[6px]",children:sA(t)}),w.jsx("div",{className:"[box-shadow:0_-0.6px_0px_0px_#F3F5F9] h-full -translate-y-[-50%] flex-1"})]})}),SX=T.memo(TX);function XS(t){const e=window.AudioContext||window.webkitAudioContext,n=new e,r=(s,o)=>{const l=n.createOscillator(),c=n.createGain();l.type="sine",l.frequency.setValueAtTime(o,s),c.gain.setValueAtTime(.5,s),c.gain.exponentialRampToValueAtTime(.001,s+.15),l.connect(c),c.connect(n.destination),l.start(s),l.stop(s+.15)},i=n.currentTime;if(t){r(i,660),r(i+.2,880);return}r(i,880),r(i+.2,660)}const _X=()=>{const t=T.useRef(null),e=T.useRef(null),n=T.useRef(null),r=T.useRef(null),[i,s]=T.useState(""),[o,l]=T.useState(0),[c,d]=T.useState([]),[f,p]=T.useState(!1),[m,g]=T.useState(!1),[x,v]=T.useState(""),[S,C]=T.useState(!0),{openQuestionDialog:A,closeQuestionDialog:k}=tG(),[M,F]=T.useState(!1),[I,D]=T.useState(null),[G,X]=T.useState(null),[P,Y]=T.useState(!1),[z,ie]=T.useState({}),[Z,ee]=T.useState(!1),[ae,de]=lt(SF),[j]=lt(tp),[W,O]=lt(As),[U]=lt(oa),[Q,R]=lt(zE),[,oe]=lt(TF),[,pe]=lt(rp),[ue,J]=T.useState([]),he=T.useRef(null),[_e,ke]=T.useState(0),Ve=T.useCallback(()=>{ke(Re=>Re+1)},[]),ot=T.useCallback(()=>{he.current&&(he.current.close(),he.current=null)},[]),qe=T.useRef(0),kt=T.useRef(null);T.useEffect(()=>{if(!W?.id||W?.id===Hi)return;he.current&&he.current.close(),kt.current!==W.id&&(J([]),qe.current=0,kt.current=W.id);const Me=`${lo}/sessions/${W.id}/events?sse=true&min_offset=${qe.current}&wait_for_data=60`,Ge=new EventSource(Me);return he.current=Ge,Ge.onmessage=Ke=>{try{const bt=JSON.parse(Ke.data);bt.offset!==void 0&&(qe.current=Math.max(qe.current,bt.offset+1)),J(vt=>[...vt,bt])}catch(bt){console.error("Error parsing SSE event:",bt)}},Ge.onerror=()=>{Ge.close(),he.current=null,setTimeout(()=>{ke(Ke=>Ke+1)},1e3)},()=>{Ge.close(),he.current=null}},[W?.id,_e]);const fn=()=>{s(""),l(0),d([]),p(!1),D(null)},nt=Re=>(Me,Ge)=>{const Ke=Re===c.length-1,bt=c[Re].offset;if(Ke)return D(null),Ct(Re,Me,bt,Ge);A("Are you sure?","Resending this message would cause all of the following messages in the session to disappear.",[{text:"Resend Anyway",onClick:()=>{D(null),k(),Ct(Re,Me,bt,Ge)},isMainAction:!0}])},Yt=Re=>Me=>{const Ge=Re===c.length-1,Ke=c.slice(0,Re+1),bt=Ke.findLastIndex($t=>$t.source==="customer"&&$t.kind==="message"),jt=Ke[bt]?.offset??c.length-1;if(Ge)return D(null),Pn(bt,Me,jt);A("Are you sure?","Regenerating this message would cause all of the following messages in the session to disappear.",[{text:"Regenerate Anyway",onClick:()=>{D(null),k(),Pn(bt,Me,jt)},isMainAction:!0}])},Ct=async(Re,Me,Ge,Ke)=>{const bt=c[Re],vt=await JS(`sessions/${Me}/events?min_offset=${Ge}`).catch(jt=>({error:jt}));if(vt?.error){Ir.error(vt.error.message||vt.error);return}ot?.(),l(Ge),d(jt=>jt.slice(0,Re)),ye(Ke??bt.data?.message)},Pn=async(Re,Me,Ge)=>{Ct(Re,Me,Ge)},Fn=()=>{if(W?.id===Hi)return;const Re=ue?.at(-1),Me=ue?.findLast(Dt=>Dt.kind==="status");if(!Re)return;const Ge=Re?.offset;(Ge||Ge===0)&&l(Ge+1);const Ke=mB(ue||[],Dt=>Dt?.trace_id.split("::")[0]),bt=ue?.filter(Dt=>Dt.kind==="message")||[],vt=bt.map((Dt,$t)=>{const qt={...Dt},V=Ke?.[Dt.trace_id.split("::")[0]]?.at(-1)?.data;return qt.serverStatus=V?.status||(bt[$t+1]?"ready":null),qt.serverStatus==="error"&&(qt.error=V?.data?.exception),qt});d(Dt=>{const $t=Dt.findLast(V=>V.source==="customer");if($t?.source==="customer"&&Ke?.[$t?.trace_id]&&($t.serverStatus=Ke[$t.trace_id].at(-1)?.data?.status||$t.serverStatus,$t.serverStatus==="error"&&($t.error=Ke[$t.trace_id].at(-1)?.data?.data?.exception)),!vt?.length)return[...Dt];ae?.data?.message&&de(NA());const qt=[];for(const V of[Dt,vt])for(const te of V)qt[te.offset]=te;return qt.filter(V=>V)});const jt=Me?.data?.status,fr=bt.some(Dt=>Dt?.data?.chunks!==void 0);bt?.length&&(m||f)&&XS(!0),jt?(g(jt==="processing"),jt==="processing"&&v(Me?.data?.data?.stage??"Thinking"),p(jt==="typing"&&!fr)):fr&&p(!1),J([])},on=()=>{t?.current?.scrollIntoView?.({behavior:S?"instant":"smooth"}),t?.current&&S&&C(!1)},dr=()=>{C(!0),Q&&W?.id!==Hi&&R(null),fn(),n?.current?.focus()},Mn=async()=>{const Me=(await a_("Parlant-flags","message_flags","sessionIndex",W?.id,{name:"sessionIndex",keyPath:"sessionId"})).reduce((Ge,Ke)=>(Ge[Ke.traceId]=Ke.flagValue,Ge),{});ie(Me)};T.useEffect(()=>{Mn()},[W?.id,Z]),T.useEffect(()=>{ooe(I),[I]),T.useEffect(Fn,[ue]),T.useEffect(on,[c?.length,ae,S]),T.useEffect(dr,[W?.id]),T.useEffect(()=>{(m||f)&&t?.current?.scrollIntoView({behavior:"smooth"})},[m,f]),T.useEffect(()=>{j&&U?.id&&X(!j?.find(Re=>Re.id===U?.id))},[j,U?.id]);const Qn=Re=>{const Me=Re?.data?.chunks;return Me===void 0?!1:Me.length===0?!0:Me[Me.length-1]!==null},li=T.useRef(new Map);T.useEffect(()=>{if(!W?.id||W?.id===Hi)return;const Re=c.filter(Qn),Me=li.current;for(const[Ge,Ke]of Me)Re.some(vt=>vt.id===Ge)||(Ke.close(),Me.delete(Ge));for(const Ge of Re){if(!Ge.id||Me.has(Ge.id))continue;const Ke=new EventSource(`${lo}/sessions/${W.id}/events/${Ge.id}?sse=true`);Ke.onmessage=bt=>{try{const vt=JSON.parse(bt.data);d(fr=>fr.map(Dt=>Dt.id===Ge.id?{...Dt,data:{...Dt.data,...vt.data}}:Dt));const jt=vt?.data?.chunks;jt&&jt.length>0&&jt[jt.length-1]===null&&(Ke.close(),Me.delete(Ge.id))}catch(vt){console.error("Error parsing SSE event:",vt)}},Ke.onerror=bt=>{console.error("SSE connection error:",bt),Ke.close(),Me.delete(Ge.id)},Me.set(Ge.id,Ke)}return()=>{for(const Ge of Me.values())Ge.close();Me.clear()}},[c,W?.id]);const ce=async()=>{if(!Q)return;const{customer_id:Re,title:Me}=Q;return dv("sessions?allow_greeting=false",{customer_id:Re,agent_id:U?.id,title:Me}).then(Ge=>(Q&&(O(Ge),R(null)),pe(Ke=>[...Ke,Ge]),Ge)).catch(()=>{Ir.error("Something went wrong")})},ye=async Re=>{de(Ke=>({...Ke,sessionId:W?.id,data:{message:Re}})),s("");const Me=Q?(await ce())?.id:W?.id;dv(`sessions/${Me}/events?moderation=${M?"auto":"none"}`,{kind:"message",message:Re,source:"customer"}).then(()=>{XS(),Ve()}).catch(()=>Ir.error("Something went wrong"))},Qe=Re=>{Re.key==="Enter"&&!Re.shiftKey?(Re.preventDefault(),e?.current?.click()):Re.key==="Enter"&&Re.shiftKey&&Re.preventDefault()},ut=W?.id===Hi&&!ae?.id||W?.id!==Hi&&ae?.sessionId===W?.id,rt=(!c?.length||ut)&&ae?.data?.message?[...c,ae]:c,an=rt.some(Re=>{const Me=Re?.data?.chunks;return Me!==void 0&&(Me.length===0||Me[Me.length-1]!==null)}),Zn=Re=>Me=>{Me.index=Re,D(Me.id===I?.id?null:Me)};return w.jsx(w.Fragment,{children:w.jsxs("div",{ref:r,className:Xe("flex items-center h-full w-full bg-white gap-[14px] rounded-[10px]",I&&"bg-green-light"),children:[w.jsx("div",{className:Xe("h-full w-full pb-[14px] pt-[10px] rounded-[10px] flex flex-col transition-all duration-500 bg-white",I&&"w-[calc(100%-min(700px,35vw))]"),children:w.jsx("div",{className:"h-full flex flex-col rounded-[10px] m-auto w-full min-w-[unset]",children:w.jsxs("div",{className:Xe("flex flex-col rounded-es-[16px] rounded-ee-[16px] items-center bg-white mx-auto w-full flex-1 overflow-hidden"),children:[w.jsxs("div",{className:On("messages fixed-scroll flex-1 flex flex-col w-full pb-4 overflow-x-hidden"),"aria-live":"polite",role:"log","aria-label":"Chat messages",children:[rt.map((Re,Me)=>w.jsxs(we.Fragment,{children:[!Ev(c[Me-1]?.creation_utc,Re.creation_utc)&&w.jsx(SX,{date:Re.creation_utc,isFirst:!Me,bgColor:"bg-white"}),w.jsx("div",{ref:t,className:"flex snap-end flex-col max-w-[min(1020px,100%)] w-[1020px] self-center",children:w.jsx(eG,{flaggedChanged:()=>{ee(Ge=>!Ge)},flagged:z[Re.trace_id],isFirstMessageInDate:!Ev(c[Me-1]?.creation_utc,Re.creation_utc),isRegenerateHidden:!!G,event:Re,sameTraceMessages:rt.filter(Ge=>Ge.trace_id===Re.trace_id),isContinual:Re.trace_id===rt[Me-1]?.trace_id&&Re.source===rt[Me-1]?.source||Re.source==="customer"&&rt[Me-1]?.source==="customer",regenerateMessageFn:Yt(Me),resendMessageFn:nt(Me),showLogsForMessage:I,showLogs:Zn(Me)})})]},(Re.trace_id||0)+`${Me}`)),(f&&!an||m)&&w.jsxs("div",{ref:t,className:"flex snap-end max-w-[min(1020px,100%)] w-[1020px] self-center",children:[w.jsx("div",{className:"bubblesWrapper snap-end","aria-hidden":"true",children:w.jsx("div",{className:"bubbles"})}),f&&!an&&w.jsx("p",{className:Xe("flex items-center font-normal text-[#A9AFB7] text-[14px] font-inter"),children:"Typing..."}),m&&w.jsxs("p",{className:Xe("flex items-center font-normal text-[#A9AFB7] text-[14px] font-inter"),children:[x,"..."]})]})]}),w.jsxs("div",{className:Xe("w-full flex justify-between",G&&"hidden"),children:[w.jsx(Qa,{}),w.jsxs("div",{className:"group relative border flex-1 border-muted border-solid rounded-[10px] flex flex-row justify-center items-center bg-white p-[0.9rem] ps-[14px] pe-0 h-[48.67px] max-w-[1000px] mb-[26px]",children:[w.jsxs(rA,{open:P,onOpenChange:Y,children:[w.jsx(iA,{className:"outline-none","data-testid":"menu-button",tabIndex:-1,onClick:Re=>Re.stopPropagation(),children:w.jsxs("div",{className:Xe("me-[2px] border border-transparent hover:bg-[#F3F5F9] rounded-[6px] size-[25px] flex items-center justify-center",P&&"!bg-[#f5f6f8]"),children:[!M&&w.jsx("img",{src:"icons/edit.svg",alt:"",className:Xe("h-[14px] w-[14px]")}),M&&w.jsx(Vv,{className:On("size-[18px]")})]})}),w.jsxs(AE,{side:"top",align:"start",className:"max-w-[480px] -ms-[10px] flex flex-col gap-[8px] py-[14px] px-[10px] border-none [box-shadow:_0px_8px_20px_-8px_#00000012] rounded-[8px]",children:[w.jsxs(rh,{tabIndex:0,onClick:()=>F(!1),className:Xe("gap-0 cursor-pointer font-normal text-[14px] px-[10px] font-inter capitalize hover:!bg-[#FAF9FF]",!M&&"!bg-[#f5f6f8] hover:!bg-[#f5f6f8]"),children:[w.jsx("img",{src:"icons/edit.svg",alt:"",className:Xe("me-[8px] size-[15px]")}),"Direct (No Moderation)"]}),w.jsxs(rh,{tabIndex:0,onClick:()=>F(!0),className:Xe("gap-0 !cursor-pointer font-normal text-[14px] items-start px-[10px] font-inter hover:!bg-[#FAF9FF]",M&&"!bg-[#f5f6f8] hover:!bg-[#f5f6f8]"),children:[w.jsx(Vv,{className:"me-[8px] !size-[17px] mt-[3px]"}),w.jsxs("div",{children:[w.jsx("div",{children:"Content Moderation"}),w.jsx("small",{className:"font-light",children:"Messages will be flagged for harmful or illicit content and censored accordingly. The agent will see such messages were sent and the reason why they were censored, but it won't see their content."})]})]})]})]}),w.jsx(ip,{role:"textbox",ref:n,placeholder:"Message...",value:i,onKeyDown:Qe,onChange:Re=>s(Re.target.value),rows:1,className:"box-shadow-none placeholder:text-[#282828] resize-none border-none h-full rounded-none min-h-[unset] p-0 whitespace-nowrap no-scrollbar font-inter font-light text-[16px] leading-[100%] bg-white"}),w.jsx(An,{variant:"ghost","data-testid":"submit-button",className:"max-w-[60px] rounded-full hover:bg-white",ref:e,disabled:!i?.trim()||!U?.id,onClick:()=>ye(i),children:w.jsx("img",{src:"icons/send.svg",alt:"Send",height:19.64,width:21.52,className:"h-10"})})]}),w.jsx(Qa,{})]}),w.jsxs("div",{className:"w-full",children:[w.jsx(Qa,{}),w.jsx("div",{}),w.jsx(Qa,{})]})]})})}),w.jsx(HA,{component:w.jsx("div",{className:"flex h-full min-w-[50%] justify-center items-center text-[20px]",children:"Failed to load logs"}),children:w.jsx("div",{className:Xe("fixed top-0 left-[unset] h-full right-0 z-[99] bg-white translate-x-[100%] max-w-[min(700px,35vw)] [box-shadow:0px_0px_30px_0px_#0000001F] w-[min(700px,35vw)] [transition-duration:600ms]",I&&"translate-x-0"),children:I&&w.jsx(wX,{flaggedChanged:()=>{ee(Re=>!Re)},sameTraceMessages:rt.filter(Re=>Re.trace_id===I.trace_id),event:I,regenerateMessageFn:I?.index?Yt(I.index):void 0,resendMessageFn:I?.index||I?.index===0?nt(I.index):void 0,closeLogs:()=>D(null)})})})]})})},CX=T.createContext({}),AX=()=>{const[t,e]=T.useState("");return w.jsxs("div",{className:"bg-white [box-shadow:0px_0px_25px_0px_#0000000A] h-full rounded-[16px] overflow-hidden border-solid w-[352px] min-w-[352px] max-mobile:hidden z-[11] ",children:[w.jsx(FA,{setFilterSessionVal:e,filterSessionVal:t}),w.jsx(UA,{filterSessionVal:t})]})};function kX(){const[t,e]=T.useState(""),{openDialog:n,DialogComponent:r,closeDialog:i}=zA(),[s,o]=T.useState(!1),[l]=lt(rp),[c,d]=lt(As),[,f]=lt(ws),[p,m]=T.useState(""),[,g]=lt(oa),[x]=lt(ws);T.useEffect(()=>{l&&o(!!l.length),setTimeout(()=>{o(!0)},500)},[l]),T.useEffect(()=>{if(c?.id)if(c?.id===ah)e("Parlant | New Session");else{const S=c?.title;S&&e(`Parlant | ${S}`)}else e("Parlant")},[c?.id]),T.useEffect(()=>{f({openDialog:n,closeDialog:i})},[]);const v=()=>{d(null),g(null),x.openDialog("",w.jsx(RA,{}),{height:"536px",width:"604px"})};return w.jsxs(HA,{children:[w.jsxs(CX.Provider,{value:{},children:[w.jsx(V0,{defaultTitle:`${t}`}),w.jsxs("div",{"data-testid":"chatbot",className:"main bg-green-light h-screen flex flex-col rounded-[16px]",children:[w.jsx("div",{className:"hidden max-mobile:block rounded-[16px]",children:w.jsx(FA,{setFilterSessionVal:m,filterSessionVal:p})}),w.jsxs("div",{className:Xe("flex bg-green-light flex-1 gap-[14px] w-full overflow-auto flex-row py-[14px] px-[14px]"),children:[w.jsx(AX,{}),c?.id?w.jsx("div",{className:"h-full w-[calc(100vw-352px-40px)] bg-white rounded-[16px] max-w-[calc(100vw-352px-40px)] max-[800px]:max-w-full max-[800px]:w-full ",children:w.jsx(_X,{})}):w.jsxs("div",{className:"flex-1 flex flex-col gap-[27px] items-center justify-center",children:[w.jsx("img",{className:"pointer-events-none",src:"select-session.svg",fetchPriority:"high",alt:""}),w.jsxs("div",{className:"text-[#3C8C71] select-none font-light text-[18px] flex flex-col gap-[10px] items-center",children:[s&&!l.length?"Start a session to begin chatting":"Select or start a session to begin chatting",w.jsxs("div",{className:"group",children:[w.jsx("img",{src:"buttons/new-session.svg",alt:"add session",className:"shadow-main cursor-pointer group-hover:hidden w-[76px]",tabIndex:1,role:"button",onKeyDown:vs,onClick:v}),w.jsx("img",{src:"buttons/new-session-hover.svg",alt:"add session",className:"shadow-main cursor-pointer hidden group-hover:block w-[76px]",tabIndex:1,role:"button",onKeyDown:vs,onClick:v})]})]})]})]})]})]}),w.jsx(r,{})]})}const NX=(t,e,n,r)=>{const[i,s]=T.useState(!1),[o,l]=T.useState(null),[c,d]=T.useState(!1),f=T.useRef(null),p=T.useCallback(v=>{f.current&&f.current.readyState===WebSocket.OPEN?f.current.send(v):console.warn("WebSocket is not open. Unable to send message:",v)},[]),m=()=>{g(),setTimeout(()=>{(!f?.current?.readyState||!{[f.current.OPEN]:!0,[f.current?.CONNECTING]:!0}[f.current.readyState])&&m()},5e3)};T.useEffect(()=>{g()},[]);const g=T.useCallback(()=>{if(c||f.current?.readyState!=null&&{[f.current.OPEN]:!0,[f.current?.CONNECTING]:!1}[f.current.readyState]){console.warn("WebSocket is already running.");return}(f.current&&f.current.readyState===f.current.OPEN||f.current&&f.current.readyState===f.current?.CONNECTING)&&f.current.close();const v=new WebSocket(t);f.current=v,v.addEventListener("open",()=>{s(!0)}),v.addEventListener("message",S=>{const C=JSON.parse(S.data||"{}");l(S.data),r?.(C)}),v.addEventListener("error",S=>{console.error("WebSocket error:",S)}),v.addEventListener("close",S=>{console.info("WebSocket closed:",S),s(!1),setTimeout(()=>{f?.current?.readyState===0||f?.current?.readyState===1||m()},5e3)}),d(!0)},[t,n,c]),x=T.useCallback(()=>{f.current&&(f.current.close(),f.current=null),s(!1),d(!1)},[]);return T.useEffect(()=>()=>{f.current&&f.current.close()},[]),{isConnected:i,lastMessage:o,sendMessage:p,start:g,pause:x,isRunning:c}},RX=()=>(NX(`${lo}/logs`,!0,null,iG),w.jsx("div",{}));function IX(){return w.jsxs("div",{className:"bg-green-light",children:[w.jsx(kX,{}),w.jsx(RX,{})]})}var QS=["light","dark"],OX="(prefers-color-scheme: dark)",MX=T.createContext(void 0),DX={setTheme:t=>{},themes:[]},LX=()=>{var t;return(t=T.useContext(MX))!=null?t:DX};T.memo(({forcedTheme:t,storageKey:e,attribute:n,enableSystem:r,enableColorScheme:i,defaultTheme:s,value:o,attrs:l,nonce:c})=>{let d=s==="system",f=n==="class"?`var d=document.documentElement,c=d.classList;${`c.remove(${l.map(x=>`'${x}'`).join(",")})`};`:`var d=document.documentElement,n='${n}',s='setAttribute';`,p=i?QS.includes(s)&&s?`if(e==='light'||e==='dark'||!e)d.style.colorScheme=e||'${s}'`:"if(e==='light'||e==='dark')d.style.colorScheme=e":"",m=(x,v=!1,S=!0)=>{let C=o?o[x]:x,A=v?x+"|| ''":`'${C}'`,k="";return i&&S&&!v&&QS.includes(x)&&(k+=`d.style.colorScheme = '${x}';`),n==="class"?v||C?k+=`c.add(${A})`:k+="null":C&&(k+=`d[s](n,${A})`),k},g=t?`!function(){${f}${m(t)}}()`:r?`!function(){try{${f}var e=localStorage.getItem('${e}');if('system'===e||(!e&&${d})){var t='${OX}',m=window.matchMedia(t);if(m.media!==t||m.matches){${m("dark")}}else{${m("light")}}}else if(e){${o?`var x=${JSON.stringify(o)};`:""}${m(o?"x[e]":"e",!0)}}${d?"":"else{"+m(s,!1,!1)+"}"}${p}}catch(e){}}()`:`!function(){try{${f}var e=localStorage.getItem('${e}');if(e){${o?`var x=${JSON.stringify(o)};`:""}${m(o?"x[e]":"e",!0)}}else{${m(s,!1,!1)};}${p}}catch(t){}}();`;return T.createElement("script",{nonce:c,dangerouslySetInnerHTML:{__html:g}})});const PX=({...t})=>{const{theme:e="system"}=LX();return w.jsx(bD,{theme:e,className:"toaster group",toastOptions:{classNames:{toast:"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",description:"group-[.toast]:text-muted-foreground",actionButton:"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",cancelButton:"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"}},...t})};jM.createRoot(document.getElementById("root")).render(w.jsxs(T.StrictMode,{children:[w.jsx(IX,{}),w.jsx(PX,{position:"bottom-center",toastOptions:{className:"rounded-full w-fit px-[34px] !bg-[#006E54] text-white"},className:"mb-[80px] transition-none animate-none rounded-full"})]})); diff --git a/src/parlant/api/chat/dist/assets/index-DIdtHchq.css b/src/parlant/api/chat/dist/assets/index-DIdtHchq.css new file mode 100644 index 0000000..d42bacf --- /dev/null +++ b/src/parlant/api/chat/dist/assets/index-DIdtHchq.css @@ -0,0 +1 @@ +@import"https://fonts.googleapis.com/css2?family=Ubuntu+Sans:ital,wght@0,100..800;1,100..800&display=swap";#root{height:100vh;margin:auto;font-family:Inter}body{pointer-events:all!important}.fixed-scroll{overflow:scroll;scrollbar-width:thin;scrollbar-color:#ebecf0 transparent}.fixed-scroll:hover{scrollbar-color:#cdcdcd transparent}.fixed-scroll::-webkit-scrollbar{width:10px}.fixed-scroll::-webkit-scrollbar-thumb{background-color:#00000080;border-radius:10px}.fixed-scroll::-webkit-scrollbar-track{background:transparent}.markdown *{font-size:revert;font-weight:revert;padding:revert;margin:revert;list-style-type:revert;color:revert;-webkit-text-decoration:revert;text-decoration:revert}img{-webkit-user-select:none;-moz-user-select:none;user-select:none}.bubblesWrapper{height:-moz-fit-content;height:fit-content;width:-moz-fit-content;width:fit-content;background-color:#f5f9f7;padding:10px;margin:10px;margin-inline-start:20px;border-radius:15px}.bubbles{height:15px;width:31px;aspect-ratio:2.5;--_g: no-repeat radial-gradient(farthest-side, #333333 90%, #0000);background:var(--_g),var(--_g),var(--_g);background-size:25% 50%;animation:l43 1s infinite linear}@keyframes l43{0%{background-position:0% 50%,50% 50%,100% 50%}20%{background-position:0% 0,50% 50%,100% 50%}40%{background-position:0% 100%,50% 0,100% 50%}60%{background-position:0% 50%,50% 100%,100% 0}80%{background-position:0% 50%,50% 50%,100% 100%}to{background-position:0% 50%,50% 50%,100% 50%}}@keyframes animate-slide-down{0%{max-height:0}to{max-height:300px;min-height:-moz-fit-content;min-height:fit-content}}@keyframes animate-slide-up{0%{max-height:150px}to{max-height:0}}.animate-slide-down{animation:animate-slide-down .5s ease-out forwards}.animate-slide-up{animation:animate-slide-up .3s linear forwards}._editSession_1nfqv_1{position:relative}._editSession_1nfqv_1:before{content:"";position:absolute;top:50%;left:50%;border:1px solid black;pointer-events:none;box-sizing:border-box;height:calc(100% - 4px);width:calc(100% - 8px);transform:translate(-50%,-50%);border-radius:6px}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}._pendingVideo_n2mv1_1{clip-path:inset(1px .9px .5px .8px round 50%)}._markdown_n2mv1_5 code{white-space:break-spaces;max-width:100%;word-break:break-word;background:transparent!important;font-size:14px}._markdown_n2mv1_5 p{word-break:break-word}._markdown_n2mv1_5 ul{all:revert;margin:0;padding:0;list-style:inside}._markdown_n2mv1_5 h2{font-weight:700}._markdown_n2mv1_5 table{white-space:nowrap;display:block;overflow:scroll;scrollbar-width:auto;border-radius:2px}._markdown_n2mv1_5 table th,._markdown_n2mv1_5 table td{padding-inline:10px;text-align:start}._markdown_n2mv1_5 table th{padding:10px}._markdown_n2mv1_5 table tr:last-child td{padding-bottom:10px}._markdown_n2mv1_5 table thead{border:1px solid lightgray;border-bottom:none;border-radius:3px 3px 0 0;padding:10px}._markdown_n2mv1_5 table tbody{border:1px solid lightgray;border-top:none;border-radius:0 0 3px 3px;padding:10px}._markdown_n2mv1_5 li>div{display:inline}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:100;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:200;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:300;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:400;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:500;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:600;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:700;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf) format("truetype")}@font-face{font-family:Ubuntu Sans;font-style:normal;font-weight:800;src:url(/chat/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:100;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:200;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:300;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:400;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:500;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:600;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:700;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:800;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf) format("truetype")}@font-face{font-family:Ubuntu Mono;font-style:normal;font-weight:900;src:url(/chat/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:100;src:url(/chat/fonts/Inter/static/Inter_28pt-Thin.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:200;src:url(/chat/fonts/Inter/static/Inter_28pt-Thin.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:300;src:url(/chat/fonts/Inter/static/Inter_28pt-Light.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:400;src:url(/chat/fonts/Inter/static/Inter_28pt-Regular.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:500;src:url(/chat/fonts/Inter/static/Inter_28pt-Medium.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:600;src:url(/chat/fonts/Inter/static/Inter_28pt-SemiBold.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:700;src:url(/chat/fonts/Inter/static/Inter_28pt-Bold.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:800;src:url(/chat/fonts/Inter/static/Inter_28pt-ExtraBold.ttf) format("truetype")}@font-face{font-family:Inter;font-style:normal;font-weight:900;src:url(/chat/fonts/Inter/static/Inter_28pt-ExtraBold.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:100;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:200;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:300;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:400;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:500;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:600;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:700;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:800;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf) format("truetype")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-weight:900;src:url(/chat/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf) format("truetype")}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--main: #fbfbfb;--background: 0 0% 100%;--foreground: 0 0% 3.9%;--card: 0 0% 100%;--card-foreground: 0 0% 3.9%;--popover: 0 0% 100%;--popover-foreground: 0 0% 3.9%;--primary: 0 0% 9%;--primary-foreground: 0 0% 98%;--secondary: 0 0% 96.1%;--secondary-foreground: 0 0% 9%;--muted: 0 0% 96.1%;--muted-foreground: 0 0% 45.1%;--accent: 0 0% 96.1%;--accent-foreground: 0 0% 9%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 0 0% 98%;--border: 0 0% 89.8%;--input: 0 0% 89.8%;--ring: 0 0% 3.9%;--chart-1: 12 76% 61%;--chart-2: 173 58% 39%;--chart-3: 197 37% 24%;--chart-4: 43 74% 66%;--chart-5: 27 87% 67%;--radius: .5rem}.dark{--main: rgb(1, 37, 21)}*{border-color:hsl(var(--border))}*{border-color:hsl(var(--border));outline-color:hsl(var(--ring) / .5)}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:801px){.container{max-width:801px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1080px){.container{max-width:1080px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.\!pointer-events-auto{pointer-events:auto!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.-bottom-\[3px\]{bottom:-3px}.-top-\[1px\]{top:-1px}.bottom-0{bottom:0}.bottom-\[-1px\]{bottom:-1px}.left-0{left:0}.left-2{left:.5rem}.left-\[-1px\]{left:-1px}.left-\[24px\]{left:24px}.left-\[34px\]{left:34px}.left-\[50\%\]{left:50%}.left-\[unset\]{left:unset}.right-0{right:0}.right-4{right:1rem}.right-\[-1px\]{right:-1px}.right-\[10px\]{right:10px}.right-\[1px\]{right:1px}.top-0{top:0}.top-4{top:1rem}.top-\[-1px\]{top:-1px}.top-\[10px\]{top:10px}.top-\[38px\]{top:38px}.top-\[50\%\]{top:50%}.top-\[8px\]{top:8px}.z-0{z-index:0}.z-10{z-index:10}.z-50{z-index:50}.z-\[11\]{z-index:11}.z-\[1\]{z-index:1}.z-\[999999\]{z-index:999999}.z-\[999\]{z-index:999}.z-\[99\]{z-index:99}.m-auto{margin:auto}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-0{margin-left:0;margin-right:0}.mx-\[10px\]{margin-left:10px;margin-right:10px}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-\[5px\]{margin-top:5px;margin-bottom:5px}.\!ms-\[12px\]{margin-inline-start:12px!important}.\!mt-0{margin-top:0!important}.-mb-\[10px\]{margin-bottom:-10px}.-mb-\[7px\]{margin-bottom:-7px}.-me-\[6px\]{margin-inline-end:-6px}.-ms-\[10px\]{margin-inline-start:-10px}.mb-1{margin-bottom:.25rem}.mb-\[10px\]{margin-bottom:10px}.mb-\[12px\]{margin-bottom:12px}.mb-\[14px\]{margin-bottom:14px}.mb-\[16px\]{margin-bottom:16px}.mb-\[1px\]{margin-bottom:1px}.mb-\[26px\]{margin-bottom:26px}.mb-\[80px\]{margin-bottom:80px}.me-4{margin-inline-end:1rem}.me-\[10px\]{margin-inline-end:10px}.me-\[14px\]{margin-inline-end:14px}.me-\[18px\]{margin-inline-end:18px}.me-\[20px\]{margin-inline-end:20px}.me-\[2px\]{margin-inline-end:2px}.me-\[30px\]{margin-inline-end:30px}.me-\[3px\]{margin-inline-end:3px}.me-\[5px\]{margin-inline-end:5px}.me-\[6px\]{margin-inline-end:6px}.me-\[8px\]{margin-inline-end:8px}.ml-0{margin-left:0}.ml-\[1px\]{margin-left:1px}.ml-\[23px\]{margin-left:23px}.ml-auto{margin-left:auto}.mr-0{margin-right:0}.ms-\[24px\]{margin-inline-start:24px}.ms-\[30px\]{margin-inline-start:30px}.ms-\[4px\]{margin-inline-start:4px}.ms-\[6px\]{margin-inline-start:6px}.ms-\[8px\]{margin-inline-start:8px}.mt-24{margin-top:6rem}.mt-\[0\]{margin-top:0}.mt-\[10px\]{margin-top:10px}.mt-\[24px\]{margin-top:24px}.mt-\[26px\]{margin-top:26px}.mt-\[30px\]{margin-top:30px}.mt-\[3px\]{margin-top:3px}.mt-\[40px\]{margin-top:40px}.mt-\[46px\]{margin-top:46px}.mt-\[4px\]{margin-top:4px}.mt-\[9px\]{margin-top:9px}.mt-auto{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.\!size-\[17px\]{width:17px!important;height:17px!important}.size-\[14px\]{width:14px;height:14px}.size-\[15px\]{width:15px;height:15px}.size-\[16px\]{width:16px;height:16px}.size-\[18px\]{width:18px;height:18px}.size-\[25px\]{width:25px;height:25px}.size-\[26px\]{width:26px;height:26px}.size-\[28px\]{width:28px;height:28px}.size-\[30px\]{width:30px;height:30px}.size-\[330px\]{width:330px;height:330px}.size-\[36px\]{width:36px;height:36px}.size-\[38px\]{width:38px;height:38px}.size-\[44px\]{width:44px;height:44px}.h-0{height:0px}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-9{height:2.25rem}.h-\[-webkit-fill-available\]{height:-webkit-fill-available}.h-\[100\%\]{height:100%}.h-\[120px\]{height:120px}.h-\[14px\]{height:14px}.h-\[1em\]{height:1em}.h-\[20px\]{height:20px}.h-\[21px\]{height:21px}.h-\[24px\]{height:24px}.h-\[28px\]{height:28px}.h-\[30px\]{height:30px}.h-\[32px\]{height:32px}.h-\[34px\]{height:34px}.h-\[35px\]{height:35px}.h-\[36px\]{height:36px}.h-\[38px\]{height:38px}.h-\[39px\]{height:39px}.h-\[46px\]{height:46px}.h-\[47px\]{height:47px}.h-\[48\.67px\]{height:48.67px}.h-\[48px\]{height:48px}.h-\[54px\]{height:54px}.h-\[58px\]{height:58px}.h-\[60px\]{height:60px}.h-\[70px\]{height:70px}.h-\[74px\]{height:74px}.h-\[78px\]{height:78px}.h-\[80\%\]{height:80%}.h-\[80px\]{height:80px}.h-\[calc\(100\%-12px\)\]{height:calc(100% - 12px)}.h-\[calc\(100\%-4px\)\]{height:calc(100% - 4px)}.h-\[calc\(100\%-60px\)\]{height:calc(100% - 60px)}.h-\[calc\(100\%-68px\)\]{height:calc(100% - 68px)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-\[200px\]{max-height:200px}.max-h-\[28px\]{max-height:28px}.max-h-\[300px\]{max-height:300px}.max-h-\[308px\]{max-height:308px}.max-h-\[30px\]{max-height:30px}.max-h-\[50\%\]{max-height:50%}.min-h-0{min-height:0px}.min-h-\[14px\]{min-height:14px}.min-h-\[26px\]{min-height:26px}.min-h-\[28px\]{min-height:28px}.min-h-\[30px\]{min-height:30px}.min-h-\[40px\]{min-height:40px}.min-h-\[42px\]{min-height:42px}.min-h-\[48px\]{min-height:48px}.min-h-\[50px\]{min-height:50px}.min-h-\[58px\]{min-height:58px}.min-h-\[60px\]{min-height:60px}.min-h-\[70px\]{min-height:70px}.min-h-\[74px\]{min-height:74px}.min-h-\[78px\]{min-height:78px}.min-h-\[80px\]{min-height:80px}.min-h-\[unset\]{min-height:unset}.\!w-fit{width:-moz-fit-content!important;width:fit-content!important}.w-10{width:2.5rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-9{width:2.25rem}.w-\[1020px\]{width:1020px}.w-\[12px\]{width:12px}.w-\[130px\]{width:130px}.w-\[14px\]{width:14px}.w-\[161px\]{width:161px}.w-\[168px\]{width:168px}.w-\[16px\]{width:16px}.w-\[246px\]{width:246px}.w-\[24px\]{width:24px}.w-\[28px\]{width:28px}.w-\[2px\]{width:2px}.w-\[352px\]{width:352px}.w-\[36px\]{width:36px}.w-\[560px\]{width:560px}.w-\[600px\]{width:600px}.w-\[68px\]{width:68px}.w-\[73px\]{width:73px}.w-\[76px\]{width:76px}.w-\[79px\]{width:79px}.w-\[84px\]{width:84px}.w-\[86px\]{width:86px}.w-\[95px\]{width:95px}.w-\[96px\]{width:96px}.w-\[calc\(100\%-412px\)\]{width:calc(100% - 412px)}.w-\[calc\(100\%-4px\)\]{width:calc(100% - 4px)}.w-\[calc\(100\%-min\(700px\,35vw\)\)\]{width:calc(100% - min(700px,35vw))}.w-\[calc\(100vw-352px-40px\)\]{width:calc(100vw - 392px)}.w-\[min\(700px\,35vw\)\]{width:min(700px,35vw)}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-\[12px\]{min-width:12px}.min-w-\[14px\]{min-width:14px}.min-w-\[16px\]{min-width:16px}.min-w-\[18px\]{min-width:18px}.min-w-\[200px\]{min-width:200px}.min-w-\[26px\]{min-width:26px}.min-w-\[28px\]{min-width:28px}.min-w-\[352px\]{min-width:352px}.min-w-\[50\%\]{min-width:50%}.min-w-\[86px\]{min-width:86px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[min\(1000px\,100\%\)\]{min-width:min(1000px,100%)}.min-w-\[min\(560px\,100\%\)\]{min-width:min(560px,100%)}.min-w-\[unset\]{min-width:unset}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.min-w-full{min-width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-\[-webkit-fill-available\]{max-width:-webkit-fill-available}.max-w-\[1000px\]{max-width:1000px}.max-w-\[200px\]{max-width:200px}.max-w-\[210px\]{max-width:210px}.max-w-\[320px\]{max-width:320px}.max-w-\[378px\]{max-width:378px}.max-w-\[480px\]{max-width:480px}.max-w-\[608px\]{max-width:608px}.max-w-\[60px\]{max-width:60px}.max-w-\[80\%\]{max-width:80%}.max-w-\[80vw\]{max-width:80vw}.max-w-\[90\%\]{max-width:90%}.max-w-\[95\%\]{max-width:95%}.max-w-\[calc\(100\%-25px\)\]{max-width:calc(100% - 25px)}.max-w-\[calc\(100vw-352px-40px\)\]{max-width:calc(100vw - 392px)}.max-w-\[min\(1000px\,100\%\)\]{max-width:min(1000px,100%)}.max-w-\[min\(1020px\,100\%\)\]{max-width:min(1020px,100%)}.max-w-\[min\(560px\,100\%\)\]{max-width:min(560px,100%)}.max-w-\[min\(560px\,90\%\)\]{max-width:min(560px,90%)}.max-w-\[min\(560px\,calc\(100\%-30px\)\)\]{max-width:min(560px,calc(100% - 30px))}.max-w-\[min\(700px\,35vw\)\]{max-width:min(700px,35vw)}.max-w-\[unset\]{max-width:unset}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.\!origin-top{transform-origin:top!important}.origin-bottom{transform-origin:bottom}.-translate-y-\[-50\%\]{--tw-translate-y: 50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-\[70px\]{--tw-translate-y: -70px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[100\%\]{--tw-translate-x: 100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[0px\]{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.animate-background-shift{animation:background-shift 5s linear infinite}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.animate-fade-in{animation:fade-in .3s linear}@keyframes fade-in-fast{0%{opacity:0;transform:translateY(6px) scale(.98);filter:blur(1px)}to{opacity:1;transform:translateY(0) scale(1);filter:blur(0)}}.animate-fade-in-fast{animation:fade-in-fast .4s ease-out}.animate-none{animation:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.\!cursor-pointer{cursor:pointer!important}.cursor-auto{cursor:auto}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.\!resize-none{resize:none!important}.resize-none{resize:none}.resize{resize:both}.snap-end{scroll-snap-align:end}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.\!justify-start{justify-content:flex-start!important}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-\[10px\]{gap:10px}.gap-\[12px\]{gap:12px}.gap-\[14px\]{gap:14px}.gap-\[16px\]{gap:16px}.gap-\[17px\]{gap:17px}.gap-\[20px\]{gap:20px}.gap-\[22px\]{gap:22px}.gap-\[27px\]{gap:27px}.gap-\[3px\]{gap:3px}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.gap-\[6px\]{gap:6px}.gap-\[7px\]{gap:7px}.gap-\[8px\]{gap:8px}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-visible{overflow-y:visible}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-ellipsis,.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.text-wrap{text-wrap:wrap}.text-nowrap{text-wrap:nowrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-\[12px\]{border-radius:12px}.rounded-\[14px\]{border-radius:14px}.rounded-\[16px\]{border-radius:16px}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[2px\]{border-radius:2px}.rounded-\[3px\]{border-radius:3px}.rounded-\[4px\]{border-radius:4px}.rounded-\[5px\]{border-radius:5px}.rounded-\[6\.5px\]{border-radius:6.5px}.rounded-\[6px\]{border-radius:6px}.rounded-\[7px\]{border-radius:7px}.rounded-\[8px\]{border-radius:8px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-s-\[16px\]{border-start-start-radius:16px;border-end-start-radius:16px}.rounded-br-none{border-bottom-right-radius:0}.rounded-ee-\[16px\]{border-end-end-radius:16px}.rounded-es-\[16px\]{border-end-start-radius:16px}.rounded-se-\[16px\]{border-start-end-radius:16px}.rounded-ss-\[16px\]{border-start-start-radius:16px}.\!border-0{border-width:0px!important}.border{border-width:1px}.border-2{border-width:2px}.border-\[0\.6px\]{border-width:.6px}.border-\[2px\]{border-width:2px}.border-\[6px\]{border-width:6px}.border-y-\[10px\]{border-top-width:10px;border-bottom-width:10px}.border-b{border-bottom-width:1px}.border-b-\[0\.6px\]{border-bottom-width:.6px}.border-b-\[12px\]{border-bottom-width:12px}.border-e{border-inline-end-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-0{border-top-width:0px}.border-solid{border-style:solid}.border-none{border-style:none}.\!border-black{--tw-border-opacity: 1 !important;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1))!important}.\!border-transparent{border-color:transparent!important}.border-\[\#9B0360\]{--tw-border-opacity: 1;border-color:rgb(155 3 96 / var(--tw-border-opacity, 1))}.border-\[\#EBECF0\]{--tw-border-opacity: 1;border-color:rgb(235 236 240 / var(--tw-border-opacity, 1))}.border-\[\#EDEFF3\]{--tw-border-opacity: 1;border-color:rgb(237 239 243 / var(--tw-border-opacity, 1))}.border-\[\#EEEEEE\]{--tw-border-opacity: 1;border-color:rgb(238 238 238 / var(--tw-border-opacity, 1))}.border-\[\#F3F5F9\]{--tw-border-opacity: 1;border-color:rgb(243 245 249 / var(--tw-border-opacity, 1))}.border-\[\#F5F9F7\]{--tw-border-opacity: 1;border-color:rgb(245 249 247 / var(--tw-border-opacity, 1))}.border-\[\#F9FAFC\]{--tw-border-opacity: 1;border-color:rgb(249 250 252 / var(--tw-border-opacity, 1))}.border-\[\#dedcdc\]{--tw-border-opacity: 1;border-color:rgb(222 220 220 / var(--tw-border-opacity, 1))}.border-\[\#ebecf0\]{--tw-border-opacity: 1;border-color:rgb(235 236 240 / var(--tw-border-opacity, 1))}.border-\[\#eeeeee\]{--tw-border-opacity: 1;border-color:rgb(238 238 238 / var(--tw-border-opacity, 1))}.border-black{--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-muted{--tw-border-opacity: 1;border-color:rgb(235 236 240 / var(--tw-border-opacity, 1))}.border-primary{border-color:hsl(var(--primary))}.border-transparent{border-color:transparent}.border-white{--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.border-b-\[\#EBECF0\],.border-b-\[\#ebecf0\]{--tw-border-opacity: 1;border-bottom-color:rgb(235 236 240 / var(--tw-border-opacity, 1))}.\!bg-\[\#006E54\]{--tw-bg-opacity: 1 !important;background-color:rgb(0 110 84 / var(--tw-bg-opacity, 1))!important}.\!bg-\[\#F5F6F8\]{--tw-bg-opacity: 1 !important;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))!important}.\!bg-\[\#FAFAFA\]{--tw-bg-opacity: 1 !important;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))!important}.\!bg-\[\#FDF2F1\]{--tw-bg-opacity: 1 !important;background-color:rgb(253 242 241 / var(--tw-bg-opacity, 1))!important}.\!bg-\[\#f5f6f8\]{--tw-bg-opacity: 1 !important;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))!important}.\!bg-gray-300{--tw-bg-opacity: 1 !important;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))!important}.\!bg-gray-4{--tw-bg-opacity: 1 !important;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))!important}.\!bg-white{--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))!important}.bg-\[\#006E53\]{--tw-bg-opacity: 1;background-color:rgb(0 110 83 / var(--tw-bg-opacity, 1))}.bg-\[\#EBECF0\]{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.bg-\[\#F2F0FC\]{--tw-bg-opacity: 1;background-color:rgb(242 240 252 / var(--tw-bg-opacity, 1))}.bg-\[\#F5F6F8\]{--tw-bg-opacity: 1;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))}.bg-\[\#F5F9F7\]{--tw-bg-opacity: 1;background-color:rgb(245 249 247 / var(--tw-bg-opacity, 1))}.bg-\[\#FAFAFA\]{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.bg-\[\#FBFBFB\]{--tw-bg-opacity: 1;background-color:rgb(251 251 251 / var(--tw-bg-opacity, 1))}.bg-\[\#ebecf0\]{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.bg-\[\#f0eeee\]{--tw-bg-opacity: 1;background-color:rgb(240 238 238 / var(--tw-bg-opacity, 1))}.bg-\[\#f5f5f9\]{--tw-bg-opacity: 1;background-color:rgb(245 245 249 / var(--tw-bg-opacity, 1))}.bg-\[\#f5f6f8\]{--tw-bg-opacity: 1;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))}.bg-background{background-color:hsl(var(--background))}.bg-black\/80{background-color:#000c}.bg-border{background-color:hsl(var(--border))}.bg-current{background-color:currentColor}.bg-destructive{background-color:hsl(var(--destructive))}.bg-gray-1{--tw-bg-opacity: 1;background-color:rgb(169 169 169 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-3{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.bg-green-light{--tw-bg-opacity: 1;background-color:rgb(245 249 247 / var(--tw-bg-opacity, 1))}.bg-green-main{--tw-bg-opacity: 1;background-color:rgb(0 110 83 / var(--tw-bg-opacity, 1))}.bg-main{background-color:var(--main)}.bg-muted{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-secondary{background-color:hsl(var(--secondary))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.fill-current{fill:currentColor}.\!p-\[4px_2px\]{padding:4px 2px!important}.p-0{padding:0}.p-1{padding:.25rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-\[0\.9rem\]{padding:.9rem}.p-\[10px\]{padding:10px}.p-\[13px_22px_17px_22px\]{padding:13px 22px 17px}.p-\[14px\]{padding:14px}.p-\[16px\]{padding:16px}.p-\[20px\]{padding:20px}.p-\[20px_22px_24px_22px\]{padding:20px 22px 24px}.p-\[5px\]{padding:5px}.p-\[5px_16px_7px_16px\]{padding:5px 16px 7px}.p-\[6px\]{padding:6px}.p-\[8px\]{padding:8px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[\.25em\]{padding-left:.25em;padding-right:.25em}.px-\[10px\]{padding-left:10px;padding-right:10px}.px-\[12px\]{padding-left:12px;padding-right:12px}.px-\[14px\]{padding-left:14px;padding-right:14px}.px-\[20px\]{padding-left:20px;padding-right:20px}.px-\[22px\]{padding-left:22px;padding-right:22px}.px-\[24px\]{padding-left:24px;padding-right:24px}.px-\[29\.5px\]{padding-left:29.5px;padding-right:29.5px}.px-\[2px\]{padding-left:2px;padding-right:2px}.px-\[34px\]{padding-left:34px;padding-right:34px}.px-\[39px\]{padding-left:39px;padding-right:39px}.px-\[8px\]{padding-left:8px;padding-right:8px}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-\[10px\]{padding-top:10px;padding-bottom:10px}.py-\[12px\]{padding-top:12px;padding-bottom:12px}.py-\[13px\]{padding-top:13px;padding-bottom:13px}.py-\[14px\]{padding-top:14px;padding-bottom:14px}.py-\[20px\]{padding-top:20px;padding-bottom:20px}.py-\[3px\]{padding-top:3px;padding-bottom:3px}.py-\[42px\]{padding-top:42px;padding-bottom:42px}.py-\[4px\]{padding-top:4px;padding-bottom:4px}.py-\[5px\]{padding-top:5px;padding-bottom:5px}.py-\[8px\]{padding-top:8px;padding-bottom:8px}.pb-0{padding-bottom:0}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-\[11px\]{padding-bottom:11px}.pb-\[14px\]{padding-bottom:14px}.pb-\[2px\]{padding-bottom:2px}.pb-\[4px\]{padding-bottom:4px}.pb-\[5px\]{padding-bottom:5px}.pb-\[8px\]{padding-bottom:8px}.pe-0{padding-inline-end:0px}.pe-\[108px\]{padding-inline-end:108px}.pe-\[10px\]{padding-inline-end:10px}.pe-\[12px\]{padding-inline-end:12px}.pe-\[14px\]{padding-inline-end:14px}.pe-\[18px\]{padding-inline-end:18px}.pe-\[20px\]{padding-inline-end:20px}.pe-\[38px\]{padding-inline-end:38px}.pe-\[6px\]{padding-inline-end:6px}.pe-\[8px\]{padding-inline-end:8px}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.ps-\[10px\]{padding-inline-start:10px}.ps-\[12px\]{padding-inline-start:12px}.ps-\[14px\]{padding-inline-start:14px}.ps-\[15px\]{padding-inline-start:15px}.ps-\[20px\]{padding-inline-start:20px}.ps-\[22px\]{padding-inline-start:22px}.ps-\[30px\]{padding-inline-start:30px}.ps-\[35px\]{padding-inline-start:35px}.ps-\[4px\]{padding-inline-start:4px}.ps-\[5px\]{padding-inline-start:5px}.ps-\[6px\]{padding-inline-start:6px}.ps-\[8px\]{padding-inline-start:8px}.pt-0{padding-top:0}.pt-\[10px\]{padding-top:10px}.pt-\[11px\]{padding-top:11px}.pt-\[1px\]{padding-top:1px}.pt-\[4px\]{padding-top:4px}.pt-\[6px\]{padding-top:6px}.text-center{text-align:center}.align-text-bottom{vertical-align:text-bottom}.font-ibm-plex-mono{font-family:IBM Plex Mono}.font-inter{font-family:inter}.font-ubuntu-mono{font-family:Ubuntu Mono}.\!text-\[13px\]{font-size:13px!important}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[8px\]{font-size:8px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.leading-\[100\%\]{line-height:100%}.leading-\[14px\]{line-height:14px}.leading-\[16px\]{line-height:16px}.leading-\[18px\]{line-height:18px}.leading-\[19px\]{line-height:19px}.leading-\[26px\]{line-height:26px}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.tracking-widest{letter-spacing:.1em}.\!text-\[\#282828\]{--tw-text-opacity: 1 !important;color:rgb(40 40 40 / var(--tw-text-opacity, 1))!important}.\!text-\[\#9B0360\]{--tw-text-opacity: 1 !important;color:rgb(155 3 96 / var(--tw-text-opacity, 1))!important}.\!text-\[\#a9a9a9\]{--tw-text-opacity: 1 !important;color:rgb(169 169 169 / var(--tw-text-opacity, 1))!important}.\!text-white{--tw-text-opacity: 1 !important;color:rgb(255 255 255 / var(--tw-text-opacity, 1))!important}.text-\[\#151515\]{--tw-text-opacity: 1;color:rgb(21 21 21 / var(--tw-text-opacity, 1))}.text-\[\#282828\]{--tw-text-opacity: 1;color:rgb(40 40 40 / var(--tw-text-opacity, 1))}.text-\[\#333\]{--tw-text-opacity: 1;color:rgb(51 51 51 / var(--tw-text-opacity, 1))}.text-\[\#3C8C71\]{--tw-text-opacity: 1;color:rgb(60 140 113 / var(--tw-text-opacity, 1))}.text-\[\#656565\]{--tw-text-opacity: 1;color:rgb(101 101 101 / var(--tw-text-opacity, 1))}.text-\[\#777\]{--tw-text-opacity: 1;color:rgb(119 119 119 / var(--tw-text-opacity, 1))}.text-\[\#959595\]{--tw-text-opacity: 1;color:rgb(149 149 149 / var(--tw-text-opacity, 1))}.text-\[\#A9A9A9\]{--tw-text-opacity: 1;color:rgb(169 169 169 / var(--tw-text-opacity, 1))}.text-\[\#A9AFB7\]{--tw-text-opacity: 1;color:rgb(169 175 183 / var(--tw-text-opacity, 1))}.text-\[\#AEB4BB\]{--tw-text-opacity: 1;color:rgb(174 180 187 / var(--tw-text-opacity, 1))}.text-\[\#CDCDCD\]{--tw-text-opacity: 1;color:rgb(205 205 205 / var(--tw-text-opacity, 1))}.text-\[\#a9a9a9\]{--tw-text-opacity: 1;color:rgb(169 169 169 / var(--tw-text-opacity, 1))}.text-\[\#ef5350\]{--tw-text-opacity: 1;color:rgb(239 83 80 / var(--tw-text-opacity, 1))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-current{color:currentColor}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-\[0\.3\]{opacity:.3}.opacity-\[33\%\]{opacity:33%}.\!shadow-main{--tw-shadow: 0 3px 3px 0 #00000005 !important;--tw-shadow-colored: 0 3px 3px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.\!shadow-none{--tw-shadow: 0 0 #0000 !important;--tw-shadow-colored: 0 0 #0000 !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-main{--tw-shadow: 0 3px 3px 0 #00000005;--tw-shadow-colored: 0 3px 3px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-main-inset{--tw-shadow: 0px 0px 3px 0px #00000054 inset;--tw-shadow-colored: inset 0px 0px 3px 0px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.\!shadow-main{--tw-shadow-color: var(--main) !important;--tw-shadow: var(--tw-shadow-colored) !important}.shadow-main{--tw-shadow-color: var(--main);--tw-shadow: var(--tw-shadow-colored) }.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.\!ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color) !important;--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color) !important;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)!important}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.\!ring-offset-0{--tw-ring-offset-width: 0px !important}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background)) }.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-\[4px\]{--tw-blur: blur(4px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-none{transition-property:none}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.animate-in{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial }.fade-in-0{--tw-enter-opacity: 0 }.zoom-in-95{--tw-enter-scale: .95 }.duration-200{animation-duration:.2s}.duration-500{animation-duration:.5s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}.running{animation-play-state:running}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.box-shadow-none{box-shadow:none!important}.\[box-shadow\:0_-0\.6px_0px_0px_\#F3F5F9\]{box-shadow:0 -.6px #f3f5f9}.\[box-shadow\:0px_0px_25px_0px_\#0000000A\]{box-shadow:0 0 25px #0000000a}.\[box-shadow\:0px_0px_30px_0px_\#0000001F\]{box-shadow:0 0 30px #0000001f}.\[box-shadow\:0px_2px_4px_0px_\#00403029\,0px_1px_5\.5px_0px_\#006E5329\]{box-shadow:0 2px 4px #00403029,0 1px 5.5px #006e5329}.\[box-shadow\:_0px_8px_20px_-8px_\#00000012\]{box-shadow:0 8px 20px -8px #00000012}.\[direction\:ltr\]{direction:ltr}.\[direction\:rtl\]{direction:rtl}.\[justify-self\:end\]{justify-self:end}.\[scroll-snap-type\:y_mandatory\]{scroll-snap-type:y mandatory}.\[stroke-width\:2px\]{stroke-width:2px}.\[transition-duration\:600ms\]{transition-duration:.6s}.\[word-break\:break-all\]{word-break:break-all}.\[word-break\:break-word\]{word-break:break-word}*{--tw-ring-offset-shadow: transparent !important;--tw-ring-shadow: transparent !important;--tw-shadow: transparent !important}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.file\:text-foreground::file-selector-button{color:hsl(var(--foreground))}.placeholder\:font-light::-moz-placeholder{font-weight:300}.placeholder\:font-light::placeholder{font-weight:300}.placeholder\:text-\[\#282828\]::-moz-placeholder{--tw-text-opacity: 1;color:rgb(40 40 40 / var(--tw-text-opacity, 1))}.placeholder\:text-\[\#282828\]::placeholder{--tw-text-opacity: 1;color:rgb(40 40 40 / var(--tw-text-opacity, 1))}.placeholder\:text-\[\#959595\]::-moz-placeholder{--tw-text-opacity: 1;color:rgb(149 149 149 / var(--tw-text-opacity, 1))}.placeholder\:text-\[\#959595\]::placeholder{--tw-text-opacity: 1;color:rgb(149 149 149 / var(--tw-text-opacity, 1))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-y-0:after{content:var(--tw-content);top:0;bottom:0}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-1:after{content:var(--tw-content);width:.25rem}.after\:-translate-x-1\/2:after{content:var(--tw-content);--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.focus-within\:\!bg-white:focus-within{--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))!important}.hover\:visible:hover{visibility:visible}@keyframes background-shift{0%,to{background-position-x:20%}50%{background-position-x:80%}}.hover\:animate-background-shift:hover{animation:background-shift 5s linear infinite}.hover\:cursor-text:hover{cursor:text}.hover\:rounded-\[6px\]:hover{border-radius:6px}.hover\:border-\[\#E4E6EA\]:hover{--tw-border-opacity: 1;border-color:rgb(228 230 234 / var(--tw-border-opacity, 1))}.hover\:border-\[\#E9EBEF\]:hover{--tw-border-opacity: 1;border-color:rgb(233 235 239 / var(--tw-border-opacity, 1))}.hover\:\!bg-\[\#F5EFEF\]:hover{--tw-bg-opacity: 1 !important;background-color:rgb(245 239 239 / var(--tw-bg-opacity, 1))!important}.hover\:\!bg-\[\#FAF9FF\]:hover{--tw-bg-opacity: 1 !important;background-color:rgb(250 249 255 / var(--tw-bg-opacity, 1))!important}.hover\:\!bg-\[\#f5f6f8\]:hover{--tw-bg-opacity: 1 !important;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))!important}.hover\:\!bg-white:hover{--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))!important}.hover\:bg-\[\#005C3F\]:hover{--tw-bg-opacity: 1;background-color:rgb(0 92 63 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#EBE9F5\]:hover{--tw-bg-opacity: 1;background-color:rgb(235 233 245 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#EBECF0\]:hover{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#F3F5F9\]:hover{--tw-bg-opacity: 1;background-color:rgb(243 245 249 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#F5F6F8\]:hover{--tw-bg-opacity: 1;background-color:rgb(245 246 248 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#F5F9F3\]:hover{--tw-bg-opacity: 1;background-color:rgb(245 249 243 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#FAFAFA\]:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#FBFBFB\]:hover{--tw-bg-opacity: 1;background-color:rgb(251 251 251 / var(--tw-bg-opacity, 1))}.hover\:bg-\[\#f3f5f9\]:hover{--tw-bg-opacity: 1;background-color:rgb(243 245 249 / var(--tw-bg-opacity, 1))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-green-hover:hover{--tw-bg-opacity: 1;background-color:rgb(0 92 63 / var(--tw-bg-opacity, 1))}.hover\:bg-main:hover{background-color:var(--main)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-white:hover{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.hover\:text-\[\#151515\]:hover{--tw-text-opacity: 1;color:rgb(21 21 21 / var(--tw-text-opacity, 1))}.hover\:text-\[\#282828\]:hover{--tw-text-opacity: 1;color:rgb(40 40 40 / var(--tw-text-opacity, 1))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:\!bg-white:focus{--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))!important}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring)) }.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px }.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring)) }.focus-visible\:ring-offset-1:focus-visible{--tw-ring-offset-width: 1px }.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px }.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background)) }.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group\/main:hover .group-hover\/main\:visible,.group:hover .group-hover\:visible{visibility:visible}.group:hover .group-hover\:block{display:block}.group:hover .group-hover\:flex{display:flex}.group:hover .group-hover\:hidden{display:none}.group:hover .group-hover\:border-\[\#FAFAFA\]{--tw-border-opacity: 1;border-color:rgb(250 250 250 / var(--tw-border-opacity, 1))}.group:hover .group-hover\:bg-\[\#EBECF0\]{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.group:hover .group-hover\:text-\[\#656565\]{--tw-text-opacity: 1;color:rgb(101 101 101 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:underline{text-decoration-line:underline}.group.toaster .group-\[\.toaster\]\:border-border{border-color:hsl(var(--border))}.group.toast .group-\[\.toast\]\:bg-muted{--tw-bg-opacity: 1;background-color:rgb(235 236 240 / var(--tw-bg-opacity, 1))}.group.toast .group-\[\.toast\]\:bg-primary{background-color:hsl(var(--primary))}.group.toaster .group-\[\.toaster\]\:bg-background{background-color:hsl(var(--background))}.group.toast .group-\[\.toast\]\:text-primary-foreground{color:hsl(var(--primary-foreground))}.group.toaster .group-\[\.toaster\]\:text-foreground{color:hsl(var(--foreground))}.group.toaster .group-\[\.toaster\]\:shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.peer:hover~.peer-hover\:visible{visibility:visible}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[panel-group-direction\=vertical\]\:h-px[data-panel-group-direction=vertical]{height:1px}.data-\[panel-group-direction\=vertical\]\:w-full[data-panel-group-direction=vertical]{width:100%}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-4[data-state=checked]{--tw-translate-x: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[panel-group-direction\=vertical\]\:flex-col[data-panel-group-direction=vertical]{flex-direction:column}.data-\[selected\=true\]\:bg-accent[data-selected=true]{background-color:hsl(var(--accent))}.data-\[state\=checked\]\:bg-green-main[data-state=checked]{--tw-bg-opacity: 1;background-color:rgb(0 110 83 / var(--tw-bg-opacity, 1))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:hsl(var(--secondary))}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:hsl(var(--primary-foreground))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=closed\]\:duration-300[data-state=closed]{transition-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{transition-duration:.5s}.data-\[state\=open\]\:animate-in[data-state=open]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial }.data-\[state\=closed\]\:animate-out[data-state=closed]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial }.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity: 0 }.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity: 0 }.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale: .95 }.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale: .95 }.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y: -.5rem }.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x: .5rem }.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x: -.5rem }.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y: .5rem }.data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y: 100% }.data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x: -100% }.data-\[state\=closed\]\:slide-out-to-left-1\/2[data-state=closed]{--tw-exit-translate-x: -50% }.data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x: 100% }.data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y: -100% }.data-\[state\=closed\]\:slide-out-to-top-\[48\%\][data-state=closed]{--tw-exit-translate-y: -48% }.data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y: 100% }.data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x: -100% }.data-\[state\=open\]\:slide-in-from-left-1\/2[data-state=open]{--tw-enter-translate-x: -50% }.data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x: 100% }.data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y: -100% }.data-\[state\=open\]\:slide-in-from-top-\[48\%\][data-state=open]{--tw-enter-translate-y: -48% }.data-\[state\=closed\]\:duration-300[data-state=closed]{animation-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{animation-duration:.5s}.data-\[panel-group-direction\=vertical\]\:after\:left-0[data-panel-group-direction=vertical]:after{content:var(--tw-content);left:0}.data-\[panel-group-direction\=vertical\]\:after\:h-1[data-panel-group-direction=vertical]:after{content:var(--tw-content);height:.25rem}.data-\[panel-group-direction\=vertical\]\:after\:w-full[data-panel-group-direction=vertical]:after{content:var(--tw-content);width:100%}.data-\[panel-group-direction\=vertical\]\:after\:-translate-y-1\/2[data-panel-group-direction=vertical]:after{content:var(--tw-content);--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[panel-group-direction\=vertical\]\:after\:translate-x-0[data-panel-group-direction=vertical]:after{content:var(--tw-content);--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:text-gray-100:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}@media(max-width:2100px){.max-\[2100px\]\:w-\[calc\(100\%-200px\)\]{width:calc(100% - 200px)}}@media(max-width:1700px){.max-\[1700px\]\:w-\[calc\(100\%-40px\)\]{width:calc(100% - 40px)}}@media(max-width:1440px){.max-\[1440px\]\:w-\[calc\(100\%-160px\)\]{width:calc(100% - 160px)}}@media(max-width:900px){.max-\[900px\]\:w-\[calc\(100\%-40px\)\]{width:calc(100% - 40px)}}@media not all and (min-width:801px){.max-mobile\:block{display:block}.max-mobile\:hidden{display:none}.max-mobile\:w-full{width:100%}.max-mobile\:justify-between{justify-content:space-between}}@media(max-width:800px){.max-\[800px\]\:w-full{width:100%}.max-\[800px\]\:max-w-full{max-width:100%}}@media(min-width:640px){.sm\:max-w-sm{max-width:24rem}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}@media(min-width:801px){.min-\[801px\]\:hidden{display:none}}.\[\&\:first-child\]\:rounded-t-\[3px\]:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.\[\&\:first-child\]\:border-\[0px\]:first-child{border-width:0px}.\[\&\:last-child\]\:border-b:last-child{border-bottom-width:1px}.\[\&\>\*\]\:w-full>*{width:100%}.\[\&\>button\[type\=button\]\]\:hidden>button[type=button]{display:none}.\[\&\>button\]\:hidden>button{display:none}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\[data-panel-group-direction\=vertical\]\>div\]\:rotate-90[data-panel-group-direction=vertical]>div{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&_\*\]\:cursor-default *{cursor:default}.\[\&_\.cm-gutters\]\:border-0 .cm-gutters{border-width:0px}.\[\&_\.cm-gutters\]\:bg-white .cm-gutters{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.\[\&_\.cm-gutters\]\:pe-\[1\.2em\] .cm-gutters{padding-inline-end:1.2em}.\[\&_\.cm-gutters\]\:ps-\[0\.5em\] .cm-gutters{padding-inline-start:.5em}.\[\&_\.cm-gutters\]\:text-\[\#bbb\] .cm-gutters{--tw-text-opacity: 1;color:rgb(187 187 187 / var(--tw-text-opacity, 1))}.\[\&_\.cm-panels\]\:sticky .cm-panels{position:sticky}.\[\&_\.cm-panels\]\:h-\[39px\] .cm-panels{height:39px}.\[\&_\.cm-panels\]\:-translate-y-\[100\%\] .cm-panels{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&_\.cm-panels\]\:translate-y-0 .cm-panels{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&_\.cm-panels\]\:border-none .cm-panels{border-style:none}.\[\&_\.cm-panels\]\:bg-white .cm-panels{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.\[\&_\.cm-panels\]\:pl-\[20px\] .cm-panels{padding-left:20px}.\[\&_\.cm-scroller\>div\:nth-child\(2\)\]\:flex-1 .cm-scroller>div:nth-child(2){flex:1 1 0%}.\[\&_\.cm-scroller\>div\:nth-child\(2\)\]\:\[white-space\:break-spaces\] .cm-scroller>div:nth-child(2){white-space:break-spaces}.\[\&_\.cm-search\]\:bg-white .cm-search{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.\[\&_\.cm-search_\*\]\:hidden .cm-search *{display:none}.\[\&_\.cm-search_input\:first-child\]\:block .cm-search input:first-child{display:block}.\[\&_\.cm-search_input\:first-child\]\:w-\[300px\] .cm-search input:first-child{width:300px}.\[\&_\.cm-search_input\:first-child\]\:rounded-\[5px\] .cm-search input:first-child{border-radius:5px}.\[\&_\.copy-icon\]\:\!block .copy-icon{display:block!important}.\[\&_\.title\]\:max-w-\[90\%\] .title{max-width:90%}.\[\&_img\]\:opacity-60 img{opacity:.6}.\[\&_span\]\:block span{display:block}.\[\&_span\]\:overflow-hidden span{overflow:hidden}.\[\&_span\]\:text-ellipsis span{text-overflow:ellipsis}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\]\:\[stroke\:\#006E53\] svg{stroke:#006e53} diff --git a/src/parlant/api/chat/dist/assets/manifest-BRNJYplA.webmanifest b/src/parlant/api/chat/dist/assets/manifest-BRNJYplA.webmanifest new file mode 100644 index 0000000..3d7fa86 --- /dev/null +++ b/src/parlant/api/chat/dist/assets/manifest-BRNJYplA.webmanifest @@ -0,0 +1,16 @@ +{ + "name": "Parlant", + "short_name": "Parlant", + "description": "Chatbot by Parlant", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#006e54", + "icons": [ + { + "src": "/chat/logo-color.svg", + "sizes": "any", + "type": "image/svg+xml" + } + ] +} diff --git a/src/parlant/api/chat/dist/buttons/new-session-hover.svg b/src/parlant/api/chat/dist/buttons/new-session-hover.svg new file mode 100644 index 0000000..fe78a27 --- /dev/null +++ b/src/parlant/api/chat/dist/buttons/new-session-hover.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/dist/buttons/new-session.svg b/src/parlant/api/chat/dist/buttons/new-session.svg new file mode 100644 index 0000000..8882647 --- /dev/null +++ b/src/parlant/api/chat/dist/buttons/new-session.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/dist/emcie-placeholder.svg b/src/parlant/api/chat/dist/emcie-placeholder.svg new file mode 100644 index 0000000..af4dd3a --- /dev/null +++ b/src/parlant/api/chat/dist/emcie-placeholder.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/empty-state.svg b/src/parlant/api/chat/dist/empty-state.svg new file mode 100644 index 0000000..04f6dd4 --- /dev/null +++ b/src/parlant/api/chat/dist/empty-state.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/favicon.svg b/src/parlant/api/chat/dist/favicon.svg new file mode 100644 index 0000000..7691705 --- /dev/null +++ b/src/parlant/api/chat/dist/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/fonts/Inter/inter.css b/src/parlant/api/chat/dist/fonts/Inter/inter.css new file mode 100644 index 0000000..162fcea --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/Inter/inter.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100; + src: url('/fonts/Inter/static/Inter_28pt-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 200; + src: url('/fonts/Inter/static/Inter_28pt-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + src: url('/fonts/Inter/static/Inter_28pt-Light.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + src: url('/fonts/Inter/static/Inter_28pt-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + src: url('/fonts/Inter/static/Inter_28pt-Medium.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + src: url('/fonts/Inter/static/Inter_28pt-SemiBold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + src: url('/fonts/Inter/static/Inter_28pt-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 800; + src: url('/fonts/Inter/static/Inter_28pt-ExtraBold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + src: url('/fonts/Inter/static/Inter_28pt-ExtraBold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Bold.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Bold.ttf new file mode 100644 index 0000000..d17828b Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraBold.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraBold.ttf new file mode 100644 index 0000000..6d87cae Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraLight.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraLight.ttf new file mode 100644 index 0000000..d42b3f5 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Italic.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Italic.ttf new file mode 100644 index 0000000..c2a143a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Light.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Light.ttf new file mode 100644 index 0000000..5eeff3a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Light.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Medium.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Medium.ttf new file mode 100644 index 0000000..00120fe Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Medium.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Regular.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Regular.ttf new file mode 100644 index 0000000..855b6f4 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-SemiBold.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-SemiBold.ttf new file mode 100644 index 0000000..8b84efc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-SemiBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Thin.ttf b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Thin.ttf new file mode 100644 index 0000000..94e6108 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/Inter/static/Inter_28pt-Thin.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/ibm-plex-mono.css b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/ibm-plex-mono.css new file mode 100644 index 0000000..fda73ff --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/ibm-plex-mono.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 900; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf new file mode 100644 index 0000000..2e437e2 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf new file mode 100644 index 0000000..f2695fc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf new file mode 100644 index 0000000..573ef76 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..ea13f86 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf new file mode 100644 index 0000000..3cb28a3 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf new file mode 100644 index 0000000..df167f0 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf new file mode 100644 index 0000000..c9072e9 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf new file mode 100644 index 0000000..39f178d Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf new file mode 100644 index 0000000..0d887f7 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf new file mode 100644 index 0000000..81ca3dc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf new file mode 100644 index 0000000..73dd5a4 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..a41b0d3 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf new file mode 100644 index 0000000..e173f5a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf new file mode 100644 index 0000000..8529275 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/OFL.txt b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/OFL.txt new file mode 100644 index 0000000..5bb330e --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/OFL.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UFL.txt b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UFL.txt new file mode 100644 index 0000000..6e722c8 --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UFL.txt @@ -0,0 +1,96 @@ +------------------------------- +UBUNTU FONT LICENCE Version 1.0 +------------------------------- + +PREAMBLE +This licence allows the licensed fonts to be used, studied, modified and +redistributed freely. The fonts, including any derivative works, can be +bundled, embedded, and redistributed provided the terms of this licence +are met. The fonts and derivatives, however, cannot be released under +any other licence. The requirement for fonts to remain under this +licence does not require any document created using the fonts or their +derivatives to be published under this licence, as long as the primary +purpose of the document is not to be a vehicle for the distribution of +the fonts. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this licence and clearly marked as such. This may +include source files, build scripts and documentation. + +"Original Version" refers to the collection of Font Software components +as received under this licence. + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to +a new environment. + +"Copyright Holder(s)" refers to all individuals and companies who have a +copyright ownership of the Font Software. + +"Substantially Changed" refers to Modified Versions which can be easily +identified as dissimilar to the Font Software by users of the Font +Software comparing the Original Version with the Modified Version. + +To "Propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification and with or without charging +a redistribution fee), making available to the public, and in some +countries other activities as well. + +PERMISSION & CONDITIONS +This licence does not grant any rights under trademark law and all such +rights are reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to propagate the Font Software, subject to +the below conditions: + +1) Each copy of the Font Software must contain the above copyright +notice and this licence. These can be included either as stand-alone +text files, human-readable headers or in the appropriate machine- +readable metadata fields within text or binary files as long as those +fields can be easily viewed by the user. + +2) The font name complies with the following: +(a) The Original Version must retain its name, unmodified. +(b) Modified Versions which are Substantially Changed must be renamed to +avoid use of the name of the Original Version or similar names entirely. +(c) Modified Versions which are not Substantially Changed must be +renamed to both (i) retain the name of the Original Version and (ii) add +additional naming elements to distinguish the Modified Version from the +Original Version. The name of such Modified Versions must be the name of +the Original Version, with "derivative X" where X represents the name of +the new work, appended to that name. + +3) The name(s) of the Copyright Holder(s) and any contributor to the +Font Software shall not be used to promote, endorse or advertise any +Modified Version, except (i) as required by this licence, (ii) to +acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with +their explicit written permission. + +4) The Font Software, modified or unmodified, in part or in whole, must +be distributed entirely under this licence, and must not be distributed +under any other licence. The requirement for fonts to remain under this +licence does not affect any document created using the Font Software, +except any version of the Font Software extracted from a document +created using the Font Software may only be distributed under this +licence. + +TERMINATION +This licence becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf new file mode 100644 index 0000000..01ad81b Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf new file mode 100644 index 0000000..731884e Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf new file mode 100644 index 0000000..b89338d Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf new file mode 100644 index 0000000..4977028 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-mono/ubuntu_mono.css b/src/parlant/api/chat/dist/fonts/ubuntu-mono/ubuntu_mono.css new file mode 100644 index 0000000..22c3b24 --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ubuntu-mono/ubuntu_mono.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 900; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/README.txt b/src/parlant/api/chat/dist/fonts/ubuntu-sans/README.txt new file mode 100644 index 0000000..1b45b91 --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ubuntu-sans/README.txt @@ -0,0 +1,112 @@ +Ubuntu Sans Variable Font +========================= + +This download contains Ubuntu Sans as both variable fonts and static fonts. + +Ubuntu Sans is a variable font with these axes: + wdth + wght + +This means all the styles are contained in these files: + Ubuntu_Sans/UbuntuSans-VariableFont_wdth,wght.ttf + Ubuntu_Sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Ubuntu Sans: + Ubuntu_Sans/static/UbuntuSans_Condensed-Thin.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Light.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Regular.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Medium.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Bold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Thin.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Light.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Regular.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Medium.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Bold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans-Thin.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans-Light.ttf + Ubuntu_Sans/static/UbuntuSans-Regular.ttf + Ubuntu_Sans/static/UbuntuSans-Medium.ttf + Ubuntu_Sans/static/UbuntuSans-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans-Bold.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Italic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Italic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans-Italic.ttf + Ubuntu_Sans/static/UbuntuSans-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraBoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (UFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/UFL.txt b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UFL.txt new file mode 100644 index 0000000..6e722c8 --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UFL.txt @@ -0,0 +1,96 @@ +------------------------------- +UBUNTU FONT LICENCE Version 1.0 +------------------------------- + +PREAMBLE +This licence allows the licensed fonts to be used, studied, modified and +redistributed freely. The fonts, including any derivative works, can be +bundled, embedded, and redistributed provided the terms of this licence +are met. The fonts and derivatives, however, cannot be released under +any other licence. The requirement for fonts to remain under this +licence does not require any document created using the fonts or their +derivatives to be published under this licence, as long as the primary +purpose of the document is not to be a vehicle for the distribution of +the fonts. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this licence and clearly marked as such. This may +include source files, build scripts and documentation. + +"Original Version" refers to the collection of Font Software components +as received under this licence. + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to +a new environment. + +"Copyright Holder(s)" refers to all individuals and companies who have a +copyright ownership of the Font Software. + +"Substantially Changed" refers to Modified Versions which can be easily +identified as dissimilar to the Font Software by users of the Font +Software comparing the Original Version with the Modified Version. + +To "Propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification and with or without charging +a redistribution fee), making available to the public, and in some +countries other activities as well. + +PERMISSION & CONDITIONS +This licence does not grant any rights under trademark law and all such +rights are reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to propagate the Font Software, subject to +the below conditions: + +1) Each copy of the Font Software must contain the above copyright +notice and this licence. These can be included either as stand-alone +text files, human-readable headers or in the appropriate machine- +readable metadata fields within text or binary files as long as those +fields can be easily viewed by the user. + +2) The font name complies with the following: +(a) The Original Version must retain its name, unmodified. +(b) Modified Versions which are Substantially Changed must be renamed to +avoid use of the name of the Original Version or similar names entirely. +(c) Modified Versions which are not Substantially Changed must be +renamed to both (i) retain the name of the Original Version and (ii) add +additional naming elements to distinguish the Modified Version from the +Original Version. The name of such Modified Versions must be the name of +the Original Version, with "derivative X" where X represents the name of +the new work, appended to that name. + +3) The name(s) of the Copyright Holder(s) and any contributor to the +Font Software shall not be used to promote, endorse or advertise any +Modified Version, except (i) as required by this licence, (ii) to +acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with +their explicit written permission. + +4) The Font Software, modified or unmodified, in part or in whole, must +be distributed entirely under this licence, and must not be distributed +under any other licence. The requirement for fonts to remain under this +licence does not affect any document created using the Font Software, +except any version of the Font Software extracted from a document +created using the Font Software may only be distributed under this +licence. + +TERMINATION +This licence becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..d964bd2 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..0f8b94f Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf new file mode 100644 index 0000000..94f2142 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf new file mode 100644 index 0000000..c627f60 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf new file mode 100644 index 0000000..b6ebd9c Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..0d2de88 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf new file mode 100644 index 0000000..de71460 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf new file mode 100644 index 0000000..8b28b35 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf new file mode 100644 index 0000000..7bac9db Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf new file mode 100644 index 0000000..54299d3 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf new file mode 100644 index 0000000..ba8a6ca Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf new file mode 100644 index 0000000..987e815 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf new file mode 100644 index 0000000..53658cb Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf new file mode 100644 index 0000000..d972bdc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf new file mode 100644 index 0000000..e7b0b27 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..eadd862 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf new file mode 100644 index 0000000..8e2e750 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf new file mode 100644 index 0000000..b005d6a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf new file mode 100644 index 0000000..6890cfc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf new file mode 100644 index 0000000..58566b0 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf new file mode 100644 index 0000000..e390f2e Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf new file mode 100644 index 0000000..3b7707a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf new file mode 100644 index 0000000..69ad3bc Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf new file mode 100644 index 0000000..1986037 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf new file mode 100644 index 0000000..d0583d1 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf new file mode 100644 index 0000000..e301155 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf new file mode 100644 index 0000000..c97b070 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf new file mode 100644 index 0000000..514b7f4 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf new file mode 100644 index 0000000..0384dc3 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf new file mode 100644 index 0000000..c99a26c Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf new file mode 100644 index 0000000..ff2c303 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf new file mode 100644 index 0000000..79cf40a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf new file mode 100644 index 0000000..bc0cf57 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf new file mode 100644 index 0000000..9dcad4b Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf new file mode 100644 index 0000000..917b408 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf new file mode 100644 index 0000000..02f9dd3 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf new file mode 100644 index 0000000..465628a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf new file mode 100644 index 0000000..850dc73 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf new file mode 100644 index 0000000..1767953 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf new file mode 100644 index 0000000..5872619 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf new file mode 100644 index 0000000..6009cce Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf new file mode 100644 index 0000000..d76f484 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf new file mode 100644 index 0000000..ad1074a Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf new file mode 100644 index 0000000..91b9fbb Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf new file mode 100644 index 0000000..2ad8564 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf new file mode 100644 index 0000000..22b011e Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf new file mode 100644 index 0000000..2eb97e8 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf new file mode 100644 index 0000000..856a6b7 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf new file mode 100644 index 0000000..aef88dd Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf new file mode 100644 index 0000000..a86b571 Binary files /dev/null and b/src/parlant/api/chat/dist/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/dist/fonts/ubuntu-sans/ubuntu_sans.css b/src/parlant/api/chat/dist/fonts/ubuntu-sans/ubuntu_sans.css new file mode 100644 index 0000000..43ac5aa --- /dev/null +++ b/src/parlant/api/chat/dist/fonts/ubuntu-sans/ubuntu_sans.css @@ -0,0 +1,48 @@ +@font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf') format('truetype') + } \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/add-filled.svg b/src/parlant/api/chat/dist/icons/add-filled.svg new file mode 100644 index 0000000..f68f879 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/add-filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/add.svg b/src/parlant/api/chat/dist/icons/add.svg new file mode 100644 index 0000000..ebab8c9 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/add.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/arrow-down.svg b/src/parlant/api/chat/dist/icons/arrow-down.svg new file mode 100644 index 0000000..e740e4b --- /dev/null +++ b/src/parlant/api/chat/dist/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/cancel.svg b/src/parlant/api/chat/dist/icons/cancel.svg new file mode 100644 index 0000000..727b23a --- /dev/null +++ b/src/parlant/api/chat/dist/icons/cancel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/close-logs-hover.svg b/src/parlant/api/chat/dist/icons/close-logs-hover.svg new file mode 100644 index 0000000..9915098 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/close-logs-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/close-logs.svg b/src/parlant/api/chat/dist/icons/close-logs.svg new file mode 100644 index 0000000..1646f66 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/close-logs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/close-white.svg b/src/parlant/api/chat/dist/icons/close-white.svg new file mode 100644 index 0000000..d836122 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/close-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/close.svg b/src/parlant/api/chat/dist/icons/close.svg new file mode 100644 index 0000000..46ebf88 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/copy-session.svg b/src/parlant/api/chat/dist/icons/copy-session.svg new file mode 100644 index 0000000..51303a7 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/copy-session.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/copy.svg b/src/parlant/api/chat/dist/icons/copy.svg new file mode 100644 index 0000000..420a550 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/copy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/delete.svg b/src/parlant/api/chat/dist/icons/delete.svg new file mode 100644 index 0000000..284138a --- /dev/null +++ b/src/parlant/api/chat/dist/icons/delete.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/dot-saparetor.svg b/src/parlant/api/chat/dist/icons/dot-saparetor.svg new file mode 100644 index 0000000..49970c3 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/dot-saparetor.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/edit-message.svg b/src/parlant/api/chat/dist/icons/edit-message.svg new file mode 100644 index 0000000..2f5880e --- /dev/null +++ b/src/parlant/api/chat/dist/icons/edit-message.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/edit-white.svg b/src/parlant/api/chat/dist/icons/edit-white.svg new file mode 100644 index 0000000..220fb39 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/edit-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/edit.svg b/src/parlant/api/chat/dist/icons/edit.svg new file mode 100644 index 0000000..7687117 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/error.svg b/src/parlant/api/chat/dist/icons/error.svg new file mode 100644 index 0000000..f8298b3 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/error.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/expand.svg b/src/parlant/api/chat/dist/icons/expand.svg new file mode 100644 index 0000000..dc48143 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/expand.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/export.svg b/src/parlant/api/chat/dist/icons/export.svg new file mode 100644 index 0000000..8ded884 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/filter.svg b/src/parlant/api/chat/dist/icons/filter.svg new file mode 100644 index 0000000..1b99fc7 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filter.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/filters.svg b/src/parlant/api/chat/dist/icons/filters.svg new file mode 100644 index 0000000..d59a3d3 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/dist/icons/filters/guideline-matcher-color.svg b/src/parlant/api/chat/dist/icons/filters/guideline-matcher-color.svg new file mode 100644 index 0000000..3aa9796 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/guideline-matcher-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/filters/guideline-matcher.svg b/src/parlant/api/chat/dist/icons/filters/guideline-matcher.svg new file mode 100644 index 0000000..6d254af --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/guideline-matcher.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/filters/message-composer-color.svg b/src/parlant/api/chat/dist/icons/filters/message-composer-color.svg new file mode 100644 index 0000000..3ec90cd --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/message-composer-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/filters/message-composer.svg b/src/parlant/api/chat/dist/icons/filters/message-composer.svg new file mode 100644 index 0000000..8691176 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/message-composer.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/filters/tool-caller-color.svg b/src/parlant/api/chat/dist/icons/filters/tool-caller-color.svg new file mode 100644 index 0000000..4431032 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/tool-caller-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/filters/tool-caller.svg b/src/parlant/api/chat/dist/icons/filters/tool-caller.svg new file mode 100644 index 0000000..9ca0d65 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/filters/tool-caller.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/funnel.svg b/src/parlant/api/chat/dist/icons/funnel.svg new file mode 100644 index 0000000..5c5dbd4 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/funnel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/green-v.svg b/src/parlant/api/chat/dist/icons/green-v.svg new file mode 100644 index 0000000..a438b32 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/green-v.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/more.svg b/src/parlant/api/chat/dist/icons/more.svg new file mode 100644 index 0000000..5aea29b --- /dev/null +++ b/src/parlant/api/chat/dist/icons/more.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/new-session.svg b/src/parlant/api/chat/dist/icons/new-session.svg new file mode 100644 index 0000000..5095531 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/new-session.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/pending.svg b/src/parlant/api/chat/dist/icons/pending.svg new file mode 100644 index 0000000..f9eaaf6 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/pending.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/icons/puzzle-hover.svg b/src/parlant/api/chat/dist/icons/puzzle-hover.svg new file mode 100644 index 0000000..0c7d9f6 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/puzzle-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/puzzle.svg b/src/parlant/api/chat/dist/icons/puzzle.svg new file mode 100644 index 0000000..0beae63 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/puzzle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/regenerate-arrow-hover.svg b/src/parlant/api/chat/dist/icons/regenerate-arrow-hover.svg new file mode 100644 index 0000000..1df8f8f --- /dev/null +++ b/src/parlant/api/chat/dist/icons/regenerate-arrow-hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/regenerate-arrow.svg b/src/parlant/api/chat/dist/icons/regenerate-arrow.svg new file mode 100644 index 0000000..d6d6268 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/regenerate-arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/regenerate-filled.svg b/src/parlant/api/chat/dist/icons/regenerate-filled.svg new file mode 100644 index 0000000..e406597 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/regenerate-filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/regenerate.svg b/src/parlant/api/chat/dist/icons/regenerate.svg new file mode 100644 index 0000000..d6d6268 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/regenerate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/rename.svg b/src/parlant/api/chat/dist/icons/rename.svg new file mode 100644 index 0000000..370e432 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/rename.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/resend-hover.svg b/src/parlant/api/chat/dist/icons/resend-hover.svg new file mode 100644 index 0000000..51dde04 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/resend-hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/dist/icons/resend.svg b/src/parlant/api/chat/dist/icons/resend.svg new file mode 100644 index 0000000..f90ed53 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/resend.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/resize.svg b/src/parlant/api/chat/dist/icons/resize.svg new file mode 100644 index 0000000..3f88f7f --- /dev/null +++ b/src/parlant/api/chat/dist/icons/resize.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/icons/save.svg b/src/parlant/api/chat/dist/icons/save.svg new file mode 100644 index 0000000..d0dbda5 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/save.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/search.svg b/src/parlant/api/chat/dist/icons/search.svg new file mode 100644 index 0000000..e61834c --- /dev/null +++ b/src/parlant/api/chat/dist/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/icons/send.svg b/src/parlant/api/chat/dist/icons/send.svg new file mode 100644 index 0000000..a8f7b35 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/send.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/icons/text.svg b/src/parlant/api/chat/dist/icons/text.svg new file mode 100644 index 0000000..ad65d87 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/dist/icons/v.svg b/src/parlant/api/chat/dist/icons/v.svg new file mode 100644 index 0000000..b194386 --- /dev/null +++ b/src/parlant/api/chat/dist/icons/v.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/dist/index.html b/src/parlant/api/chat/dist/index.html new file mode 100644 index 0000000..3b601fe --- /dev/null +++ b/src/parlant/api/chat/dist/index.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + Parlant + + + + +
+ + diff --git a/src/parlant/api/chat/dist/logo-color.svg b/src/parlant/api/chat/dist/logo-color.svg new file mode 100644 index 0000000..2484564 --- /dev/null +++ b/src/parlant/api/chat/dist/logo-color.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/dist/logo-muted.svg b/src/parlant/api/chat/dist/logo-muted.svg new file mode 100644 index 0000000..2d16b01 --- /dev/null +++ b/src/parlant/api/chat/dist/logo-muted.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/parlant/api/chat/dist/logo.svg b/src/parlant/api/chat/dist/logo.svg new file mode 100644 index 0000000..016a388 --- /dev/null +++ b/src/parlant/api/chat/dist/logo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/dist/mp4/loading.mp4 b/src/parlant/api/chat/dist/mp4/loading.mp4 new file mode 100644 index 0000000..4deb48f Binary files /dev/null and b/src/parlant/api/chat/dist/mp4/loading.mp4 differ diff --git a/src/parlant/api/chat/dist/parlant-bubble-app-logo.svg b/src/parlant/api/chat/dist/parlant-bubble-app-logo.svg new file mode 100644 index 0000000..942cd7b --- /dev/null +++ b/src/parlant/api/chat/dist/parlant-bubble-app-logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/parlant-bubble-muted.svg b/src/parlant/api/chat/dist/parlant-bubble-muted.svg new file mode 100644 index 0000000..338fa6f --- /dev/null +++ b/src/parlant/api/chat/dist/parlant-bubble-muted.svg @@ -0,0 +1,5 @@ + + + + diff --git a/src/parlant/api/chat/dist/parlant-bubble.svg b/src/parlant/api/chat/dist/parlant-bubble.svg new file mode 100644 index 0000000..64fa44f --- /dev/null +++ b/src/parlant/api/chat/dist/parlant-bubble.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/parlant-logo-after.svg b/src/parlant/api/chat/dist/parlant-logo-after.svg new file mode 100644 index 0000000..511f41f --- /dev/null +++ b/src/parlant/api/chat/dist/parlant-logo-after.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/dist/select-session.svg b/src/parlant/api/chat/dist/select-session.svg new file mode 100644 index 0000000..9a9911d --- /dev/null +++ b/src/parlant/api/chat/dist/select-session.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/parlant/api/chat/eslint.config.js b/src/parlant/api/chat/eslint.config.js new file mode 100644 index 0000000..977c827 --- /dev/null +++ b/src/parlant/api/chat/eslint.config.js @@ -0,0 +1,27 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + {ignores: ['dist']}, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + quotes: ['warn', 'single'], + semi: ['warn', 'always'], + 'react-refresh/only-export-components': ['warn', {allowConstantExport: true}], + }, + } +); diff --git a/src/parlant/api/chat/index.html b/src/parlant/api/chat/index.html new file mode 100644 index 0000000..edf0734 --- /dev/null +++ b/src/parlant/api/chat/index.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + Parlant + + +
+ + + diff --git a/src/parlant/api/chat/manifest.webmanifest b/src/parlant/api/chat/manifest.webmanifest new file mode 100644 index 0000000..3d7fa86 --- /dev/null +++ b/src/parlant/api/chat/manifest.webmanifest @@ -0,0 +1,16 @@ +{ + "name": "Parlant", + "short_name": "Parlant", + "description": "Chatbot by Parlant", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#006e54", + "icons": [ + { + "src": "/chat/logo-color.svg", + "sizes": "any", + "type": "image/svg+xml" + } + ] +} diff --git a/src/parlant/api/chat/package-lock.json b/src/parlant/api/chat/package-lock.json new file mode 100644 index 0000000..4fbcf59 --- /dev/null +++ b/src/parlant/api/chat/package-lock.json @@ -0,0 +1,9852 @@ +{ + "name": "chat", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "chat", + "version": "0.0.0", + "dependencies": { + "@codemirror/basic-setup": "^0.20.0", + "@codemirror/lang-javascript": "^6.2.3", + "@codemirror/language": "^6.10.8", + "@codemirror/search": "^6.5.10", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.4", + "@radix-ui/react-checkbox": "^1.1.3", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.4", + "@radix-ui/react-radio-group": "^1.2.2", + "@radix-ui/react-select": "^2.1.2", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.2.2", + "@radix-ui/react-tooltip": "^1.1.3", + "@testing-library/user-event": "^14.5.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cross-spawn": "^7.0.6", + "jotai": "^2.11.0", + "lucide-react": "^0.453.0", + "next-themes": "^0.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-helmet": "^6.1.0", + "react-markdown": "^9.0.1", + "react-resizable-panels": "^2.1.7", + "rehype-highlight": "^7.0.1", + "rehype-raw": "^7.0.0", + "remark-breaks": "^4.0.0", + "remark-gfm": "^4.0.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.5.4", + "tailwindcss-animate": "^1.0.7", + "vaul": "^1.1.2", + "vite": "^7.3.2" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@testing-library/jest-dom": "^6.6.2", + "@testing-library/react": "^16.0.1", + "@types/jest": "^29.5.13", + "@types/node": "^22.7.5", + "@types/react": "^18.3.10", + "@types/react-dom": "^18.3.0", + "@types/react-helmet": "^6.1.11", + "@vitejs/plugin-react": "^4.3.2", + "@vitest/ui": "^4.0.6", + "autoprefixer": "^10.4.20", + "eslint": "^9.11.1", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.12", + "globals": "^15.9.0", + "jsdom": "^25.0.1", + "postcss": "^8.4.47", + "sass-embedded": "^1.85.1", + "tailwindcss": "^3.4.14", + "typescript": "^5.5.3", + "typescript-eslint": "^8.7.0", + "vitest": "^4.0.6" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", + "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.2.tgz", + "integrity": "sha512-vLu7SRY84CV/Dd+NUdgtidn2hS5hSMUC1vDBY0VcviTdgRYkU43vIz3vIFbmx14cX1r+mM7WjzE5Fl1fGEM0RQ==", + "devOptional": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@codemirror/autocomplete": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.20.3.tgz", + "integrity": "sha512-lYB+NPGP+LEzAudkWhLfMxhTrxtLILGl938w+RcFrGdrIc54A+UgmCoz+McE3IYRFp4xyQcL4uFJwo+93YdgHw==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^0.20.0", + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/autocomplete/node_modules/@codemirror/language": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz", + "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "@lezer/common": "^0.16.0", + "@lezer/highlight": "^0.16.0", + "@lezer/lr": "^0.16.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/autocomplete/node_modules/@codemirror/state": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", + "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", + "license": "MIT" + }, + "node_modules/@codemirror/autocomplete/node_modules/@codemirror/view": { + "version": "0.20.7", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", + "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/autocomplete/node_modules/@lezer/highlight": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz", + "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/autocomplete/node_modules/@lezer/lr": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz", + "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/basic-setup": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.20.0.tgz", + "integrity": "sha512-W/ERKMLErWkrVLyP5I8Yh8PXl4r+WFNkdYVSzkXYPQv2RMPSkWpr2BgggiSJ8AHF/q3GuApncDD8I4BZz65fyg==", + "deprecated": "In version 6.0, this package has been renamed to just 'codemirror'", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^0.20.0", + "@codemirror/commands": "^0.20.0", + "@codemirror/language": "^0.20.0", + "@codemirror/lint": "^0.20.0", + "@codemirror/search": "^0.20.0", + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0" + } + }, + "node_modules/@codemirror/basic-setup/node_modules/@codemirror/language": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz", + "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "@lezer/common": "^0.16.0", + "@lezer/highlight": "^0.16.0", + "@lezer/lr": "^0.16.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/basic-setup/node_modules/@codemirror/search": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.20.1.tgz", + "integrity": "sha512-ROe6gRboQU5E4z6GAkNa2kxhXqsGNbeLEisbvzbOeB7nuDYXUZ70vGIgmqPu0tB+1M3F9yWk6W8k2vrFpJaD4Q==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/basic-setup/node_modules/@codemirror/state": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", + "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", + "license": "MIT" + }, + "node_modules/@codemirror/basic-setup/node_modules/@codemirror/view": { + "version": "0.20.7", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", + "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/basic-setup/node_modules/@lezer/highlight": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz", + "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/basic-setup/node_modules/@lezer/lr": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz", + "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.20.0.tgz", + "integrity": "sha512-v9L5NNVA+A9R6zaFvaTbxs30kc69F6BkOoiEbeFw4m4I0exmDEKBILN6mK+GksJtvTzGBxvhAPlVFTdQW8GB7Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^0.20.0", + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/commands/node_modules/@codemirror/language": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz", + "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.0", + "@lezer/common": "^0.16.0", + "@lezer/highlight": "^0.16.0", + "@lezer/lr": "^0.16.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/commands/node_modules/@codemirror/state": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", + "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", + "license": "MIT" + }, + "node_modules/@codemirror/commands/node_modules/@codemirror/view": { + "version": "0.20.7", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", + "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/commands/node_modules/@lezer/highlight": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz", + "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/commands/node_modules/@lezer/lr": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz", + "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.16.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", + "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript/node_modules/@codemirror/autocomplete": { + "version": "6.18.6", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", + "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript/node_modules/@codemirror/lint": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", + "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/lang-javascript/node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@codemirror/language": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.2.tgz", + "integrity": "sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/language/node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@codemirror/lint": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.20.3.tgz", + "integrity": "sha512-06xUScbbspZ8mKoODQCEx6hz1bjaq9m8W8DxdycWARMiiX1wMtfCh/MoHpaL7ws/KUMwlsFFfp2qhm32oaCvVA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "@codemirror/view": "^0.20.2", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/lint/node_modules/@codemirror/state": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", + "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", + "license": "MIT" + }, + "node_modules/@codemirror/lint/node_modules/@codemirror/view": { + "version": "0.20.7", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", + "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.20.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", + "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.38.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.1.tgz", + "integrity": "sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.4.tgz", + "integrity": "sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz", + "integrity": "sha512-qPmG7YTZ6lATyTOAWf8vXE+iRrt1NJd4cm2nJHK+v7X9TsOF6+HtuU/ctaZy2RCrluxDb89hI6KWQ5LfQGQWuA==", + "license": "MIT" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/highlight/node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@lezer/javascript": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz", + "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/javascript/node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr/node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.2.tgz", + "integrity": "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", + "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz", + "integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz", + "integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz", + "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.4.tgz", + "integrity": "sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", + "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", + "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-helmet": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz", + "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.38.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.6.tgz", + "integrity": "sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.6", + "@vitest/utils": "4.0.6", + "chai": "^6.0.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.6.tgz", + "integrity": "sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.19" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.6.tgz", + "integrity": "sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.6.tgz", + "integrity": "sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.6", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.6.tgz", + "integrity": "sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.6", + "magic-string": "^0.30.19", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.6.tgz", + "integrity": "sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.6.tgz", + "integrity": "sha512-1ekpBsYNUm0Xv/0YsTvoSRmiRkmzz9Pma7qQ3Ui76sg2gwp2/ewSWqx4W/HfaN5dF0E8iBbidFo1wGaeqXYIrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.6", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.6" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.6.tgz", + "integrity": "sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.6", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "devOptional": true, + "license": "MIT/X11" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.0.tgz", + "integrity": "sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "license": "MIT", + "peer": true + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.191", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.191.tgz", + "integrity": "sha512-xcwe9ELcuxYLUFqZZxL19Z6HVKcvNkIwhbHUz7L3us6u12yR+7uY89dSl570f/IqNthx8dAw3tojG7i4Ni4tDA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jotai": { + "version": "2.12.5", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.12.5.tgz", + "integrity": "sha512-G8m32HW3lSmcz/4mbqx0hgJIQ0ekndKWiYP7kWVKi0p6saLXdSoye+FZiOFyonnd7Q482LCzm8sMDl7Ar1NWDw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowlight": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.3.0.tgz", + "integrity": "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.453.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz", + "integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-newline-to-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", + "integrity": "sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-find-and-replace": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT", + "peer": true + }, + "node_modules/react-markdown": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz", + "integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-resizable-panels": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.1.9.tgz", + "integrity": "sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rehype-highlight": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-7.0.2.tgz", + "integrity": "sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-text": "^4.0.0", + "lowlight": "^3.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-breaks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", + "integrity": "sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-newline-to-break": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass-embedded": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.89.2.tgz", + "integrity": "sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.5.0", + "buffer-builder": "^0.2.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.0.2", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-android-arm": "1.89.2", + "sass-embedded-android-arm64": "1.89.2", + "sass-embedded-android-riscv64": "1.89.2", + "sass-embedded-android-x64": "1.89.2", + "sass-embedded-darwin-arm64": "1.89.2", + "sass-embedded-darwin-x64": "1.89.2", + "sass-embedded-linux-arm": "1.89.2", + "sass-embedded-linux-arm64": "1.89.2", + "sass-embedded-linux-musl-arm": "1.89.2", + "sass-embedded-linux-musl-arm64": "1.89.2", + "sass-embedded-linux-musl-riscv64": "1.89.2", + "sass-embedded-linux-musl-x64": "1.89.2", + "sass-embedded-linux-riscv64": "1.89.2", + "sass-embedded-linux-x64": "1.89.2", + "sass-embedded-win32-arm64": "1.89.2", + "sass-embedded-win32-x64": "1.89.2" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.89.2.tgz", + "integrity": "sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.89.2.tgz", + "integrity": "sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.89.2.tgz", + "integrity": "sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.89.2.tgz", + "integrity": "sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.89.2.tgz", + "integrity": "sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.89.2.tgz", + "integrity": "sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.89.2.tgz", + "integrity": "sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.89.2.tgz", + "integrity": "sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.89.2.tgz", + "integrity": "sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.89.2.tgz", + "integrity": "sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.89.2.tgz", + "integrity": "sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.89.2.tgz", + "integrity": "sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.89.2.tgz", + "integrity": "sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.89.2.tgz", + "integrity": "sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.89.2.tgz", + "integrity": "sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.89.2.tgz", + "integrity": "sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sonner": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", + "integrity": "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "license": "MIT" + }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, + "node_modules/style-to-object": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", + "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.6.tgz", + "integrity": "sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.6", + "@vitest/mocker": "4.0.6", + "@vitest/pretty-format": "4.0.6", + "@vitest/runner": "4.0.6", + "@vitest/snapshot": "4.0.6", + "@vitest/spy": "4.0.6", + "@vitest/utils": "4.0.6", + "debug": "^4.4.3", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.19", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.6", + "@vitest/browser-preview": "4.0.6", + "@vitest/browser-webdriverio": "4.0.6", + "@vitest/ui": "4.0.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/src/parlant/api/chat/package.json b/src/parlant/api/chat/package.json new file mode 100644 index 0000000..33e4391 --- /dev/null +++ b/src/parlant/api/chat/package.json @@ -0,0 +1,75 @@ +{ + "name": "chat", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview", + "test": "vitest", + "test-ui": "vitest --ui" + }, + "dependencies": { + "@codemirror/basic-setup": "^0.20.0", + "@codemirror/lang-javascript": "^6.2.3", + "@codemirror/language": "^6.10.8", + "@codemirror/search": "^6.5.10", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.4", + "@radix-ui/react-checkbox": "^1.1.3", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.4", + "@radix-ui/react-radio-group": "^1.2.2", + "@radix-ui/react-select": "^2.1.2", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.2.2", + "@radix-ui/react-tooltip": "^1.1.3", + "@testing-library/user-event": "^14.5.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cross-spawn": "^7.0.6", + "jotai": "^2.11.0", + "lucide-react": "^0.453.0", + "next-themes": "^0.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-helmet": "^6.1.0", + "react-markdown": "^9.0.1", + "react-resizable-panels": "^2.1.7", + "rehype-highlight": "^7.0.1", + "rehype-raw": "^7.0.0", + "remark-breaks": "^4.0.0", + "remark-gfm": "^4.0.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.5.4", + "tailwindcss-animate": "^1.0.7", + "vaul": "^1.1.2", + "vite": "^7.3.2" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@testing-library/jest-dom": "^6.6.2", + "@testing-library/react": "^16.0.1", + "@types/jest": "^29.5.13", + "@types/node": "^22.7.5", + "@types/react": "^18.3.10", + "@types/react-dom": "^18.3.0", + "@types/react-helmet": "^6.1.11", + "@vitejs/plugin-react": "^4.3.2", + "@vitest/ui": "^4.0.6", + "autoprefixer": "^10.4.20", + "eslint": "^9.11.1", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.12", + "globals": "^15.9.0", + "jsdom": "^25.0.1", + "postcss": "^8.4.47", + "sass-embedded": "^1.85.1", + "tailwindcss": "^3.4.14", + "typescript": "^5.5.3", + "typescript-eslint": "^8.7.0", + "vitest": "^4.0.6" + } +} diff --git a/src/parlant/api/chat/postcss.config.js b/src/parlant/api/chat/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/src/parlant/api/chat/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/parlant/api/chat/public/app-logo.svg b/src/parlant/api/chat/public/app-logo.svg new file mode 100644 index 0000000..fa26858 --- /dev/null +++ b/src/parlant/api/chat/public/app-logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/buttons/new-session-hover.svg b/src/parlant/api/chat/public/buttons/new-session-hover.svg new file mode 100644 index 0000000..fe78a27 --- /dev/null +++ b/src/parlant/api/chat/public/buttons/new-session-hover.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/public/buttons/new-session.svg b/src/parlant/api/chat/public/buttons/new-session.svg new file mode 100644 index 0000000..8882647 --- /dev/null +++ b/src/parlant/api/chat/public/buttons/new-session.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/public/emcie-placeholder.svg b/src/parlant/api/chat/public/emcie-placeholder.svg new file mode 100644 index 0000000..af4dd3a --- /dev/null +++ b/src/parlant/api/chat/public/emcie-placeholder.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/empty-state.svg b/src/parlant/api/chat/public/empty-state.svg new file mode 100644 index 0000000..04f6dd4 --- /dev/null +++ b/src/parlant/api/chat/public/empty-state.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/favicon.svg b/src/parlant/api/chat/public/favicon.svg new file mode 100644 index 0000000..7691705 --- /dev/null +++ b/src/parlant/api/chat/public/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/fonts/Inter/inter.css b/src/parlant/api/chat/public/fonts/Inter/inter.css new file mode 100644 index 0000000..162fcea --- /dev/null +++ b/src/parlant/api/chat/public/fonts/Inter/inter.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100; + src: url('/fonts/Inter/static/Inter_28pt-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 200; + src: url('/fonts/Inter/static/Inter_28pt-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + src: url('/fonts/Inter/static/Inter_28pt-Light.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + src: url('/fonts/Inter/static/Inter_28pt-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + src: url('/fonts/Inter/static/Inter_28pt-Medium.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + src: url('/fonts/Inter/static/Inter_28pt-SemiBold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + src: url('/fonts/Inter/static/Inter_28pt-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 800; + src: url('/fonts/Inter/static/Inter_28pt-ExtraBold.ttf') format('truetype'); +} +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + src: url('/fonts/Inter/static/Inter_28pt-ExtraBold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Bold.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Bold.ttf new file mode 100644 index 0000000..d17828b Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraBold.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraBold.ttf new file mode 100644 index 0000000..6d87cae Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraLight.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraLight.ttf new file mode 100644 index 0000000..d42b3f5 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Italic.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Italic.ttf new file mode 100644 index 0000000..c2a143a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Light.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Light.ttf new file mode 100644 index 0000000..5eeff3a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Light.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Medium.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Medium.ttf new file mode 100644 index 0000000..00120fe Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Medium.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Regular.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Regular.ttf new file mode 100644 index 0000000..855b6f4 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-SemiBold.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-SemiBold.ttf new file mode 100644 index 0000000..8b84efc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-SemiBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Thin.ttf b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Thin.ttf new file mode 100644 index 0000000..94e6108 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/Inter/static/Inter_28pt-Thin.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css b/src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css new file mode 100644 index 0000000..fda73ff --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 900; + src: url('/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf new file mode 100644 index 0000000..2e437e2 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf new file mode 100644 index 0000000..f2695fc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf new file mode 100644 index 0000000..573ef76 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..ea13f86 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf new file mode 100644 index 0000000..3cb28a3 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf new file mode 100644 index 0000000..df167f0 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Light.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf new file mode 100644 index 0000000..c9072e9 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-LightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf new file mode 100644 index 0000000..39f178d Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Medium.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf new file mode 100644 index 0000000..0d887f7 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf new file mode 100644 index 0000000..81ca3dc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf new file mode 100644 index 0000000..73dd5a4 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..a41b0d3 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf new file mode 100644 index 0000000..e173f5a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-Thin.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf new file mode 100644 index 0000000..8529275 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/IBMPlexMono-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt new file mode 100644 index 0000000..5bb330e --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt new file mode 100644 index 0000000..6e722c8 --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt @@ -0,0 +1,96 @@ +------------------------------- +UBUNTU FONT LICENCE Version 1.0 +------------------------------- + +PREAMBLE +This licence allows the licensed fonts to be used, studied, modified and +redistributed freely. The fonts, including any derivative works, can be +bundled, embedded, and redistributed provided the terms of this licence +are met. The fonts and derivatives, however, cannot be released under +any other licence. The requirement for fonts to remain under this +licence does not require any document created using the fonts or their +derivatives to be published under this licence, as long as the primary +purpose of the document is not to be a vehicle for the distribution of +the fonts. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this licence and clearly marked as such. This may +include source files, build scripts and documentation. + +"Original Version" refers to the collection of Font Software components +as received under this licence. + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to +a new environment. + +"Copyright Holder(s)" refers to all individuals and companies who have a +copyright ownership of the Font Software. + +"Substantially Changed" refers to Modified Versions which can be easily +identified as dissimilar to the Font Software by users of the Font +Software comparing the Original Version with the Modified Version. + +To "Propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification and with or without charging +a redistribution fee), making available to the public, and in some +countries other activities as well. + +PERMISSION & CONDITIONS +This licence does not grant any rights under trademark law and all such +rights are reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to propagate the Font Software, subject to +the below conditions: + +1) Each copy of the Font Software must contain the above copyright +notice and this licence. These can be included either as stand-alone +text files, human-readable headers or in the appropriate machine- +readable metadata fields within text or binary files as long as those +fields can be easily viewed by the user. + +2) The font name complies with the following: +(a) The Original Version must retain its name, unmodified. +(b) Modified Versions which are Substantially Changed must be renamed to +avoid use of the name of the Original Version or similar names entirely. +(c) Modified Versions which are not Substantially Changed must be +renamed to both (i) retain the name of the Original Version and (ii) add +additional naming elements to distinguish the Modified Version from the +Original Version. The name of such Modified Versions must be the name of +the Original Version, with "derivative X" where X represents the name of +the new work, appended to that name. + +3) The name(s) of the Copyright Holder(s) and any contributor to the +Font Software shall not be used to promote, endorse or advertise any +Modified Version, except (i) as required by this licence, (ii) to +acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with +their explicit written permission. + +4) The Font Software, modified or unmodified, in part or in whole, must +be distributed entirely under this licence, and must not be distributed +under any other licence. The requirement for fonts to remain under this +licence does not affect any document created using the Font Software, +except any version of the Font Software extracted from a document +created using the Font Software may only be distributed under this +licence. + +TERMINATION +This licence becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf new file mode 100644 index 0000000..01ad81b Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf new file mode 100644 index 0000000..731884e Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf new file mode 100644 index 0000000..b89338d Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf new file mode 100644 index 0000000..4977028 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css b/src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css new file mode 100644 index 0000000..22c3b24 --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css @@ -0,0 +1,54 @@ +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Ubuntu Mono'; + font-style: normal; + font-weight: 900; + src: url('/fonts/ubuntu-mono/static/UbuntuMono-Bold.ttf') format('truetype'); +} diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt b/src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt new file mode 100644 index 0000000..1b45b91 --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt @@ -0,0 +1,112 @@ +Ubuntu Sans Variable Font +========================= + +This download contains Ubuntu Sans as both variable fonts and static fonts. + +Ubuntu Sans is a variable font with these axes: + wdth + wght + +This means all the styles are contained in these files: + Ubuntu_Sans/UbuntuSans-VariableFont_wdth,wght.ttf + Ubuntu_Sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Ubuntu Sans: + Ubuntu_Sans/static/UbuntuSans_Condensed-Thin.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Light.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Regular.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Medium.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Bold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Thin.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Light.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Regular.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Medium.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Bold.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans-Thin.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraLight.ttf + Ubuntu_Sans/static/UbuntuSans-Light.ttf + Ubuntu_Sans/static/UbuntuSans-Regular.ttf + Ubuntu_Sans/static/UbuntuSans-Medium.ttf + Ubuntu_Sans/static/UbuntuSans-SemiBold.ttf + Ubuntu_Sans/static/UbuntuSans-Bold.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraBold.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-Italic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-Italic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ThinItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraLightItalic.ttf + Ubuntu_Sans/static/UbuntuSans-LightItalic.ttf + Ubuntu_Sans/static/UbuntuSans-Italic.ttf + Ubuntu_Sans/static/UbuntuSans-MediumItalic.ttf + Ubuntu_Sans/static/UbuntuSans-SemiBoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-BoldItalic.ttf + Ubuntu_Sans/static/UbuntuSans-ExtraBoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (UFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt b/src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt new file mode 100644 index 0000000..6e722c8 --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt @@ -0,0 +1,96 @@ +------------------------------- +UBUNTU FONT LICENCE Version 1.0 +------------------------------- + +PREAMBLE +This licence allows the licensed fonts to be used, studied, modified and +redistributed freely. The fonts, including any derivative works, can be +bundled, embedded, and redistributed provided the terms of this licence +are met. The fonts and derivatives, however, cannot be released under +any other licence. The requirement for fonts to remain under this +licence does not require any document created using the fonts or their +derivatives to be published under this licence, as long as the primary +purpose of the document is not to be a vehicle for the distribution of +the fonts. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this licence and clearly marked as such. This may +include source files, build scripts and documentation. + +"Original Version" refers to the collection of Font Software components +as received under this licence. + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to +a new environment. + +"Copyright Holder(s)" refers to all individuals and companies who have a +copyright ownership of the Font Software. + +"Substantially Changed" refers to Modified Versions which can be easily +identified as dissimilar to the Font Software by users of the Font +Software comparing the Original Version with the Modified Version. + +To "Propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification and with or without charging +a redistribution fee), making available to the public, and in some +countries other activities as well. + +PERMISSION & CONDITIONS +This licence does not grant any rights under trademark law and all such +rights are reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to propagate the Font Software, subject to +the below conditions: + +1) Each copy of the Font Software must contain the above copyright +notice and this licence. These can be included either as stand-alone +text files, human-readable headers or in the appropriate machine- +readable metadata fields within text or binary files as long as those +fields can be easily viewed by the user. + +2) The font name complies with the following: +(a) The Original Version must retain its name, unmodified. +(b) Modified Versions which are Substantially Changed must be renamed to +avoid use of the name of the Original Version or similar names entirely. +(c) Modified Versions which are not Substantially Changed must be +renamed to both (i) retain the name of the Original Version and (ii) add +additional naming elements to distinguish the Modified Version from the +Original Version. The name of such Modified Versions must be the name of +the Original Version, with "derivative X" where X represents the name of +the new work, appended to that name. + +3) The name(s) of the Copyright Holder(s) and any contributor to the +Font Software shall not be used to promote, endorse or advertise any +Modified Version, except (i) as required by this licence, (ii) to +acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with +their explicit written permission. + +4) The Font Software, modified or unmodified, in part or in whole, must +be distributed entirely under this licence, and must not be distributed +under any other licence. The requirement for fonts to remain under this +licence does not affect any document created using the Font Software, +except any version of the Font Software extracted from a document +created using the Font Software may only be distributed under this +licence. + +TERMINATION +This licence becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..d964bd2 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-Italic-VariableFont_wdth,wght.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..0f8b94f Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/UbuntuSans-VariableFont_wdth,wght.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf new file mode 100644 index 0000000..94f2142 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf new file mode 100644 index 0000000..c627f60 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf new file mode 100644 index 0000000..b6ebd9c Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..0d2de88 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf new file mode 100644 index 0000000..de71460 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf new file mode 100644 index 0000000..8b28b35 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf new file mode 100644 index 0000000..7bac9db Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf new file mode 100644 index 0000000..54299d3 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf new file mode 100644 index 0000000..ba8a6ca Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-LightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf new file mode 100644 index 0000000..987e815 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf new file mode 100644 index 0000000..53658cb Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf new file mode 100644 index 0000000..d972bdc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf new file mode 100644 index 0000000..e7b0b27 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..eadd862 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf new file mode 100644 index 0000000..8e2e750 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf new file mode 100644 index 0000000..b005d6a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf new file mode 100644 index 0000000..6890cfc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf new file mode 100644 index 0000000..58566b0 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf new file mode 100644 index 0000000..e390f2e Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf new file mode 100644 index 0000000..3b7707a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf new file mode 100644 index 0000000..69ad3bc Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf new file mode 100644 index 0000000..1986037 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf new file mode 100644 index 0000000..d0583d1 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf new file mode 100644 index 0000000..e301155 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Light.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf new file mode 100644 index 0000000..c97b070 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-LightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf new file mode 100644 index 0000000..514b7f4 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Medium.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf new file mode 100644 index 0000000..0384dc3 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf new file mode 100644 index 0000000..c99a26c Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf new file mode 100644 index 0000000..ff2c303 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf new file mode 100644 index 0000000..79cf40a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf new file mode 100644 index 0000000..bc0cf57 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-Thin.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf new file mode 100644 index 0000000..9dcad4b Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_Condensed-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf new file mode 100644 index 0000000..917b408 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Bold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf new file mode 100644 index 0000000..02f9dd3 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-BoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf new file mode 100644 index 0000000..465628a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf new file mode 100644 index 0000000..850dc73 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf new file mode 100644 index 0000000..1767953 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLight.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf new file mode 100644 index 0000000..5872619 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ExtraLightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf new file mode 100644 index 0000000..6009cce Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Italic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf new file mode 100644 index 0000000..d76f484 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Light.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf new file mode 100644 index 0000000..ad1074a Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-LightItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf new file mode 100644 index 0000000..91b9fbb Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Medium.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf new file mode 100644 index 0000000..2ad8564 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-MediumItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf new file mode 100644 index 0000000..22b011e Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Regular.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf new file mode 100644 index 0000000..2eb97e8 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBold.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf new file mode 100644 index 0000000..856a6b7 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-SemiBoldItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf new file mode 100644 index 0000000..aef88dd Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-Thin.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf new file mode 100644 index 0000000..a86b571 Binary files /dev/null and b/src/parlant/api/chat/public/fonts/ubuntu-sans/static/UbuntuSans_SemiCondensed-ThinItalic.ttf differ diff --git a/src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css b/src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css new file mode 100644 index 0000000..43ac5aa --- /dev/null +++ b/src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css @@ -0,0 +1,48 @@ +@font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Thin.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-ExtraLight.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Light.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Regular.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Medium.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-SemiBold.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-Bold.ttf') format('truetype') + } + @font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-weight: 800; + src: url('/fonts/ubuntu-sans/static/UbuntuSans-ExtraBold.ttf') format('truetype') + } \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/add-filled.svg b/src/parlant/api/chat/public/icons/add-filled.svg new file mode 100644 index 0000000..f68f879 --- /dev/null +++ b/src/parlant/api/chat/public/icons/add-filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/add.svg b/src/parlant/api/chat/public/icons/add.svg new file mode 100644 index 0000000..ebab8c9 --- /dev/null +++ b/src/parlant/api/chat/public/icons/add.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/arrow-down.svg b/src/parlant/api/chat/public/icons/arrow-down.svg new file mode 100644 index 0000000..e740e4b --- /dev/null +++ b/src/parlant/api/chat/public/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/cancel.svg b/src/parlant/api/chat/public/icons/cancel.svg new file mode 100644 index 0000000..727b23a --- /dev/null +++ b/src/parlant/api/chat/public/icons/cancel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/close-logs-hover.svg b/src/parlant/api/chat/public/icons/close-logs-hover.svg new file mode 100644 index 0000000..9915098 --- /dev/null +++ b/src/parlant/api/chat/public/icons/close-logs-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/close-logs.svg b/src/parlant/api/chat/public/icons/close-logs.svg new file mode 100644 index 0000000..1646f66 --- /dev/null +++ b/src/parlant/api/chat/public/icons/close-logs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/close-white.svg b/src/parlant/api/chat/public/icons/close-white.svg new file mode 100644 index 0000000..d836122 --- /dev/null +++ b/src/parlant/api/chat/public/icons/close-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/close.svg b/src/parlant/api/chat/public/icons/close.svg new file mode 100644 index 0000000..46ebf88 --- /dev/null +++ b/src/parlant/api/chat/public/icons/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/copy-session.svg b/src/parlant/api/chat/public/icons/copy-session.svg new file mode 100644 index 0000000..51303a7 --- /dev/null +++ b/src/parlant/api/chat/public/icons/copy-session.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/copy.svg b/src/parlant/api/chat/public/icons/copy.svg new file mode 100644 index 0000000..420a550 --- /dev/null +++ b/src/parlant/api/chat/public/icons/copy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/delete.svg b/src/parlant/api/chat/public/icons/delete.svg new file mode 100644 index 0000000..284138a --- /dev/null +++ b/src/parlant/api/chat/public/icons/delete.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/dot-saparetor.svg b/src/parlant/api/chat/public/icons/dot-saparetor.svg new file mode 100644 index 0000000..49970c3 --- /dev/null +++ b/src/parlant/api/chat/public/icons/dot-saparetor.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/edit-message.svg b/src/parlant/api/chat/public/icons/edit-message.svg new file mode 100644 index 0000000..2f5880e --- /dev/null +++ b/src/parlant/api/chat/public/icons/edit-message.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/edit-white.svg b/src/parlant/api/chat/public/icons/edit-white.svg new file mode 100644 index 0000000..220fb39 --- /dev/null +++ b/src/parlant/api/chat/public/icons/edit-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/edit.svg b/src/parlant/api/chat/public/icons/edit.svg new file mode 100644 index 0000000..7687117 --- /dev/null +++ b/src/parlant/api/chat/public/icons/edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/error.svg b/src/parlant/api/chat/public/icons/error.svg new file mode 100644 index 0000000..f8298b3 --- /dev/null +++ b/src/parlant/api/chat/public/icons/error.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/expand.svg b/src/parlant/api/chat/public/icons/expand.svg new file mode 100644 index 0000000..dc48143 --- /dev/null +++ b/src/parlant/api/chat/public/icons/expand.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/export.svg b/src/parlant/api/chat/public/icons/export.svg new file mode 100644 index 0000000..8ded884 --- /dev/null +++ b/src/parlant/api/chat/public/icons/export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/filter.svg b/src/parlant/api/chat/public/icons/filter.svg new file mode 100644 index 0000000..1b99fc7 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filter.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/filters.svg b/src/parlant/api/chat/public/icons/filters.svg new file mode 100644 index 0000000..d59a3d3 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/parlant/api/chat/public/icons/filters/guideline-matcher-color.svg b/src/parlant/api/chat/public/icons/filters/guideline-matcher-color.svg new file mode 100644 index 0000000..3aa9796 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/guideline-matcher-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/filters/guideline-matcher.svg b/src/parlant/api/chat/public/icons/filters/guideline-matcher.svg new file mode 100644 index 0000000..6d254af --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/guideline-matcher.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/filters/message-composer-color.svg b/src/parlant/api/chat/public/icons/filters/message-composer-color.svg new file mode 100644 index 0000000..3ec90cd --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/message-composer-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/filters/message-composer.svg b/src/parlant/api/chat/public/icons/filters/message-composer.svg new file mode 100644 index 0000000..8691176 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/message-composer.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/filters/tool-caller-color.svg b/src/parlant/api/chat/public/icons/filters/tool-caller-color.svg new file mode 100644 index 0000000..4431032 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/tool-caller-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/filters/tool-caller.svg b/src/parlant/api/chat/public/icons/filters/tool-caller.svg new file mode 100644 index 0000000..9ca0d65 --- /dev/null +++ b/src/parlant/api/chat/public/icons/filters/tool-caller.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/funnel.svg b/src/parlant/api/chat/public/icons/funnel.svg new file mode 100644 index 0000000..5c5dbd4 --- /dev/null +++ b/src/parlant/api/chat/public/icons/funnel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/green-v.svg b/src/parlant/api/chat/public/icons/green-v.svg new file mode 100644 index 0000000..a438b32 --- /dev/null +++ b/src/parlant/api/chat/public/icons/green-v.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/more.svg b/src/parlant/api/chat/public/icons/more.svg new file mode 100644 index 0000000..5aea29b --- /dev/null +++ b/src/parlant/api/chat/public/icons/more.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/new-session.svg b/src/parlant/api/chat/public/icons/new-session.svg new file mode 100644 index 0000000..5095531 --- /dev/null +++ b/src/parlant/api/chat/public/icons/new-session.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/pending.svg b/src/parlant/api/chat/public/icons/pending.svg new file mode 100644 index 0000000..f9eaaf6 --- /dev/null +++ b/src/parlant/api/chat/public/icons/pending.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/icons/puzzle-hover.svg b/src/parlant/api/chat/public/icons/puzzle-hover.svg new file mode 100644 index 0000000..0c7d9f6 --- /dev/null +++ b/src/parlant/api/chat/public/icons/puzzle-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/puzzle.svg b/src/parlant/api/chat/public/icons/puzzle.svg new file mode 100644 index 0000000..0beae63 --- /dev/null +++ b/src/parlant/api/chat/public/icons/puzzle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/regenerate-arrow-hover.svg b/src/parlant/api/chat/public/icons/regenerate-arrow-hover.svg new file mode 100644 index 0000000..1df8f8f --- /dev/null +++ b/src/parlant/api/chat/public/icons/regenerate-arrow-hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/regenerate-arrow.svg b/src/parlant/api/chat/public/icons/regenerate-arrow.svg new file mode 100644 index 0000000..d6d6268 --- /dev/null +++ b/src/parlant/api/chat/public/icons/regenerate-arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/regenerate-filled.svg b/src/parlant/api/chat/public/icons/regenerate-filled.svg new file mode 100644 index 0000000..e406597 --- /dev/null +++ b/src/parlant/api/chat/public/icons/regenerate-filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/regenerate.svg b/src/parlant/api/chat/public/icons/regenerate.svg new file mode 100644 index 0000000..d6d6268 --- /dev/null +++ b/src/parlant/api/chat/public/icons/regenerate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/rename.svg b/src/parlant/api/chat/public/icons/rename.svg new file mode 100644 index 0000000..370e432 --- /dev/null +++ b/src/parlant/api/chat/public/icons/rename.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/resend-hover.svg b/src/parlant/api/chat/public/icons/resend-hover.svg new file mode 100644 index 0000000..51dde04 --- /dev/null +++ b/src/parlant/api/chat/public/icons/resend-hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/parlant/api/chat/public/icons/resend.svg b/src/parlant/api/chat/public/icons/resend.svg new file mode 100644 index 0000000..f90ed53 --- /dev/null +++ b/src/parlant/api/chat/public/icons/resend.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/resize.svg b/src/parlant/api/chat/public/icons/resize.svg new file mode 100644 index 0000000..3f88f7f --- /dev/null +++ b/src/parlant/api/chat/public/icons/resize.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/icons/save.svg b/src/parlant/api/chat/public/icons/save.svg new file mode 100644 index 0000000..d0dbda5 --- /dev/null +++ b/src/parlant/api/chat/public/icons/save.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/search.svg b/src/parlant/api/chat/public/icons/search.svg new file mode 100644 index 0000000..e61834c --- /dev/null +++ b/src/parlant/api/chat/public/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/public/icons/send.svg b/src/parlant/api/chat/public/icons/send.svg new file mode 100644 index 0000000..a8f7b35 --- /dev/null +++ b/src/parlant/api/chat/public/icons/send.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/icons/text.svg b/src/parlant/api/chat/public/icons/text.svg new file mode 100644 index 0000000..ad65d87 --- /dev/null +++ b/src/parlant/api/chat/public/icons/text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/parlant/api/chat/public/icons/v.svg b/src/parlant/api/chat/public/icons/v.svg new file mode 100644 index 0000000..b194386 --- /dev/null +++ b/src/parlant/api/chat/public/icons/v.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/parlant/api/chat/public/logo-color.svg b/src/parlant/api/chat/public/logo-color.svg new file mode 100644 index 0000000..2484564 --- /dev/null +++ b/src/parlant/api/chat/public/logo-color.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/parlant/api/chat/public/logo-muted.svg b/src/parlant/api/chat/public/logo-muted.svg new file mode 100644 index 0000000..2d16b01 --- /dev/null +++ b/src/parlant/api/chat/public/logo-muted.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/parlant/api/chat/public/logo.svg b/src/parlant/api/chat/public/logo.svg new file mode 100644 index 0000000..016a388 --- /dev/null +++ b/src/parlant/api/chat/public/logo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/parlant/api/chat/public/mp4/loading.mp4 b/src/parlant/api/chat/public/mp4/loading.mp4 new file mode 100644 index 0000000..4deb48f Binary files /dev/null and b/src/parlant/api/chat/public/mp4/loading.mp4 differ diff --git a/src/parlant/api/chat/public/parlant-bubble-app-logo.svg b/src/parlant/api/chat/public/parlant-bubble-app-logo.svg new file mode 100644 index 0000000..942cd7b --- /dev/null +++ b/src/parlant/api/chat/public/parlant-bubble-app-logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/parlant-bubble-muted.svg b/src/parlant/api/chat/public/parlant-bubble-muted.svg new file mode 100644 index 0000000..338fa6f --- /dev/null +++ b/src/parlant/api/chat/public/parlant-bubble-muted.svg @@ -0,0 +1,5 @@ + + + + diff --git a/src/parlant/api/chat/public/parlant-bubble.svg b/src/parlant/api/chat/public/parlant-bubble.svg new file mode 100644 index 0000000..64fa44f --- /dev/null +++ b/src/parlant/api/chat/public/parlant-bubble.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/parlant-logo-after.svg b/src/parlant/api/chat/public/parlant-logo-after.svg new file mode 100644 index 0000000..511f41f --- /dev/null +++ b/src/parlant/api/chat/public/parlant-logo-after.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/parlant/api/chat/public/select-session.svg b/src/parlant/api/chat/public/select-session.svg new file mode 100644 index 0000000..9a9911d --- /dev/null +++ b/src/parlant/api/chat/public/select-session.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/parlant/api/chat/setupTests.ts b/src/parlant/api/chat/setupTests.ts new file mode 100644 index 0000000..6df58f0 --- /dev/null +++ b/src/parlant/api/chat/setupTests.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest'; \ No newline at end of file diff --git a/src/parlant/api/chat/src/App.css b/src/parlant/api/chat/src/App.css new file mode 100644 index 0000000..f5ab8ba --- /dev/null +++ b/src/parlant/api/chat/src/App.css @@ -0,0 +1,113 @@ +#root { + height: 100vh; + margin: auto; + font-family: 'Inter'; +} + +body { + pointer-events: all !important; +} + +.fixed-scroll { + overflow: scroll; + scrollbar-width: thin; + scrollbar-color: #ebecf0 transparent; +} + +.fixed-scroll:hover { + scrollbar-color: #cdcdcd transparent; +} + +.fixed-scroll::-webkit-scrollbar { + width: 10px; +} + +.fixed-scroll::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.5); + border-radius: 10px; +} + +.fixed-scroll::-webkit-scrollbar-track { + background: transparent; +} + +.markdown * { + font-size: revert; + font-weight: revert; + padding: revert; + margin: revert; + list-style-type: revert; + color: revert; + text-decoration: revert; +} + +img { + user-select: none; +} + +.bubblesWrapper { + height: fit-content; + width: fit-content; + background-color: #f5f9f7; + padding: 10px; + margin: 10px; + margin-inline-start: 20px; + border-radius: 15px; +} + +.bubbles { + height: 15px; + width: 31px; + aspect-ratio: 2.5; + --_g: no-repeat radial-gradient(farthest-side, #333333 90%, #0000); + background: var(--_g), var(--_g), var(--_g); + background-size: 25% 50%; + animation: l43 1s infinite linear; +} + +@keyframes l43 { + 0% { + background-position: calc(0 * 100% / 2) 50%, calc(1 * 100% / 2) 50%, calc(2 * 100% / 2) 50%; + } + 20% { + background-position: calc(0 * 100% / 2) 0, calc(1 * 100% / 2) 50%, calc(2 * 100% / 2) 50%; + } + 40% { + background-position: calc(0 * 100% / 2) 100%, calc(1 * 100% / 2) 0, calc(2 * 100% / 2) 50%; + } + 60% { + background-position: calc(0 * 100% / 2) 50%, calc(1 * 100% / 2) 100%, calc(2 * 100% / 2) 0; + } + 80% { + background-position: calc(0 * 100% / 2) 50%, calc(1 * 100% / 2) 50%, calc(2 * 100% / 2) 100%; + } + 100% { + background-position: calc(0 * 100% / 2) 50%, calc(1 * 100% / 2) 50%, calc(2 * 100% / 2) 50%; + } +} + +@keyframes animate-slide-down { + from { + max-height: 0; + } + to { + max-height: 300px; + min-height: fit-content; + } +} + +@keyframes animate-slide-up { + from { + max-height: 150px; + } + to { + max-height: 0; + } +} + +.animate-slide-down { + animation: animate-slide-down 0.5s ease-out forwards; +} +.animate-slide-up { + animation: animate-slide-up 0.3s linear forwards; +} diff --git a/src/parlant/api/chat/src/App.tsx b/src/parlant/api/chat/src/App.tsx new file mode 100644 index 0000000..413cecb --- /dev/null +++ b/src/parlant/api/chat/src/App.tsx @@ -0,0 +1,22 @@ +import './App.css'; +import Chatbot from './components/chatbot/chatbot'; +import {useWebSocket} from './hooks/useWebSocket'; +import {BASE_URL} from './utils/api'; +import {handleChatLogs} from './utils/logs'; + +const WebSocketComp = () => { + const socket = useWebSocket(`${BASE_URL}/logs`, true, null, handleChatLogs); + void socket; + return
; +}; + +function App() { + return ( +
+ + +
+ ); +} + +export default App; diff --git a/src/parlant/api/chat/src/assets/react.svg b/src/parlant/api/chat/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/parlant/api/chat/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/agents-list/agent-list.module.scss b/src/parlant/api/chat/src/components/agents-list/agent-list.module.scss new file mode 100644 index 0000000..c7f1009 --- /dev/null +++ b/src/parlant/api/chat/src/components/agents-list/agent-list.module.scss @@ -0,0 +1,6 @@ +.select { + padding: 0 !important; + button { + display: none; + } +} \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/agents-list/agent-list.tsx b/src/parlant/api/chat/src/components/agents-list/agent-list.tsx new file mode 100644 index 0000000..7f84350 --- /dev/null +++ b/src/parlant/api/chat/src/components/agents-list/agent-list.tsx @@ -0,0 +1,81 @@ +import {AgentInterface, CustomerInterface, SessionInterface} from '@/utils/interfaces'; +import {ReactNode, useEffect} from 'react'; + +import {spaceClick} from '@/utils/methods'; +import {DialogDescription, DialogHeader, DialogTitle} from '../ui/dialog'; +import clsx from 'clsx'; +import {useAtom} from 'jotai'; +import {agentAtom, agentsAtom, customerAtom, customersAtom, dialogAtom, newSessionAtom, sessionAtom} from '@/store'; +import Avatar from '../avatar/avatar'; + +export const NEW_SESSION_ID = 'NEW_SESSION'; + +const newSessionObj: SessionInterface = { + customer_id: '', + title: 'New Conversation', + agent_id: '', + creation_utc: new Date().toLocaleString('en-US'), + id: NEW_SESSION_ID, +}; + +const AgentList = (): ReactNode => { + const [, setSession] = useAtom(sessionAtom); + const [agent, setAgent] = useAtom(agentAtom); + const [agents] = useAtom(agentsAtom); + const [customers] = useAtom(customersAtom); + const [, setCustomer] = useAtom(customerAtom); + const [, setNewSession] = useAtom(newSessionAtom); + const [dialog] = useAtom(dialogAtom); + + useEffect(() => { + if (agents?.length && agents.length === 1) selectAgent(agents[0]); + }, []); + + const selectAgent = (agent: AgentInterface): void => { + setAgent(agent); + if (customers.length < 2) { + selectCustomer(customers?.[0], agent); + } + }; + + const selectCustomer = (customer: CustomerInterface, currAgent?: AgentInterface) => { + setAgent(agent || currAgent || null); + setCustomer(customer); + setNewSession({...newSessionObj, agent_id: agent?.id as string, customer_id: customer.id}); + setSession(newSessionObj); + dialog.closeDialog(); + }; + + return ( +
+ + +
+ {agent ? 'Select a Customer' : 'Select an Agent'} + close +
+
+
+
+ {(agent ? customers : agents)?.map((entity) => ( +
(agent ? selectCustomer(entity) : selectAgent(entity))} + key={entity.id} + className={clsx('cursor-pointer hover:bg-[#FBFBFB] min-h-[78px] h-[78px] w-full border-b-[0.6px] border-b-solid border-b-[#EBECF0] flex items-center ps-[30px] pe-[20px]')}> + +
+
{entity.id === 'guest' ? 'Guest' : entity.name}
+
(id={entity.id})
+
+
+ ))} +
+
+ ); +}; + +export default AgentList; diff --git a/src/parlant/api/chat/src/components/avatar/avatar.tsx b/src/parlant/api/chat/src/components/avatar/avatar.tsx new file mode 100644 index 0000000..3986754 --- /dev/null +++ b/src/parlant/api/chat/src/components/avatar/avatar.tsx @@ -0,0 +1,85 @@ +/* eslint-disable react-refresh/only-export-components */ +import {AgentInterface, CustomerInterface} from '@/utils/interfaces'; +import React, {ReactNode} from 'react'; +import Tooltip from '../ui/custom/tooltip'; +import {twMerge} from 'tailwind-merge'; + +interface Props { + agent: AgentInterface; + customer?: CustomerInterface; + tooltip?: boolean; +} + +interface Color { + text: string; + background: string; + outerBackground: string; + iconBackground?: string; + iconText?: string; +} + +const colors = { + green: {dark: 'rgb(80 130 1)', light: 'rgb(80 130 1 / 10%)', extraLight: 'rgb(80 130 1 / 5%)'}, + purple: {dark: 'rgb(85 1 104)', light: 'rgb(85 1 104 / 10%)', extraLight: 'rgb(85 1 104 / 5%)'}, + pink: {dark: 'rgb(155 3 95)', light: 'rgb(155 3 95 / 10%)', extraLight: 'rgb(155 3 95 / 5%)'}, + orange: {dark: 'rgb(183 99 0)', light: 'rgb(183 99 0 / 10%)', extraLight: 'rgb(183 99 0 / 5%)'}, + blue: {dark: 'rgb(46 128 108)', light: 'rgb(46 128 108 / 10%)', extraLight: 'rgb(46 128 108 / 5%)'}, +}; + +const agentColors: Color[] = [ + {text: 'white', background: colors.green.dark, outerBackground: colors.green.light}, + {text: 'white', background: colors.purple.dark, outerBackground: colors.purple.light}, + {text: 'white', background: colors.pink.dark, outerBackground: colors.pink.light}, + {text: 'white', background: colors.orange.dark, outerBackground: colors.orange.light}, + {text: 'white', background: colors.blue.dark, outerBackground: colors.blue.light}, +]; +const customerColors: Color[] = [ + {iconBackground: colors.green.dark, background: colors.green.light, text: colors.green.dark, outerBackground: colors.green.extraLight}, + {iconBackground: colors.purple.dark, background: colors.purple.light, text: colors.purple.dark, outerBackground: colors.purple.extraLight}, + {iconBackground: colors.pink.dark, background: colors.pink.light, text: colors.pink.dark, outerBackground: colors.pink.extraLight}, + {iconBackground: colors.orange.dark, background: colors.orange.light, text: colors.orange.dark, outerBackground: colors.orange.extraLight}, + {iconBackground: colors.blue.dark, background: colors.blue.light, text: colors.blue.dark, outerBackground: colors.blue.extraLight}, +]; + +export const getAvatarColor = (id: string, type: 'agent' | 'customer') => { + const palette = type === 'agent' ? agentColors : customerColors; + const hash = [...id].reduce((acc, char) => acc + char.charCodeAt(0), 0); + return palette[hash % palette.length]; +}; + +const Avatar = ({agent, customer, tooltip = true}: Props): ReactNode => { + const agentColor = getAvatarColor(agent.id, 'agent'); + const customerColor = customer && getAvatarColor(customer.id, 'customer'); + const isAgentUnavailable = agent?.name === 'N/A'; + const isCustomerUnavailable = customer?.name === 'N/A'; + const agentFirstLetter = agent.name.replaceAll(/>| +
+
+
+ {isAgentUnavailable ? 'N/A' : agentFirstLetter} +
+
+ {agent && customer && ( +
+ {isCustomerUnavailable ? 'N/A' : customerFirstLetter} +
+ )} +
+ + ); +}; + +export default Avatar; diff --git a/src/parlant/api/chat/src/components/canned-response/canned-response.tsx b/src/parlant/api/chat/src/components/canned-response/canned-response.tsx new file mode 100644 index 0000000..185872f --- /dev/null +++ b/src/parlant/api/chat/src/components/canned-response/canned-response.tsx @@ -0,0 +1,35 @@ +import Tooltip from '../ui/custom/tooltip'; +import {copy} from '@/lib/utils'; +import {twMerge} from 'tailwind-merge'; + +// const TooltipComponent = ({fragmentId}: {fragmentId: string}) => { +// return ( +//
copy(fragmentId)}> +//
Fragment ID: {fragmentId}
+// +//
+// ); +// }; + +const CannedResponse = ({cannedResponse: cannedResponse}: {cannedResponse: {id: string; value: string}}) => { + const [id, value] = cannedResponse?.value || ['', '']; + return ( +
+
+ +
{value || 'loading'}
+
+ +
copy(id || '', e.currentTarget)} + className='hidden absolute right-[10px] top-[8px] cursor-pointer size-[28px] group-hover:flex justify-center items-center bg-white hover:bg-[#F3F5F9] border border-[#EEEEEE] hover:border-[#E9EBEF] rounded-[6px]'> + +
+
+
+ // } side='top' align='start' className='ml-[23px] -mb-[10px] font-medium font-inter'> + // + ); +}; + +export default CannedResponse; diff --git a/src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx b/src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx new file mode 100644 index 0000000..cbcefc5 --- /dev/null +++ b/src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx @@ -0,0 +1,39 @@ +import {useState} from 'react'; +import {ClassNameValue, twMerge} from 'tailwind-merge'; +import CannedResponse from '../canned-response/canned-response'; +import ErrorBoundary from '../error-boundary/error-boundary'; + +export interface Utterance { + id: string; + value: string; +} + +const CannedResponses = ({cannedResponses: cannedResponses, className}: {cannedResponses: {id: string; value: string}[]; className?: ClassNameValue}) => { + const [isOpen, setIsOpen] = useState(false); + + const onToggle = (e: any) => { + setIsOpen(e.target.open); + }; + + return ( +
+ + Canned Responses + + +
+
+
+ Could not load canned responses
}> + {cannedResponses.map((cannedResponse) => ( + + ))} + +
+
+ +
+ ); +}; + +export default CannedResponses; diff --git a/src/parlant/api/chat/src/components/chat-header/chat-header.tsx b/src/parlant/api/chat/src/components/chat-header/chat-header.tsx new file mode 100644 index 0000000..d6da39c --- /dev/null +++ b/src/parlant/api/chat/src/components/chat-header/chat-header.tsx @@ -0,0 +1,82 @@ +import {ReactNode, useEffect, useState} from 'react'; +import Tooltip from '../ui/custom/tooltip'; +import {spaceClick} from '@/utils/methods'; +import AgentList from '../agents-list/agent-list'; +import {Menu} from 'lucide-react'; +import {Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger} from '../ui/sheet'; +import SessionList from '../session-list/session-list'; +import HeaderWrapper from '../header-wrapper/header-wrapper'; +import {useAtom} from 'jotai'; +import {agentAtom, dialogAtom, sessionAtom} from '@/store'; +import {Input} from '../ui/input'; +// import DarkModeToggle from '../dark-mode-toggle/dark-mode-toggle'; + +export const NEW_SESSION_ID = 'NEW_SESSION'; + +const ChatHeader = ({setFilterSessionVal, filterSessionVal}: {setFilterSessionVal: (value: string) => void; filterSessionVal: string}): ReactNode => { + const [sheetOpen, setSheetOpen] = useState(false); + const [session, setSession] = useAtom(sessionAtom); + const [, setAgent] = useAtom(agentAtom); + const [dialog] = useAtom(dialogAtom); + + useEffect(() => { + if (sheetOpen) setSheetOpen(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [session]); + + const createNewSession = () => { + setSession(null); + setAgent(null); + dialog.openDialog('', , {height: '536px', width: '604px'}); + }; + + return ( + +
+
+
+ logo +
+
+ setSheetOpen(!sheetOpen)}> + setSheetOpen(true)}> + + + + + + + +
+ + setFilterSessionVal(e.target.value)} className='!ring-0 !ring-offset-0 h-[38px] w-full placeholder:font-light ps-[35px] rounded-[6px] !pointer-events-auto' /> +
+ +
+ +
+
+ + logo + +
+ + setFilterSessionVal(e.target.value)} className='!ring-0 !ring-offset-0 h-[38px] w-full placeholder:font-light ps-[35px] rounded-[6px] !pointer-events-auto' /> +
+
+ + <> + add session + add session + + +
+
+ {/*
+ +
*/} +
+ ); +}; + +export default ChatHeader; diff --git a/src/parlant/api/chat/src/components/chatbot/chatbot.tsx b/src/parlant/api/chat/src/components/chatbot/chatbot.tsx new file mode 100644 index 0000000..911888f --- /dev/null +++ b/src/parlant/api/chat/src/components/chatbot/chatbot.tsx @@ -0,0 +1,102 @@ +/* eslint-disable react-refresh/only-export-components */ +import {createContext, ReactElement, useEffect, useState} from 'react'; +import SessionList from '../session-list/session-list'; +import ErrorBoundary from '../error-boundary/error-boundary'; +import ChatHeader from '../chat-header/chat-header'; +import {useDialog} from '@/hooks/useDialog'; +import {Helmet} from 'react-helmet'; +import AgentList, {NEW_SESSION_ID} from '../agents-list/agent-list'; +import {useAtom} from 'jotai'; +import {agentAtom, dialogAtom, sessionAtom, sessionsAtom} from '@/store'; +import {twMerge} from 'tailwind-merge'; +import SessionView from '../session-view/session-view'; +import {spaceClick} from '@/utils/methods'; + +export const SessionProvider = createContext({}); + +const SessionsSection = () => { + const [filterSessionVal, setFilterSessionVal] = useState(''); + return ( +
+ + +
+ ); +}; + +export default function Chatbot(): ReactElement { + // const SessionView = lazy(() => import('../session-view/session-view')); + const [sessionName, setSessionName] = useState(''); + const {openDialog, DialogComponent, closeDialog} = useDialog(); + const [showMessage, setShowMessage] = useState(false); + const [sessions] = useAtom(sessionsAtom); + const [session, setSession] = useAtom(sessionAtom); + const [, setDialog] = useAtom(dialogAtom); + const [filterSessionVal, setFilterSessionVal] = useState(''); + const [, setAgent] = useAtom(agentAtom); + const [dialog] = useAtom(dialogAtom); + + useEffect(() => { + if (sessions) { + setShowMessage(!!sessions.length); + } + setTimeout(() => { + setShowMessage(true); + }, 500); + }, [sessions]); + + useEffect(() => { + if (session?.id) { + if (session?.id === NEW_SESSION_ID) setSessionName('Parlant | New Session'); + else { + const sessionTitle = session?.title; + if (sessionTitle) setSessionName(`Parlant | ${sessionTitle}`); + } + } else setSessionName('Parlant'); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [session?.id]); + + useEffect(() => { + setDialog({openDialog, closeDialog}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const createNewSession = () => { + setSession(null); + setAgent(null); + dialog.openDialog('', , {height: '536px', width: '604px'}); + }; + + return ( + + + +
+
+ +
+
+ + {session?.id ? ( +
+ +
+ ) : ( +
+ +
+ {showMessage && !sessions.length ? 'Start a session to begin chatting' : 'Select or start a session to begin chatting'} +
+ add session + add session +
+
+
+ )} +
+
+
+ +
+ ); +} diff --git a/src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx b/src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx new file mode 100644 index 0000000..3bec73b --- /dev/null +++ b/src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx @@ -0,0 +1,33 @@ +import { ReactNode, useEffect, useState } from 'react'; + +const DarkModeToggle = (): ReactNode =>{ + const getInitialTheme = () => localStorage.getItem('theme') || 'light'; + const [theme, setTheme] = useState(getInitialTheme); + + useEffect(() => { + const root = window.document.documentElement; + + if (theme === 'dark') { + root.classList.add('dark'); + } else { + root.classList.remove('dark'); + } + + localStorage.setItem('theme', theme); + }, [theme]); + + const toggleTheme = () => { + setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); + }; + + return ( +
+ +
+ ); +}; + +export default DarkModeToggle; \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx b/src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx new file mode 100644 index 0000000..3aee387 --- /dev/null +++ b/src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx @@ -0,0 +1,47 @@ +import {Component, ReactNode} from 'react'; + +interface Props { + children: ReactNode; + component?: ReactNode; +} + +interface State { + hasError: boolean; + errorStack?: string; +} + +export default class ErrorBoundary extends Component { + constructor(props: Props) { + super(props); + this.state = {hasError: false}; + } + + static getDerivedStateFromError() { + return {hasError: true}; + } + + componentDidCatch(error: Error) { + this.setState({errorStack: error.stack}); + } + + render(): ReactNode { + return this.state.hasError + ? this.props.component || ( +
+ Logo +

Oops! Something went wrong

+

+ We apologize for the inconvenience. Please try again later, or{' '} + + try again now + + . +

+
+ {this.state.errorStack} +
+
+ ) + : this.props.children; + } +} diff --git a/src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss b/src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss new file mode 100644 index 0000000..3661e0f --- /dev/null +++ b/src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss @@ -0,0 +1,18 @@ + .colorsButton { + .children { + color: white; + border-radius: 6px; + border: none; + } + &:hover, &:focus { + background: linear-gradient(89.94deg, #FFB800, #B4E64A, #87DAC6, #FF68C3, #005CE7); + background-size: 200% 200%; + div { + background: linear-gradient(89.94deg, #FFB800, #B4E64A, #87DAC6, #FF68C3, #005CE7); + } + .children { + color: black !important; + background-color: #ffffffc8 !important; + } + } + } \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx b/src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx new file mode 100644 index 0000000..1288d0d --- /dev/null +++ b/src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx @@ -0,0 +1,21 @@ +import { spaceClick } from '@/utils/methods'; +import styles from './gradient-button.module.scss'; +import { ReactElement, ReactNode } from 'react'; + +interface GradientButtonProps { + className?: string; + buttonClassName?: string; + children: ReactNode + onClick: (e: React.MouseEvent) => void; +} + +export default function GradientButton({className, buttonClassName, children, onClick}: GradientButtonProps): ReactElement { + return ( + +
+ + {children} + +
+ ); +} \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx b/src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx new file mode 100644 index 0000000..aaa0c55 --- /dev/null +++ b/src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx @@ -0,0 +1,12 @@ +import {ReactNode} from 'react'; +import {twMerge} from 'tailwind-merge'; + +const HeaderWrapper = ({children, className}: {children?: ReactNode; className?: string}) => { + return
+
+ {children} +
+
; +}; + +export default HeaderWrapper; diff --git a/src/parlant/api/chat/src/components/log-filters/log-filters.tsx b/src/parlant/api/chat/src/components/log-filters/log-filters.tsx new file mode 100644 index 0000000..b1af15b --- /dev/null +++ b/src/parlant/api/chat/src/components/log-filters/log-filters.tsx @@ -0,0 +1,347 @@ +import {memo, ReactNode, useEffect, useRef, useState} from 'react'; +import {Button} from '../ui/button'; +import {Checkbox} from '../ui/checkbox'; +import {Input} from '../ui/input'; +import {Dialog, DialogClose, DialogContent, DialogDescription, DialogPortal, DialogTitle, DialogTrigger} from '../ui/dialog'; +import {ClassNameValue, twMerge} from 'tailwind-merge'; +import {X} from 'lucide-react'; +import {getDistanceToRight} from '@/utils/methods'; +import Tooltip from '../ui/custom/tooltip'; +import {Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue} from '../ui/select'; + +export type Type = 'GuidelineMatcher' | 'MessageEventComposer' | 'ToolCaller'; +export type Level = 'CRITICAL' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG' | 'TRACE'; + +const ALL_TYPES: Type[] = ['GuidelineMatcher', 'ToolCaller', 'MessageEventComposer']; +const ALL_LEVELS: Level[] = ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'TRACE']; + +const typeOptions: {[key in Type]: {label: string; icon: string; color: string}} = { + GuidelineMatcher: { + label: 'Guideline Matcher', + icon: 'icons/filters/guideline-matcher-color.svg', + color: '#419480', + }, + MessageEventComposer: { + label: 'Message Event Composer', + icon: 'icons/filters/message-composer-color.svg', + color: '#7E3A89', + }, + ToolCaller: { + label: 'Tool Caller', + icon: 'icons/filters/tool-caller-color.svg', + color: '#CB7714', + }, +}; + +const AddFilterChip = ({className}: {className?: ClassNameValue}) => { + return ( +
+
+ {/*

+

*/} + +

Add Content Filter

+
+
+ ); +}; + +const FilterDialogContent = ({contentChanged, defaultValue}: {contentChanged: (text: string) => void; defaultValue?: string}) => { + const [inputVal, setInputVal] = useState(defaultValue || ''); + + const onApplyClick = () => { + const trimmed = inputVal.trim(); + if (trimmed) contentChanged(inputVal); + }; + + return ( +
+

Filter by content

+
+ setInputVal(e.target.value)} name='filter' className='h-[36px] !ring-0 !ring-offset-0 border-none text-[16px] bg-[#FBFBFB] hover:bg-[#F5F6F8] focus:!bg-white' /> +
+
+ Cancel + + Apply + +
+
+ ); +}; + +const FilterDialog = ({contentChanged, content, children, className}: {contentChanged: (text: string) => void; content?: string; children?: ReactNode; className?: ClassNameValue}) => { + return ( + + {children || } + + + Filter by content + Filter by content + + + + + ); +}; + +const LogFilters = ({ + applyFn, + def, + filterId, + className, + showDropdown, + showTags, + deleteFilterTab, +}: { + applyFn: (types: string[], level: string, content: string[]) => void; + filterId?: number; + def?: {level?: Level; types?: Type[]; content?: string[]} | null; + className?: ClassNameValue; + showDropdown?: boolean; + showTags?: boolean; + deleteFilterTab?: (filterId: number | undefined) => void; +}) => { + const [sources, setSources] = useState(structuredClone(def?.types || [])); + const [contentConditions, setContentConditions] = useState(structuredClone(def?.content || [])); + const [level, setLevel] = useState(def?.level || ALL_LEVELS[ALL_LEVELS.length - 1]); + const [prevTabId, setPrevTabId] = useState(); + + useEffect(() => { + if (!showTags) return; + if (filterId && filterId !== prevTabId) { + const types = structuredClone(def?.types || ALL_TYPES); + const level = def?.level || ALL_LEVELS[ALL_LEVELS.length - 1]; + const content = def?.content || []; + setSources(types); + setLevel(level); + setContentConditions(content); + applyFn(types, level, content); + setPrevTabId(filterId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filterId]); + + useEffect(() => { + setSources(def?.types || []); + setLevel(def?.level || ALL_LEVELS[ALL_LEVELS.length - 1]); + setContentConditions(def?.content || []); + }, [def]); + + // const changeSource = (type: Type, value: boolean, cb?: (sources: Type[], level: Level, contentConditions: string[]) => void) => { + // setSources((val) => { + // if (value) val.push(type); + // else val = val.filter((item) => item !== type); + // const vals = [...new Set(val)]; + // cb?.(vals, level, contentConditions); + // return vals; + // }); + // }; + + const TypeChip = ({type, className}: {type: Type; className?: ClassNameValue}) => { + return ( +
+ {type} +

{typeOptions[type].label}

+ {/* changeSource(type, false, applyFn)} /> */} +
+ ); + }; + + const CondChip = ({ + text, + index, + apply, + deleted, + wrapperClassName, + className, + deleteButtonClassName, + }: { + text: string; + index: number; + apply?: boolean; + deleted?: () => void; + className?: ClassNameValue; + wrapperClassName?: ClassNameValue; + deleteButtonClassName?: ClassNameValue; + }) => { + return ( + +
+
+
+ +

{text}

+
+ {deleted && ( + { + e.stopPropagation(); + const newContentConditions = contentConditions?.filter((_, i) => i !== index); + if (apply) { + setContentConditions(newContentConditions); + applyFn(sources, level, newContentConditions); + } + deleted?.(); + }} + /> + )} +
+
+
+ ); + }; + + const DropDownFilter = () => { + const [dropdownOpen, setDropdownOpen] = useState(false); + const [sources, setSources] = useState(structuredClone(def?.types || [])); + const [content, setContent] = useState(structuredClone(def?.content || [])); + const [level, setLevel] = useState(def?.level || ALL_LEVELS[ALL_LEVELS.length - 1]); + const wrapperRef = useRef(null); + const [usePopupToLeft, setUsePopupToLeft] = useState(false); + + const changeSource = (type: Type, value: boolean) => { + setSources((val) => { + if (value) val.push(type); + else val = val.filter((item) => item !== type); + const vals = [...new Set(val)]; + return vals; + }); + }; + + useEffect(() => { + if (!dropdownOpen) { + setSources(structuredClone(def?.types || [])); + setContent(structuredClone(def?.content || [])); + } + }, [dropdownOpen]); + + useEffect(() => { + if (wrapperRef?.current) { + if (getDistanceToRight(wrapperRef.current) < 218) setUsePopupToLeft(true); + else setUsePopupToLeft(false); + } + }, [wrapperRef?.current?.scrollWidth, dropdownOpen]); + + const changeMenuOpen = () => { + setDropdownOpen(!dropdownOpen); + setSources(structuredClone(def?.types || [])); + setContent(structuredClone(def?.content || [])); + }; + + return ( +
+
+
+ +

Edit Filters

+
+
+
+
+
+ {/* */} +

Filter

+
+
+ close +
+
+
+
+

Level:

+ +
+
+
+ {ALL_TYPES.map((type) => ( +
+ changeSource(type, !!isChecked)} /> + +
+ ))} +
+
+
+ {content?.map((item, i) => ( + { + setContent((c) => { + c[i] = inputVal; + return [...c]; + }); + }}> + setContent(content.filter((_, index) => index !== i))} + wrapperClassName='w-full !border-0 bg-[#F5F6F8] hover:bg-[#EBECF0]' + className='justify-between !border-0 bg-[#F5F6F8] group-hover:bg-[#EBECF0]' + deleteButtonClassName='visible' + /> + + ))} +
+ {!!content?.length &&
} +
+ setContent((val) => [...val, inputVal])} /> +
+
+
+ + +
+
+
+ ); + }; + + return ( +
+
+
+ {showTags && !!def?.types?.length && def.types.map((type) => )} + {showTags && def?.content?.map((c: string, index: number) => )} + {showDropdown && } +
+
+ {deleteFilterTab && ( + + )} +
+ ); +}; + +export default memo(LogFilters); diff --git a/src/parlant/api/chat/src/components/markdown/markdown.tsx b/src/parlant/api/chat/src/components/markdown/markdown.tsx new file mode 100644 index 0000000..de24807 --- /dev/null +++ b/src/parlant/api/chat/src/components/markdown/markdown.tsx @@ -0,0 +1,29 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; +import rehypeHighlight from 'rehype-highlight'; +import rehypeRaw from 'rehype-raw'; +import 'highlight.js/styles/github.css'; +import styles from '../message/message.module.scss'; +import {twMerge} from 'tailwind-merge'; + +function preserveBlankLines(md: string): string { + return md?.replace?.(/\\n/g, '\n')?.replace(/\n(?!-)/g, '
') || md; +} + +const Markdown = ({children, className}: {children: string; className?: string}) => { + return ( + + }} + rehypePlugins={[rehypeHighlight, rehypeRaw]} + remarkPlugins={[remarkGfm]} + className={twMerge('leading-[19px]', styles.markdown, className)}> + {preserveBlankLines(children)} + + ); +}; + +export default Markdown; \ No newline at end of file diff --git a/src/parlant/api/chat/src/components/message-details/empty-state.tsx b/src/parlant/api/chat/src/components/message-details/empty-state.tsx new file mode 100644 index 0000000..4c3f9bb --- /dev/null +++ b/src/parlant/api/chat/src/components/message-details/empty-state.tsx @@ -0,0 +1,24 @@ +import {ClassNameValue, twMerge} from 'tailwind-merge'; + +interface Props { + title: string; + subTitle?: string; + className?: ClassNameValue; + wrapperClassName?: ClassNameValue; + imgClassName?: ClassNameValue; + imgUrl?: string; +} + +const EmptyState = ({title, subTitle, wrapperClassName, className, imgClassName, imgUrl}: Props) => { + return ( +
+
+ +

{title}

+ {subTitle &&

{subTitle}

} +
+
+ ); +}; + +export default EmptyState; diff --git a/src/parlant/api/chat/src/components/message-details/filter-tabs.tsx b/src/parlant/api/chat/src/components/message-details/filter-tabs.tsx new file mode 100644 index 0000000..d501895 --- /dev/null +++ b/src/parlant/api/chat/src/components/message-details/filter-tabs.tsx @@ -0,0 +1,114 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {twJoin, twMerge} from 'tailwind-merge'; +import {Level, Type} from '../log-filters/log-filters'; +import {useState} from 'react'; +import {Plus} from 'lucide-react'; + +interface DefInterface { + level?: Level; + types?: Type[]; + content?: string[]; +} + +export interface Filter { + id: number; + name: string; + def: DefInterface | null; +} + +interface FilterTabsFilterProps { + filterTabs: Filter[]; + setCurrFilterTabs: React.Dispatch>; + setFilterTabs: React.Dispatch>; + currFilterTabs: number | null; +} + +const FilterTabs = ({filterTabs, setCurrFilterTabs, setFilterTabs, currFilterTabs}: FilterTabsFilterProps) => { + const [isEditing, setIsEditing] = useState(false); + const [inputVal, setInputVal] = useState(''); + + const addFilter = () => { + const val: Filter = {id: Date.now(), name: 'Logs', def: {level: 'DEBUG', types: []}}; + const allTabs = [...filterTabs, val]; + setFilterTabs(allTabs); + setCurrFilterTabs(val.id); + }; + + const clicked = (e: React.MouseEvent, tab: Filter) => { + e.stopPropagation(); + setIsEditing(true); + setInputVal(tab.name); + function selectText() { + const range = document.createRange(); + const selection = window.getSelection(); + if (!e.target) return; + range.selectNodeContents(e.target as Node); + selection?.removeAllRanges(); + selection?.addRange(range); + } + selectText(); + }; + + const editFinished = (e: any, tab: Filter) => { + setIsEditing(false); + if (!e.target.textContent) e.target.textContent = inputVal || tab.name; + tab.name = e.target.textContent; + localStorage.setItem('filters', JSON.stringify(filterTabs)); + e.target.blur(); + const selection = window.getSelection(); + selection?.removeAllRanges(); + }; + + const editCancelled = (e: any, tab: Filter) => { + setIsEditing(false); + e.target.textContent = tab.name; + e.target.blur(); + }; + + return ( +
+ {filterTabs.map((tab: Filter) => ( +
{ + setIsEditing(false); + setCurrFilterTabs(tab.id); + }}> +
+
+

tab.id === currFilterTabs && clicked(e, tab)} + contentEditable={tab.id === currFilterTabs && isEditing} + suppressContentEditableWarning + onKeyDown={(e) => (e.key === 'Enter' ? editFinished(e, tab) : e.key === 'Escape' && editCancelled(e, tab))} + onBlur={(e) => editFinished(e, tab)} + className={twMerge( + 'text-[15px] flex-1 overflow-hidden whitespace-nowrap text-ellipsis h-[28px] px-[8px] outline-none items-center border border-transparent flex !justify-start', + tab.id === currFilterTabs && !isEditing && 'hover:cursor-text' + )}> + {tab.name} +

+ {/* {filterTabs.length > 0 && close deleteFilterTab(tab.id)} />} */} +
+
+
+ ))} +
+ +
+
+ ); +}; + +export default FilterTabs; diff --git a/src/parlant/api/chat/src/components/message-details/flag-message.tsx b/src/parlant/api/chat/src/components/message-details/flag-message.tsx new file mode 100644 index 0000000..57b31ed --- /dev/null +++ b/src/parlant/api/chat/src/components/message-details/flag-message.tsx @@ -0,0 +1,65 @@ +import {EventInterface} from '@/utils/interfaces'; +import {Textarea} from '../ui/textarea'; +import {Button} from '../ui/button'; +import {dialogAtom} from '@/store'; +import {useAtom} from 'jotai'; +import {addItemToIndexedDB, deleteItemFromIndexedDB} from '@/lib/utils'; +import {useState} from 'react'; + +interface FlagMessageProps { + events: EventInterface[]; + sessionId: string; + onFlag?: (flagValue: string) => void; + existingFlagValue?: string; +} + +const FlagMessage = ({events, sessionId, existingFlagValue, onFlag}: FlagMessageProps) => { + const [dialog] = useAtom(dialogAtom); + const [flagValue, setFlagValue] = useState(existingFlagValue || ''); + const traceId = events?.[0]?.trace_id; + + const flagMessage = async () => { + await addItemToIndexedDB('Parlant-flags', 'message_flags', traceId, {sessionId, traceId: traceId, flagValue: flagValue || 'This message is flagged'}, 'update', {name: 'sessionIndex', keyPath: 'sessionId'}); + onFlag?.(flagValue || ''); + dialog.closeDialog(); + }; + + const unflagMessage = async () => { + await deleteItemFromIndexedDB('Parlant-flags', 'message_flags', traceId); + onFlag?.(''); + dialog.closeDialog(); + }; + + return ( +
+
+

Feedback provided here will show up in the session's exported CSV file.

+
+
+ {events.map((event) => { + return ( +
+
{event?.data?.message}
+
+ ); + })} +
+