diff --git a/.env.example b/.env.example
index 7be5ab5ac..717650c50 100644
--- a/.env.example
+++ b/.env.example
@@ -16,3 +16,4 @@ RABBITMQ_HOST=rabbitmq
REDIS_PORT=6379
REDIS_USER=redis
REDIS_PASSWORD=changeme
+
\ No newline at end of file
diff --git a/.github/.env.ci.example b/.github/.env.ci.example
index 8cc1e128c..3765f4206 100644
--- a/.github/.env.ci.example
+++ b/.github/.env.ci.example
@@ -1,12 +1,5 @@
-# Application configuration
+COMPOSE_NAME=opengatellm-ci
CONFIG_FILE=api/tests/integ/config.test.yml
-COMPOSE_FILE=.github/compose.ci.yml
-
-# Dependencies
POSTGRES_PORT=15432
REDIS_PORT=16379
-RABBITMQ_PORT=25672
-RABBITMQ_UI_PORT=15672
-
-# Secrets (to complete)
-# ALBERT_API_KEY=
+ALBERT_API_KEY=
diff --git a/.github/.trivyignore b/.github/.trivyignore
index 558d77719..39e2f8d0d 100644
--- a/.github/.trivyignore
+++ b/.github/.trivyignore
@@ -22,6 +22,14 @@ CVE-2026-42496 exp:2026-09-01
# Reported in perl-base from base image. Re-evaluate after 2026-09-01.
CVE-2026-8376 exp:2026-09-01
+# Perl regex trie overflow (incorrect matches with >65535 alternation branches) — no upstream Debian fix yet
+# Reported in perl-base from base image. Upstream fix is in Perl 5.43.10 only. Re-evaluate after 2026-09-01.
+CVE-2026-13221 exp:2026-09-01
+
+# Perl Storable signed integer overflow on crafted SX_HOOK — no upstream Debian fix yet
+# Reported in perl-base from base image. Fixed upstream in Storable 3.41. Re-evaluate after 2026-09-01.
+CVE-2026-57433 exp:2026-09-01
+
# libssh2 Out-of-Bounds Write via Unchecked — no upstream Debian fix yet
# Reported in libssh2-1t64 from base image. Re-evaluate after 2026-09-01.
CVE-2026-55200 exp:2026-09-01
diff --git a/.github/badges/coverage.json b/.github/badges/coverage.json
index 776684cd9..28994b3fc 100644
--- a/.github/badges/coverage.json
+++ b/.github/badges/coverage.json
@@ -1 +1 @@
-{"schemaVersion":1,"label":"coverage","message":"55.48%","color":"red"}
+{"schemaVersion": 1, "label": "coverage", "message": "59.81%", "color": "red"}
\ No newline at end of file
diff --git a/.github/compose.ci.yml b/.github/compose.ci.yml
deleted file mode 100644
index 3442b61c9..000000000
--- a/.github/compose.ci.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: opengatellm-ci
-
-services:
- postgres:
- extends:
- file: ../compose.example.yml
- service: postgres
-
- redis:
- extends:
- file: ../compose.example.yml
- service: redis
-
- elasticsearch:
- image: docker.elastic.co/elasticsearch/elasticsearch:9.0.2
- restart: always
- ports:
- - "${ELASTICSEARCH_PORT:-9200}:9200"
- environment:
- - discovery.type=single-node
- - xpack.security.enabled=false
- - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
- - "ELASTIC_USERNAME=elasticsearch"
- - "ELASTIC_PASSWORD=changeme"
- volumes:
- - elasticsearch:/usr/share/elasticsearch/data
- healthcheck:
- test: [ "CMD-SHELL", "curl -fs 'http://127.0.0.1:9200/_cluster/health?wait_for_status=yellow&timeout=5s' || exit 1" ]
- interval: 4s
- timeout: 10s
- retries: 5
- start_period: 60s
-
-volumes:
- postgres:
- redis:
- elasticsearch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c42e8b623..e1101e2cb 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,11 +15,11 @@ on:
jobs:
prepare:
name: Prepare build
+ if: >-
+ github.event_name == 'workflow_dispatch' ||
+ github.event_name == 'release' ||
+ github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
- # Builds triggered by a PR commit wait here for a manual approval from the GitHub Actions UI
- # (configure required reviewers on the "build-approval" environment in repo settings).
- # Builds triggered by push/release/workflow_dispatch use the unprotected "build-auto" environment
- # and therefore run immediately, exactly like before.
environment: ${{ github.event_name == 'pull_request' && 'build-approval' || 'build-auto' }}
outputs:
image_tag: ${{ steps.set_tag.outputs.tag }}
@@ -49,17 +49,12 @@ jobs:
env:
API_IMAGE_NAME: ghcr.io/etalab-ia/opengatellm/api
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
- outputs:
- commit_title: ${{ steps.get_head_commit_title.outputs.title }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
- - id: get_head_commit_title
- run: echo "title=$(git log --format=%B -n 1 HEAD | head -n 1)" >> $GITHUB_OUTPUT
-
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -206,20 +201,3 @@ jobs:
with:
image-name: ghcr.io/etalab-ia/opengatellm/playground
image-tag: ${{ needs.prepare.outputs.image_tag }}
-
- deploy-dev:
- # Only chain automatically into the deploy workflow for the pre-existing, auto-triggered flow
- # (push to main). Builds approved manually from a PR are not deployed automatically.
- if: github.event_name == 'push'
- name: Deploy to dev
- needs:
- - build-opengatellm-api
- - trivy-scan-api
- - build-opengatellm-playground
- - trivy-scan-playground
- - build-albert-playground
- uses: ./.github/workflows/deploy.yml
- with:
- commit_title: ${{ needs.build-opengatellm-api.outputs.commit_title }}
- secrets:
- GITLAB_CI_TOKEN: ${{ secrets.GITLAB_CI_TOKEN }}
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index deb8296df..b44835853 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -1,20 +1,10 @@
name: Deploy
on:
- workflow_call:
- inputs:
- commit_title:
- description: "Title of the commit that triggered the build, used for the GitLab pipeline name"
- required: true
- type: string
- environment:
- description: "Deployment environment"
- required: false
- type: string
- default: dev
- secrets:
- GITLAB_CI_TOKEN:
- required: true
+ workflow_run:
+ workflows: ["Build and scan images"]
+ types:
+ - completed
workflow_dispatch:
inputs:
commit_title:
@@ -30,14 +20,35 @@ on:
jobs:
deploy-dev:
- name: Deploy from ${{ github.ref_name }}/${{ github.sha }}
+ if: >-
+ github.event_name == 'workflow_dispatch' ||
+ (
+ github.event.workflow_run.conclusion == 'success' &&
+ github.event.workflow_run.event == 'push' &&
+ github.event.workflow_run.actor.login != 'github-actions[bot]'
+ )
+ name: Deploy from ${{ github.event.workflow_run.head_branch || github.ref_name }}/${{ github.event.workflow_run.head_sha || github.sha }}
runs-on: ubuntu-latest
steps:
+ - name: Get commit title
+ id: commit_title
+ env:
+ HEAD_COMMIT_MESSAGE: ${{ github.event.workflow_run.head_commit.message }}
+ EVENT_NAME: ${{ github.event_name }}
+ COMMIT_TITLE_INPUT: ${{ inputs.commit_title }}
+ run: |
+ if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
+ TITLE="$COMMIT_TITLE_INPUT"
+ else
+ TITLE="$(echo "$HEAD_COMMIT_MESSAGE" | head -n 1)"
+ fi
+ echo "title=$TITLE" >> "$GITHUB_OUTPUT"
+
- name: Trigger dev deployment
env:
GITLAB_CI_TOKEN: ${{ secrets.GITLAB_CI_TOKEN }}
- PIPELINE_NAME: ${{ github.event.repository.name }} - ${{ inputs.commit_title }}
- DEPLOYMENT_ENVIRONMENT: ${{ inputs.environment }}
+ PIPELINE_NAME: ${{ github.event.repository.name }} - ${{ steps.commit_title.outputs.title }}
+ DEPLOYMENT_ENVIRONMENT: ${{ inputs.environment || 'dev' }}
run: |
RESPONSE="$(curl --request POST \
--form token="$GITLAB_CI_TOKEN" \
diff --git a/.github/workflows/release_updates.yml b/.github/workflows/release_updates.yml
index ea638d09e..97eac83f7 100644
--- a/.github/workflows/release_updates.yml
+++ b/.github/workflows/release_updates.yml
@@ -18,22 +18,14 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
+
- name: Checkout du code
uses: actions/checkout@v4
with:
- ref: main
+ ref: ${{ github.event_name == 'pull_request' && github.sha || 'main' }}
fetch-depth: 0
- - name: Configure Python
- uses: actions/setup-python@v5
- with:
- python-version: '3.12'
-
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install ".[api,playground,dev]"
-
- name: Update project version
run: |
git fetch --tags --force
@@ -43,34 +35,36 @@ jobs:
exit 0
fi
sed -i -E "s/^[[:space:]]*version[[:space:]]*=.*/version = \"${latest_version}\"/" pyproject.toml
- sed -i -E "s|(image:[[:space:]]*ghcr.io/etalab-ia/opengatellm/api:).*|\\1${latest_version}|" compose.example.yml
- sed -i -E "s|(image:[[:space:]]*ghcr.io/etalab-ia/opengatellm/playground:).*|\\1${latest_version}|" compose.example.yml
sed -i -E "s/^[[:space:]]*swagger_version:[[:space:]]*.*/ swagger_version: ${latest_version}/" config.example.yml
sed -i -E "s/(badge:[[:space:]]*)'[^']*'/\1'v${latest_version}'/" docs/astro.config.mjs
-
+
- name: Generate documentation
+ env:
+ DOCS_DIR: ${{ github.workspace }}/docs
+ CONFIG_FILE: ${{ github.workspace }}/config.example.yml
run: |
+ uv venv
+ uv pip install -p .venv/bin/python ".[api,playground,dev]"
+ . .venv/bin/activate
PYTHONPATH=. python ./scripts/docs/generate_configuration_documentation.py --output ./docs/src/content/docs/configuration/configuration_file.mdx
- make quickstart
- api_health=unknown
- for _ in $(seq 1 30); do
- api_container_id="$(docker compose --env-file .env --file compose.example.yml ps -q api)"
- if [ -n "$api_container_id" ]; then
- api_health="$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$api_container_id")"
- if [ "$api_health" = "healthy" ]; then
- break
- fi
- fi
- sleep 2
- done
- if [ "$api_health" != "healthy" ]; then
- echo "API container is not healthy (status: $api_health)"
- docker compose --env-file .env --file compose.yml logs --no-color api
+ if ! docker compose --file ./compose.example.yml up --detach --wait; then
+ echo "Services did not become healthy." >&2
+ echo "::group::Docker Compose status"
+ docker compose --file ./compose.example.yml ps || true
+ echo "::endgroup::"
+
+ echo "::group::Docker Compose logs (all services)"
+ docker compose --file ./compose.example.yml logs --no-color || true
+ echo "::endgroup::"
+
+ echo "::group::API health probe"
+ curl -sv "http://localhost:8000/health" || true
+ echo "::endgroup::"
exit 1
fi
curl -fSL --retry 8 --retry-all-errors --retry-delay 2 http://localhost:8000/openapi.json -o ./docs/openapi.json
docker pull redocly/cli
- docker run --rm -v ${{ github.workspace }}/docs:/spec redocly/cli build-docs /spec/openapi.json --output /spec/redoc-static.html
+ docker run --rm -v "$DOCS_DIR:/spec" redocly/cli build-docs /spec/openapi.json --output /spec/redoc-static.html
- name: Create pull request for release updates
uses: peter-evans/create-pull-request@v6
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
index 98b26c080..d0847a989 100644
--- a/.github/workflows/run_tests.yml
+++ b/.github/workflows/run_tests.yml
@@ -11,6 +11,10 @@ on:
jobs:
unit-tests:
name: Unit tests
+ if: >-
+ github.event_name == 'workflow_call' ||
+ github.event_name == 'workflow_dispatch' ||
+ github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
@@ -18,34 +22,51 @@ jobs:
with:
ref: ${{ github.head_ref || github.ref_name }}
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
+
- name: Set up Docker Compose
run: |
cp config.example.yml config.yml
- name: Run unit tests with coverage and publish unit badge
run: |
- # Install uv
- curl -LsSf https://astral.sh/uv/install.sh | sh
- echo "$HOME/.local/bin" >> $GITHUB_PATH
-
# Create a local virtual environment and install dependencies
- "$HOME/.local/bin/uv" venv
- "$HOME/.local/bin/uv" pip install -p .venv/bin/python ".[api,playground,dev,test]"
+ uv venv
+ uv pip install -p .venv/bin/python ".[api,dev,test]"
# Activate venv for the test run
. .venv/bin/activate
# Run unit tests with coverage
- make test-unit
+ pytest -s api/tests/unit --config-file=pyproject.toml --cov=./api --cov-report=html --cov-report=term-missing --cov-branch --cov-report=xml
# Export coverage data to XML for badge computation
python -m coverage xml -o coverage.xml
# Build unit coverage badge JSON
mkdir -p .github/badges
- COVERAGE=$(python -c "import xml.etree.ElementTree as ET; print(ET.parse('coverage.xml').getroot().get('line-rate'))")
- COVERAGE_PCT=$(printf "%.2f" $(echo "${COVERAGE} * 100" | bc))
- echo "{\"schemaVersion\":1,\"label\":\"coverage\",\"message\":\"${COVERAGE_PCT}%\",\"color\":\"$(if (( $(echo \"${COVERAGE_PCT} >= 80\" | bc -l) )); then echo "green"; elif (( $(echo \"${COVERAGE_PCT} >= 70\" | bc -l) )); then echo "yellow"; else echo "red"; fi)\"}" > .github/badges/coverage.json
+ python - <<'PY'
+ import json
+ import xml.etree.ElementTree as ET
+
+ coverage = float(ET.parse("coverage.xml").getroot().get("line-rate"))
+ coverage_pct = f"{coverage * 100:.2f}"
+ if float(coverage_pct) >= 80:
+ color = "green"
+ elif float(coverage_pct) >= 70:
+ color = "yellow"
+ else:
+ color = "red"
+
+ badge = {
+ "schemaVersion": 1,
+ "label": "coverage",
+ "message": f"{coverage_pct}%",
+ "color": color,
+ }
+ with open(".github/badges/coverage.json", "w", encoding="utf-8") as badge_file:
+ json.dump(badge, badge_file)
+ PY
- name: Commit unit coverage badge
if: github.event.pull_request.base.ref == 'main'
@@ -56,38 +77,32 @@ jobs:
commit_user_name: "GitHub Actions"
commit_user_email: "actions@github.com"
- integration-tests:
- name: Integration tests
+ e2e-tests:
+ name: e2e tests
+ if: >-
+ github.event_name == 'workflow_call' ||
+ github.event_name == 'workflow_dispatch' ||
+ github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
- strategy:
- matrix:
- config_file: [api/tests/integ/config.test.yml]
-
steps:
- uses: actions/checkout@v4
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
+
- name: Run integration tests
run: |
- cp .github/.env.ci.example .github/.env.ci
-
- # Install uv
- curl -LsSf https://astral.sh/uv/install.sh | sh
- echo "$HOME/.local/bin" >> $GITHUB_PATH
-
# Create a local virtual environment and install dependencies
- "$HOME/.local/bin/uv" venv
- "$HOME/.local/bin/uv" pip install -p .venv/bin/python ".[api,playground,dev,test]"
+ uv venv
+ uv pip install -p .venv/bin/python ".[api,dev,test]"
# Activate venv for the test run
. .venv/bin/activate
- echo "Listing files in root:"
- ls -la .
- echo "Listing files in api/tests/integ:"
- ls -la api/tests/integ
+ # Start dependencies services
+ docker compose --file compose.example.yml up --detach --quiet-pull --wait postgres redis
# Run integration tests
- make test-integ
+ PYTHONPATH=. pytest api/tests/integ --config-file=pyproject.toml --cov=./api --cov-report=xml
env:
- CONFIG_FILE: ${{ matrix.config_file }}
+ CONFIG_FILE: ./api/tests/integ/config.test.yml
ALBERT_API_KEY: ${{ secrets.ALBERT_API_KEY }}
diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml
index 462f049f4..13410c954 100644
--- a/.github/workflows/semgrep.yml
+++ b/.github/workflows/semgrep.yml
@@ -16,7 +16,7 @@ on:
jobs:
semgrep-diff:
name: Semgrep SAST (diff)
- if: github.event_name == 'pull_request'
+ if: github.event_name == 'pull_request' && github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
@@ -27,7 +27,10 @@ jobs:
semgrep-full:
name: Semgrep SAST (full)
- if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
+ if: >-
+ github.event_name == 'release' ||
+ github.event_name == 'workflow_dispatch' ||
+ (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.actor != 'github-actions[bot]')
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
diff --git a/Makefile b/Makefile
index f2201f899..7b3697296 100644
--- a/Makefile
+++ b/Makefile
@@ -29,11 +29,12 @@ TEST_INTEG_SUFFIX := $(if $(TEST_INTEG_ARG),/$(TEST_INTEG_ARG),)
# test-integ -----------------------------------------------------------------------------------------------------------------------------------------
test-integ:
- @python cli.py --test-integ && \
- set -a; . .github/.env.ci; set +a; \
+ @if [ -z "$${ALBERT_API_KEY}" ]; then \
+ echo "ALBERT_API_KEY is not set. Export it first, see .github/.env.ci.example"; \
+ exit 1; \
+ fi; \
+ export CONFIG_FILE=./api/tests/integ/config.test.yml; \
+ docker compose --file compose.example.yml up --detach --quiet-pull --wait postgres redis; \
PYTHONPATH=. pytest api/tests/integ$(TEST_INTEG_SUFFIX) --config-file=pyproject.toml --cov=./api --cov-report=xml;
-%:
- @:
-
.PHONY: help quickstart dev lint test-unit test-integ create-api-key
diff --git a/api/dependencies.py b/api/dependencies.py
index d19f54a9e..27a9bb3e8 100644
--- a/api/dependencies.py
+++ b/api/dependencies.py
@@ -20,6 +20,7 @@
from api.domain.role import LimitRepository, PermissionRepository
from api.domain.router import RouterRateLimiter
from api.domain.user import UserPasswordEncoder
+from api.domain.user.views import AuthenticatedUserView
from api.infrastructure.bcrypt import BcryptUserPasswordEncoder
from api.infrastructure.ecologit import EcologitModelEnvironmentalImpactsComputer
from api.infrastructure.fastapi.context import request_context
@@ -39,7 +40,7 @@
from api.infrastructure.redis import RedisProviderLoadBalancer, RedisProviderMetricsLogger, RedisRouterRateLimiter
from api.infrastructure.tiktoken import TiktokenModelTokenizer
from api.schemas.core.context import RequestContext
-from api.use_cases.admin.keys import CreateKeyUseCase
+from api.use_cases.admin.keys import CreateKeyUseCase, GetKeysUseCase, GetOneKeyUseCase
from api.use_cases.admin.providers import (
CreateProviderUseCase,
DeleteProviderUseCase,
@@ -49,7 +50,7 @@
)
from api.use_cases.admin.roles import CreateRoleUseCase, DeleteRoleUseCase, GetRolesUseCase, GetRoleUseCase, UpdateRoleUseCase
from api.use_cases.admin.routers import CreateRouterUseCase, DeleteRouterUseCase, GetOneRouterUseCase, GetRoutersUseCase, UpdateRouterUseCase
-from api.use_cases.admin.users import CreateUserUseCase, DeleteUserUseCase, GetOneUserUseCase, GetUsersUseCase
+from api.use_cases.admin.users import CreateUserUseCase, DeleteUserUseCase, GetOneUserUseCase, GetUsersUseCase, UpdateUserUseCase
from api.use_cases.auth import AuthLoginUseCase
from api.use_cases.embeddings import CreateEmbeddingsUseCase
from api.use_cases.health import GetHealthModelsUseCase
@@ -63,6 +64,10 @@ def get_request_context() -> ContextVar[RequestContext]:
return request_context
+def get_authenticated_user() -> AuthenticatedUserView:
+ return request_context.get().user
+
+
def get_secret_key() -> str:
return configuration.settings.auth_secret_key
@@ -222,6 +227,14 @@ def create_key_use_case_factory(key_repository: KeyRepository = Depends(_key_rep
return CreateKeyUseCase(key_repository=key_repository)
+def get_keys_use_case_factory(key_repository: KeyRepository = Depends(_key_repository)) -> GetKeysUseCase:
+ return GetKeysUseCase(key_repository=key_repository)
+
+
+def get_one_key_use_case_factory(key_repository: KeyRepository = Depends(_key_repository)) -> GetOneKeyUseCase:
+ return GetOneKeyUseCase(key_repository=key_repository)
+
+
# models use cases
def get_models_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> GetModelsUseCase:
return GetModelsUseCase(router_repository=_router_repository(postgres_session))
@@ -252,6 +265,10 @@ def delete_user_use_case_factory(postgres_session: AsyncSession = Depends(get_po
)
+def update_user_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> UpdateUserUseCase:
+ return UpdateUserUseCase(user_repository=_user_repository(postgres_session), user_password_encoder=_user_password_encoder())
+
+
# rerank use cases
def create_rerank_use_case_factory(
postgres_session: AsyncSession = Depends(get_postgres_session),
diff --git a/api/domain/key/_keyrepository.py b/api/domain/key/_keyrepository.py
index eeae4123c..965c72dde 100644
--- a/api/domain/key/_keyrepository.py
+++ b/api/domain/key/_keyrepository.py
@@ -2,7 +2,8 @@
from pydantic import FutureDatetime
-from api.domain.key.entities import Key
+from api.domain import SortField, SortOrder
+from api.domain.key.entities import Key, KeyPage
from api.domain.key.errors import KeyAlreadyExistsError, KeyNotFoundError
from api.domain.user.errors import UserNotFoundError
@@ -12,6 +13,18 @@ class KeyRepository(ABC):
async def get_key_by_id(self, key_id: int) -> Key | KeyNotFoundError:
pass
+ @abstractmethod
+ async def get_keys_page(
+ self,
+ user_id: int | None = None,
+ limit: int = 10,
+ offset: int = 0,
+ sort_by: SortField = SortField.ID,
+ sort_order: SortOrder = SortOrder.ASC,
+ exclude_expired: bool = True,
+ ) -> KeyPage:
+ pass
+
@abstractmethod
async def create_key(self, user_id: int, name: str, expire: FutureDatetime | None) -> Key | KeyAlreadyExistsError | UserNotFoundError:
pass
diff --git a/api/domain/key/entities.py b/api/domain/key/entities.py
index 94be3055f..6e61b8ccb 100644
--- a/api/domain/key/entities.py
+++ b/api/domain/key/entities.py
@@ -1,6 +1,6 @@
from datetime import UTC, datetime
-from api.domain import BaseModel
+from api.domain import BaseModel, EntitiesPage
class Key(BaseModel):
@@ -38,3 +38,6 @@ def _expires_timestamp(expires: datetime | None) -> int | None:
if expires is None:
return None
return int(expires.timestamp())
+
+
+KeyPage = EntitiesPage["Key"]
diff --git a/api/domain/user/entities.py b/api/domain/user/entities.py
index cbd9ebad7..c51d767a4 100644
--- a/api/domain/user/entities.py
+++ b/api/domain/user/entities.py
@@ -1,6 +1,6 @@
from enum import StrEnum
-from pydantic import BaseModel
+from pydantic import BaseModel, SecretStr
from api.domain import EntitiesPage
@@ -28,3 +28,4 @@ class User(BaseModel):
created: int
updated: int
priority: int
+ password: SecretStr | None
diff --git a/api/domain/user/errors.py b/api/domain/user/errors.py
index ad77d3fef..5c9cc86ea 100644
--- a/api/domain/user/errors.py
+++ b/api/domain/user/errors.py
@@ -47,3 +47,8 @@ class UserExpiredError:
@dataclass
class UserHasNoAccessToRouterError:
id: int
+
+
+@dataclass
+class IncorrectCurrentPasswordError:
+ user_id: int
diff --git a/api/endpoints/admin/__init__.py b/api/endpoints/admin/__init__.py
index db6c89eba..72f6eeeaa 100644
--- a/api/endpoints/admin/__init__.py
+++ b/api/endpoints/admin/__init__.py
@@ -4,4 +4,4 @@
router = APIRouter(prefix="/v1", tags=[RouterName.ADMIN.title()])
-from . import organizations, tokens, users # noqa: F401 E402
+from . import organizations, tokens # noqa: F401 E402
diff --git a/api/endpoints/admin/tokens.py b/api/endpoints/admin/tokens.py
index 9120c2560..a2ebd3c21 100644
--- a/api/endpoints/admin/tokens.py
+++ b/api/endpoints/admin/tokens.py
@@ -1,13 +1,11 @@
-from typing import Literal
-
-from fastapi import Body, Depends, Path, Query, Request, Security
+from fastapi import Body, Depends, Path, Request, Security
from fastapi.responses import JSONResponse, Response
from sqlalchemy.ext.asyncio import AsyncSession
from api.domain.role.entities import PermissionType
from api.endpoints.admin import router
from api.helpers._accesscontroller import AccessController
-from api.schemas.admin.tokens import CreateToken, Token, Tokens, TokensResponse
+from api.schemas.admin.tokens import CreateToken, TokensResponse
from api.utils.context import global_context
from api.utils.dependencies import get_postgres_session
from api.utils.variables import EndpointRoute
@@ -56,54 +54,3 @@ async def delete_token(
await global_context.identity_access_manager.delete_token(postgres_session=postgres_session, user_id=user, token_id=token)
return Response(status_code=204)
-
-
-@router.get(
- path=EndpointRoute.ADMIN_TOKENS + "/{token}",
- dependencies=[Security(dependency=AccessController(permissions=[PermissionType.ADMIN]))],
- status_code=200,
- response_model=Token,
-)
-async def get_token(
- request: Request,
- token: int = Path(description="The token ID of the token to get."),
- postgres_session: AsyncSession = Depends(get_postgres_session),
-) -> JSONResponse:
- """
- Get your token by id.
- """
-
- tokens = await global_context.identity_access_manager.get_tokens(postgres_session=postgres_session, token_id=token)
-
- return JSONResponse(content=tokens[0].model_dump(), status_code=200)
-
-
-@router.get(
- path=EndpointRoute.ADMIN_TOKENS,
- dependencies=[Security(dependency=AccessController(permissions=[PermissionType.ADMIN]))],
- status_code=200,
- response_model=Tokens,
-)
-async def get_tokens(
- request: Request,
- user: int | None = Query(default=None, description="The user ID of the user to get the tokens for."),
- offset: int = Query(default=0, ge=0, description="The offset of the tokens to get."),
- limit: int = Query(default=10, ge=1, le=100, description="The limit of the tokens to get."),
- order_by: Literal["id", "name", "created"] = Query(default="id", description="The field to order the tokens by."),
- order_direction: Literal["asc", "desc"] = Query(default="asc", description="The direction to order the tokens by."),
- postgres_session: AsyncSession = Depends(get_postgres_session),
-) -> JSONResponse:
- """
- Get all your tokens.
- """
-
- data = await global_context.identity_access_manager.get_tokens(
- postgres_session=postgres_session,
- user_id=user,
- offset=offset,
- limit=limit,
- order_by=order_by,
- order_direction=order_direction,
- )
-
- return JSONResponse(content=Tokens(data=data).model_dump(), status_code=200)
diff --git a/api/endpoints/admin/users.py b/api/endpoints/admin/users.py
deleted file mode 100644
index ab7b802d0..000000000
--- a/api/endpoints/admin/users.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from fastapi import Body, Depends, Path, Request, Security
-from fastapi.responses import Response
-from sqlalchemy.ext.asyncio import AsyncSession
-
-from api.domain.role.entities import PermissionType
-from api.endpoints.admin import router
-from api.helpers._accesscontroller import AccessController
-from api.schemas.admin.users import UserUpdateRequest
-from api.utils.context import global_context
-from api.utils.dependencies import get_postgres_session
-from api.utils.variables import EndpointRoute
-
-
-@router.patch(
- path=EndpointRoute.ADMIN_USERS + "/{user}",
- dependencies=[Security(dependency=AccessController(permissions=[PermissionType.ADMIN]))],
- status_code=204,
-)
-async def update_user(
- request: Request,
- user: int = Path(description="The ID of the user to update."),
- body: UserUpdateRequest = Body(description="The user update request."),
- postgres_session: AsyncSession = Depends(get_postgres_session),
-) -> Response:
- """
- Update a user.
- """
- await global_context.identity_access_manager.update_user(
- postgres_session=postgres_session,
- user_id=user,
- email=body.email,
- name=body.name,
- current_password=body.current_password,
- password=body.password,
- role_id=body.role,
- organization_id=body.organization,
- budget=body.budget,
- expires=body.expires,
- priority=body.priority,
- )
-
- return Response(status_code=204)
diff --git a/api/helpers/_limiter.py b/api/helpers/_limiter.py
index f2a0fbcd7..287f4ce18 100644
--- a/api/helpers/_limiter.py
+++ b/api/helpers/_limiter.py
@@ -2,7 +2,7 @@
from limits import RateLimitItemPerDay, RateLimitItemPerMinute
from limits.aio import storage, strategies
-from redis.asyncio import ConnectionPool, Redis, RedisError
+from redis.asyncio import ConnectionPool, Redis
from api.domain.role.entities import PermissionType
from api.schemas.admin.roles import LimitType
@@ -27,15 +27,6 @@ def __init__(self, redis_pool: ConnectionPool, strategy: LimitingStrategy):
else: # SLIDING_WINDOW
self.strategy = strategies.SlidingWindowCounterRateLimiter(storage=self.redis_storage)
- async def reset(self) -> None:
- """
- Reset the limits when starting the API.
- """
- try:
- await self.redis_storage.reset()
- except RedisError:
- logger.error(msg="Redis error during rate limit reset.", exc_info=True)
-
async def _get_limit(self, type: LimitType, value: int | None = None) -> RateLimitItemPerMinute | RateLimitItemPerDay | None:
if value is None:
return None
diff --git a/api/infrastructure/fastapi/context.py b/api/infrastructure/fastapi/context.py
index 58f8c010f..8705b9427 100644
--- a/api/infrastructure/fastapi/context.py
+++ b/api/infrastructure/fastapi/context.py
@@ -3,6 +3,7 @@
from pydantic import BaseModel, ConfigDict
from api.domain.key.entities import Key
+from api.domain.user.views import AuthenticatedUserView
class RequestContext(BaseModel):
@@ -15,6 +16,7 @@ class RequestContext(BaseModel):
# user identifiers
key: Key | None = None
+ user: AuthenticatedUserView | None = None
user_email: str | None = None
# model identifiers
diff --git a/api/infrastructure/fastapi/endpoints/admin/keys.py b/api/infrastructure/fastapi/endpoints/admin/keys.py
index f86b352f2..b2c118715 100644
--- a/api/infrastructure/fastapi/endpoints/admin/keys.py
+++ b/api/infrastructure/fastapi/endpoints/admin/keys.py
@@ -1,10 +1,11 @@
from contextvars import ContextVar
import logging
-from fastapi import Body, Depends, Security
+from fastapi import Body, Depends, Path, Query, Security
-from api.dependencies import create_key_use_case_factory
-from api.domain.key.errors import KeyAlreadyExistsError
+from api.dependencies import create_key_use_case_factory, get_keys_use_case_factory, get_one_key_use_case_factory
+from api.domain import SortField, SortOrder
+from api.domain.key.errors import KeyAlreadyExistsError, KeyNotFoundError
from api.domain.user.errors import UserNotFoundError
from api.infrastructure.fastapi import AccessController
from api.infrastructure.fastapi.context import RequestContext
@@ -13,11 +14,22 @@
from api.infrastructure.fastapi.endpoints.exceptions import (
InternalServerHTTPException,
KeyAlreadyExistsHTTPException,
+ KeyNotFoundHTTPException,
NotAdminUserHTTPException,
UserNotFoundHTTPException,
)
-from api.infrastructure.fastapi.schemas.admin.keys import CreateKeyBody, CreateKeyResponse
-from api.use_cases.admin.keys import CreateKeyCommand, CreateKeyUseCase, CreateKeyUseCaseSuccess
+from api.infrastructure.fastapi.schemas.admin.keys import CreateKeyBody, KeyResponse, KeysResponse
+from api.use_cases.admin.keys import (
+ CreateKeyCommand,
+ CreateKeyUseCase,
+ CreateKeyUseCaseSuccess,
+ GetKeysCommand,
+ GetKeysUseCase,
+ GetKeysUseCaseSuccess,
+ GetOneKeyCommand,
+ GetOneKeyUseCase,
+ GetOneKeyUseCaseSuccess,
+)
from api.utils.dependencies import get_request_context
from api.utils.variables import EndpointRoute
@@ -34,7 +46,7 @@ async def create_key(
body: CreateKeyBody = Body(description="The key creation request."),
create_key_use_case: CreateKeyUseCase = Depends(create_key_use_case_factory),
request_context: ContextVar[RequestContext] = Depends(get_request_context),
-) -> CreateKeyResponse:
+) -> KeyResponse:
"""
Create a new key for a user.
"""
@@ -54,8 +66,82 @@ async def create_key(
match result:
case CreateKeyUseCaseSuccess(key=key):
- return CreateKeyResponse.model_validate(key, from_attributes=True)
+ return KeyResponse.model_validate(key, from_attributes=True)
case KeyAlreadyExistsError(name=name):
raise KeyAlreadyExistsHTTPException(name)
case UserNotFoundError(id=user_id):
raise UserNotFoundHTTPException(user_id)
+
+
+@router.get(
+ path=EndpointRoute.ADMIN_KEYS + "/{key_id}",
+ dependencies=[Security(dependency=AccessController(only_admin=True))],
+ status_code=200,
+ responses=get_documentation_responses([KeyNotFoundHTTPException, NotAdminUserHTTPException]),
+)
+async def get_key(
+ key_id: int = Path(description="The ID of the key to get."),
+ get_one_key_use_case: GetOneKeyUseCase = Depends(get_one_key_use_case_factory),
+ request_context: ContextVar[RequestContext] = Depends(get_request_context),
+) -> KeyResponse:
+ command = GetOneKeyCommand(key_id=key_id)
+ try:
+ result = await get_one_key_use_case.execute(command)
+ except Exception as e:
+ logger.exception(
+ "Unexpected error while executing get_key use case",
+ extra={
+ "authenticated_user_id": request_context.get().user.id,
+ "key_id": key_id,
+ "error_type": type(e).__name__,
+ },
+ )
+ raise InternalServerHTTPException()
+
+ match result:
+ case GetOneKeyUseCaseSuccess(key=key):
+ return KeyResponse.model_validate(key, from_attributes=True)
+ case KeyNotFoundError(id=not_found_key_id):
+ raise KeyNotFoundHTTPException(not_found_key_id)
+
+
+@router.get(
+ path=EndpointRoute.ADMIN_KEYS,
+ dependencies=[Security(dependency=AccessController(only_admin=True))],
+ status_code=200,
+ responses=get_documentation_responses([NotAdminUserHTTPException]),
+)
+async def get_keys(
+ user: int | None = Query(default=None, description="The user ID to filter keys by."),
+ offset: int = Query(default=0, ge=0, description="Number of keys to skip."),
+ limit: int = Query(default=10, ge=1, le=100, description="Maximum number of keys to return."),
+ sort_by: SortField = Query(default=SortField.ID, description="Field to sort by."),
+ sort_order: SortOrder = Query(default=SortOrder.ASC, description="Sort order."),
+ get_keys_use_case: GetKeysUseCase = Depends(get_keys_use_case_factory),
+ request_context: ContextVar[RequestContext] = Depends(get_request_context),
+) -> KeysResponse:
+ command = GetKeysCommand(user_id=user, offset=offset, limit=limit, sort_by=sort_by, sort_order=sort_order)
+ try:
+ result = await get_keys_use_case.execute(command)
+ except Exception as e:
+ logger.exception(
+ "Unexpected error while executing get_keys use case",
+ extra={
+ "authenticated_user_id": request_context.get().user.id,
+ "offset": command.offset,
+ "limit": command.limit,
+ "sort_by": command.sort_by,
+ "sort_order": command.sort_order,
+ "error_type": type(e).__name__,
+ },
+ )
+ raise InternalServerHTTPException()
+
+ match result:
+ case GetKeysUseCaseSuccess(key_page=key_page):
+ return KeysResponse(
+ total=key_page.total,
+ offset=offset,
+ limit=limit,
+ data=[KeyResponse.model_validate(key, from_attributes=True) for key in key_page.data],
+ )
diff --git a/api/infrastructure/fastapi/endpoints/admin/users.py b/api/infrastructure/fastapi/endpoints/admin/users.py
index b3d9b79d8..8657367ea 100644
--- a/api/infrastructure/fastapi/endpoints/admin/users.py
+++ b/api/infrastructure/fastapi/endpoints/admin/users.py
@@ -1,4 +1,3 @@
-from contextvars import ContextVar
import logging
from typing import assert_never
@@ -7,9 +6,10 @@
from api.dependencies import (
create_user_use_case_factory,
delete_user_use_case_factory,
+ get_authenticated_user,
get_one_user_use_case_factory,
- get_request_context,
get_users_use_case_factory,
+ update_user_use_case_factory,
)
from api.domain import SortOrder
from api.domain.organization.errors import OrganizationNotFoundError
@@ -18,24 +18,26 @@
from api.domain.user.errors import (
DeleteUserWithProvidersError,
DeleteUserWithRoutersError,
+ IncorrectCurrentPasswordError,
UserAlreadyExistsError,
UserNotFoundError,
)
+from api.domain.user.views import AuthenticatedUserView
from api.infrastructure.fastapi import AccessController
-from api.infrastructure.fastapi.context import RequestContext
from api.infrastructure.fastapi.documentation import get_documentation_responses
from api.infrastructure.fastapi.endpoints.admin import router
from api.infrastructure.fastapi.endpoints.exceptions import (
DeleteUserWithProvidersHTTPException,
DeleteUserWithRoutersHTTPException,
InternalServerHTTPException,
+ InvalidCurrentPasswordHTTPException,
NotAdminUserHTTPException,
OrganizationNotFoundHTTPException,
RoleNotFoundHTTPException,
UserAlreadyExistsHTTPException,
UserNotFoundHTTPException,
)
-from api.infrastructure.fastapi.schemas.admin.users import CreateUserBody, UserResponse, UsersResponse
+from api.infrastructure.fastapi.schemas.admin.users import CreateUserBody, UserResponse, UsersResponse, UserUpdateRequest
from api.use_cases.admin.users import (
CreateUserCommand,
CreateUserUseCase,
@@ -49,6 +51,9 @@
GetUsersCommand,
GetUsersUseCase,
GetUsersUseCaseSuccess,
+ UpdateUserCommand,
+ UpdateUserUseCase,
+ UpdateUserUseCaseSuccess,
)
from api.utils.variables import EndpointRoute
@@ -71,7 +76,7 @@
async def create_user(
body: CreateUserBody = Body(description="The user creation request."),
create_user_use_case: CreateUserUseCase = Depends(create_user_use_case_factory),
- request_context: ContextVar[RequestContext] = Depends(get_request_context),
+ authenticated_user: AuthenticatedUserView = Depends(get_authenticated_user),
) -> UserResponse:
try:
command = CreateUserCommand(
@@ -89,7 +94,7 @@ async def create_user(
logger.exception(
"Unexpected error while executing create_user use case",
extra={
- "authenticated_user_id": request_context.get().user.id,
+ "authenticated_user_id": authenticated_user.id,
"email": body.email,
"error_type": type(e).__name__,
},
@@ -116,7 +121,7 @@ async def create_user(
async def get_user(
user_id: int = Path(description="The ID of the user to get."),
get_one_user_use_case: GetOneUserUseCase = Depends(get_one_user_use_case_factory),
- request_context: ContextVar[RequestContext] = Depends(get_request_context),
+ authenticated_user: AuthenticatedUserView = Depends(get_authenticated_user),
) -> UserResponse:
command = GetOneUserCommand(user_id=user_id)
try:
@@ -125,7 +130,7 @@ async def get_user(
logger.exception(
"Unexpected error while executing get_user use case",
extra={
- "authenticated_user_id": request_context.get().user.id,
+ "authenticated_user_id": authenticated_user.id,
"user_id": command.user_id,
"error_type": type(e).__name__,
},
@@ -155,7 +160,7 @@ async def get_users(
sort_by: UserSortField = Query(default=UserSortField.ID, description="Field to sort by."),
sort_order: SortOrder = Query(default=SortOrder.ASC, description="Sort order."),
get_users_use_case: GetUsersUseCase = Depends(get_users_use_case_factory),
- request_context: ContextVar[RequestContext] = Depends(get_request_context),
+ authenticated_user: AuthenticatedUserView = Depends(get_authenticated_user),
) -> UsersResponse:
command = GetUsersCommand(
role_id=role_id,
@@ -172,7 +177,7 @@ async def get_users(
logger.exception(
"Unexpected error while executing get_users use case",
extra={
- "authenticated_user_id": request_context.get().user.id,
+ "authenticated_user_id": authenticated_user.id,
"error_type": type(e).__name__,
},
)
@@ -205,7 +210,7 @@ async def get_users(
async def delete_user(
user_id: int = Path(description="The ID of the user to delete."),
delete_user_use_case: DeleteUserUseCase = Depends(delete_user_use_case_factory),
- request_context: ContextVar[RequestContext] = Depends(get_request_context),
+ authenticated_user: AuthenticatedUserView = Depends(get_authenticated_user),
) -> UserResponse:
command = DeleteUserCommand(user_id=user_id)
try:
@@ -214,7 +219,7 @@ async def delete_user(
logger.exception(
"Unexpected error while executing delete_user use case",
extra={
- "authenticated_user_id": command.authenticated_user_id,
+ "authenticated_user_id": authenticated_user.id,
"user_id": command.user_id,
"error_type": type(e).__name__,
},
@@ -231,3 +236,65 @@ async def delete_user(
raise DeleteUserWithProvidersHTTPException(provider_ids=provider_ids)
case _ as unreachable:
assert_never(unreachable)
+
+
+@router.patch(
+ path=EndpointRoute.ADMIN_USERS + "/{user_id}",
+ dependencies=[Security(dependency=AccessController(only_admin=True))],
+ status_code=200,
+ responses=get_documentation_responses(
+ [
+ UserNotFoundHTTPException,
+ UserAlreadyExistsHTTPException,
+ RoleNotFoundHTTPException,
+ OrganizationNotFoundHTTPException,
+ InvalidCurrentPasswordHTTPException,
+ NotAdminUserHTTPException,
+ ]
+ ),
+)
+async def update_user(
+ user_id: int = Path(description="The ID of the user to update."),
+ body: UserUpdateRequest = Body(description="The user update request."),
+ update_user_use_case: UpdateUserUseCase = Depends(update_user_use_case_factory),
+ authenticated_user: AuthenticatedUserView = Depends(get_authenticated_user),
+) -> UserResponse:
+ command = UpdateUserCommand(
+ user_id=user_id,
+ email=body.email,
+ name=body.name,
+ current_password=body.current_password,
+ new_password=body.password,
+ role_id=body.role,
+ organization_id=body.organization,
+ budget=body.budget,
+ expires=body.expires,
+ priority=body.priority,
+ )
+ try:
+ result = await update_user_use_case.execute(command)
+ except Exception as e:
+ logger.exception(
+ "Unexpected error while executing update_user use case",
+ extra={
+ "authenticated_user_id": authenticated_user.id,
+ "user_id": command.user_id,
+ "error_type": type(e).__name__,
+ },
+ )
+ raise InternalServerHTTPException()
+ match result:
+ case UpdateUserUseCaseSuccess(user=user):
+ return UserResponse.model_validate(user, from_attributes=True)
+ case UserNotFoundError(id=not_found_id):
+ raise UserNotFoundHTTPException(user_id=not_found_id)
+ case UserAlreadyExistsError(email=email):
+ raise UserAlreadyExistsHTTPException(email=email)
+ case RoleNotFoundError(id=role_id):
+ raise RoleNotFoundHTTPException(role_id)
+ case OrganizationNotFoundError(id=organization_id):
+ raise OrganizationNotFoundHTTPException(organization_id)
+ case IncorrectCurrentPasswordError():
+ raise InvalidCurrentPasswordHTTPException()
+ case _ as unreachable:
+ assert_never(unreachable)
diff --git a/api/infrastructure/fastapi/endpoints/auth.py b/api/infrastructure/fastapi/endpoints/auth.py
index 0f16f1544..f773dd0be 100644
--- a/api/infrastructure/fastapi/endpoints/auth.py
+++ b/api/infrastructure/fastapi/endpoints/auth.py
@@ -5,7 +5,7 @@
from api.dependencies import auth_login_use_case_factory
from api.domain.user.errors import InvalidUserPasswordError, UserNotFoundError
from api.infrastructure.fastapi.documentation import get_documentation_responses
-from api.infrastructure.fastapi.endpoints.exceptions import InternalServerHTTPException, InvalidPasswordHTTPException, UserNotFoundHTTPException
+from api.infrastructure.fastapi.endpoints.exceptions import InternalServerHTTPException, InvalidCredentialsHTTPException
from api.infrastructure.fastapi.schemas.auth import AuthLoginBody, AuthLoginResponse
from api.use_cases.auth import AuthLoginCommand, AuthLoginUseCase, AuthLoginUseCaseSuccess
from api.utils.variables import EndpointRoute, RouterName
@@ -19,7 +19,7 @@
path=EndpointRoute.AUTH_LOGIN,
status_code=200,
response_model=AuthLoginResponse,
- responses=get_documentation_responses([InvalidPasswordHTTPException, UserNotFoundHTTPException], add_auth_exceptions=False),
+ responses=get_documentation_responses([InvalidCredentialsHTTPException], add_auth_exceptions=False),
)
async def login(body: AuthLoginBody, auth_login_use_case: AuthLoginUseCase = Depends(auth_login_use_case_factory)):
command = AuthLoginCommand(email=body.email, password=body.password)
@@ -38,7 +38,5 @@ async def login(body: AuthLoginBody, auth_login_use_case: AuthLoginUseCase = Dep
match result:
case AuthLoginUseCaseSuccess(key=key):
return AuthLoginResponse.model_validate(key, from_attributes=True)
- case InvalidUserPasswordError():
- raise InvalidPasswordHTTPException()
- case UserNotFoundError(email=email):
- raise UserNotFoundHTTPException(email=email)
+ case InvalidUserPasswordError() | UserNotFoundError():
+ raise InvalidCredentialsHTTPException()
diff --git a/api/infrastructure/fastapi/endpoints/exceptions.py b/api/infrastructure/fastapi/endpoints/exceptions.py
index fb432680b..1176ff652 100644
--- a/api/infrastructure/fastapi/endpoints/exceptions.py
+++ b/api/infrastructure/fastapi/endpoints/exceptions.py
@@ -29,9 +29,17 @@ def __init__(self) -> None:
super().__init__(status_code=self.status_code, detail=self.detail)
-class InvalidPasswordHTTPException(HTTPException):
+class InvalidCredentialsHTTPException(HTTPException):
status_code = 401
- detail = "Invalid password."
+ detail = "Invalid email or password."
+
+ def __init__(self) -> None:
+ super().__init__(status_code=self.status_code, detail=self.detail)
+
+
+class InvalidCurrentPasswordHTTPException(HTTPException):
+ status_code = 401
+ detail = "Invalid current password."
def __init__(self) -> None:
super().__init__(status_code=self.status_code, detail=self.detail)
@@ -141,6 +149,14 @@ def __init__(self, user_id: int | None = None, email: str | None = None) -> None
super().__init__(status_code=self.status_code, detail=detail)
+class KeyNotFoundHTTPException(HTTPException):
+ status_code = 404
+ detail = "Key {key_id} not found."
+
+ def __init__(self, key_id: int) -> None:
+ super().__init__(status_code=self.status_code, detail=f"Key {key_id} not found.")
+
+
# 409
class KeyAlreadyExistsHTTPException(HTTPException):
status_code = 409
diff --git a/api/infrastructure/fastapi/schemas/admin/keys.py b/api/infrastructure/fastapi/schemas/admin/keys.py
index 472bb93cc..26b237b96 100644
--- a/api/infrastructure/fastapi/schemas/admin/keys.py
+++ b/api/infrastructure/fastapi/schemas/admin/keys.py
@@ -25,7 +25,7 @@ def must_be_future_and_convert_to_datetime(cls, expires) -> None | datetime:
return expires
-class CreateKeyResponse(BaseModel):
+class KeyResponse(BaseModel):
object: Annotated[Literal["key"], Field(default="key", description="Type of the object.")]
id: Annotated[int, Field(description="ID of the key.")]
name: Annotated[str, Field(description="Name of the key.")]
@@ -48,3 +48,11 @@ def from_key(cls, data):
"created": int(data.created.timestamp()),
}
return data
+
+
+class KeysResponse(BaseModel):
+ object: Annotated[Literal["list"], Field(default="list", description="Type of the object.")]
+ total: Annotated[int, Field(description="Total number of keys.")]
+ offset: Annotated[int, Field(description="Offset of the keys list.")]
+ limit: Annotated[int, Field(description="Limit of the keys list.")]
+ data: Annotated[list[KeyResponse], Field(description="List of keys.")]
diff --git a/api/infrastructure/fastapi/schemas/admin/users.py b/api/infrastructure/fastapi/schemas/admin/users.py
index 6262f42de..18893c366 100644
--- a/api/infrastructure/fastapi/schemas/admin/users.py
+++ b/api/infrastructure/fastapi/schemas/admin/users.py
@@ -1,11 +1,20 @@
import datetime as dt
from typing import Annotated, Literal
-from pydantic import Field, StringConstraints, field_validator
+from pydantic import AfterValidator, ConfigDict, Field, StringConstraints
from api.infrastructure.fastapi.schemas import BaseModel
+def _must_be_future(expires: int) -> int:
+ if expires <= int(dt.datetime.now(tz=dt.UTC).timestamp()):
+ raise ValueError("Wrong timestamp, must be in the future.")
+ return expires
+
+
+FutureTimestamp = Annotated[int, AfterValidator(_must_be_future)]
+
+
class CreateUserBody(BaseModel):
email: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=254), Field(..., description="The user email.")]
name: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)] | None = Field(default=None, description="The user name.")
@@ -13,18 +22,13 @@ class CreateUserBody(BaseModel):
role: int = Field(..., description="The role ID.")
organization_id: int | None = Field(default=None, description="The organization ID.")
budget: float | None = Field(default=None, description="The budget.")
- expires: int | None = Field(default=None, description="The expiration timestamp.")
+ expires: FutureTimestamp | None = Field(default=None, description="The expiration timestamp.")
priority: int = Field(default=0, ge=0, description="The user priority. Higher value means higher priority.")
- @field_validator("expires", mode="before")
- def must_be_future(cls, expires):
- if isinstance(expires, int):
- if expires <= int(dt.datetime.now(tz=dt.UTC).timestamp()):
- raise ValueError("Wrong timestamp, must be in the future.")
- return expires
-
class UserResponse(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+
object: Annotated[Literal["user"], Field("user", description="Type of the object.")]
id: Annotated[int, Field(..., description="ID of the user.")]
email: Annotated[str, Field(..., description="Email of the user.")]
@@ -46,3 +50,15 @@ class UsersResponse(BaseModel):
offset: Annotated[int, Field(..., description="Number of users skipped.")]
limit: Annotated[int, Field(..., description="Maximum number of users returned.")]
data: Annotated[list[UserResponse], Field(..., description="List of users.")]
+
+
+class UserUpdateRequest(BaseModel):
+ email: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=254)] | None = Field(default=None, description="The new user email. If None, the user email is not changed.") # fmt: off
+ name: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)] | None = Field(default=None, description="The new user name. If None, the user name is not changed.") # fmt: off
+ current_password: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=72)] | None = Field(default=None, description="The current user password.") # fmt: off
+ password: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=72)] | None = Field(default=None, description="The new user password. If None, the user password is not changed.") # fmt: off
+ role: int | None = Field(default=None, description="The new role ID. If None, the user role is not changed.") # fmt: off
+ organization: int | None = Field(default=None, description="The new organization ID. If None, the user will be removed from the organization if he was in one.") # fmt: off
+ budget: float | None = Field(default=None, description="The new budget. If None, the user will have no budget.") # fmt: off
+ expires: FutureTimestamp | None = Field(default=None, description="The new expiration timestamp. If None, the user will never expire.") # fmt: off
+ priority: int | None = Field(default=None, ge=0, description="The new user priority. Higher value means higher priority. If None, unchanged.") # fmt: off
diff --git a/api/infrastructure/fastapi/schemas/auth.py b/api/infrastructure/fastapi/schemas/auth.py
index 465562d5f..552eb95da 100644
--- a/api/infrastructure/fastapi/schemas/auth.py
+++ b/api/infrastructure/fastapi/schemas/auth.py
@@ -2,7 +2,7 @@
from pydantic import Field, StringConstraints
-from api.infrastructure.fastapi.schemas.admin.keys import CreateKeyResponse
+from api.infrastructure.fastapi.schemas.admin.keys import KeyResponse
from api.schemas import BaseModel
@@ -11,5 +11,5 @@ class AuthLoginBody(BaseModel):
password: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=72)] = Field(description="The user password.")
-class AuthLoginResponse(CreateKeyResponse):
+class AuthLoginResponse(KeyResponse):
pass
diff --git a/api/infrastructure/postgres/_postgreskeyrepository.py b/api/infrastructure/postgres/_postgreskeyrepository.py
index 5995cb9a4..cac15a891 100644
--- a/api/infrastructure/postgres/_postgreskeyrepository.py
+++ b/api/infrastructure/postgres/_postgreskeyrepository.py
@@ -1,11 +1,12 @@
from pydantic import FutureDatetime
-from sqlalchemy import insert, select, update
+from sqlalchemy import asc, desc, func, insert, or_, select, update
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
+from api.domain import SortField, SortOrder
from api.domain.key import KeyEncoder, KeyRepository
-from api.domain.key.entities import Key
+from api.domain.key.entities import Key, KeyPage
from api.domain.key.errors import KeyAlreadyExistsError, KeyNotFoundError
from api.domain.user.errors import UserNotFoundError
from api.sql.models import Token as KeyTable
@@ -26,6 +27,36 @@ async def get_key_by_id(self, key_id: int) -> Key | KeyNotFoundError:
return Key(id=row.id, name=row.name, user_id=row.user_id, value=row.token, expires=row.expires, created=row.created)
+ async def get_keys_page(
+ self,
+ user_id: int | None = None,
+ limit: int = 10,
+ offset: int = 0,
+ sort_by: SortField = SortField.ID,
+ sort_order: SortOrder = SortOrder.ASC,
+ exclude_expired: bool = True,
+ ) -> KeyPage:
+ sort_column = {SortField.ID: KeyTable.id, SortField.NAME: KeyTable.name, SortField.CREATED: KeyTable.created}[sort_by]
+ order_fn = asc if sort_order == SortOrder.ASC else desc
+
+ filters = []
+ if user_id is not None:
+ filters.append(KeyTable.user_id == user_id)
+ if exclude_expired:
+ filters.append(or_(KeyTable.expires.is_(None), KeyTable.expires >= func.now()))
+
+ key_query = select(KeyTable).where(*filters).order_by(order_fn(sort_column)).offset(offset).limit(limit)
+ count_query = select(func.count()).select_from(KeyTable).where(*filters)
+
+ total = (await self.postgres_session.execute(count_query)).scalar_one()
+ result = await self.postgres_session.execute(key_query)
+ keys = [
+ Key(id=row.id, name=row.name, user_id=row.user_id, value=row.token, expires=row.expires, created=row.created)
+ for row in result.scalars().all()
+ ]
+
+ return KeyPage(total=total, data=keys)
+
async def create_key(self, user_id: int, name: str, expire: FutureDatetime | None) -> Key | KeyAlreadyExistsError | UserNotFoundError:
try:
result = await self.postgres_session.execute(insert(KeyTable).values(user_id=user_id, name=name, expires=expire).returning(KeyTable))
diff --git a/api/infrastructure/postgres/_postgresusersrepository.py b/api/infrastructure/postgres/_postgresusersrepository.py
index c98ad83eb..73ede70bd 100644
--- a/api/infrastructure/postgres/_postgresusersrepository.py
+++ b/api/infrastructure/postgres/_postgresusersrepository.py
@@ -27,6 +27,7 @@ def _unix_timestamp(column):
UserTable.id,
UserTable.email,
UserTable.name,
+ UserTable.password,
UserTable.sub,
UserTable.iss,
UserTable.role_id.label("role"),
@@ -49,6 +50,7 @@ def _row_to_user(row) -> User:
id=row.id,
email=row.email,
name=row.name,
+ password=row.password,
sub=row.sub,
iss=row.iss,
role=row.role,
@@ -98,20 +100,7 @@ async def create_user(
expires=expires_value,
priority=priority,
)
- .returning(
- UserTable.id,
- UserTable.email,
- UserTable.name,
- UserTable.sub,
- UserTable.iss,
- UserTable.role_id.label("role"),
- UserTable.organization_id.label("organization"),
- UserTable.budget,
- _unix_timestamp(UserTable.expires).label("expires"),
- _unix_timestamp(UserTable.created).label("created"),
- _unix_timestamp(UserTable.updated).label("updated"),
- UserTable.priority,
- )
+ .returning(*_USER_COLUMNS)
)
row = result.one()
except IntegrityError as e:
@@ -190,28 +179,16 @@ async def update_user(self, user: User) -> User | UserNotFoundError | UserAlread
.values(
email=user.email,
name=user.name,
+ password=user.password.get_secret_value() if user.password is not None else None,
sub=user.sub,
iss=user.iss,
role_id=user.role,
- organization_id=user.organization,
+ organization_id=user.organization_id,
budget=user.budget,
expires=expires_value,
priority=user.priority,
)
- .returning(
- UserTable.id,
- UserTable.email,
- UserTable.name,
- UserTable.sub,
- UserTable.iss,
- UserTable.role_id.label("role"),
- UserTable.organization_id.label("organization"),
- UserTable.budget,
- _unix_timestamp(UserTable.expires).label("expires"),
- _unix_timestamp(UserTable.created).label("created"),
- _unix_timestamp(UserTable.updated).label("updated"),
- UserTable.priority,
- )
+ .returning(*_USER_COLUMNS)
.where(UserTable.id == user.id)
)
try:
@@ -219,11 +196,12 @@ async def update_user(self, user: User) -> User | UserNotFoundError | UserAlread
row = result.one_or_none()
except IntegrityError as e:
if "user_organization_id_fkey" in str(e.orig):
- return OrganizationNotFoundError(id=user.organization)
+ return OrganizationNotFoundError(id=user.organization_id)
if "user_role_id_fkey" in str(e.orig):
return RoleNotFoundError(id=user.role)
- if "ix_user_email_key" in str(e.orig):
+ if "ix_user_email" in str(e.orig):
return UserAlreadyExistsError(email=user.email)
+ raise
if row is None:
return UserNotFoundError(id=user.id)
diff --git a/api/schemas/admin/users.py b/api/schemas/admin/users.py
index a8de241a5..89e54bbcc 100644
--- a/api/schemas/admin/users.py
+++ b/api/schemas/admin/users.py
@@ -6,26 +6,6 @@
from api.schemas import BaseModel
-class UserUpdateRequest(BaseModel):
- email: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=254)] | None = Field(default=None, description="The new user email. If None, the user email is not changed.") # fmt: off
- name: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)] | None = Field(default=None, description="The new user name. If None, the user name is not changed.") # fmt: off
- current_password: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=72)] | None = Field(default=None, description="The current user password.") # fmt: off
- password: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=72)] | None = Field(default=None, description="The new user password. If None, the user password is not changed.") # fmt: off
- role: int | None = Field(default=None, description="The new role ID. If None, the user role is not changed.") # fmt: off
- organization: int | None = Field(default=None, description="The new organization ID. If None, the user will be removed from the organization if he was in one.") # fmt: off
- budget: float | None = Field(default=None, description="The new budget. If None, the user will have no budget.") # fmt: off
- expires: int | None = Field(default=None, description="The new expiration timestamp. If None, the user will never expire.") # fmt: off
- priority: int | None = Field(default=None, ge=0, description="The new user priority. Higher value means higher priority. If None, unchanged.") # fmt: off
-
- @field_validator("expires", mode="before")
- def must_be_future(cls, expires):
- if isinstance(expires, int):
- if expires <= int(dt.datetime.now(tz=dt.UTC).timestamp()):
- raise ValueError("Wrong timestamp, must be in the future.")
-
- return expires
-
-
class UsersResponse(BaseModel):
id: int = Field(description="The user ID.")
diff --git a/api/tests/integ/config.test.yml b/api/tests/integ/config.test.yml
index 35cbf3762..ee732cea2 100644
--- a/api/tests/integ/config.test.yml
+++ b/api/tests/integ/config.test.yml
@@ -75,5 +75,4 @@ settings:
auth_key_max_expiration_days: 365
monitoring_sentry_enabled: False
monitoring_postgres_enabled: True
- monitoring_prometheus_enabled: True
- opengaterag_url: http://localhost:8001
+ monitoring_prometheus_enabled: False
diff --git a/api/tests/integ/test_admin/test_admin.py b/api/tests/integ/test_admin/test_admin.py
index a30fd6198..607085d62 100644
--- a/api/tests/integ/test_admin/test_admin.py
+++ b/api/tests/integ/test_admin/test_admin.py
@@ -103,7 +103,7 @@ def test_user_account_expiration_format(self, client: TestClient, roles: tuple[d
# Update expiration to now
future_current = int((datetime.now() + timedelta(seconds=10)).timestamp())
response = client.patch_with_permissions(url=f"/v1{EndpointRoute.ADMIN_USERS}/{user_with_expiration_id}", json={"expires": future_current})
- assert response.status_code == 204, response.text
+ assert response.status_code == 200, response.text
# Check updated expiration
response = client.get_with_permissions(url=f"/v1{EndpointRoute.ADMIN_USERS}/{user_with_expiration_id}")
@@ -343,7 +343,7 @@ def test_user_budget(self, client: TestClient, tokenizer, text_generation_router
# Update the budget
response = client.patch_with_permissions(url=f"/v1{EndpointRoute.ADMIN_USERS}/{user_id}", json={"budget": 0})
- assert response.status_code == 204, response.text
+ assert response.status_code == 200, response.text
# Check that the budget is updated
response = client.get_with_permissions(url=f"/v1{EndpointRoute.ADMIN_USERS}/{user_id}")
diff --git a/api/tests/integration/endpoints/admin/keys/test_get_key.py b/api/tests/integration/endpoints/admin/keys/test_get_key.py
new file mode 100644
index 000000000..7445736b7
--- /dev/null
+++ b/api/tests/integration/endpoints/admin/keys/test_get_key.py
@@ -0,0 +1,87 @@
+from unittest.mock import AsyncMock
+
+from httpx import AsyncClient
+import pytest
+import pytest_asyncio
+
+from api.dependencies import get_one_key_use_case_factory
+from api.domain.key.errors import KeyNotFoundError
+from api.tests.helpers import INVALID_API_KEY, create_key
+from api.tests.integration.factories.sql import KeySQLFactory, UserSQLFactory
+from api.utils.variables import EndpointRoute
+
+URL = f"/v1{EndpointRoute.ADMIN_KEYS}"
+
+
+@pytest.mark.asyncio(loop_scope="session")
+class TestGetKey:
+ @pytest_asyncio.fixture(autouse=True)
+ async def setup(self, db_session):
+ self.admin_user = UserSQLFactory(admin_user=True)
+ self.key = await create_key(db_session, name="admin_key", user=self.admin_user)
+
+ async def test_happy_path(self, client: AsyncClient, db_session):
+ user = UserSQLFactory()
+ key = KeySQLFactory(user=user, name="my-key", never_expires=True)
+ await db_session.flush()
+
+ response = await client.get(
+ url=f"{URL}/{key.id}",
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ )
+
+ assert response.status_code == 200, response.text
+ data = response.json()
+ assert data["id"] == key.id
+ assert data["object"] == "key"
+ assert data["name"] == "my-key"
+ assert data["user"] == user.id
+
+ @pytest.mark.parametrize(
+ "use_case_result,expected_status,expected_detail",
+ [
+ (
+ KeyNotFoundError(id=1),
+ 404,
+ "Key 1 not found.",
+ ),
+ ],
+ )
+ async def test_error_maps_to_correct_http_status(self, client: AsyncClient, app, use_case_result, expected_status, expected_detail):
+ mock_use_case = AsyncMock()
+ mock_use_case.execute.return_value = use_case_result
+ app.dependency_overrides[get_one_key_use_case_factory] = lambda: mock_use_case
+
+ response = await client.get(
+ url=f"{URL}/1",
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ )
+
+ assert response.status_code == expected_status
+ assert response.json().get("detail") == expected_detail
+
+ async def test_rejects_non_admin_user(self, client: AsyncClient, db_session):
+ regular_user = UserSQLFactory(regular_user=True)
+ key = await create_key(db_session, name="regular_user_key", user=regular_user, never_expires=True)
+
+ response = await client.get(
+ url=f"{URL}/1",
+ headers={"Authorization": f"Bearer {key.token}"},
+ )
+
+ assert response.status_code == 403, response.text
+ assert response.json().get("detail") == "User has no admin rights."
+
+ @pytest.mark.parametrize(
+ "headers,expected_status,expected_detail",
+ [
+ ({}, 401, "Not authenticated"),
+ ({"Authorization": "Bearer malformed-token"}, 401, "Invalid API key."),
+ ({"Authorization": f"Bearer {INVALID_API_KEY}"}, 401, "Invalid API key."),
+ ],
+ )
+ async def test_auth(self, client: AsyncClient, headers, expected_status, expected_detail):
+ response = await client.get(url=f"{URL}/1", headers=headers)
+
+ assert response.status_code == expected_status
+ assert response.json().get("detail") == expected_detail
diff --git a/api/tests/integration/endpoints/admin/keys/test_get_keys.py b/api/tests/integration/endpoints/admin/keys/test_get_keys.py
new file mode 100644
index 000000000..c363264bc
--- /dev/null
+++ b/api/tests/integration/endpoints/admin/keys/test_get_keys.py
@@ -0,0 +1,82 @@
+from httpx import AsyncClient
+import pytest
+import pytest_asyncio
+
+from api.tests.helpers import INVALID_API_KEY, create_key
+from api.tests.integration.factories.sql import KeySQLFactory, UserSQLFactory
+from api.utils.variables import EndpointRoute
+
+URL = f"/v1{EndpointRoute.ADMIN_KEYS}"
+
+
+@pytest.mark.asyncio(loop_scope="session")
+class TestGetKeys:
+ @pytest_asyncio.fixture(autouse=True)
+ async def setup(self, db_session):
+ self.admin_user = UserSQLFactory(admin_user=True)
+ self.key = await create_key(db_session, name="admin_key", user=self.admin_user)
+
+ async def test_happy_path(self, client: AsyncClient, db_session):
+ user = UserSQLFactory()
+ KeySQLFactory(user=user, name="key-a", never_expires=True)
+ KeySQLFactory(user=user, name="key-b", never_expires=True)
+ await db_session.flush()
+
+ response = await client.get(
+ url=URL,
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ )
+
+ assert response.status_code == 200, response.text
+ data = response.json()
+ assert data["object"] == "list"
+ assert isinstance(data["total"], int)
+ assert data["offset"] == 0
+ assert data["limit"] == 10
+ assert len(data["data"]) >= 2
+ assert all(item["object"] == "key" for item in data["data"])
+
+ async def test_filters_by_user(self, client: AsyncClient, db_session):
+ user = UserSQLFactory()
+ other_user = UserSQLFactory()
+ key = KeySQLFactory(user=user, name="user-key", never_expires=True)
+ KeySQLFactory(user=other_user, name="other-key", never_expires=True)
+ await db_session.flush()
+
+ response = await client.get(
+ url=URL,
+ params={"user": user.id},
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ )
+
+ assert response.status_code == 200, response.text
+ data = response.json()
+ assert data["total"] == 1
+ assert data["data"][0]["id"] == key.id
+ assert data["data"][0]["user"] == user.id
+
+ async def test_rejects_non_admin_user(self, client: AsyncClient, db_session):
+ regular_user = UserSQLFactory(regular_user=True)
+ key = await create_key(db_session, name="regular_user_key", user=regular_user, never_expires=True)
+
+ response = await client.get(
+ url=URL,
+ headers={"Authorization": f"Bearer {key.token}"},
+ )
+
+ assert response.status_code == 403, response.text
+ assert response.json().get("detail") == "User has no admin rights."
+
+ @pytest.mark.parametrize(
+ "headers,expected_status,expected_detail",
+ [
+ ({}, 401, "Not authenticated"),
+ ({"Authorization": "Bearer malformed-token"}, 401, "Invalid API key."),
+ ({"Authorization": f"Bearer {INVALID_API_KEY}"}, 401, "Invalid API key."),
+ ],
+ )
+ async def test_auth(self, client: AsyncClient, headers, expected_status, expected_detail):
+ response = await client.get(url=URL, headers=headers)
+
+ assert response.status_code == expected_status
+ assert response.json().get("detail") == expected_detail
diff --git a/api/tests/integration/endpoints/admin/users/test_update_user.py b/api/tests/integration/endpoints/admin/users/test_update_user.py
new file mode 100644
index 000000000..b0f92c4b0
--- /dev/null
+++ b/api/tests/integration/endpoints/admin/users/test_update_user.py
@@ -0,0 +1,113 @@
+from unittest.mock import AsyncMock
+
+from httpx import AsyncClient
+import pytest
+import pytest_asyncio
+
+from api.dependencies import update_user_use_case_factory
+from api.domain.organization.errors import OrganizationNotFoundError
+from api.domain.role.errors import RoleNotFoundError
+from api.domain.user.errors import IncorrectCurrentPasswordError, UserAlreadyExistsError, UserNotFoundError
+from api.tests.helpers import INVALID_API_KEY, create_key
+from api.tests.integration.factories.sql import UserSQLFactory
+from api.utils.variables import EndpointRoute
+
+URL = f"/v1{EndpointRoute.ADMIN_USERS}"
+
+
+@pytest.mark.asyncio(loop_scope="session")
+class TestUpdateUser:
+ @pytest_asyncio.fixture(autouse=True)
+ async def setup(self, db_session):
+ self.admin_user = UserSQLFactory(admin_user=True)
+ self.key = await create_key(db_session, name="admin_key", user=self.admin_user)
+
+ async def test_happy_path(self, client: AsyncClient, db_session):
+ user = UserSQLFactory()
+ await db_session.flush()
+
+ response = await client.patch(
+ url=f"{URL}/{user.id}",
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ json={"email": "updated@example.com", "name": "Updated Name", "budget": 50.5, "priority": 2},
+ )
+
+ assert response.status_code == 200, response.text
+ data = response.json()
+ assert data["id"] == user.id
+ assert data["email"] == "updated@example.com"
+ assert data["name"] == "Updated Name"
+ assert data["budget"] == 50.5
+ assert data["priority"] == 2
+ assert data["role"] == user.role_id
+
+ @pytest.mark.parametrize(
+ "use_case_result,expected_status,expected_detail",
+ [
+ (
+ UserNotFoundError(id=1),
+ 404,
+ "User 1 not found.",
+ ),
+ (
+ UserAlreadyExistsError(email="taken@example.com"),
+ 409,
+ "User taken@example.com already exists.",
+ ),
+ (
+ RoleNotFoundError(id=99),
+ 404,
+ "Role 99 not found.",
+ ),
+ (
+ OrganizationNotFoundError(id=99),
+ 404,
+ "Organization 99 not found.",
+ ),
+ (
+ IncorrectCurrentPasswordError(user_id=1),
+ 401,
+ "Invalid current password.",
+ ),
+ ],
+ )
+ async def test_error_maps_to_correct_http_status(self, client: AsyncClient, app, use_case_result, expected_status, expected_detail):
+ mock_use_case = AsyncMock()
+ mock_use_case.execute.return_value = use_case_result
+ app.dependency_overrides[update_user_use_case_factory] = lambda: mock_use_case
+
+ response = await client.patch(
+ url=f"{URL}/1",
+ headers={"Authorization": f"Bearer {self.key.token}"},
+ json={},
+ )
+
+ assert response.status_code == expected_status
+ assert response.json().get("detail") == expected_detail
+
+ async def test_rejects_non_admin_user(self, client: AsyncClient, db_session):
+ regular_user = UserSQLFactory(regular_user=True)
+ key = await create_key(db_session, name="regular_user_key", user=regular_user, never_expires=True)
+
+ response = await client.patch(
+ url=f"{URL}/1",
+ headers={"Authorization": f"Bearer {key.token}"},
+ json={},
+ )
+
+ assert response.status_code == 403, response.text
+ assert response.json().get("detail") == "User has no admin rights."
+
+ @pytest.mark.parametrize(
+ "headers,expected_status,expected_detail",
+ [
+ ({}, 401, "Not authenticated"),
+ ({"Authorization": "Bearer malformed-token"}, 401, "Invalid API key."),
+ ({"Authorization": f"Bearer {INVALID_API_KEY}"}, 401, "Invalid API key."),
+ ],
+ )
+ async def test_auth(self, client: AsyncClient, headers, expected_status, expected_detail):
+ response = await client.patch(url=f"{URL}/1", headers=headers, json={})
+
+ assert response.status_code == expected_status
+ assert response.json().get("detail") == expected_detail
diff --git a/api/tests/integration/endpoints/test_auth_login.py b/api/tests/integration/endpoints/test_auth_login.py
index cba728f78..118565562 100644
--- a/api/tests/integration/endpoints/test_auth_login.py
+++ b/api/tests/integration/endpoints/test_auth_login.py
@@ -51,13 +51,13 @@ async def test_happy_path(self, client: AsyncClient):
[
(
UserNotFoundError(email="missing@test.com"),
- 404,
- "User missing@test.com not found.",
+ 401,
+ "Invalid email or password.",
),
(
InvalidUserPasswordError(),
401,
- "Invalid password.",
+ "Invalid email or password.",
),
],
)
diff --git a/api/tests/integration/postgres/test_postgreskeyrepository.py b/api/tests/integration/postgres/test_postgreskeyrepository.py
index 34dd17656..6e08fb13f 100644
--- a/api/tests/integration/postgres/test_postgreskeyrepository.py
+++ b/api/tests/integration/postgres/test_postgreskeyrepository.py
@@ -3,6 +3,7 @@
import pytest
from sqlalchemy import select
+from api.domain import EntitiesPage, SortField, SortOrder
from api.domain.key.entities import Key
from api.domain.key.errors import KeyNotFoundError
from api.domain.user.errors import UserNotFoundError
@@ -83,6 +84,57 @@ async def test_get_key_by_id_should_return_key_not_found_when_token_does_not_exi
assert result.id == 999999
+@pytest.mark.asyncio(loop_scope="session")
+class TestGetKeysPage:
+ async def test_returns_correct_page_with_limit_and_offset(self, repository, db_session):
+ user = UserSQLFactory()
+ KeySQLFactory(user=user, name="key_a", never_expires=True)
+ KeySQLFactory(user=user, name="key_b", never_expires=True)
+ KeySQLFactory(user=user, name="key_c", never_expires=True)
+ await db_session.flush()
+
+ result = await repository.get_keys_page(user_id=user.id, limit=2, offset=0, sort_by=SortField.NAME, sort_order=SortOrder.ASC)
+
+ assert isinstance(result, EntitiesPage)
+ assert all(isinstance(k, Key) for k in result.data)
+ returned_names = [k.name for k in result.data]
+ assert returned_names == ["key_a", "key_b"]
+
+ async def test_filters_by_user_id(self, repository, db_session):
+ user = UserSQLFactory()
+ other_user = UserSQLFactory()
+ KeySQLFactory(user=user, name="user-key", never_expires=True)
+ KeySQLFactory(user=other_user, name="other-key", never_expires=True)
+ await db_session.flush()
+
+ result = await repository.get_keys_page(user_id=user.id)
+
+ assert result.total == 1
+ assert result.data[0].name == "user-key"
+
+ async def test_excludes_expired_keys(self, repository, db_session):
+ user = UserSQLFactory()
+ KeySQLFactory(user=user, name="active-key", never_expires=True)
+ KeySQLFactory(user=user, name="expired-key", expired=True)
+ await db_session.flush()
+
+ result = await repository.get_keys_page(user_id=user.id)
+
+ assert result.total == 1
+ assert result.data[0].name == "active-key"
+
+ async def test_sort_by_name_desc(self, repository, db_session):
+ user = UserSQLFactory()
+ KeySQLFactory(user=user, name="key_a", never_expires=True)
+ KeySQLFactory(user=user, name="key_c", never_expires=True)
+ KeySQLFactory(user=user, name="key_b", never_expires=True)
+ await db_session.flush()
+
+ result = await repository.get_keys_page(user_id=user.id, sort_by=SortField.NAME, sort_order=SortOrder.DESC)
+
+ assert [k.name for k in result.data] == ["key_c", "key_b", "key_a"]
+
+
@pytest.mark.asyncio(loop_scope="session")
class TestCreateKey:
async def test_create_key_should_return_key_when_user_exists(self, repository, db_session, key_encoder):
diff --git a/api/tests/integration/postgres/user_repository/test_update_user.py b/api/tests/integration/postgres/user_repository/test_update_user.py
new file mode 100644
index 000000000..931d272df
--- /dev/null
+++ b/api/tests/integration/postgres/user_repository/test_update_user.py
@@ -0,0 +1,131 @@
+from datetime import datetime, timedelta
+
+from pydantic import SecretStr
+import pytest
+from sqlalchemy import select
+
+from api.domain.organization.errors import OrganizationNotFoundError
+from api.domain.role.errors import RoleNotFoundError
+from api.domain.user.entities import User
+from api.domain.user.errors import UserAlreadyExistsError, UserNotFoundError
+from api.infrastructure.postgres import PostgresUserRepository
+from api.sql.models import User as UserTable
+from api.tests.integration.factories.sql import OrganizationSQLFactory, RoleSQLFactory, UserSQLFactory
+
+
+@pytest.fixture
+def repository(db_session):
+ return PostgresUserRepository(postgres_session=db_session)
+
+
+async def _get_user_entity(repository, user_id: int) -> User:
+ user = await repository.get_user_by_id(user_id=user_id)
+ assert isinstance(user, User)
+ return user
+
+
+@pytest.mark.asyncio(loop_scope="session")
+class TestUpdateUser:
+ async def test_updates_fields_and_returns_updated_user_entity(self, repository, db_session):
+ # Arrange
+ user = UserSQLFactory()
+ new_role = RoleSQLFactory()
+ new_organization = OrganizationSQLFactory()
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+
+ # Act
+ result = await repository.update_user(
+ user=existing_user.model_copy(
+ update={
+ "email": "updated@test.com",
+ "name": "Updated Name",
+ "budget": 50.5,
+ "priority": 3,
+ "password": SecretStr("encoded:new-secret"),
+ "role": new_role.id,
+ "organization_id": new_organization.id,
+ }
+ )
+ )
+
+ # Assert
+ assert isinstance(result, User)
+ assert result.id == user.id
+ assert result.email == "updated@test.com"
+ assert result.name == "Updated Name"
+ assert result.budget == 50.5
+ assert result.priority == 3
+ assert result.role == new_role.id
+ assert result.organization_id == new_organization.id
+ assert result.password == SecretStr("encoded:new-secret")
+ assert result.expires is None
+ row = (await db_session.execute(select(UserTable.password).where(UserTable.id == user.id))).scalar_one()
+ assert row == "encoded:new-secret"
+
+ async def test_persists_expires_when_set(self, repository, db_session):
+ # Arrange
+ user = UserSQLFactory(expires=None)
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+ expires = int((datetime.now() + timedelta(days=30)).timestamp())
+
+ # Act
+ result = await repository.update_user(user=existing_user.model_copy(update={"expires": expires}))
+
+ # Assert
+ assert isinstance(result, User)
+ assert result.expires == expires
+
+ async def test_returns_user_not_found_error_when_user_does_not_exist(self, repository, db_session):
+ # Arrange
+ user = UserSQLFactory()
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+
+ # Act
+ result = await repository.update_user(user=existing_user.model_copy(update={"id": 999999}))
+
+ # Assert
+ assert isinstance(result, UserNotFoundError)
+ assert result.id == 999999
+
+ async def test_returns_user_already_exists_error_when_email_is_duplicate(self, repository, db_session):
+ # Arrange
+ UserSQLFactory(email="taken@test.com")
+ user = UserSQLFactory(email="other@test.com")
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+
+ # Act
+ result = await repository.update_user(user=existing_user.model_copy(update={"email": "taken@test.com"}))
+
+ # Assert
+ assert isinstance(result, UserAlreadyExistsError)
+ assert result.email == "taken@test.com"
+
+ async def test_returns_role_not_found_error_when_role_does_not_exist(self, repository, db_session):
+ # Arrange
+ user = UserSQLFactory()
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+
+ # Act
+ result = await repository.update_user(user=existing_user.model_copy(update={"role": 999999}))
+
+ # Assert
+ assert isinstance(result, RoleNotFoundError)
+ assert result.id == 999999
+
+ async def test_returns_organization_not_found_error_when_organization_does_not_exist(self, repository, db_session):
+ # Arrange
+ user = UserSQLFactory()
+ await db_session.flush()
+ existing_user = await _get_user_entity(repository, user.id)
+
+ # Act
+ result = await repository.update_user(user=existing_user.model_copy(update={"organization_id": 999999}))
+
+ # Assert
+ assert isinstance(result, OrganizationNotFoundError)
+ assert result.id == 999999
diff --git a/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_key.py b/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_key.py
new file mode 100644
index 000000000..b63d95484
--- /dev/null
+++ b/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_key.py
@@ -0,0 +1,52 @@
+from datetime import UTC, datetime
+from unittest.mock import AsyncMock, MagicMock
+
+import pytest
+
+from api.domain.key.entities import Key
+from api.domain.key.errors import KeyNotFoundError
+from api.infrastructure.fastapi.endpoints.admin.keys import get_key
+from api.infrastructure.fastapi.endpoints.exceptions import KeyNotFoundHTTPException
+from api.infrastructure.fastapi.schemas.admin.keys import KeyResponse
+from api.use_cases.admin.keys import GetOneKeyCommand, GetOneKeyUseCaseSuccess
+
+
+@pytest.fixture
+def mock_request_context():
+ mock_ctx = MagicMock()
+ mock_ctx.get.return_value = MagicMock(user=MagicMock(id=1))
+ return mock_ctx
+
+
+class TestGetKeyEndpoint:
+ @pytest.mark.asyncio
+ async def test_should_map_key_to_key_response(self, mock_request_context):
+ key = Key(
+ id=1,
+ name="my-key",
+ user_id=42,
+ value="sk-masked...value",
+ expires=None,
+ created=datetime(2030, 1, 1, tzinfo=UTC),
+ )
+ mock_use_case = MagicMock()
+ mock_use_case.execute = AsyncMock(return_value=GetOneKeyUseCaseSuccess(key=key))
+
+ result = await get_key(key_id=1, get_one_key_use_case=mock_use_case, request_context=mock_request_context)
+
+ assert isinstance(result, KeyResponse)
+ assert result.id == 1
+ assert result.name == "my-key"
+ assert result.user == 42
+ mock_use_case.execute.assert_awaited_once_with(GetOneKeyCommand(key_id=1))
+
+ @pytest.mark.asyncio
+ async def test_should_raise_key_not_found_http_exception(self, mock_request_context):
+ mock_use_case = MagicMock()
+ mock_use_case.execute = AsyncMock(return_value=KeyNotFoundError(id=99))
+
+ with pytest.raises(KeyNotFoundHTTPException) as exc_info:
+ await get_key(key_id=99, get_one_key_use_case=mock_use_case, request_context=mock_request_context)
+
+ assert exc_info.value.status_code == 404
+ assert exc_info.value.detail == "Key 99 not found."
diff --git a/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_keys.py b/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_keys.py
new file mode 100644
index 000000000..81e368f14
--- /dev/null
+++ b/api/tests/unit/infrastructure/fastapi/endpoints/admin/keys/test_get_keys.py
@@ -0,0 +1,53 @@
+from datetime import UTC, datetime
+from unittest.mock import AsyncMock, MagicMock
+
+import pytest
+
+from api.domain import EntitiesPage, SortField, SortOrder
+from api.domain.key.entities import Key
+from api.infrastructure.fastapi.endpoints.admin.keys import get_keys
+from api.infrastructure.fastapi.schemas.admin.keys import KeysResponse
+from api.use_cases.admin.keys import GetKeysCommand, GetKeysUseCaseSuccess
+
+
+@pytest.fixture
+def mock_request_context():
+ mock_ctx = MagicMock()
+ mock_ctx.get.return_value = MagicMock(user=MagicMock(id=1))
+ return mock_ctx
+
+
+class TestGetKeysEndpoint:
+ @pytest.mark.asyncio
+ async def test_should_map_key_page_to_keys_response(self, mock_request_context):
+ key = Key(
+ id=1,
+ name="my-key",
+ user_id=42,
+ value="sk-masked...value",
+ expires=None,
+ created=datetime(2030, 1, 1, tzinfo=UTC),
+ )
+ mock_use_case = MagicMock()
+ mock_use_case.execute = AsyncMock(return_value=GetKeysUseCaseSuccess(key_page=EntitiesPage(total=1, data=[key])))
+
+ result = await get_keys(
+ user=None,
+ offset=0,
+ limit=10,
+ sort_by=SortField.ID,
+ sort_order=SortOrder.ASC,
+ get_keys_use_case=mock_use_case,
+ request_context=mock_request_context,
+ )
+
+ assert isinstance(result, KeysResponse)
+ assert result.total == 1
+ assert result.offset == 0
+ assert result.limit == 10
+ assert len(result.data) == 1
+ assert result.data[0].name == "my-key"
+ assert result.data[0].user == 42
+ mock_use_case.execute.assert_awaited_once_with(
+ GetKeysCommand(user_id=None, offset=0, limit=10, sort_by=SortField.ID, sort_order=SortOrder.ASC)
+ )
diff --git a/api/tests/unit/test_helpers/test_limiter.py b/api/tests/unit/test_helpers/test_limiter.py
index 8c5c69e0f..3db4fc3c0 100644
--- a/api/tests/unit/test_helpers/test_limiter.py
+++ b/api/tests/unit/test_helpers/test_limiter.py
@@ -4,7 +4,6 @@
from limits.aio import strategies
from limits.aio.storage import RedisStorage
import pytest
-from redis.exceptions import RedisError
from api.helpers._limiter import Limiter
from api.schemas.admin.roles import Limit, LimitType, PermissionType
@@ -38,83 +37,6 @@ async def test_limiter_initialization_strategies(strategy, expected_class):
assert isinstance(limiter.strategy, expected_class)
-# =========================== RESET METHOD ============================
-
-
-@pytest.mark.asyncio
-@pytest.mark.parametrize(
- "strategy",
- [
- LimitingStrategy.MOVING_WINDOW,
- LimitingStrategy.FIXED_WINDOW,
- LimitingStrategy.SLIDING_WINDOW,
- ],
-)
-async def test_limiter_reset_success(strategy):
- """Test that reset successfully calls redis_client.reset()."""
- # Mock the Redis pool instead of using global_context
- mock_redis_pool = MagicMock()
- mock_redis_pool.url = "redis://localhost:6379"
-
- with patch("api.helpers._limiter.storage.RedisStorage") as MockStorage, patch("api.helpers._limiter.Redis") as MockRedis:
- mock_storage_instance = AsyncMock(spec=RedisStorage)
- MockStorage.return_value = mock_storage_instance
-
- mock_internal_redis = AsyncMock()
- MockRedis.return_value = mock_internal_redis
-
- redis_state = ["LIMITS:key1", "LIMITS:key2"]
- mock_internal_redis.keys.side_effect = lambda pattern: redis_state
- # When storage.reset() is called, clear the state
-
- async def simulate_reset():
- redis_state.clear()
-
- mock_storage_instance.reset.side_effect = simulate_reset
-
- limiter = Limiter(mock_redis_pool, strategy=strategy)
-
- # Verify keys exist before reset
- initial_keys = await limiter.redis_client.keys("LIMITS*")
- assert len(initial_keys) == 2
-
- await limiter.reset()
-
- mock_storage_instance.reset.assert_awaited_once()
-
- final_keys = await limiter.redis_client.keys("LIMITS*")
- assert len(final_keys) == 0
-
-
-@pytest.mark.asyncio
-async def test_limiter_reset_handles_redis_error():
- """Test that reset handles RedisError gracefully."""
- mock_redis_pool = MagicMock()
- mock_redis_pool.url = "redis://localhost:6379"
- strategy = LimitingStrategy.FIXED_WINDOW
-
- with (
- patch("api.helpers._limiter.storage.RedisStorage") as MockStorage,
- patch("api.helpers._limiter.Redis") as MockRedis,
- patch("api.helpers._limiter.logger") as mock_logger,
- ):
- mock_storage_instance = AsyncMock(spec=RedisStorage)
- mock_storage_instance.reset.side_effect = RedisError("Test Error")
- MockStorage.return_value = mock_storage_instance
-
- mock_internal_redis = AsyncMock()
- MockRedis.return_value = mock_internal_redis
-
- limiter = Limiter(mock_redis_pool, strategy)
-
- await limiter.reset()
-
- mock_storage_instance.reset.assert_awaited_once()
- mock_logger.error.assert_called_once()
- logged_msg = mock_logger.error.call_args[1]["msg"]
- assert "Redis error during rate limit reset." in logged_msg
-
-
# =========================== HIT METHOD ============================
diff --git a/api/tests/unit/use_case/admin/users/test_updateuserusecase.py b/api/tests/unit/use_case/admin/users/test_updateuserusecase.py
new file mode 100644
index 000000000..25cb3277b
--- /dev/null
+++ b/api/tests/unit/use_case/admin/users/test_updateuserusecase.py
@@ -0,0 +1,204 @@
+from unittest.mock import AsyncMock, Mock
+
+from pydantic import SecretStr
+import pytest
+
+from api.domain.organization.errors import OrganizationNotFoundError
+from api.domain.role.errors import RoleNotFoundError
+from api.domain.user.errors import IncorrectCurrentPasswordError, UserAlreadyExistsError, UserNotFoundError
+from api.tests.unit.use_case.factories import UserFactory
+from api.use_cases.admin.users import UpdateUserCommand, UpdateUserUseCase, UpdateUserUseCaseSuccess
+
+
+@pytest.fixture
+def user_repository():
+ return AsyncMock()
+
+
+@pytest.fixture
+def user_password_encoder():
+ encoder = Mock()
+ encoder.encode_password.side_effect = lambda password: f"encoded-{password}"
+ encoder.validate_password.return_value = True
+ return encoder
+
+
+@pytest.fixture
+def use_case(user_repository, user_password_encoder):
+ return UpdateUserUseCase(user_repository=user_repository, user_password_encoder=user_password_encoder)
+
+
+@pytest.fixture
+def sample_user():
+ return UserFactory(id=42, organization_id=7, budget=100.0, expires=None, priority=1)
+
+
+class TestUpdateUserUseCase:
+ @pytest.mark.asyncio
+ async def test_should_return_updated_user_when_user_exists(self, use_case, user_repository, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.side_effect = lambda user: user
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, email="new@example.com", role_id=3))
+
+ # Assert
+ assert isinstance(result, UpdateUserUseCaseSuccess)
+ assert result.user.email == "new@example.com"
+ assert result.user.role == 3
+ user_repository.get_user_by_id.assert_called_once_with(user_id=sample_user.id)
+ user_repository.update_user.assert_called_once()
+
+ @pytest.mark.asyncio
+ async def test_should_keep_non_nullable_fields_and_clear_nullable_fields_when_fields_are_none(self, use_case, user_repository, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.side_effect = lambda user: user
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id))
+
+ # Assert
+ assert isinstance(result, UpdateUserUseCaseSuccess)
+ # Non-nullable columns keep their current value.
+ assert result.user.email == sample_user.email
+ assert result.user.role == sample_user.role
+ assert result.user.priority == sample_user.priority
+ assert result.user.password == sample_user.password
+ # Nullable columns are cleared.
+ assert result.user.name is None
+ assert result.user.organization_id is None
+ assert result.user.budget is None
+ assert result.user.expires is None
+
+ @pytest.mark.asyncio
+ async def test_should_keep_current_password_when_no_new_password(self, use_case, user_repository, user_password_encoder, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user.model_copy(update={"password": SecretStr("encoded-old")})
+ user_repository.update_user.side_effect = lambda user: user
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, current_password="old"))
+
+ # Assert
+ assert isinstance(result, UpdateUserUseCaseSuccess)
+ assert result.user.password == SecretStr("encoded-old")
+ user_password_encoder.encode_password.assert_not_called()
+
+ @pytest.mark.asyncio
+ async def test_should_encode_new_password_without_verification_when_no_current_password(
+ self, use_case, user_repository, user_password_encoder, sample_user
+ ):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.side_effect = lambda user: user
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, new_password="secret"))
+
+ # Assert
+ assert isinstance(result, UpdateUserUseCaseSuccess)
+ assert result.user.password == SecretStr("encoded-secret")
+ user_password_encoder.encode_password.assert_called_once_with(password="secret")
+ user_password_encoder.validate_password.assert_not_called()
+
+ @pytest.mark.asyncio
+ async def test_should_encode_new_password_when_current_password_is_correct(self, use_case, user_repository, user_password_encoder, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user.model_copy(update={"password": SecretStr("encoded-old")})
+ user_repository.update_user.side_effect = lambda user: user
+ user_password_encoder.validate_password.return_value = True
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, current_password="old", new_password="secret"))
+
+ # Assert
+ assert isinstance(result, UpdateUserUseCaseSuccess)
+ assert result.user.password == SecretStr("encoded-secret")
+ user_password_encoder.validate_password.assert_called_once_with(password="old", encoded_password="encoded-old")
+
+ @pytest.mark.asyncio
+ async def test_should_return_user_not_found_error_when_user_does_not_exist(self, use_case, user_repository):
+ # Arrange
+ user_repository.get_user_by_id.return_value = UserNotFoundError(id=99)
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=99, email="new@example.com"))
+
+ # Assert
+ assert isinstance(result, UserNotFoundError)
+ assert result.id == 99
+ user_repository.update_user.assert_not_called()
+
+ @pytest.mark.asyncio
+ async def test_should_return_incorrect_current_password_error_when_current_password_is_wrong(
+ self, use_case, user_repository, user_password_encoder, sample_user
+ ):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user.model_copy(update={"password": SecretStr("encoded-old")})
+ user_password_encoder.validate_password.return_value = False
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, current_password="wrong", new_password="secret"))
+
+ # Assert
+ assert isinstance(result, IncorrectCurrentPasswordError)
+ assert result.user_id == sample_user.id
+ user_repository.update_user.assert_not_called()
+
+ @pytest.mark.asyncio
+ async def test_should_return_incorrect_current_password_error_when_user_has_no_password(
+ self, use_case, user_repository, user_password_encoder, sample_user
+ ):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user.model_copy(update={"password": None})
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, current_password="old", new_password="secret"))
+
+ # Assert
+ assert isinstance(result, IncorrectCurrentPasswordError)
+ user_password_encoder.validate_password.assert_not_called()
+ user_repository.update_user.assert_not_called()
+
+ @pytest.mark.asyncio
+ async def test_should_return_role_not_found_error_when_repository_reports_unknown_role(self, use_case, user_repository, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.return_value = RoleNotFoundError(id=3)
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, role_id=3))
+
+ # Assert
+ assert isinstance(result, RoleNotFoundError)
+ assert result.id == 3
+
+ @pytest.mark.asyncio
+ async def test_should_return_organization_not_found_error_when_repository_reports_unknown_organization(
+ self, use_case, user_repository, sample_user
+ ):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.return_value = OrganizationNotFoundError(id=8)
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, organization_id=8))
+
+ # Assert
+ assert isinstance(result, OrganizationNotFoundError)
+ assert result.id == 8
+
+ @pytest.mark.asyncio
+ async def test_should_return_user_already_exists_error_when_email_is_taken(self, use_case, user_repository, sample_user):
+ # Arrange
+ user_repository.get_user_by_id.return_value = sample_user
+ user_repository.update_user.return_value = UserAlreadyExistsError(email="taken@example.com")
+
+ # Act
+ result = await use_case.execute(UpdateUserCommand(user_id=sample_user.id, email="taken@example.com"))
+
+ # Assert
+ assert isinstance(result, UserAlreadyExistsError)
+ assert result.email == "taken@example.com"
diff --git a/api/tests/unit/use_case/factories.py b/api/tests/unit/use_case/factories.py
index 7c017a8d8..f017a746d 100644
--- a/api/tests/unit/use_case/factories.py
+++ b/api/tests/unit/use_case/factories.py
@@ -104,6 +104,7 @@ class Meta:
id = factory.Sequence(lambda n: n + 1)
email = factory.Faker("email")
name = factory.Faker("name", locale="fr_FR")
+ password = None
sub = None
iss = None
role = factory.Faker("random_int", min=1, max=100)
diff --git a/api/use_cases/admin/keys/__init__.py b/api/use_cases/admin/keys/__init__.py
index f2dca387b..9b8549ed2 100644
--- a/api/use_cases/admin/keys/__init__.py
+++ b/api/use_cases/admin/keys/__init__.py
@@ -1,3 +1,15 @@
from ._createkeyusecase import CreateKeyCommand, CreateKeyUseCase, CreateKeyUseCaseSuccess
+from ._getkeysusecase import GetKeysCommand, GetKeysUseCase, GetKeysUseCaseSuccess
+from ._getonekeyusecase import GetOneKeyCommand, GetOneKeyUseCase, GetOneKeyUseCaseSuccess
-__all__ = ["CreateKeyCommand", "CreateKeyUseCase", "CreateKeyUseCaseSuccess"]
+__all__ = [
+ "CreateKeyCommand",
+ "CreateKeyUseCase",
+ "CreateKeyUseCaseSuccess",
+ "GetKeysCommand",
+ "GetKeysUseCase",
+ "GetKeysUseCaseSuccess",
+ "GetOneKeyCommand",
+ "GetOneKeyUseCase",
+ "GetOneKeyUseCaseSuccess",
+]
diff --git a/api/use_cases/admin/keys/_getkeysusecase.py b/api/use_cases/admin/keys/_getkeysusecase.py
new file mode 100644
index 000000000..38779a432
--- /dev/null
+++ b/api/use_cases/admin/keys/_getkeysusecase.py
@@ -0,0 +1,38 @@
+from dataclasses import dataclass
+
+from api.domain import SortField, SortOrder
+from api.domain.key import KeyRepository
+from api.domain.key.entities import KeyPage
+
+
+@dataclass
+class GetKeysCommand:
+ user_id: int | None
+ offset: int
+ limit: int
+ sort_by: SortField
+ sort_order: SortOrder
+
+
+@dataclass
+class GetKeysUseCaseSuccess:
+ key_page: KeyPage
+
+
+type GetKeysUseCaseResult = GetKeysUseCaseSuccess
+
+
+class GetKeysUseCase:
+ def __init__(self, key_repository: KeyRepository):
+ self.key_repository = key_repository
+
+ async def execute(self, command: GetKeysCommand) -> GetKeysUseCaseResult:
+ key_page = await self.key_repository.get_keys_page(
+ user_id=command.user_id,
+ limit=command.limit,
+ offset=command.offset,
+ sort_by=command.sort_by,
+ sort_order=command.sort_order,
+ )
+
+ return GetKeysUseCaseSuccess(key_page=key_page)
diff --git a/api/use_cases/admin/keys/_getonekeyusecase.py b/api/use_cases/admin/keys/_getonekeyusecase.py
new file mode 100644
index 000000000..fd04c95ad
--- /dev/null
+++ b/api/use_cases/admin/keys/_getonekeyusecase.py
@@ -0,0 +1,31 @@
+from dataclasses import dataclass
+
+from api.domain.key import KeyRepository
+from api.domain.key.entities import Key
+from api.domain.key.errors import KeyNotFoundError
+
+
+@dataclass
+class GetOneKeyCommand:
+ key_id: int
+
+
+@dataclass
+class GetOneKeyUseCaseSuccess:
+ key: Key
+
+
+type GetOneKeyUseCaseResult = GetOneKeyUseCaseSuccess | KeyNotFoundError
+
+
+class GetOneKeyUseCase:
+ def __init__(self, key_repository: KeyRepository):
+ self.key_repository = key_repository
+
+ async def execute(self, command: GetOneKeyCommand) -> GetOneKeyUseCaseResult:
+ result = await self.key_repository.get_key_by_id(command.key_id)
+
+ if isinstance(result, KeyNotFoundError):
+ return result
+
+ return GetOneKeyUseCaseSuccess(key=result)
diff --git a/api/use_cases/admin/users/__init__.py b/api/use_cases/admin/users/__init__.py
index 26b551619..bd5ac2b54 100644
--- a/api/use_cases/admin/users/__init__.py
+++ b/api/use_cases/admin/users/__init__.py
@@ -2,6 +2,7 @@
from ._deleteuserusecase import DeleteUserCommand, DeleteUserUseCase, DeleteUserUseCaseSuccess
from ._getoneuserusecase import GetOneUserCommand, GetOneUserUseCase, GetOneUserUseCaseSuccess
from ._getusersusecase import GetUsersCommand, GetUsersUseCase, GetUsersUseCaseSuccess
+from ._updateuserusecase import UpdateUserCommand, UpdateUserUseCase, UpdateUserUseCaseSuccess
__all__ = [
"CreateUserCommand",
@@ -16,4 +17,7 @@
"DeleteUserCommand",
"DeleteUserUseCase",
"DeleteUserUseCaseSuccess",
+ "UpdateUserCommand",
+ "UpdateUserUseCase",
+ "UpdateUserUseCaseSuccess",
]
diff --git a/api/use_cases/admin/users/_updateuserusecase.py b/api/use_cases/admin/users/_updateuserusecase.py
index e69de29bb..a9d85a6e9 100644
--- a/api/use_cases/admin/users/_updateuserusecase.py
+++ b/api/use_cases/admin/users/_updateuserusecase.py
@@ -0,0 +1,81 @@
+from dataclasses import dataclass
+
+from pydantic import SecretStr
+
+from api.domain.organization.errors import OrganizationNotFoundError
+from api.domain.role.errors import RoleNotFoundError
+from api.domain.user import UserPasswordEncoder, UserRepository
+from api.domain.user.entities import User
+from api.domain.user.errors import IncorrectCurrentPasswordError, UserAlreadyExistsError, UserNotFoundError
+
+
+@dataclass
+class UpdateUserCommand:
+ user_id: int
+ email: str | None = None
+ name: str | None = None
+ current_password: str | None = None
+ new_password: str | None = None
+ role_id: int | None = None
+ organization_id: int | None = None
+ budget: float | None = None
+ expires: int | None = None
+ priority: int | None = None
+
+
+@dataclass
+class UpdateUserUseCaseSuccess:
+ user: User
+
+
+type UpdateUserUseCaseResult = (
+ UpdateUserUseCaseSuccess
+ | UserNotFoundError
+ | UserAlreadyExistsError
+ | RoleNotFoundError
+ | OrganizationNotFoundError
+ | IncorrectCurrentPasswordError
+)
+
+
+class UpdateUserUseCase:
+ def __init__(self, user_repository: UserRepository, user_password_encoder: UserPasswordEncoder):
+ self.user_repository = user_repository
+ self.user_password_encoder = user_password_encoder
+
+ async def execute(self, command: UpdateUserCommand) -> UpdateUserUseCaseResult:
+ existing_user = await self.user_repository.get_user_by_id(user_id=command.user_id)
+ if isinstance(existing_user, UserNotFoundError):
+ return existing_user
+
+ if command.new_password is None:
+ password = existing_user.password
+ elif command.current_password is None:
+ password = SecretStr(self.user_password_encoder.encode_password(password=command.new_password))
+ elif existing_user.password is not None and self.user_password_encoder.validate_password(
+ password=command.current_password, encoded_password=existing_user.password.get_secret_value()
+ ):
+ password = SecretStr(self.user_password_encoder.encode_password(password=command.new_password))
+ else:
+ return IncorrectCurrentPasswordError(user_id=existing_user.id)
+
+ updated_user = existing_user.model_copy(
+ update={
+ "email": command.email if command.email is not None else existing_user.email,
+ "role": command.role_id if command.role_id is not None else existing_user.role,
+ "priority": command.priority if command.priority is not None else existing_user.priority,
+ "name": command.name,
+ "organization_id": command.organization_id,
+ "budget": command.budget,
+ "expires": command.expires,
+ "password": password,
+ }
+ )
+
+ result = await self.user_repository.update_user(user=updated_user)
+
+ match result:
+ case User() as user:
+ return UpdateUserUseCaseSuccess(user)
+ case error:
+ return error
diff --git a/api/utils/lifespan.py b/api/utils/lifespan.py
index b100e43db..8bee4ba9a 100755
--- a/api/utils/lifespan.py
+++ b/api/utils/lifespan.py
@@ -63,8 +63,6 @@ async def lifespan(_: FastAPI):
global_context.tokenizer = create_tokenizer(configuration=configuration)
global_context._tokenizer = initialize_tokenizer(configuration=configuration)
- await global_context.limiter.reset()
-
yield
if global_context.redis_pool:
diff --git a/cli.py b/cli.py
index d7151d538..9788b8c07 100644
--- a/cli.py
+++ b/cli.py
@@ -508,7 +508,6 @@ def main() -> None:
parser.add_argument("--make-help", action="store_true", default=False)
parser.add_argument("--quickstart", action="store_true", default=False)
parser.add_argument("--dev", action="store_true", default=False)
- parser.add_argument("--test-integ", action="store_true", default=False)
args = parser.parse_args()
console = Console()
@@ -541,16 +540,6 @@ def main() -> None:
if exit_code != 0:
raise SystemExit(exit_code)
- elif args.test_integ:
- display_header(console, tag="test")
- env, exit_code = setup(console, env_file=str(project_root / ".github/.env.ci"))
- if exit_code != 0:
- raise SystemExit(exit_code)
- exit_code = run_docker_compose(console, env=env, local_api=False, local_playground=False)
- if exit_code != 0:
- raise SystemExit(exit_code)
- raise SystemExit(0)
-
else: # error
display_header(console)
console.print("❌ Invalid command", style="bold red")
diff --git a/compose.example.yml b/compose.example.yml
index 0cc57f0a2..352579d09 100644
--- a/compose.example.yml
+++ b/compose.example.yml
@@ -2,9 +2,8 @@ name: opengatellm
services:
api:
- image: ghcr.io/etalab-ia/opengatellm/api:0.4.7
+ image: ghcr.io/etalab-ia/opengatellm/api:latest
restart: always
- env_file: .env
ports:
- "${API_PORT:-8000}:8000"
volumes:
@@ -22,7 +21,7 @@ services:
condition: service_healthy
playground:
- image: ghcr.io/etalab-ia/opengatellm/playground:0.4.7
+ image: ghcr.io/etalab-ia/opengatellm/playground:latest
environment:
- "OPENGATELLM_URL=${OPENGATELLM_URL:-http://api:8000}"
- "REDIS_HOST=redis"
diff --git a/config.example.yml b/config.example.yml
index a1b1a80a4..6b858b70b 100644
--- a/config.example.yml
+++ b/config.example.yml
@@ -17,7 +17,6 @@ dependencies:
health_check_interval: 30
decode_responses: False
socket_keepalive: True
-
# sentry:
# dsn: ${SENTRY_DSN}
@@ -37,7 +36,7 @@ settings:
# log_level: INFO
# log_format: [%(asctime)s][%(process)d:%(name)s][%(levelname)s] %(client_ip)s - %(message)s
- swagger_version: 0.4.7
+ swagger_version: 0.4.9
# swagger_contact_url: https://github.com/etalab-ia/OpenGateLLM
# swagger_contact_email: john.doe@example.com
# swagger_docs_url: /docs
@@ -53,7 +52,7 @@ settings:
# monitoring_postgres_enabled: True
# monitoring_prometheus_enabled: True
- playground_opengatellm_url: ${OPENGATELLM_URL}
+ playground_opengatellm_url: ${OPENGATELLM_URL:-http://api:8000}
# playground_opengatellm_timeout: 60
# playground_disabled_pages: []
# playground_default_model: my-model
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
index 8e7c35e6f..d820ba5ef 100644
--- a/docs/astro.config.mjs
+++ b/docs/astro.config.mjs
@@ -85,7 +85,7 @@ export default defineConfig({
}, {
label: '[lucide:rocket] Release notes',
link: 'https://github.com/etalab-ia/OpenGateLLM/releases',
- badge: 'v0.4.7',
+ badge: 'v0.4.9',
attrs: { target: '_blank', style: 'font-size: 0.875rem;' },
},
{
diff --git a/docs/openapi.json b/docs/openapi.json
index a238383fe..0bbcbfca7 100644
--- a/docs/openapi.json
+++ b/docs/openapi.json
@@ -1 +1 @@
-{"openapi":"3.1.0","info":{"title":"OpenGateLLM","summary":"OpenGateLLM connect to your models. You can configuration this swagger UI in the configuration file, like hide routes or change the title.","description":"[See documentation](https://github.com/etalab-ia/opengatellm/blob/main/README.md)","license":{"name":"MIT Licence","identifier":"MIT","url":"https://raw.githubusercontent.com/etalab-ia/opengatellm/refs/heads/main/LICENSE"},"version":"0.4.7"},"paths":{"/v1/admin/providers":{"post":{"tags":["Admin"],"summary":"Create Provider","operationId":"create_provider_v1_admin_providers_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderResponse"}}}},"403":{"description":"Inconsistent max context length for {model_name}. Expected: {expected_length}. Actual: {actual_length}
Inconsistent vector size for {model_name}. Expected: {expected_size}. Actual: {actual_size}
User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Invalid model provider type {input_type} for {expected_type} router.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"424":{"description":"Model provider {name} not reachable ({status_code}): {detail}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Model provider {model_name} for url {url} already exists for router {router_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Providers","operationId":"get_providers_v1_admin_providers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter providers by router ID.","title":"Router Id"},"description":"Filter providers by router ID."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of providers to skip.","default":0,"title":"Offset"},"description":"Number of providers to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of providers to return.","default":10,"title":"Limit"},"description":"Maximum number of providers to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ProviderSortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvidersResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/providers/{provider_id}":{"delete":{"tags":["Admin"],"summary":"Delete Provider","operationId":"delete_provider_v1_admin_providers__provider_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to delete.","title":"Provider Id"},"description":"The ID of the provider to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"404":{"description":"Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Provider","operationId":"update_provider_v1_admin_providers__provider_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to update.","title":"Provider Id"},"description":"The ID of the provider to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderBody","description":"The provider update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"403":{"description":"Inconsistent max context length for {model_name}. Expected: {expected_length}. Actual: {actual_length}
Inconsistent vector size for {model_name}. Expected: {expected_size}. Actual: {actual_size}
User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Invalid model provider type {input_type} for {expected_type} router.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Model provider {model_name} for url {url} already exists for router {router_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.
Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Provider","operationId":"get_provider_v1_admin_providers__provider_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to get.","title":"Provider Id"},"description":"The ID of the provider to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/roles":{"post":{"tags":["Admin"],"summary":"Create Role","operationId":"create_role_v1_admin_roles_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleBody","description":"The role creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Roles","operationId":"get_roles_v1_admin_roles_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of roles to skip.","default":0,"title":"Offset"},"description":"Number of roles to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of roles to return.","default":10,"title":"Limit"},"description":"Maximum number of roles to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolesResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/roles/{role_id}":{"patch":{"tags":["Admin"],"summary":"Update Role","operationId":"update_role_v1_admin_roles__role_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to update.","title":"Role Id"},"description":"The ID of the role to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleBody","description":"The role update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Role","operationId":"get_role_v1_admin_roles__role_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to get.","title":"Role Id"},"description":"The ID of the role to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete Role","operationId":"delete_role_v1_admin_roles__role_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to delete.","title":"Role Id"},"description":"The ID of the role to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_id} has {number_of_users} users and cannot be removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/routers":{"post":{"tags":["Admin"],"summary":"Create Router","operationId":"create_router_v1_admin_routers_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouterBody","description":"The router creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"409":{"description":"Following aliases already exist: '{router_aliases}'
Router {router_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Routers","operationId":"get_routers_v1_admin_routers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of routers to skip.","default":0,"title":"Offset"},"description":"Number of routers to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of routers to return.","default":10,"title":"Limit"},"description":"Maximum number of routers to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutersResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/routers/{router_id}":{"get":{"tags":["Admin"],"summary":"Get Router","operationId":"get_router_v1_admin_routers__router_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The router ID.","title":"Router Id"},"description":"The router ID."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete Router","operationId":"delete_router_v1_admin_routers__router_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the router to delete (router ID, eg. 123).","title":"Router Id"},"description":"The ID of the router to delete (router ID, eg. 123)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Router","operationId":"update_router_v1_admin_routers__router_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the router to update (router ID, eg. 123).","title":"Router Id"},"description":"The ID of the router to update (router ID, eg. 123)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouterBody","description":"The router update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Following aliases already exist: '{router_aliases}'
Router {router_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users":{"post":{"tags":["Admin"],"summary":"Create User","operationId":"create_user_v1_admin_users_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserBody","description":"The user creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"409":{"description":"User {email} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.
Organization {organization_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Users","operationId":"get_users_v1_admin_users_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The ID of the role to filter the users by.","title":"Role Id"},"description":"The ID of the role to filter the users by."},{"name":"organization_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The ID of the organization to filter the users by.","title":"Organization Id"},"description":"The ID of the organization to filter the users by."},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Email substring to filter the users by.","title":"Email"},"description":"Email substring to filter the users by."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of users to skip.","default":0,"title":"Offset"},"description":"Number of users to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of users to return.","default":10,"title":"Limit"},"description":"Maximum number of users to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/UserSortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersResponse"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user_id}":{"get":{"tags":["Admin"],"summary":"Get User","operationId":"get_user_v1_admin_users__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to get.","title":"User Id"},"description":"The ID of the user to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete User","operationId":"delete_user_v1_admin_users__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to delete.","title":"User Id"},"description":"The ID of the user to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"User cannot be deleted because the user owns routers: {router_ids}.
User cannot be deleted because the user owns providers: {provider_ids}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/audio/transcriptions":{"post":{"tags":["Audio"],"summary":"Audio Transcriptions","description":"Transcribes audio into the input language.","operationId":"audio_transcriptions_v1_audio_transcriptions_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_audio_transcriptions_v1_audio_transcriptions_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioTranscription"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/login":{"post":{"tags":["Auth"],"summary":"Login","description":"Receive encrypted token from playground encoded with shared key via POST body.\nThe token contains user id. Refresh and return playground api key associated with the user.","operationId":"login_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Login"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/chat/completions":{"post":{"tags":["Chat"],"summary":"Chat Completions","description":"Creates a model response for the given chat conversation.","operationId":"chat_completions_v1_chat_completions_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Required"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChatCompletion"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletion"},{"$ref":"#/components/schemas/ChatCompletionChunk"}],"title":"Response Chat Completions V1 Chat Completions Post"}}}},"404":{"description":"Model not found. Collection not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"422":{"description":"Wrong model type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}}}}},"/v1/chunks/{document}/{chunk}":{"get":{"tags":["Chunks"],"summary":"Get Chunk","description":"Get a chunk of a document.","operationId":"get_chunk_v1_chunks__document___chunk__get","deprecated":true,"security":[{"HTTPBearer":[]}],"parameters":[{"name":"document","in":"path","required":true,"schema":{"type":"integer","description":"The document ID","title":"Document"},"description":"The document ID"},{"name":"chunk","in":"path","required":true,"schema":{"type":"integer","description":"The chunk ID","title":"Chunk"},"description":"The chunk ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chunk"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/chunks/{document}":{"get":{"tags":["Chunks"],"summary":"Get Chunks","description":"Get chunks of a document.","operationId":"get_chunks_v1_chunks__document__get","deprecated":true,"security":[{"HTTPBearer":[]}],"parameters":[{"name":"document","in":"path","required":true,"schema":{"type":"integer","description":"The document ID","title":"Document"},"description":"The document ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The number of documents to return","default":10,"title":"Limit"},"description":"The number of documents to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","description":"The offset of the first document to return","default":0,"title":"Offset"},"description":"The offset of the first document to return"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chunks"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/collections":{"post":{"tags":["Collections"],"summary":"Create Collection","description":"Create a new collection.","operationId":"create_collection_v1_collections_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Collections"],"summary":"Get Collections","description":"Get list of collections.","operationId":"get_collections_v1_collections_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Filter by collection name.","title":"Name"},"description":"Filter by collection name."},{"name":"visibility","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/CollectionVisibility"},{"type":"null"}],"description":"Filter by collection visibility.","title":"Visibility"},"description":"Filter by collection visibility."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the collections to get.","default":0,"title":"Offset"},"description":"The offset of the collections to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the collections to get.","default":10,"title":"Limit"},"description":"The limit of the collections to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created","updated"],"type":"string","description":"The order by field to sort the collections by.","default":"id","title":"Order By"},"description":"The order by field to sort the collections by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the collections by.","default":"asc","title":"Order Direction"},"description":"The direction to order the collections by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collections"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/collections/{collection_id}":{"get":{"tags":["Collections"],"summary":"Get Collection","description":"Get a collection by ID.","operationId":"get_collection_v1_collections__collection_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"integer","description":"The collection ID","title":"Collection Id"},"description":"The collection ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Collections"],"summary":"Delete Collection","description":"Delete a collection.","operationId":"delete_collection_v1_collections__collection_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"integer","description":"The collection ID","title":"Collection Id"},"description":"The collection ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Collections"],"summary":"Update Collection","description":"Update a collection.","operationId":"update_collection_v1_collections__collection_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"integer","description":"The collection ID","title":"Collection Id"},"description":"The collection ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateRequest","description":"The collection to update."}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents":{"post":{"tags":["Documents"],"summary":"Create Document","description":"Upload a file, parse and split it into chunks, then create a document. If no file is provided, the document will be created without content, use POST `/v1/documents/{document_id}/chunks` to fill it.","operationId":"create_document_v1_documents_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_document_v1_documents_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Documents"],"summary":"Get Documents","description":"Get all documents ID from a collection.","operationId":"get_documents_v1_documents_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter documents by name","title":"Name"},"description":"Filter documents by name"},{"name":"collection_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","exclusiveMinimum":0},{"type":"null"}],"description":"Filter documents by collection ID","title":"Collection Id"},"description":"Filter documents by collection ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The number of documents to return","default":10,"title":"Limit"},"description":"The number of documents to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","description":"The offset of the first document to return","default":0,"title":"Offset"},"description":"The offset of the first document to return"},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created"],"type":"string","description":"The order by field to sort the documents by.","default":"id","title":"Order By"},"description":"The order by field to sort the documents by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the documents by.","default":"asc","title":"Order Direction"},"description":"The direction to order the documents by."},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}":{"get":{"tags":["Documents"],"summary":"Get Document","description":"Get a document by ID.","operationId":"get_document_v1_documents__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Documents"],"summary":"Delete Document","description":"Delete a document.","operationId":"delete_document_v1_documents__document_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","exclusiveMinimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}/chunks":{"post":{"tags":["Documents"],"summary":"Create Document Chunks","description":"Fill document with chunks.","operationId":"create_document_chunks_v1_documents__document_id__chunks_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","exclusiveMinimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChunks"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Documents"],"summary":"Get Document Chunks","description":"Get chunks of a document.","operationId":"get_document_chunks_v1_documents__document_id__chunks_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","exclusiveMinimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The number of chunks to return","default":10,"title":"Limit"},"description":"The number of chunks to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","description":"The offset of the first chunk to return","default":0,"title":"Offset"},"description":"The offset of the first chunk to return"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}/chunks/{chunk_id}":{"delete":{"tags":["Documents"],"summary":"Delete Document Chunk","description":"Delete a chunk of a document.","operationId":"delete_document_chunk_v1_documents__document_id__chunks__chunk_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","exclusiveMinimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"chunk_id","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The chunk ID","title":"Chunk Id"},"description":"The chunk ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Documents"],"summary":"Get Document Chunk","description":"Get a chunk of a document.","operationId":"get_document_chunk_v1_documents__document_id__chunks__chunk_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"integer","exclusiveMinimum":0,"description":"The document ID","title":"Document Id"},"description":"The document ID"},{"name":"chunk_id","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The chunk ID","title":"Chunk Id"},"description":"The chunk ID"},{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embeddings":{"post":{"tags":["Embeddings"],"summary":"Embeddings","description":"Creates an embedding vector representing the input text.","operationId":"embeddings_v1_embeddings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Embeddings"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/health":{"get":{"tags":["Health"],"summary":"Get Health","description":"Get the health of the API.","operationId":"get_health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health/models":{"get":{"tags":["Health"],"summary":"Get Health Models","description":"Get the health of the models.","operationId":"get_health_models_health_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/me/info":{"get":{"tags":["Me"],"summary":"Get User","description":"Get information about the current user.","operationId":"get_user_v1_me_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["Me"],"summary":"Update User","description":"Update information about the current user.","operationId":"update_user_v1_me_info_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserInfo","description":"The user update request."}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/me/keys":{"post":{"tags":["Me"],"summary":"Create Key","description":"Create a new API key.","operationId":"create_key_v1_me_keys_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKey","description":"The token creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Me"],"summary":"Get Keys","description":"Get all your tokens.","operationId":"get_keys_v1_me_keys_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the tokens to get.","default":0,"title":"Offset"},"description":"The offset of the tokens to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the tokens to get.","default":10,"title":"Limit"},"description":"The limit of the tokens to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created"],"type":"string","description":"The field to order the tokens by.","default":"id","title":"Order By"},"description":"The field to order the tokens by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the tokens by.","default":"asc","title":"Order Direction"},"description":"The direction to order the tokens by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Keys"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me/keys/{key}":{"delete":{"tags":["Me"],"summary":"Delete Key","description":"Delete a API key.","operationId":"delete_key_v1_me_keys__key__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"integer","description":"The key ID of the key to delete.","title":"Key"},"description":"The key ID of the key to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Me"],"summary":"Get Key","description":"Get your token by id.","operationId":"get_key_v1_me_keys__key__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"integer","description":"The key ID of the key to get.","title":"Key"},"description":"The key ID of the key to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me/usage":{"get":{"tags":["Me"],"summary":"Get Usage","description":"Get usage for the current user.","operationId":"get_usage_v1_me_usage_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the usages to get.","default":0,"title":"Offset"},"description":"The offset of the usages to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the usages to get.","default":10,"title":"Limit"},"description":"The limit of the usages to get."},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Start time as Unix timestamp (if not provided, will be set to 30 days ago)","title":"Start Time"},"description":"Start time as Unix timestamp (if not provided, will be set to 30 days ago)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"End time as Unix timestamp (if not provided, will be set to now)","title":"End Time"},"description":"End time as Unix timestamp (if not provided, will be set to now)"},{"name":"endpoint","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/EndpointUsage"},{"type":"null"}],"description":"The endpoint to get usage for.","title":"Endpoint"},"description":"The endpoint to get usage for."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usages"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["Models"],"summary":"Get Models","description":"Lists the currently available models and provides basic information.","operationId":"get_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelsResponse"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/models/{model}":{"get":{"tags":["Models"],"summary":"Get Model","description":"Get a model by name and provide basic information.","operationId":"get_model_v1_models__model__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"model","in":"path","required":true,"schema":{"type":"string","description":"The name of the model to get.","title":"Model"},"description":"The name of the model to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"404":{"description":"Model {name} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ocr":{"post":{"tags":["OCR"],"summary":"Ocr","description":"Extracts text from files using OCR.","operationId":"ocr_v1_ocr_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOCR"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OCR"}}}},"404":{"description":"Model not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"422":{"description":"Wrong model type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/parse-beta":{"post":{"tags":["Parse"],"summary":"Parse","description":"Parse a PDF file into Markdown.","operationId":"parse_v1_parse_beta_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parse_v1_parse_beta_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParsedDocument"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"deprecated":true,"security":[{"HTTPBearer":[]}]}},"/v1/rerank":{"post":{"tags":["Rerank"],"summary":"Create Rerank","operationId":"create_rerank_v1_rerank_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRerankBody","description":"The rerank creation request."}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RerankResponse"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model {name} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"429":{"description":"Token/request limit per minute/day exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Model has wrong type. Expected: {expected_type}. Actual: {actual_type}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/search":{"post":{"tags":["Search"],"summary":"Search","description":"Get relevant chunks from the collections and a query.","operationId":"search_v1_search_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"required","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Required"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSearch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Searches"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/organizations":{"post":{"tags":["Admin"],"summary":"Create Organization","operationId":"create_organization_v1_admin_organizations_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationRequest","description":"The organization creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Organizations","operationId":"get_organizations_v1_admin_organizations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the organizations to get.","default":0,"title":"Offset"},"description":"The offset of the organizations to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the organizations to get.","default":10,"title":"Limit"},"description":"The limit of the organizations to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created","updated"],"type":"string","description":"The field to order the organizations by.","default":"id","title":"Order By"},"description":"The field to order the organizations by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the organizations by.","default":"asc","title":"Order Direction"},"description":"The direction to order the organizations by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organizations"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/organizations/{organization}":{"delete":{"tags":["Admin"],"summary":"Delete Organization","operationId":"delete_organization_v1_admin_organizations__organization__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to delete.","title":"Organization"},"description":"The ID of the organization to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Organization","operationId":"update_organization_v1_admin_organizations__organization__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to update.","title":"Organization"},"description":"The ID of the organization to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUpdateRequest","description":"The organization update request."}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Organization","operationId":"get_organization_v1_admin_organizations__organization__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to get.","title":"Organization"},"description":"The ID of the organization to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tokens":{"post":{"tags":["Admin"],"summary":"Create Token","description":"Create a new token.","operationId":"create_token_v1_admin_tokens_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToken","description":"The token creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Tokens","description":"Get all your tokens.","operationId":"get_tokens_v1_admin_tokens_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The user ID of the user to get the tokens for.","title":"User"},"description":"The user ID of the user to get the tokens for."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the tokens to get.","default":0,"title":"Offset"},"description":"The offset of the tokens to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the tokens to get.","default":10,"title":"Limit"},"description":"The limit of the tokens to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created"],"type":"string","description":"The field to order the tokens by.","default":"id","title":"Order By"},"description":"The field to order the tokens by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the tokens by.","default":"asc","title":"Order Direction"},"description":"The direction to order the tokens by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tokens"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tokens/{token}":{"delete":{"tags":["Admin"],"summary":"Delete Token","description":"Delete a token.","operationId":"delete_token_v1_admin_tokens__token__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"integer","description":"The user ID of the user to delete the token for.","title":"User"},"description":"The user ID of the user to delete the token for."},{"name":"token","in":"path","required":true,"schema":{"type":"integer","description":"The token ID of the token to delete.","title":"Token"},"description":"The token ID of the token to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Token","description":"Get your token by id.","operationId":"get_token_v1_admin_tokens__token__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"integer","description":"The token ID of the token to get.","title":"Token"},"description":"The token ID of the token to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user}":{"patch":{"tags":["Admin"],"summary":"Update User","description":"Update a user.","operationId":"update_user_v1_admin_users__user__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to update.","title":"User"},"description":"The ID of the user to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateRequest","description":"The user update request."}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/metrics":{"get":{"tags":["Monitoring"],"summary":"Get Metrics","operationId":"get_metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"Annotation":{"properties":{"type":{"type":"string","const":"url_citation","title":"Type"},"url_citation":{"$ref":"#/components/schemas/AnnotationURLCitation"}},"additionalProperties":true,"type":"object","required":["type","url_citation"],"title":"Annotation","description":"A URL citation when using web search."},"AnnotationURLCitation":{"properties":{"end_index":{"type":"integer","title":"End Index"},"start_index":{"type":"integer","title":"Start Index"},"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"}},"additionalProperties":true,"type":"object","required":["end_index","start_index","title","url"],"title":"AnnotationURLCitation","description":"A URL citation when using web search."},"AudioTranscription":{"properties":{"id":{"type":"string","title":"Id","description":"A unique identifier for the audio transcription."},"text":{"type":"string","title":"Text","description":"The transcription text."},"model":{"type":"string","title":"Model","description":"The model used to generate the transcription."},"segments":{"anyOf":[{"items":{"$ref":"#/components/schemas/Segment"},"type":"array"},{"type":"null"}],"title":"Segments","description":"Diarized segments, only set when `response_format=diarized_json`."},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["id","text","model"],"title":"AudioTranscription"},"AudioTranscriptionLanguage":{"type":"string","enum":["af","afrikaans","albanian","am","amharic","ar","arabic","armenian","as","assamese","az","azerbaijani","ba","bashkir","basque","be","belarusian","bengali","bg","bn","bo","bosnian","br","breton","bs","bulgarian","burmese","ca","cantonese","castilian","catalan","chinese","croatian","cs","cy","czech","da","danish","de","dutch","el","en","english","es","estonian","et","eu","fa","faroese","fi","finnish","flemish","fo","fr","french","galician","georgian","german","gl","greek","gu","gujarati","ha","haitian","haitian creole","hausa","haw","hawaiian","he","hebrew","hi","hindi","hr","ht","hu","hungarian","hy","icelandic","id","indonesian","is","it","italian","ja","japanese","javanese","jw","ka","kannada","kazakh","khmer","kk","km","kn","ko","korean","la","lao","latin","latvian","lb","letzeburgesch","lingala","lithuanian","ln","lo","lt","luxembourgish","lv","macedonian","malagasy","malay","malayalam","maltese","mandarin","maori","marathi","mg","mi","mk","ml","mn","moldavian","moldovan","mongolian","mr","ms","mt","my","myanmar","ne","nepali","nl","nn","no","norwegian","nynorsk","oc","occitan","pa","panjabi","pashto","persian","pl","polish","portuguese","ps","pt","punjabi","pushto","ro","romanian","ru","russian","sa","sanskrit","sd","serbian","shona","si","sindhi","sinhala","sinhalese","sk","sl","slovak","slovenian","sn","so","somali","spanish","sq","sr","su","sundanese","sv","sw","swahili","swedish","ta","tagalog","tajik","tamil","tatar","te","telugu","tg","th","thai","tibetan","tk","tl","tr","tt","turkish","turkmen","uk","ukrainian","ur","urdu","uz","uzbek","valencian","vi","vietnamese","welsh","yi","yiddish","yo","yoruba","yue","zh"],"title":"AudioTranscriptionLanguage"},"AudioTranscriptionResponseFormat":{"type":"string","enum":["json","text","verbose_json","diarized_json","srt","vtt"],"title":"AudioTranscriptionResponseFormat"},"BasicAuth":{"properties":{"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"}},"additionalProperties":true,"type":"object","required":["username","password"],"title":"BasicAuth"},"Body_audio_transcriptions_v1_audio_transcriptions_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The audio file object (not file name) to transcribe, in one of these formats: mp3 or wav."},"model":{"type":"string","title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `automatic-speech-recognition` model type is supported."},"language":{"anyOf":[{"$ref":"#/components/schemas/AudioTranscriptionLanguage"},{"type":"null"}],"description":"The language of the output audio. If the output language is different than the audio language, the audio language will be translated into the output language. Output language must be supplied in ISO-639-1 format (e.g. en, fr) format."},"prompt":{"type":"string","title":"Prompt","description":"An optional text to tell the model what to do with the input audio.","default":""},"response_format":{"$ref":"#/components/schemas/AudioTranscriptionResponseFormat","description":"The format of the transcript output: `json` (default), `text`, `diarized_json` to return per-segment speaker labels, `srt` or `vtt` for subtitle formats.","default":"json"},"temperature":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Temperature","description":"The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.","default":0.0}},"type":"object","required":["file","model"],"title":"Body_audio_transcriptions_v1_audio_transcriptions_post"},"Body_create_document_v1_documents_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File","description":"The file to create a document from. If not provided, the document will be created without content, use POST `/v1/documents/{document_id}/chunks` to fill it."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Name of document if no file is provided or to override file name."},"collection_id":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Collection Id","description":"The collection ID to use for the file upload. The file will be vectorized with model defined by the collection."},"collection":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Collection","deprecated":true},"disable_chunking":{"type":"boolean","title":"Disable Chunking","description":"Whether to disable `RecursiveCharacterTextSplitter` chunking for the upload file.","default":false},"chunk_size":{"type":"integer","minimum":0.0,"title":"Chunk Size","description":"The size in characters of the chunks to use for the upload file. If not provided, the document will not be split into chunks.","default":2048},"chunk_min_size":{"type":"integer","minimum":0.0,"title":"Chunk Min Size","description":"The minimum size in characters of the chunks to use for the upload file.","default":0},"chunk_overlap":{"type":"integer","minimum":0.0,"title":"Chunk Overlap","description":"The overlap in characters of the chunks to use for the upload file.","default":0},"is_separator_regex":{"type":"boolean","title":"Is Separator Regex","description":"Whether the separator is a regex to use for the upload file.","default":false},"separators":{"items":{"type":"string"},"type":"array","minItems":0,"title":"Separators","description":"Delimiters used by RecursiveCharacterTextSplitter for further splitting. If provided, `preset_separators` is ignored.","default":[]},"preset_separators":{"$ref":"#/components/schemas/PresetSeparators","description":"Preset separators used by RecursiveCharacterTextSplitter for further splitting. See [implemented details](https://github.com/langchain-ai/langchain/blob/eb122945832eae9b9df7c70ccd8d51fcd7a1899b/libs/text-splitters/langchain_text_splitters/character.py#L164).","default":"markdown"},"metadata":{"type":"string","title":"Metadata","description":"Optional additional metadata to add to each chunk if a file is provided. Provide a stringified JSON object matching the Metadata schema.","default":"","examples":["{\"source_date\": \"2026-01-05\", \"source_tags\": [\"tag1\", \"tag2\"]}"]}},"type":"object","title":"Body_create_document_v1_documents_post"},"Body_parse_v1_parse_beta_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The file to parse."},"page_range":{"type":"string","title":"Page Range","description":"Page range to convert, specify comma separated page numbers or ranges. Example: '0,5-10,20'","default":""},"force_ocr":{"type":"boolean","title":"Force Ocr","description":"Force OCR on all pages of the PDF. Defaults to False. This can lead to worse results if you have good text in your PDFs (which is true in most cases).","default":false}},"type":"object","required":["file"],"title":"Body_parse_v1_parse_beta_post"},"CarbonFootprintUsage":{"properties":{"kWh":{"$ref":"#/components/schemas/CarbonFootprintUsageKWh","deprecated":true},"kgCO2eq":{"$ref":"#/components/schemas/CarbonFootprintUsageKgCO2eq","deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsage"},"CarbonFootprintUsageKWh":{"properties":{"min":{"type":"number","title":"Min","description":"Minimum carbon footprint in kWh.","default":0.0,"deprecated":true},"max":{"type":"number","title":"Max","description":"Maximum carbon footprint in kWh.","default":0.0,"deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsageKWh"},"CarbonFootprintUsageKgCO2eq":{"properties":{"min":{"type":"number","title":"Min","description":"Minimum carbon footprint in kgCO2eq (global warming potential).","default":0.0,"deprecated":true},"max":{"type":"number","title":"Max","description":"Maximum carbon footprint in kgCO2eq (global warming potential).","default":0.0,"deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsageKgCO2eq"},"ChatCompletion":{"properties":{"id":{"type":"string","title":"Id","description":"A unique identifier for the chat completion."},"choices":{"items":{"$ref":"#/components/schemas/openai__types__chat__chat_completion__Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."},"search_results":{"items":{"$ref":"#/components/schemas/Search"},"type":"array","title":"Search Results","default":[]}},"additionalProperties":true,"type":"object","required":["choices","created","model","object"],"title":"ChatCompletion"},"ChatCompletionAudio":{"properties":{"id":{"type":"string","title":"Id"},"data":{"type":"string","title":"Data"},"expires_at":{"type":"integer","title":"Expires At"},"transcript":{"type":"string","title":"Transcript"}},"additionalProperties":true,"type":"object","required":["id","data","expires_at","transcript"],"title":"ChatCompletionAudio","description":"If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio)."},"ChatCompletionChunk":{"properties":{"id":{"type":"string","title":"Id"},"choices":{"items":{"$ref":"#/components/schemas/openai__types__chat__chat_completion_chunk__Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion.chunk","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"anyOf":[{"$ref":"#/components/schemas/CompletionUsage"},{"type":"null"}]},"search_results":{"items":{"$ref":"#/components/schemas/Search"},"type":"array","title":"Search Results","default":[]}},"additionalProperties":true,"type":"object","required":["id","choices","created","model","object"],"title":"ChatCompletionChunk"},"ChatCompletionMessage":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"type":"string","const":"assistant","title":"Role"},"annotations":{"anyOf":[{"items":{"$ref":"#/components/schemas/Annotation"},"type":"array"},{"type":"null"}],"title":"Annotations"},"audio":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionAudio"},{"type":"null"}]},"function_call":{"anyOf":[{"$ref":"#/components/schemas/FunctionCall"},{"type":"null"}]},"tool_calls":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionMessageFunctionToolCall"},{"$ref":"#/components/schemas/ChatCompletionMessageCustomToolCall"}]},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","required":["role"],"title":"ChatCompletionMessage","description":"A chat completion message generated by the model."},"ChatCompletionMessageCustomToolCall":{"properties":{"id":{"type":"string","title":"Id"},"custom":{"$ref":"#/components/schemas/Custom"},"type":{"type":"string","const":"custom","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","custom","type"],"title":"ChatCompletionMessageCustomToolCall","description":"A call to a custom tool created by the model."},"ChatCompletionMessageFunctionToolCall":{"properties":{"id":{"type":"string","title":"Id"},"function":{"$ref":"#/components/schemas/Function"},"type":{"type":"string","const":"function","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","function","type"],"title":"ChatCompletionMessageFunctionToolCall","description":"A call to a function tool created by the model."},"ChatCompletionTokenLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"},"top_logprobs":{"items":{"$ref":"#/components/schemas/TopLogprob"},"type":"array","title":"Top Logprobs"}},"additionalProperties":true,"type":"object","required":["token","logprob","top_logprobs"],"title":"ChatCompletionTokenLogprob"},"ChoiceDelta":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"function_call":{"anyOf":[{"$ref":"#/components/schemas/ChoiceDeltaFunctionCall"},{"type":"null"}]},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"anyOf":[{"type":"string","enum":["developer","system","user","assistant","tool"]},{"type":"null"}],"title":"Role"},"tool_calls":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChoiceDeltaToolCall"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","title":"ChoiceDelta","description":"A chat completion delta generated by streamed model responses."},"ChoiceDeltaFunctionCall":{"properties":{"arguments":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arguments"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"additionalProperties":true,"type":"object","title":"ChoiceDeltaFunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"ChoiceDeltaToolCall":{"properties":{"index":{"type":"integer","title":"Index"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"function":{"anyOf":[{"$ref":"#/components/schemas/ChoiceDeltaToolCallFunction"},{"type":"null"}]},"type":{"anyOf":[{"type":"string","const":"function"},{"type":"null"}],"title":"Type"}},"additionalProperties":true,"type":"object","required":["index"],"title":"ChoiceDeltaToolCall"},"ChoiceDeltaToolCallFunction":{"properties":{"arguments":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arguments"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"additionalProperties":true,"type":"object","title":"ChoiceDeltaToolCallFunction"},"ChoiceLogprobs":{"properties":{"content":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Refusal"}},"additionalProperties":true,"type":"object","title":"ChoiceLogprobs","description":"Log probability information for the choice."},"Chunk":{"properties":{"object":{"type":"string","const":"chunk","title":"Object","description":"The type of the object.","default":"chunk"},"id":{"type":"integer","minimum":0.0,"title":"Id","description":"The ID of the chunk."},"collection_id":{"type":"integer","minimum":0.0,"title":"Collection Id","description":"The ID of the collection the chunk belongs to."},"document_id":{"type":"integer","minimum":0.0,"title":"Document Id","description":"The ID of the document the chunk belongs to."},"content":{"type":"string","minLength":1,"title":"Content","description":"The content of the chunk."},"metadata":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"integer","maximum":1e+16,"minimum":-1e+16},{"type":"number","maximum":1e+16,"minimum":-1e+16},{"type":"boolean"}]},"propertyNames":{"maxLength":255,"minLength":1},"type":"object","maxProperties":10,"minProperties":1,"description":"Extra metadata for the source"},{"type":"null"}],"title":"Metadata","description":"Metadata of the chunk"},"created":{"type":"integer","title":"Created","description":"The date of the chunk creation."}},"additionalProperties":true,"type":"object","required":["id","collection_id","document_id","content"],"title":"Chunk"},"Chunks":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"The type of the object.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Chunk"},"type":"array","title":"Data","description":"The list of chunks."}},"additionalProperties":true,"type":"object","required":["data"],"title":"Chunks"},"Collection":{"properties":{"object":{"type":"string","const":"collection","title":"Object","default":"collection"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"owner":{"type":"string","title":"Owner"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"visibility":{"anyOf":[{"$ref":"#/components/schemas/CollectionVisibility"},{"type":"null"}]},"created":{"type":"integer","title":"Created"},"updated":{"type":"integer","title":"Updated"},"documents":{"type":"integer","title":"Documents","default":0},"size":{"type":"integer","title":"Size","default":0}},"additionalProperties":true,"type":"object","required":["id","name","owner","created","updated"],"title":"Collection"},"CollectionRequest":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"The name of the collection."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"The description of the collection."},"visibility":{"$ref":"#/components/schemas/CollectionVisibility","description":"The type of the collection. Public collections are available to all users, private collections are only available to the user who created them.","default":"private"}},"additionalProperties":true,"type":"object","required":["name"],"title":"CollectionRequest"},"CollectionUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The name of the collection."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"The description of the collection."},"visibility":{"anyOf":[{"$ref":"#/components/schemas/CollectionVisibility"},{"type":"null"}],"description":"The type of the collection. Public collections are available to all users, private collections are only available to the user who created them."}},"additionalProperties":true,"type":"object","title":"CollectionUpdateRequest"},"CollectionVisibility":{"type":"string","enum":["private","public"],"title":"CollectionVisibility"},"Collections":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Collection"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Collections"},"ComparisonFilter":{"properties":{"key":{"type":"string","maxLength":255,"minLength":1,"title":"Key"},"type":{"$ref":"#/components/schemas/ComparisonFilterType"},"value":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"integer","maximum":1e+16,"minimum":-1e+16},{"type":"number","maximum":1e+16,"minimum":-1e+16},{"type":"boolean"}],"title":"Value"}},"additionalProperties":true,"type":"object","required":["key","type","value"],"title":"ComparisonFilter"},"ComparisonFilterType":{"type":"string","enum":["eq","sw","ew","co"],"title":"ComparisonFilterType","description":"Comparison filter type for metadata filters.","x-enumDescriptions":{"co":"Contains the value provided.","eq":"Equal to the value provided.","ew":"Ends with the value provided.","sw":"Starts with the value provided."}},"CompletionTokensDetails":{"properties":{"accepted_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accepted Prediction Tokens"},"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"rejected_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rejected Prediction Tokens"}},"additionalProperties":true,"type":"object","title":"CompletionTokensDetails","description":"Breakdown of tokens used in a completion."},"CompletionUsage":{"properties":{"completion_tokens":{"type":"integer","title":"Completion Tokens"},"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"completion_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/CompletionTokensDetails"},{"type":"null"}]},"prompt_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/PromptTokensDetails"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["completion_tokens","prompt_tokens","total_tokens"],"title":"CompletionUsage","description":"Usage statistics for the completion request."},"CompoundFilter":{"properties":{"filters":{"items":{"$ref":"#/components/schemas/ComparisonFilter"},"type":"array","maxItems":4,"minItems":2,"title":"Filters","description":"List of filters to apply to the search."},"operator":{"$ref":"#/components/schemas/CompoundFilterOperator","description":"Operator to use for the compound filter."}},"additionalProperties":true,"type":"object","required":["filters","operator"],"title":"CompoundFilter"},"CompoundFilterOperator":{"type":"string","enum":["and","or"],"title":"CompoundFilterOperator","description":"Compound filter operator for metadata filters.","x-enumDescriptions":{"and":"AND operator","or":"OR operator"}},"CreateChatCompletion":{"properties":{"messages":{"items":{},"type":"array","title":"Messages","description":"A list of messages comprising the conversation so far."},"model":{"type":"string","title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `text-generation` model type is supported."},"frequency_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Frequency Penalty","description":"Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.","default":0.0},"logit_bias":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Logit Bias","description":"Modify the likelihood of specified tokens appearing in the completion. Accepts a JSON object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token."},"logprobs":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Logprobs","description":"Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the `content` of `message`.","default":false},"top_logprobs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top Logprobs","description":"An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. `logprobs` must be set to `true` if this parameter is used."},"presence_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Presence Penalty","description":"Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.","default":0.0},"max_completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Completion Tokens","description":"An upper bound for the number of tokens that can be generated for a completion."},"n":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N","description":"How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs.","default":1},"response_format":{"anyOf":[{},{"type":"null"}],"title":"Response Format","description":"Setting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more in the Structured Outputs guide. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which ensures the message the model generates is valid JSON.
**Important**: when using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message. Without this, the model may generate an unending stream of whitespace until the generation reaches the token limit, resulting in a long-running and seemingly \"stuck\" request. Also note that the message content may be partially cut off if `finish_reason=\"length\"`, which indicates the generation exceeded `max_tokens` or the conversation exceeded the max context length."},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend."},"stop":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stop","description":"Up to 4 sequences where the API will stop generating further tokens."},"stream":{"anyOf":[{"type":"boolean","enum":[true,false]},{"type":"null"}],"title":"Stream","description":"If set, partial message deltas will be sent. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.","default":false},"stream_options":{"anyOf":[{},{"type":"null"}],"title":"Stream Options","description":"Options for streaming response. Only set this when you set `stream: true`."},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature","description":"What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both."},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P","description":"An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
We generally recommend altering this or `temperature` but not both."},"tools":{"anyOf":[{"anyOf":[{"items":{"anyOf":[{"additionalProperties":true,"type":"object"},{"$ref":"#/components/schemas/SearchTool"}]},"type":"array"},{"type":"null"}],"description":"A list of tools the model may call. Currently, only functions are supported as a tool. Support function calling and build-in tools (currently only SearchTool). Use this to provide a list of functions the model may generate JSON inputs for."},{"type":"null"}],"title":"Tools"},"tool_choice":{"title":"Tool Choice","description":"Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools. Specifying a particular tool via `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.
`none` is the default when no tools are present. `auto` is the default if tools are present.","default":"none"},"parallel_tool_calls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Parallel Tool Calls","description":"Whether to call tools in parallel or sequentially. If true, the model will call tools in parallel. If false, the model will call tools sequentially. If None, the model will call tools in parallel if the model supports it, otherwise it will call tools sequentially.","default":false},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User","description":"A unique identifier representing the user."},"search":{"type":"boolean","title":"Search","default":false,"deprecated":true},"search_args":{"anyOf":[{"$ref":"#/components/schemas/SearchArgs"},{"type":"null"}],"deprecated":true}},"additionalProperties":true,"type":"object","required":["messages","model"],"title":"CreateChatCompletion"},"CreateChunks":{"properties":{"chunks":{"items":{"$ref":"#/components/schemas/InputChunk"},"type":"array","maxItems":64,"minItems":1,"title":"Chunks","description":"The list of chunks to create."}},"additionalProperties":true,"type":"object","required":["chunks"],"title":"CreateChunks"},"CreateKey":{"properties":{"name":{"type":"string","title":"Name"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["name"],"title":"CreateKey"},"CreateKeyResponse":{"properties":{"id":{"type":"integer","title":"Id"},"token":{"type":"string","title":"Token"}},"additionalProperties":true,"type":"object","required":["id","token"],"title":"CreateKeyResponse"},"CreateOCR":{"properties":{"bbox_annotation_format":{"anyOf":[{"$ref":"#/components/schemas/ResponseFormat"},{"type":"null"}],"description":"Specify the format that the model must output for the bounding boxes. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide."},"document":{"anyOf":[{"$ref":"#/components/schemas/DocumentURLChunk"},{"$ref":"#/components/schemas/ImageURLChunk"}],"title":"Document","description":"Document to run OCR on."},"document_annotation_format":{"anyOf":[{"$ref":"#/components/schemas/ResponseFormat"},{"type":"null"}],"description":"Specify the format that the model must output for the document. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide."},"image_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Limit","description":"Max images to extract"},"image_min_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Min Size","description":"Minimum height and width of image to extract"},"include_image_base64":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Image Base64","description":"Include image URLs in response"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"The model to use for the OCR."},"pages":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Pages","description":"Specific pages user wants to process in various formats: single number, range, or list of both. Starts from 0"}},"additionalProperties":true,"type":"object","required":["document"],"title":"CreateOCR"},"CreateProviderBody":{"properties":{"type":{"$ref":"#/components/schemas/ProviderType","description":"Model provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"Model provider API url. The url must only contain the domain name (without `/v1` suffix for example). Depends of the model provider type, the url can be optional (Albert, OpenAI)."},"key":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Key","description":"Model provider API key."},"basic_auth":{"anyOf":[{"$ref":"#/components/schemas/BasicAuth"},{"type":"null"}],"description":"Model provider basic authentication."},"timeout":{"type":"integer","title":"Timeout","description":"Timeout for the model provider requests, after user receive an 503 error (model is too busy).","default":300},"model_name":{"type":"string","title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR"},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/Metric"},{"type":"null"}],"description":"The metric to use for the quality of service policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the model to create the provider for (router ID, eg. 123)."}},"additionalProperties":true,"type":"object","required":["type","model_name","router_id"],"title":"CreateProviderBody"},"CreateProviderResponse":{"properties":{"id":{"type":"integer","title":"Id","description":"Provider ID."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the router that owns the provider."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the provider."},"type":{"$ref":"#/components/schemas/ProviderType","description":"Provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"Provider API url. The url must only contain the domain name (without `/v1` suffix for example)."},"key":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Key","description":"Provider API key."},"basic_auth":{"anyOf":[{"$ref":"#/components/schemas/BasicAuth"},{"type":"null"}],"description":"Provider basic authentication."},"timeout":{"type":"integer","maximum":3600.0,"minimum":1.0,"title":"Timeout","description":"Timeout for the provider requests, after user receive an 500 error (model is too busy)."},"model_name":{"type":"string","minLength":1,"title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR","examples":["WOR"]},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the QoS policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"created":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","router_id","user_id","type","timeout","model_name"],"title":"CreateProviderResponse"},"CreateRerankBody":{"properties":{"query":{"type":"string","minLength":1,"title":"Query","description":"The search query to use for the reranking. `query` and `prompt` cannot both be provided."},"documents":{"items":{"type":"string","minLength":1},"type":"array","title":"Documents"},"model":{"type":"string","minLength":1,"title":"Model","description":"The model to use for the reranking, call `/v1/models` endpoint to get the list of available models, only `text-classification` model type is supported."},"top_n":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Top N","description":"The number of top results to return. If set to None, all results will be returned."}},"additionalProperties":true,"type":"object","required":["query","documents","model"],"title":"CreateRerankBody"},"CreateRoleBody":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"Name of the role.","examples":["my-role"]},"permissions":{"anyOf":[{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array"},{"type":"null"}],"title":"Permissions","description":"List of permissions."},"limits":{"anyOf":[{"items":{"$ref":"#/components/schemas/Limit"},"type":"array"},{"type":"null"}],"title":"Limits","description":"List of limits."}},"additionalProperties":true,"type":"object","title":"CreateRoleBody"},"CreateRouterBody":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name of the model router.","examples":["model-router-1"]},"type":{"$ref":"#/components/schemas/ModelType-Input","description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"$ref":"#/components/schemas/RouterLoadBalancingStrategy","description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","default":"shuffle"},"cost_prompt_tokens":{"type":"number","minimum":0.0,"title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)","default":0.0},"cost_completion_tokens":{"type":"number","minimum":0.0,"title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)","default":0.0}},"additionalProperties":true,"type":"object","required":["name","type"],"title":"CreateRouterBody"},"CreateSearch":{"properties":{"collection_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Collection Ids","description":"List of collections ID.","default":[]},"document_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Document Ids","description":"List of document IDs","default":[]},"metadata_filters":{"anyOf":[{"$ref":"#/components/schemas/ComparisonFilter"},{"$ref":"#/components/schemas/CompoundFilter"},{"type":"null"}],"title":"Metadata Filters","description":"Metadata filters to apply to the search."},"limit":{"type":"integer","maximum":100.0,"exclusiveMinimum":0.0,"title":"Limit","description":"Number of results to return.","default":10},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Offset for pagination, specifying how many results to skip from the beginning.","default":0},"method":{"$ref":"#/components/schemas/SearchMethod","description":"Search method to use.","default":"semantic"},"rff_k":{"type":"integer","maximum":16384.0,"minimum":0.0,"title":"Rff K","description":"Smoothing constant for Reciprocal Rank Fusion (RRF) algorithm in hybrid search (recommended: from 10 to 100).","default":60},"score_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score Threshold","description":"Score of cosine similarity threshold for filtering results, only available for semantic search method.","default":0.0},"query":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Query","description":"Query related to the search."}},"additionalProperties":true,"type":"object","title":"CreateSearch"},"CreateToken":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"user":{"type":"integer","title":"User","description":"User ID to create the token for another user (by default, the current user). Required CREATE_USER permission."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["name","user"],"title":"CreateToken"},"CreateUserBody":{"properties":{"email":{"type":"string","maxLength":254,"minLength":1,"title":"Email","description":"The user email."},"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The user name."},"password":{"type":"string","maxLength":72,"minLength":1,"title":"Password","description":"The user password."},"role":{"type":"integer","title":"Role","description":"The role ID."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"The organization ID."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The budget."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The expiration timestamp."},"priority":{"type":"integer","minimum":0.0,"title":"Priority","description":"The user priority. Higher value means higher priority.","default":0}},"additionalProperties":true,"type":"object","required":["email","password","role"],"title":"CreateUserBody"},"Custom":{"properties":{"input":{"type":"string","title":"Input"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["input","name"],"title":"Custom","description":"The custom tool that the model called."},"Document":{"properties":{"object":{"type":"string","const":"document","title":"Object","description":"The type of the object.","default":"document"},"id":{"type":"integer","exclusiveMinimum":0.0,"title":"Id","description":"The ID of the document."},"name":{"type":"string","minLength":1,"title":"Name","description":"The name of the document."},"collection_id":{"type":"integer","exclusiveMinimum":0.0,"title":"Collection Id","description":"The ID of the collection the document belongs to."},"created":{"type":"integer","title":"Created","description":"The date of the document creation."},"chunks":{"type":"integer","minimum":0.0,"title":"Chunks","description":"The number of chunks the document has.","default":0},"size":{"type":"integer","minimum":0.0,"title":"Size","description":"The size of the document in bytes.","default":0}},"additionalProperties":true,"type":"object","required":["id","name","collection_id","created"],"title":"Document"},"DocumentResponse":{"properties":{"id":{"type":"integer","minimum":0.0,"title":"Id","description":"The ID of the document created."}},"additionalProperties":true,"type":"object","required":["id"],"title":"DocumentResponse"},"DocumentURLChunk":{"properties":{"document_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Name","description":"The filename of the document."},"document_url":{"type":"string","title":"Document Url","description":"The URL of the document."},"type":{"type":"string","const":"document_url","title":"Type","description":"The type of the document.","default":"document_url"}},"additionalProperties":true,"type":"object","required":["document_url"],"title":"DocumentURLChunk"},"Embedding":{"properties":{"embedding":{"items":{"type":"number"},"type":"array","title":"Embedding"},"index":{"type":"integer","title":"Index"},"object":{"type":"string","const":"embedding","title":"Object"}},"additionalProperties":true,"type":"object","required":["embedding","index","object"],"title":"Embedding","description":"Represents an embedding vector returned by embedding endpoint."},"Embeddings":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Embedding"},"type":"array","title":"Data"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"list","title":"Object","default":"list"},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."},"id":{"type":"string","title":"Id","description":"A unique identifier for the embedding."}},"additionalProperties":true,"type":"object","required":["data","model"],"title":"Embeddings"},"EmbeddingsRequest":{"properties":{"input":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"items":{"items":{"type":"integer"},"type":"array"},"type":"array"},{"type":"string"},{"items":{"type":"string"},"type":"array"}],"title":"Input","description":"Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model (call `/v1/models` endpoint to get the `max_context_length` by model) and cannot be an empty string."},"model":{"type":"string","title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `text-embeddings-inference` model type is supported."},"dimensions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Dimensions","description":"The number of dimensions the resulting output embeddings should have."},"encoding_format":{"$ref":"#/components/schemas/EncodingFormat","description":"The format of the output embeddings.","default":"float"}},"additionalProperties":true,"type":"object","required":["input","model"],"title":"EmbeddingsRequest"},"EncodingFormat":{"type":"string","enum":["float","base64"],"title":"EncodingFormat"},"EndpointUsage":{"type":"string","enum":["/v1/audio/transcriptions","/v1/chat/completions","/v1/embeddings","/v1/ocr","/v1/rerank","/v1/search"],"title":"EndpointUsage"},"Function":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"Function","description":"The function that the model called."},"FunctionCall":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"FunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HostingZone":{"type":"string","enum":["ABW","AFG","AGO","AIA","ALA","ALB","AND","ARE","ARG","ARM","ASM","ATA","ATF","ATG","AUS","AUT","AZE","BDI","BEL","BEN","BES","BFA","BGD","BGR","BHR","BHS","BIH","BLM","BLR","BLZ","BMU","BOL","BRA","BRB","BRN","BTN","BVT","BWA","CAF","CAN","CCK","CHE","CHL","CHN","CIV","CMR","COD","COG","COK","COL","COM","CPV","CRI","CUB","CUW","CXR","CYM","CYP","CZE","DEU","DJI","DMA","DNK","DOM","DZA","ECU","EGY","ERI","ESH","ESP","EST","ETH","FIN","FJI","FLK","FRA","FRO","FSM","GAB","GBR","GEO","GGY","GHA","GIB","GIN","GLP","GMB","GNB","GNQ","GRC","GRD","GRL","GTM","GUF","GUM","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN","IMN","IND","IOT","IRL","IRN","IRQ","ISL","ISR","ITA","JAM","JEY","JOR","JPN","KAZ","KEN","KGZ","KHM","KIR","KNA","KOR","KWT","LAO","LBN","LBR","LBY","LCA","LIE","LKA","LSO","LTU","LUX","LVA","MAC","MAF","MAR","MCO","MDA","MDG","MDV","MEX","MHL","MKD","MLI","MLT","MMR","MNE","MNG","MNP","MOZ","MRT","MSR","MTQ","MUS","MWI","MYS","MYT","NAM","NCL","NER","NFK","NGA","NIC","NIU","NLD","NOR","NPL","NRU","NZL","OMN","PAK","PAN","PCN","PER","PHL","PLW","PNG","POL","PRI","PRK","PRT","PRY","PSE","PYF","QAT","REU","ROU","RUS","RWA","SAU","SDN","SEN","SGP","SGS","SHN","SJM","SLB","SLE","SLV","SMR","SOM","SPM","SRB","SSD","STP","SUR","SVK","SVN","SWE","SWZ","SXM","SYC","SYR","TCA","TCD","TGO","THA","TJK","TKL","TKM","TLS","TON","TTO","TUN","TUR","TUV","TWN","TZA","UGA","UKR","UMI","URY","USA","UZB","VAT","VCT","VEN","VGB","VIR","VNM","VUT","WLF","WOR","WSM","YEM","ZAF","ZMB","ZWE"],"title":"HostingZone"},"ImageURL":{"properties":{"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"The detail of the image."},"url":{"type":"string","title":"Url","description":"The URL of the image."}},"additionalProperties":true,"type":"object","required":["url"],"title":"ImageURL"},"ImageURLChunk":{"properties":{"image_url":{"anyOf":[{"$ref":"#/components/schemas/ImageURL"},{"type":"string"}],"title":"Image Url","description":"The URL of the image to OCR."},"type":{"type":"string","const":"image_url","title":"Type","description":"The type of the image.","default":"image_url"}},"additionalProperties":true,"type":"object","required":["image_url"],"title":"ImageURLChunk"},"InputChunk":{"properties":{"content":{"type":"string","title":"Content","description":"The content of the chunk."},"metadata":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"integer","maximum":1e+16,"minimum":-1e+16},{"type":"number","maximum":1e+16,"minimum":-1e+16},{"type":"boolean"}]},"propertyNames":{"maxLength":255,"minLength":1},"type":"object","maxProperties":10,"minProperties":1,"description":"Extra metadata for the source"},{"type":"null"}],"title":"Metadata","description":"Metadata of the chunk"}},"additionalProperties":true,"type":"object","required":["content"],"title":"InputChunk"},"JsonSchema":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the JSON schema."},"schema_definition":{"additionalProperties":true,"type":"object","title":"Schema Definition","description":"The JSON schema definition."},"strict":{"type":"boolean","title":"Strict","description":"Whether to use strict mode.","default":false},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description of the schema."}},"additionalProperties":true,"type":"object","required":["name","schema_definition"],"title":"JsonSchema"},"Key":{"properties":{"object":{"type":"string","const":"key","title":"Object","default":"key"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"token":{"type":"string","title":"Token"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires"},"created":{"type":"integer","title":"Created"}},"additionalProperties":true,"type":"object","required":["id","name","token","created"],"title":"Key"},"Keys":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Key"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Keys"},"Limit":{"properties":{"router_id":{"type":"integer","title":"Router Id","description":"The router ID."},"type":{"$ref":"#/components/schemas/LimitType","description":"The limit type."},"value":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Value","description":"The limit value."}},"additionalProperties":true,"type":"object","required":["router_id","type"],"title":"Limit"},"LimitType":{"type":"string","enum":["tpm","tpd","rpm","rpd"],"title":"LimitType"},"Login":{"properties":{"email":{"type":"string","maxLength":254,"minLength":1,"title":"Email","description":"The user email."},"password":{"type":"string","maxLength":72,"minLength":1,"title":"Password","description":"The user password."}},"additionalProperties":true,"type":"object","required":["email","password"],"title":"Login"},"LoginResponse":{"properties":{"id":{"type":"integer","title":"Id","description":"The Playground API key ID."},"key":{"type":"string","title":"Key","description":"The playground API key."}},"additionalProperties":true,"type":"object","required":["id","key"],"title":"LoginResponse"},"Metric":{"type":"string","enum":["ttft","latency","inflight","performance","normalized_latency"],"title":"Metric"},"MetricsUsage":{"properties":{"latency":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latency"},"ttft":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttft"}},"additionalProperties":true,"type":"object","title":"MetricsUsage"},"Model":{"properties":{"object":{"type":"string","const":"model","title":"Object","description":"Type of the object.","default":"model"},"id":{"type":"string","title":"Id","description":"The model identifier, which can be referenced in the API endpoints."},"type":{"anyOf":[{"$ref":"#/components/schemas/api__domain__model__entities__ModelType"},{"type":"null"}],"description":"The type of the model, which can be used to identify the model type.","examples":["text-generation"]},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"owned_by":{"type":"string","title":"Owned By","description":"The organization that owns the model."},"max_context_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Context Length","description":"Maximum amount of tokens a context could contains. Makes sure it is the same for all models."},"costs":{"$ref":"#/components/schemas/ModelCosts","description":"Costs of the model."}},"additionalProperties":true,"type":"object","required":["id","created","owned_by"],"title":"Model"},"ModelCosts":{"properties":{"prompt_tokens":{"type":"number","minimum":0.0,"title":"Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)","default":0.0},"completion_tokens":{"type":"number","minimum":0.0,"title":"Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)","default":0.0}},"additionalProperties":true,"type":"object","title":"ModelCosts"},"ModelType-Input":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-embeddings-inference","text-generation","text-classification"],"title":"ModelType"},"ModelsResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Model"},"type":"array","title":"Data","description":"List of models."}},"additionalProperties":true,"type":"object","required":["data"],"title":"ModelsResponse"},"OCR":{"properties":{"document_annotation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Annotation","description":"Formatted response in the request_format if provided in json str"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"The ID of the OCR request."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"The model used to generate the OCR."},"pages":{"items":{"$ref":"#/components/schemas/OCRPageObject"},"type":"array","title":"Pages","description":"List of OCR info for pages."},"usage":{"anyOf":[{"$ref":"#/components/schemas/api__schemas__usage__Usage"},{"type":"null"}],"description":"Usage information for the request."},"usage_info":{"anyOf":[{"$ref":"#/components/schemas/OCRUsage"},{"type":"null"}],"description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["pages"],"title":"OCR"},"OCRImageObject":{"properties":{"bottom_right_x":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bottom Right X","description":"X coordinate of bottom-right corner of the extracted image"},"bottom_right_y":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bottom Right Y","description":"Y coordinate of bottom-right corner of the extracted image"},"id":{"type":"string","title":"Id","description":"Image ID for extracted image in a page"},"image_annotation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Annotation","description":"Annotation of the extracted image in json str"},"image_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base64","description":"Base64 string of the extracted image"},"top_left_x":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top Left X","description":"X coordinate of top-left corner of the extracted image"},"top_left_y":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top Left Y","description":"Y coordinate of top-left corner of the extracted image"}},"additionalProperties":true,"type":"object","required":["id"],"title":"OCRImageObject"},"OCRPageDimensions":{"properties":{"dpi":{"type":"integer","title":"Dpi","description":"Dots per inch of the page-image"},"height":{"type":"integer","title":"Height","description":"Height of the image in pixels"},"width":{"type":"integer","title":"Width","description":"Width of the image in pixels"}},"additionalProperties":true,"type":"object","required":["dpi","height","width"],"title":"OCRPageDimensions"},"OCRPageObject":{"properties":{"dimensions":{"anyOf":[{"$ref":"#/components/schemas/OCRPageDimensions"},{"type":"null"}],"description":"The dimensions of the PDF Page's screenshot image"},"images":{"items":{"$ref":"#/components/schemas/OCRImageObject"},"type":"array","title":"Images","description":"List of all extracted images in the page."},"index":{"type":"integer","title":"Index","description":"The page index in a pdf document starting from 0"},"markdown":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown","description":"The markdown string response of the page"}},"additionalProperties":true,"type":"object","required":["images","index"],"title":"OCRPageObject"},"OCRUsage":{"properties":{"doc_size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Doc Size Bytes","description":"Document size in bytes"},"pages_processed":{"type":"integer","title":"Pages Processed","description":"Number of pages processed"}},"additionalProperties":true,"type":"object","required":["pages_processed"],"title":"OCRUsage"},"Organization":{"properties":{"object":{"type":"string","const":"organization","title":"Object","default":"organization"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"users":{"type":"integer","title":"Users"},"created":{"type":"integer","title":"Created"},"updated":{"type":"integer","title":"Updated"}},"additionalProperties":true,"type":"object","required":["id","name","users"],"title":"Organization"},"OrganizationRequest":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"The organization name."}},"additionalProperties":true,"type":"object","required":["name"],"title":"OrganizationRequest"},"OrganizationUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The new organization name."}},"additionalProperties":true,"type":"object","title":"OrganizationUpdateRequest"},"Organizations":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Organization"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Organizations"},"OrganizationsResponse":{"properties":{"id":{"type":"integer","title":"Id"}},"additionalProperties":true,"type":"object","required":["id"],"title":"OrganizationsResponse"},"ParsedDocument":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/ParsedDocumentPage"},"type":"array","title":"Data"},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["data"],"title":"ParsedDocument"},"ParsedDocumentMetadata":{"properties":{"document_name":{"type":"string","title":"Document Name"},"page":{"type":"integer","title":"Page","default":0}},"additionalProperties":true,"type":"object","required":["document_name"],"title":"ParsedDocumentMetadata"},"ParsedDocumentPage":{"properties":{"object":{"type":"string","const":"documentPage","title":"Object","default":"documentPage"},"content":{"type":"string","title":"Content"},"images":{"additionalProperties":{"type":"string"},"type":"object","title":"Images"},"metadata":{"$ref":"#/components/schemas/ParsedDocumentMetadata"}},"additionalProperties":true,"type":"object","required":["content","images","metadata"],"title":"ParsedDocumentPage"},"PermissionType":{"type":"string","enum":["admin","create_public_collection","read_metric","provide_models"],"title":"PermissionType"},"PresetSeparators":{"type":"string","enum":["cpp","go","java","kotlin","js","ts","php","proto","python","r","rst","ruby","rust","scala","swift","markdown","latex","html","sol","csharp","cobol","c","lua","perl","haskell","elixir","powershell","visualbasic6"],"title":"PresetSeparators"},"PromptTokensDetails":{"properties":{"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"cached_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Tokens"}},"additionalProperties":true,"type":"object","title":"PromptTokensDetails","description":"Breakdown of tokens used in the prompt."},"ProviderResponse":{"properties":{"object":{"type":"string","const":"provider","title":"Object","description":"Type of the object.","default":"provider"},"id":{"type":"integer","title":"Id","description":"provider ID."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the router that owns the provider."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the provider."},"type":{"$ref":"#/components/schemas/ProviderType","description":"Provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"provider API url. The url must only contain the domain name (without `/v1` suffix for example)."},"timeout":{"type":"integer","title":"Timeout","description":"Timeout for the provider requests, after user receive an 500 error (model is too busy)."},"model_name":{"type":"string","minLength":1,"title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR","examples":["WOR"]},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the QoS policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"created":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","router_id","user_id","type","timeout","model_name","qos_metric"],"title":"ProviderResponse"},"ProviderSortField":{"type":"string","enum":["id","model_name","created"],"title":"ProviderSortField"},"ProviderType":{"type":"string","enum":["albert","openai","mistral","tei","vllm"],"title":"ProviderType"},"ProvidersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of providers."},"offset":{"type":"integer","title":"Offset","description":"Offset of the providers list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the providers list."},"data":{"items":{"$ref":"#/components/schemas/ProviderResponse"},"type":"array","title":"Data","description":"List of providers."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"ProvidersResponse"},"QoSMetric":{"type":"string","enum":["ttft","latency","inflight","performance"],"title":"QoSMetric"},"RerankResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"id":{"type":"string","title":"Id","description":"A unique identifier for the request."},"results":{"items":{"$ref":"#/components/schemas/RerankResult"},"type":"array","title":"Results","description":"The list of reranked texts."},"model":{"type":"string","title":"Model","description":"The model used to generate the reranking."},"usage":{"$ref":"#/components/schemas/api__domain__usage__entities__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["id","results","model"],"title":"RerankResponse"},"RerankResult":{"properties":{"relevance_score":{"type":"number","title":"Relevance Score","description":"The relevance score of the reranked text."},"index":{"type":"integer","title":"Index","description":"The index of the reranked text."}},"additionalProperties":true,"type":"object","required":["relevance_score","index"],"title":"RerankResult"},"ResponseFormat":{"properties":{"type":{"type":"string","enum":["text","json_object","json_schema"],"title":"Type","description":"Specify the format that the model must output. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide.","default":"text"},"json_schema":{"anyOf":[{"$ref":"#/components/schemas/JsonSchema"},{"type":"null"}],"description":"The JSON schema definition. Required when type is 'json_schema'."}},"additionalProperties":true,"type":"object","title":"ResponseFormat"},"RoleResponse":{"properties":{"object":{"type":"string","const":"role","title":"Object","description":"Type of the object.","default":"role"},"id":{"type":"integer","title":"Id","description":"ID of the role."},"name":{"type":"string","title":"Name","description":"Name of the role."},"permissions":{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array","title":"Permissions","description":"List of permissions."},"limits":{"items":{"$ref":"#/components/schemas/Limit"},"type":"array","title":"Limits","description":"List of limits."},"users":{"type":"integer","title":"Users","description":"Number of users assigned to the role."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","permissions","limits","users","created","updated"],"title":"RoleResponse"},"RolesResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of roles."},"offset":{"type":"integer","title":"Offset","description":"Offset of the roles list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the roles list."},"data":{"items":{"$ref":"#/components/schemas/RoleResponse"},"type":"array","title":"Data","description":"List of roles."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"RolesResponse"},"RouterLoadBalancingStrategy":{"type":"string","enum":["shuffle","least_busy"],"title":"RouterLoadBalancingStrategy"},"RouterResponse":{"properties":{"object":{"type":"string","const":"router","title":"Object","description":"Type of the object.","default":"router"},"id":{"type":"integer","title":"Id","description":"ID of the router."},"name":{"type":"string","title":"Name","description":"Name of the router."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the router."},"type":{"$ref":"#/components/schemas/api__schemas__models__ModelType","description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"$ref":"#/components/schemas/RouterLoadBalancingStrategy","description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","examples":["least_busy"]},"vector_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Vector Size","description":"Dimension of the vectors, if the models are embeddings. Make sure it is the same for all models."},"max_context_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Context Length","description":"Maximum amount of tokens a context could contains. Make sure it is the same for all models."},"cost_prompt_tokens":{"type":"number","title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)"},"cost_completion_tokens":{"type":"number","title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)"},"providers":{"type":"integer","title":"Providers","description":"Number of providers in the router.","default":0},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","user_id","type","aliases","load_balancing_strategy","cost_prompt_tokens","cost_completion_tokens","created","updated"],"title":"RouterResponse"},"RoutersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of routers."},"offset":{"type":"integer","title":"Offset","description":"Offset of the routers list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the routers list."},"data":{"items":{"$ref":"#/components/schemas/RouterResponse"},"type":"array","title":"Data","description":"List of routers."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"RoutersResponse"},"Search":{"properties":{"method":{"$ref":"#/components/schemas/SearchMethod","description":"Search method used."},"score":{"type":"number","title":"Score","description":"Score of the search result."},"chunk":{"$ref":"#/components/schemas/Chunk","description":"Chunk of the search result."}},"additionalProperties":true,"type":"object","required":["method","score","chunk"],"title":"Search"},"SearchArgs":{"properties":{"collection_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Collection Ids","description":"List of collections ID.","default":[]},"document_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Document Ids","description":"List of document IDs","default":[]},"metadata_filters":{"anyOf":[{"$ref":"#/components/schemas/ComparisonFilter"},{"$ref":"#/components/schemas/CompoundFilter"},{"type":"null"}],"title":"Metadata Filters","description":"Metadata filters to apply to the search."},"limit":{"type":"integer","maximum":100.0,"exclusiveMinimum":0.0,"title":"Limit","description":"Number of results to return.","default":10},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Offset for pagination, specifying how many results to skip from the beginning.","default":0},"method":{"$ref":"#/components/schemas/SearchMethod","description":"Search method to use.","default":"semantic"},"rff_k":{"type":"integer","maximum":16384.0,"minimum":0.0,"title":"Rff K","description":"Smoothing constant for Reciprocal Rank Fusion (RRF) algorithm in hybrid search (recommended: from 10 to 100).","default":60},"score_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score Threshold","description":"Score of cosine similarity threshold for filtering results, only available for semantic search method.","default":0.0}},"additionalProperties":true,"type":"object","title":"SearchArgs"},"SearchMethod":{"type":"string","enum":["hybrid","semantic","lexical"],"title":"SearchMethod"},"SearchTool":{"properties":{"collection_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Collection Ids","description":"List of collections ID.","default":[]},"document_ids":{"items":{"type":"integer","exclusiveMinimum":0.0},"type":"array","maxItems":100,"minItems":0,"title":"Document Ids","description":"List of document IDs","default":[]},"metadata_filters":{"anyOf":[{"$ref":"#/components/schemas/ComparisonFilter"},{"$ref":"#/components/schemas/CompoundFilter"},{"type":"null"}],"title":"Metadata Filters","description":"Metadata filters to apply to the search."},"limit":{"type":"integer","maximum":100.0,"exclusiveMinimum":0.0,"title":"Limit","description":"Number of results to return.","default":10},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Offset for pagination, specifying how many results to skip from the beginning.","default":0},"method":{"$ref":"#/components/schemas/SearchMethod","description":"Search method to use.","default":"semantic"},"rff_k":{"type":"integer","maximum":16384.0,"minimum":0.0,"title":"Rff K","description":"Smoothing constant for Reciprocal Rank Fusion (RRF) algorithm in hybrid search (recommended: from 10 to 100).","default":60},"score_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score Threshold","description":"Score of cosine similarity threshold for filtering results, only available for semantic search method.","default":0.0},"type":{"type":"string","const":"search","title":"Type","description":"The type of tool to call.","default":"search"}},"additionalProperties":true,"type":"object","title":"SearchTool","description":"Built-in search tool available in `tools`.\n\nUse `type=\"search\"` to trigger retrieval over indexed documents.\nAll additional parameters are inherited from `SearchArgs`."},"Searches":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"The type of the object.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Search"},"type":"array","title":"Data","description":"List of search results."},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["data"],"title":"Searches"},"Segment":{"properties":{"id":{"type":"integer","title":"Id","description":"A unique identifier for the segment."},"type":{"type":"string","title":"Type","description":"The type of the segment.","default":"transcript.text.segment"},"text":{"type":"string","title":"Text","description":"The segment text."},"start":{"type":"number","title":"Start","description":"Start time of the segment in seconds."},"end":{"type":"number","title":"End","description":"End time of the segment in seconds."},"speaker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker","description":"Speaker label assigned by diarization, if available."}},"additionalProperties":true,"type":"object","required":["id","text","start","end"],"title":"Segment"},"SortField":{"type":"string","enum":["id","name","created"],"title":"SortField"},"SortOrder":{"type":"string","enum":["asc","desc"],"title":"SortOrder"},"Token":{"properties":{"object":{"type":"string","const":"token","title":"Object","default":"token"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"token":{"type":"string","title":"Token"},"user":{"type":"integer","title":"User"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires"},"created":{"type":"integer","title":"Created"}},"additionalProperties":true,"type":"object","required":["id","name","token","user","created"],"title":"Token"},"Tokens":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Token"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Tokens"},"TokensResponse":{"properties":{"id":{"type":"integer","title":"Id"},"token":{"type":"string","title":"Token"}},"additionalProperties":true,"type":"object","required":["id","token"],"title":"TokensResponse"},"TopLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"}},"additionalProperties":true,"type":"object","required":["token","logprob"],"title":"TopLogprob"},"UpdateProviderBody":{"properties":{"router_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Router Id","description":"The ID of the new router to assign to the provider."},"timeout":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timeout","description":"Timeout for the model provider requests, after user receive an 500 error (model is too busy)."},"model_hosting_zone":{"anyOf":[{"$ref":"#/components/schemas/HostingZone"},{"type":"null"}],"description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai"},"model_total_params":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai"},"model_active_params":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai"},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the quality of service policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."}},"additionalProperties":true,"type":"object","title":"UpdateProviderBody"},"UpdateRouterBody":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"Name of the model router.","examples":["model-router-1"]},"type":{"anyOf":[{"$ref":"#/components/schemas/ModelType-Input"},{"type":"null"}],"description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"anyOf":[{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array"},{"type":"null"}],"title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"anyOf":[{"$ref":"#/components/schemas/RouterLoadBalancingStrategy"},{"type":"null"}],"description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","examples":["least_busy"]},"cost_prompt_tokens":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)"},"cost_completion_tokens":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)"}},"additionalProperties":true,"type":"object","title":"UpdateRouterBody"},"UpdateUserInfo":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The user name."},"email":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"title":"Email","description":"The user email."},"current_password":{"anyOf":[{"type":"string","maxLength":72},{"type":"null"}],"title":"Current Password","description":"The current user password."},"password":{"anyOf":[{"type":"string","maxLength":72},{"type":"null"}],"title":"Password","description":"The new user password. If None, the user password is not changed."}},"additionalProperties":true,"type":"object","title":"UpdateUserInfo"},"UsageDetail":{"properties":{"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prompt Tokens","description":"Number of prompt tokens (e.g. input tokens)."},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completion Tokens","description":"Number of completion tokens (e.g. output tokens)."},"total_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens","description":"Total number of tokens (e.g. input and output tokens)."},"cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost","description":"Total cost of the request."},"impacts":{"$ref":"#/components/schemas/api__schemas__usage__EnvironmentalImpacts"},"metrics":{"$ref":"#/components/schemas/MetricsUsage"}},"additionalProperties":true,"type":"object","title":"UsageDetail"},"Usages":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Object type.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/api__schemas__me__usage__Usage"},"type":"array","title":"Data","description":"List of usages."}},"additionalProperties":true,"type":"object","required":["data"],"title":"Usages"},"UserInfo":{"properties":{"object":{"type":"string","const":"userInfo","title":"Object","description":"The user info object type.","default":"userInfo"},"id":{"type":"integer","title":"Id","description":"The user ID."},"email":{"type":"string","title":"Email","description":"The user email."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The user name."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"The user organization ID."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The user budget. If None, the user has unlimited budget."},"permissions":{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array","title":"Permissions","description":"The user permissions."},"limits":{"items":{"$ref":"#/components/schemas/Limit"},"type":"array","title":"Limits","description":"The user rate limits."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The user expiration timestamp. If None, the user will never expire."},"priority":{"type":"integer","title":"Priority","description":"The user priority (higher = higher priority). This value influences scheduling/queue priority for non-streaming model invocations.","default":0},"created":{"type":"integer","title":"Created","description":"The user creation timestamp."},"updated":{"type":"integer","title":"Updated","description":"The user update timestamp."}},"additionalProperties":true,"type":"object","required":["id","email","permissions","limits","created","updated"],"title":"UserInfo"},"UserResponse":{"properties":{"object":{"type":"string","const":"user","title":"Object","description":"Type of the object.","default":"user"},"id":{"type":"integer","title":"Id","description":"ID of the user."},"email":{"type":"string","title":"Email","description":"Email of the user."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Name of the user."},"sub":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sub","description":"Subject identifier for SSO."},"iss":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Iss","description":"Issuer identifier for SSO."},"role":{"type":"integer","title":"Role","description":"ID of the role assigned to the user."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"ID of the organization the user belongs to."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"Budget allocated to the user."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Expiration time of the user, as Unix timestamp."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."},"priority":{"type":"integer","title":"Priority","description":"Priority of the user. Higher value means higher priority."}},"additionalProperties":true,"type":"object","required":["id","email","role","created","updated","priority"],"title":"UserResponse"},"UserSortField":{"type":"string","enum":["id","email","created","updated"],"title":"UserSortField"},"UserUpdateRequest":{"properties":{"email":{"anyOf":[{"type":"string","maxLength":254,"minLength":1},{"type":"null"}],"title":"Email","description":"The new user email. If None, the user email is not changed."},"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The new user name. If None, the user name is not changed."},"current_password":{"anyOf":[{"type":"string","maxLength":72,"minLength":1},{"type":"null"}],"title":"Current Password","description":"The current user password."},"password":{"anyOf":[{"type":"string","maxLength":72,"minLength":1},{"type":"null"}],"title":"Password","description":"The new user password. If None, the user password is not changed."},"role":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Role","description":"The new role ID. If None, the user role is not changed."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"The new organization ID. If None, the user will be removed from the organization if he was in one."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The new budget. If None, the user will have no budget."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The new expiration timestamp. If None, the user will never expire."},"priority":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Priority","description":"The new user priority. Higher value means higher priority. If None, unchanged."}},"additionalProperties":true,"type":"object","title":"UserUpdateRequest"},"UsersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of users matching the query."},"offset":{"type":"integer","title":"Offset","description":"Number of users skipped."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of users returned."},"data":{"items":{"$ref":"#/components/schemas/UserResponse"},"type":"array","title":"Data","description":"List of users."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"UsersResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"api__domain__model__entities__ModelType":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-classification","text-embeddings-inference","text-generation"],"title":"ModelType"},"api__domain__usage__entities__EnvironmentalImpacts":{"properties":{"kWh":{"type":"number","title":"Kwh","default":0.0},"kgCO2eq":{"type":"number","title":"Kgco2Eq","default":0.0}},"additionalProperties":true,"type":"object","title":"EnvironmentalImpacts"},"api__domain__usage__entities__Usage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens","default":0},"completion_tokens":{"type":"integer","title":"Completion Tokens","default":0},"total_tokens":{"type":"integer","title":"Total Tokens","default":0},"cost":{"type":"number","title":"Cost","default":0.0},"impacts":{"$ref":"#/components/schemas/api__domain__usage__entities__EnvironmentalImpacts","default":{"kWh":0.0,"kgCO2eq":0.0}}},"additionalProperties":true,"type":"object","title":"Usage"},"api__infrastructure__fastapi__documentation__HTTPExceptionModel":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"detail":{"type":"string","title":"Detail"},"headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Headers"}},"type":"object","required":["status_code","detail"],"title":"HTTPExceptionModel"},"api__schemas__exception__HTTPExceptionModel":{"properties":{"status_code":{"type":"integer","maximum":599.0,"minimum":100.0,"title":"Status Code","description":"HTTP status code to send to the client."},"detail":{"title":"Detail","description":"Any data to be sent to the client in the `detail` key of the JSON response."},"headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Headers","description":"Any headers to send to the client in the response."}},"type":"object","required":["status_code","detail","headers"],"title":"HTTPExceptionModel"},"api__schemas__me__usage__Usage":{"properties":{"object":{"type":"string","const":"me.usage","title":"Object","description":"Object type.","default":"me.usage"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Model used for the request."},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key","description":"Key used for the request."},"endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint","description":"Endpoint used for the request."},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method","description":"Method used for the request."},"status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status","description":"Status code of the response."},"usage":{"$ref":"#/components/schemas/UsageDetail"},"created":{"type":"integer","title":"Created","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["created"],"title":"Usage"},"api__schemas__models__ModelType":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-embeddings-inference","text-generation","text-classification"],"title":"ModelType"},"api__schemas__usage__EnvironmentalImpacts":{"properties":{"kWh":{"type":"number","title":"Kwh","description":"Carbon footprint in kWh.","default":0.0},"kgCO2eq":{"type":"number","title":"Kgco2Eq","description":"Carbon footprint in kgCO2eq (global warming potential).","default":0.0}},"additionalProperties":true,"type":"object","title":"EnvironmentalImpacts"},"api__schemas__usage__Usage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens","description":"Number of prompt tokens (e.g. input tokens).","default":0},"completion_tokens":{"type":"integer","title":"Completion Tokens","description":"Number of completion tokens (e.g. output tokens).","default":0},"total_tokens":{"type":"integer","title":"Total Tokens","description":"Total number of tokens (e.g. input and output tokens).","default":0},"cost":{"type":"number","title":"Cost","description":"Total cost of the request.","default":0.0},"carbon":{"$ref":"#/components/schemas/CarbonFootprintUsage","deprecated":true},"impacts":{"$ref":"#/components/schemas/api__schemas__usage__EnvironmentalImpacts"},"requests":{"type":"integer","title":"Requests","description":"Number of model requests.","default":0}},"additionalProperties":true,"type":"object","title":"Usage"},"openai__types__chat__chat_completion__Choice":{"properties":{"finish_reason":{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]},"message":{"$ref":"#/components/schemas/ChatCompletionMessage"}},"additionalProperties":true,"type":"object","required":["finish_reason","index","message"],"title":"Choice"},"openai__types__chat__chat_completion_chunk__Choice":{"properties":{"delta":{"$ref":"#/components/schemas/ChoiceDelta"},"finish_reason":{"anyOf":[{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"]},{"type":"null"}],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["delta","index"],"title":"Choice"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}
\ No newline at end of file
+{"openapi":"3.1.0","info":{"title":"OpenGateLLM","summary":"OpenGateLLM connect to your models. You can configuration this swagger UI in the configuration file, like hide routes or change the title.","description":"[See documentation](https://github.com/etalab-ia/opengatellm/blob/main/README.md)","license":{"name":"MIT Licence","identifier":"MIT","url":"https://raw.githubusercontent.com/etalab-ia/opengatellm/refs/heads/main/LICENSE"},"version":"0.4.9"},"paths":{"/v1/admin/keys":{"post":{"tags":["Admin"],"summary":"Create Key","description":"Create a new key for a user.","operationId":"create_key_v1_admin_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyBody","description":"The key creation request."}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__schemas__admin__keys__CreateKeyResponse"}}}},"409":{"description":"Key {name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/providers":{"post":{"tags":["Admin"],"summary":"Create Provider","operationId":"create_provider_v1_admin_providers_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderResponse"}}}},"403":{"description":"Inconsistent max context length for {model_name}. Expected: {expected_length}. Actual: {actual_length}
Inconsistent vector size for {model_name}. Expected: {expected_size}. Actual: {actual_size}
User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Invalid model provider type {input_type} for {expected_type} router.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"424":{"description":"Model provider {name} not reachable ({status_code}): {detail}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Model provider {model_name} for url {url} already exists for router {router_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Providers","operationId":"get_providers_v1_admin_providers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter providers by router ID.","title":"Router Id"},"description":"Filter providers by router ID."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of providers to skip.","default":0,"title":"Offset"},"description":"Number of providers to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of providers to return.","default":10,"title":"Limit"},"description":"Maximum number of providers to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ProviderSortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvidersResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/providers/{provider_id}":{"delete":{"tags":["Admin"],"summary":"Delete Provider","operationId":"delete_provider_v1_admin_providers__provider_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to delete.","title":"Provider Id"},"description":"The ID of the provider to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"404":{"description":"Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Provider","operationId":"update_provider_v1_admin_providers__provider_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to update.","title":"Provider Id"},"description":"The ID of the provider to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderBody","description":"The provider update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"403":{"description":"Inconsistent max context length for {model_name}. Expected: {expected_length}. Actual: {actual_length}
Inconsistent vector size for {model_name}. Expected: {expected_size}. Actual: {actual_size}
User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Invalid model provider type {input_type} for {expected_type} router.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Model provider {model_name} for url {url} already exists for router {router_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.
Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Provider","operationId":"get_provider_v1_admin_providers__provider_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the provider to get.","title":"Provider Id"},"description":"The ID of the provider to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model provider {provider_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/roles":{"post":{"tags":["Admin"],"summary":"Create Role","operationId":"create_role_v1_admin_roles_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleBody","description":"The role creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Roles","operationId":"get_roles_v1_admin_roles_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of roles to skip.","default":0,"title":"Offset"},"description":"Number of roles to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of roles to return.","default":10,"title":"Limit"},"description":"Maximum number of roles to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolesResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/roles/{role_id}":{"patch":{"tags":["Admin"],"summary":"Update Role","operationId":"update_role_v1_admin_roles__role_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to update.","title":"Role Id"},"description":"The ID of the role to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleBody","description":"The role update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Role","operationId":"get_role_v1_admin_roles__role_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to get.","title":"Role Id"},"description":"The ID of the role to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete Role","operationId":"delete_role_v1_admin_roles__role_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the role to delete.","title":"Role Id"},"description":"The ID of the role to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Role {role_id} has {number_of_users} users and cannot be removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/routers":{"post":{"tags":["Admin"],"summary":"Create Router","operationId":"create_router_v1_admin_routers_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouterBody","description":"The router creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"409":{"description":"Following aliases already exist: '{router_aliases}'
Router {router_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Routers","operationId":"get_routers_v1_admin_routers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of routers to skip.","default":0,"title":"Offset"},"description":"Number of routers to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of routers to return.","default":10,"title":"Limit"},"description":"Maximum number of routers to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutersResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/routers/{router_id}":{"get":{"tags":["Admin"],"summary":"Get Router","operationId":"get_router_v1_admin_routers__router_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The router ID.","title":"Router Id"},"description":"The router ID."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete Router","operationId":"delete_router_v1_admin_routers__router_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the router to delete (router ID, eg. 123).","title":"Router Id"},"description":"The ID of the router to delete (router ID, eg. 123)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Router","operationId":"update_router_v1_admin_routers__router_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"router_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the router to update (router ID, eg. 123).","title":"Router Id"},"description":"The ID of the router to update (router ID, eg. 123)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouterBody","description":"The router update request."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model router {router_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"Following aliases already exist: '{router_aliases}'
Router {router_name} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users":{"post":{"tags":["Admin"],"summary":"Create User","operationId":"create_user_v1_admin_users_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserBody","description":"The user creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"409":{"description":"User {email} already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Role {role_id} not found.
Organization {organization_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Users","operationId":"get_users_v1_admin_users_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"role_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The ID of the role to filter the users by.","title":"Role Id"},"description":"The ID of the role to filter the users by."},{"name":"organization_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The ID of the organization to filter the users by.","title":"Organization Id"},"description":"The ID of the organization to filter the users by."},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Email substring to filter the users by.","title":"Email"},"description":"Email substring to filter the users by."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of users to skip.","default":0,"title":"Offset"},"description":"Number of users to skip."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum number of users to return.","default":10,"title":"Limit"},"description":"Maximum number of users to return."},{"name":"sort_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/UserSortField","description":"Field to sort by.","default":"id"},"description":"Field to sort by."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/SortOrder","description":"Sort order.","default":"asc"},"description":"Sort order."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersResponse"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user_id}":{"get":{"tags":["Admin"],"summary":"Get User","operationId":"get_user_v1_admin_users__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to get.","title":"User Id"},"description":"The ID of the user to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete User","operationId":"delete_user_v1_admin_users__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to delete.","title":"User Id"},"description":"The ID of the user to delete."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"409":{"description":"User cannot be deleted because the user owns routers: {router_ids}.
User cannot be deleted because the user owns providers: {provider_ids}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"User has no admin rights.
Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/audio/transcriptions":{"post":{"tags":["Audio"],"summary":"Audio Transcriptions","description":"Transcribes audio into the input language.","operationId":"audio_transcriptions_v1_audio_transcriptions_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_audio_transcriptions_v1_audio_transcriptions_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioTranscription"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/login":{"post":{"tags":["Auth"],"summary":"Login","operationId":"login_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthLoginBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthLoginResponse"}}}},"401":{"description":"Invalid password.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"User {user_id} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/chat/completions":{"post":{"tags":["Chat"],"summary":"Chat Completions","description":"Creates a model response for the given chat conversation.","operationId":"chat_completions_v1_chat_completions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChatCompletion"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletion"},{"$ref":"#/components/schemas/ChatCompletionChunk"}],"title":"Response Chat Completions V1 Chat Completions Post"}}}},"404":{"description":"Model not found. Collection not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"422":{"description":"Wrong model type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/embeddings":{"post":{"tags":["Embeddings"],"summary":"Create Embeddings","operationId":"create_embeddings_v1_embeddings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmbeddingsBody","description":"The embeddings creation request."}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsResponse"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model {name} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"429":{"description":"Token/request limit per minute/day exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Model has wrong type. Expected: {expected_type}. Actual: {actual_type}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Insufficient budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/health":{"get":{"tags":["Health"],"summary":"Get Health","description":"Get the health of the API.","operationId":"get_health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health/models":{"get":{"tags":["Health"],"summary":"Get Health Models","description":"Get the health of the models.","operationId":"get_health_models_health_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/me/info":{"get":{"tags":["Me"],"summary":"Get User","description":"Get information about the current user.","operationId":"get_user_v1_me_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["Me"],"summary":"Update User","description":"Update information about the current user.","operationId":"update_user_v1_me_info_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserInfo","description":"The user update request."}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/me/keys":{"post":{"tags":["Me"],"summary":"Create Key","description":"Create a new API key.","operationId":"create_key_v1_me_keys_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKey","description":"The token creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__me__keys__CreateKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Me"],"summary":"Get Keys","description":"Get all your tokens.","operationId":"get_keys_v1_me_keys_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the tokens to get.","default":0,"title":"Offset"},"description":"The offset of the tokens to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the tokens to get.","default":10,"title":"Limit"},"description":"The limit of the tokens to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created"],"type":"string","description":"The field to order the tokens by.","default":"id","title":"Order By"},"description":"The field to order the tokens by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the tokens by.","default":"asc","title":"Order Direction"},"description":"The direction to order the tokens by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Keys"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me/keys/{key}":{"delete":{"tags":["Me"],"summary":"Delete Key","description":"Delete a API key.","operationId":"delete_key_v1_me_keys__key__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"integer","description":"The key ID of the key to delete.","title":"Key"},"description":"The key ID of the key to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Me"],"summary":"Get Key","description":"Get your token by id.","operationId":"get_key_v1_me_keys__key__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"integer","description":"The key ID of the key to get.","title":"Key"},"description":"The key ID of the key to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me/usage":{"get":{"tags":["Me"],"summary":"Get Usage","description":"Get usage for the current user.","operationId":"get_usage_v1_me_usage_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the usages to get.","default":0,"title":"Offset"},"description":"The offset of the usages to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the usages to get.","default":10,"title":"Limit"},"description":"The limit of the usages to get."},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Start time as Unix timestamp (if not provided, will be set to 30 days ago)","title":"Start Time"},"description":"Start time as Unix timestamp (if not provided, will be set to 30 days ago)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"End time as Unix timestamp (if not provided, will be set to now)","title":"End Time"},"description":"End time as Unix timestamp (if not provided, will be set to now)"},{"name":"endpoint","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/EndpointUsage"},{"type":"null"}],"description":"The endpoint to get usage for.","title":"Endpoint"},"description":"The endpoint to get usage for."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usages"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["Models"],"summary":"Get Models","description":"Lists the currently available models and provides basic information.","operationId":"get_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelsResponse"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/models/{model}":{"get":{"tags":["Models"],"summary":"Get Model","description":"Get a model by name and provide basic information.","operationId":"get_model_v1_models__model__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"model","in":"path","required":true,"schema":{"type":"string","description":"The name of the model to get.","title":"Model"},"description":"The name of the model to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"404":{"description":"Model {name} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ocr":{"post":{"tags":["OCR"],"summary":"Ocr","description":"Extracts text from files using OCR.","operationId":"ocr_v1_ocr_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOCR"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OCR"}}}},"404":{"description":"Model not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"422":{"description":"Wrong model type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__schemas__exception__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/rerank":{"post":{"tags":["Rerank"],"summary":"Create Rerank","operationId":"create_rerank_v1_rerank_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRerankBody","description":"The rerank creation request."}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RerankResponse"}}}},"503":{"description":"Model is too busy, please try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"404":{"description":"Model {name} not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"429":{"description":"Token/request limit per minute/day exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"422":{"description":"Model has wrong type. Expected: {expected_type}. Actual: {actual_type}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"400":{"description":"Insufficient budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"401":{"description":"Invalid authentication scheme.
Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}},"403":{"description":"Your account has expired. Please contact support to renew your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__infrastructure__fastapi__documentation__HTTPExceptionModel"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/organizations":{"post":{"tags":["Admin"],"summary":"Create Organization","operationId":"create_organization_v1_admin_organizations_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationRequest","description":"The organization creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Organizations","operationId":"get_organizations_v1_admin_organizations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the organizations to get.","default":0,"title":"Offset"},"description":"The offset of the organizations to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the organizations to get.","default":10,"title":"Limit"},"description":"The limit of the organizations to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created","updated"],"type":"string","description":"The field to order the organizations by.","default":"id","title":"Order By"},"description":"The field to order the organizations by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the organizations by.","default":"asc","title":"Order Direction"},"description":"The direction to order the organizations by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organizations"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/organizations/{organization}":{"delete":{"tags":["Admin"],"summary":"Delete Organization","operationId":"delete_organization_v1_admin_organizations__organization__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to delete.","title":"Organization"},"description":"The ID of the organization to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin"],"summary":"Update Organization","operationId":"update_organization_v1_admin_organizations__organization__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to update.","title":"Organization"},"description":"The ID of the organization to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUpdateRequest","description":"The organization update request."}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Organization","operationId":"get_organization_v1_admin_organizations__organization__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the organization to get.","title":"Organization"},"description":"The ID of the organization to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tokens":{"post":{"tags":["Admin"],"summary":"Create Token","description":"Create a new token.","operationId":"create_token_v1_admin_tokens_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToken","description":"The token creation request."}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Tokens","description":"Get all your tokens.","operationId":"get_tokens_v1_admin_tokens_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The user ID of the user to get the tokens for.","title":"User"},"description":"The user ID of the user to get the tokens for."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"The offset of the tokens to get.","default":0,"title":"Offset"},"description":"The offset of the tokens to get."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"The limit of the tokens to get.","default":10,"title":"Limit"},"description":"The limit of the tokens to get."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created"],"type":"string","description":"The field to order the tokens by.","default":"id","title":"Order By"},"description":"The field to order the tokens by."},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"The direction to order the tokens by.","default":"asc","title":"Order Direction"},"description":"The direction to order the tokens by."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tokens"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tokens/{token}":{"delete":{"tags":["Admin"],"summary":"Delete Token","description":"Delete a token.","operationId":"delete_token_v1_admin_tokens__token__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"integer","description":"The user ID of the user to delete the token for.","title":"User"},"description":"The user ID of the user to delete the token for."},{"name":"token","in":"path","required":true,"schema":{"type":"integer","description":"The token ID of the token to delete.","title":"Token"},"description":"The token ID of the token to delete."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin"],"summary":"Get Token","description":"Get your token by id.","operationId":"get_token_v1_admin_tokens__token__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"integer","description":"The token ID of the token to get.","title":"Token"},"description":"The token ID of the token to get."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user}":{"patch":{"tags":["Admin"],"summary":"Update User","description":"Update a user.","operationId":"update_user_v1_admin_users__user__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"integer","description":"The ID of the user to update.","title":"User"},"description":"The ID of the user to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateRequest","description":"The user update request."}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/metrics":{"get":{"tags":["Monitoring"],"summary":"Get Metrics","operationId":"get_metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"Annotation":{"properties":{"type":{"type":"string","const":"url_citation","title":"Type"},"url_citation":{"$ref":"#/components/schemas/AnnotationURLCitation"}},"additionalProperties":true,"type":"object","required":["type","url_citation"],"title":"Annotation","description":"A URL citation when using web search."},"AnnotationURLCitation":{"properties":{"end_index":{"type":"integer","title":"End Index"},"start_index":{"type":"integer","title":"Start Index"},"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"}},"additionalProperties":true,"type":"object","required":["end_index","start_index","title","url"],"title":"AnnotationURLCitation","description":"A URL citation when using web search."},"AudioTranscription":{"properties":{"id":{"type":"string","title":"Id","description":"A unique identifier for the audio transcription."},"text":{"type":"string","title":"Text","description":"The transcription text."},"model":{"type":"string","title":"Model","description":"The model used to generate the transcription."},"segments":{"anyOf":[{"items":{"$ref":"#/components/schemas/Segment"},"type":"array"},{"type":"null"}],"title":"Segments","description":"Diarized segments, only set when `response_format=diarized_json`."},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["id","text","model"],"title":"AudioTranscription"},"AudioTranscriptionLanguage":{"type":"string","enum":["af","afrikaans","albanian","am","amharic","ar","arabic","armenian","as","assamese","az","azerbaijani","ba","bashkir","basque","be","belarusian","bengali","bg","bn","bo","bosnian","br","breton","bs","bulgarian","burmese","ca","cantonese","castilian","catalan","chinese","croatian","cs","cy","czech","da","danish","de","dutch","el","en","english","es","estonian","et","eu","fa","faroese","fi","finnish","flemish","fo","fr","french","galician","georgian","german","gl","greek","gu","gujarati","ha","haitian","haitian creole","hausa","haw","hawaiian","he","hebrew","hi","hindi","hr","ht","hu","hungarian","hy","icelandic","id","indonesian","is","it","italian","ja","japanese","javanese","jw","ka","kannada","kazakh","khmer","kk","km","kn","ko","korean","la","lao","latin","latvian","lb","letzeburgesch","lingala","lithuanian","ln","lo","lt","luxembourgish","lv","macedonian","malagasy","malay","malayalam","maltese","mandarin","maori","marathi","mg","mi","mk","ml","mn","moldavian","moldovan","mongolian","mr","ms","mt","my","myanmar","ne","nepali","nl","nn","no","norwegian","nynorsk","oc","occitan","pa","panjabi","pashto","persian","pl","polish","portuguese","ps","pt","punjabi","pushto","ro","romanian","ru","russian","sa","sanskrit","sd","serbian","shona","si","sindhi","sinhala","sinhalese","sk","sl","slovak","slovenian","sn","so","somali","spanish","sq","sr","su","sundanese","sv","sw","swahili","swedish","ta","tagalog","tajik","tamil","tatar","te","telugu","tg","th","thai","tibetan","tk","tl","tr","tt","turkish","turkmen","uk","ukrainian","ur","urdu","uz","uzbek","valencian","vi","vietnamese","welsh","yi","yiddish","yo","yoruba","yue","zh"],"title":"AudioTranscriptionLanguage"},"AudioTranscriptionResponseFormat":{"type":"string","enum":["json","text","verbose_json","diarized_json","srt","vtt"],"title":"AudioTranscriptionResponseFormat"},"AuthLoginBody":{"properties":{"email":{"type":"string","maxLength":254,"minLength":1,"title":"Email","description":"The user email."},"password":{"type":"string","maxLength":72,"minLength":1,"title":"Password","description":"The user password."}},"additionalProperties":true,"type":"object","required":["email","password"],"title":"AuthLoginBody"},"AuthLoginResponse":{"properties":{"object":{"type":"string","const":"key","title":"Object","description":"Type of the object.","default":"key"},"id":{"type":"integer","title":"Id","description":"ID of the key."},"name":{"type":"string","title":"Name","description":"Name of the key."},"value":{"type":"string","title":"Value","description":"Value of the key."},"user":{"type":"integer","title":"User","description":"ID of the user that owns the key."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Time of expiration, as Unix timestamp. If None, the key never expires."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","value","user","created"],"title":"AuthLoginResponse"},"BasicAuth":{"properties":{"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"}},"additionalProperties":true,"type":"object","required":["username","password"],"title":"BasicAuth"},"Body_audio_transcriptions_v1_audio_transcriptions_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The audio file object (not file name) to transcribe, in one of these formats: mp3 or wav."},"model":{"type":"string","title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `automatic-speech-recognition` model type is supported."},"language":{"anyOf":[{"$ref":"#/components/schemas/AudioTranscriptionLanguage"},{"type":"null"}],"description":"The language of the output audio. If the output language is different than the audio language, the audio language will be translated into the output language. Output language must be supplied in ISO-639-1 format (e.g. en, fr) format."},"prompt":{"type":"string","title":"Prompt","description":"An optional text to tell the model what to do with the input audio.","default":""},"response_format":{"$ref":"#/components/schemas/AudioTranscriptionResponseFormat","description":"The format of the transcript output: `json` (default), `text`, `diarized_json` to return per-segment speaker labels, `srt` or `vtt` for subtitle formats.","default":"json"},"temperature":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Temperature","description":"The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.","default":0.0}},"type":"object","required":["file","model"],"title":"Body_audio_transcriptions_v1_audio_transcriptions_post"},"CarbonFootprintUsage":{"properties":{"kWh":{"$ref":"#/components/schemas/CarbonFootprintUsageKWh","deprecated":true},"kgCO2eq":{"$ref":"#/components/schemas/CarbonFootprintUsageKgCO2eq","deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsage"},"CarbonFootprintUsageKWh":{"properties":{"min":{"type":"number","title":"Min","description":"Minimum carbon footprint in kWh.","default":0.0,"deprecated":true},"max":{"type":"number","title":"Max","description":"Maximum carbon footprint in kWh.","default":0.0,"deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsageKWh"},"CarbonFootprintUsageKgCO2eq":{"properties":{"min":{"type":"number","title":"Min","description":"Minimum carbon footprint in kgCO2eq (global warming potential).","default":0.0,"deprecated":true},"max":{"type":"number","title":"Max","description":"Maximum carbon footprint in kgCO2eq (global warming potential).","default":0.0,"deprecated":true}},"additionalProperties":true,"type":"object","title":"CarbonFootprintUsageKgCO2eq"},"ChatCompletion":{"properties":{"id":{"type":"string","title":"Id","description":"A unique identifier for the chat completion."},"choices":{"items":{"$ref":"#/components/schemas/openai__types__chat__chat_completion__Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"$ref":"#/components/schemas/api__schemas__usage__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["choices","created","model","object"],"title":"ChatCompletion"},"ChatCompletionAudio":{"properties":{"id":{"type":"string","title":"Id"},"data":{"type":"string","title":"Data"},"expires_at":{"type":"integer","title":"Expires At"},"transcript":{"type":"string","title":"Transcript"}},"additionalProperties":true,"type":"object","required":["id","data","expires_at","transcript"],"title":"ChatCompletionAudio","description":"If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio)."},"ChatCompletionChunk":{"properties":{"id":{"type":"string","title":"Id"},"choices":{"items":{"$ref":"#/components/schemas/openai__types__chat__chat_completion_chunk__Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion.chunk","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"anyOf":[{"$ref":"#/components/schemas/CompletionUsage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["id","choices","created","model","object"],"title":"ChatCompletionChunk"},"ChatCompletionMessage":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"type":"string","const":"assistant","title":"Role"},"annotations":{"anyOf":[{"items":{"$ref":"#/components/schemas/Annotation"},"type":"array"},{"type":"null"}],"title":"Annotations"},"audio":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionAudio"},{"type":"null"}]},"function_call":{"anyOf":[{"$ref":"#/components/schemas/FunctionCall"},{"type":"null"}]},"tool_calls":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionMessageFunctionToolCall"},{"$ref":"#/components/schemas/ChatCompletionMessageCustomToolCall"}]},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","required":["role"],"title":"ChatCompletionMessage","description":"A chat completion message generated by the model."},"ChatCompletionMessageCustomToolCall":{"properties":{"id":{"type":"string","title":"Id"},"custom":{"$ref":"#/components/schemas/Custom"},"type":{"type":"string","const":"custom","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","custom","type"],"title":"ChatCompletionMessageCustomToolCall","description":"A call to a custom tool created by the model."},"ChatCompletionMessageFunctionToolCall":{"properties":{"id":{"type":"string","title":"Id"},"function":{"$ref":"#/components/schemas/Function"},"type":{"type":"string","const":"function","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","function","type"],"title":"ChatCompletionMessageFunctionToolCall","description":"A call to a function tool created by the model."},"ChatCompletionTokenLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"},"top_logprobs":{"items":{"$ref":"#/components/schemas/TopLogprob"},"type":"array","title":"Top Logprobs"}},"additionalProperties":true,"type":"object","required":["token","logprob","top_logprobs"],"title":"ChatCompletionTokenLogprob"},"ChoiceDelta":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"function_call":{"anyOf":[{"$ref":"#/components/schemas/ChoiceDeltaFunctionCall"},{"type":"null"}]},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"anyOf":[{"type":"string","enum":["developer","system","user","assistant","tool"]},{"type":"null"}],"title":"Role"},"tool_calls":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChoiceDeltaToolCall"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","title":"ChoiceDelta","description":"A chat completion delta generated by streamed model responses."},"ChoiceDeltaFunctionCall":{"properties":{"arguments":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arguments"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"additionalProperties":true,"type":"object","title":"ChoiceDeltaFunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"ChoiceDeltaToolCall":{"properties":{"index":{"type":"integer","title":"Index"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"function":{"anyOf":[{"$ref":"#/components/schemas/ChoiceDeltaToolCallFunction"},{"type":"null"}]},"type":{"anyOf":[{"type":"string","const":"function"},{"type":"null"}],"title":"Type"}},"additionalProperties":true,"type":"object","required":["index"],"title":"ChoiceDeltaToolCall"},"ChoiceDeltaToolCallFunction":{"properties":{"arguments":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arguments"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"additionalProperties":true,"type":"object","title":"ChoiceDeltaToolCallFunction"},"ChoiceLogprobs":{"properties":{"content":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Refusal"}},"additionalProperties":true,"type":"object","title":"ChoiceLogprobs","description":"Log probability information for the choice."},"CompletionTokensDetails":{"properties":{"accepted_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accepted Prediction Tokens"},"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"rejected_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rejected Prediction Tokens"}},"additionalProperties":true,"type":"object","title":"CompletionTokensDetails","description":"Breakdown of tokens used in a completion."},"CompletionUsage":{"properties":{"completion_tokens":{"type":"integer","title":"Completion Tokens"},"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"completion_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/CompletionTokensDetails"},{"type":"null"}]},"prompt_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/PromptTokensDetails"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["completion_tokens","prompt_tokens","total_tokens"],"title":"CompletionUsage","description":"Usage statistics for the completion request."},"CreateChatCompletion":{"properties":{"messages":{"items":{},"type":"array","title":"Messages","description":"A list of messages comprising the conversation so far."},"model":{"type":"string","title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `text-generation` model type is supported."},"frequency_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Frequency Penalty","description":"Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.","default":0.0},"logit_bias":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Logit Bias","description":"Modify the likelihood of specified tokens appearing in the completion. Accepts a JSON object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token."},"logprobs":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Logprobs","description":"Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the `content` of `message`.","default":false},"top_logprobs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top Logprobs","description":"An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. `logprobs` must be set to `true` if this parameter is used."},"presence_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Presence Penalty","description":"Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.","default":0.0},"max_completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Completion Tokens","description":"An upper bound for the number of tokens that can be generated for a completion."},"n":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N","description":"How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs.","default":1},"response_format":{"anyOf":[{},{"type":"null"}],"title":"Response Format","description":"Setting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more in the Structured Outputs guide. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which ensures the message the model generates is valid JSON.
**Important**: when using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message. Without this, the model may generate an unending stream of whitespace until the generation reaches the token limit, resulting in a long-running and seemingly \"stuck\" request. Also note that the message content may be partially cut off if `finish_reason=\"length\"`, which indicates the generation exceeded `max_tokens` or the conversation exceeded the max context length."},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend."},"stop":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stop","description":"Up to 4 sequences where the API will stop generating further tokens."},"stream":{"anyOf":[{"type":"boolean","enum":[true,false]},{"type":"null"}],"title":"Stream","description":"If set, partial message deltas will be sent. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.","default":false},"stream_options":{"anyOf":[{},{"type":"null"}],"title":"Stream Options","description":"Options for streaming response. Only set this when you set `stream: true`."},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature","description":"What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both."},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P","description":"An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
We generally recommend altering this or `temperature` but not both."},"tools":{"anyOf":[{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"description":"A list of tools the model may call. Currently, only functions are supported as a tool."},{"type":"null"}],"title":"Tools"},"tool_choice":{"title":"Tool Choice","description":"Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools. Specifying a particular tool via `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.
`none` is the default when no tools are present. `auto` is the default if tools are present.","default":"none"},"parallel_tool_calls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Parallel Tool Calls","description":"Whether to call tools in parallel or sequentially. If true, the model will call tools in parallel. If false, the model will call tools sequentially. If None, the model will call tools in parallel if the model supports it, otherwise it will call tools sequentially.","default":false},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User","description":"A unique identifier representing the user."}},"additionalProperties":true,"type":"object","required":["messages","model"],"title":"CreateChatCompletion"},"CreateEmbeddingsBody":{"properties":{"input":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"items":{"items":{"type":"integer"},"type":"array","minItems":1},"type":"array"},{"type":"string"},{"items":{"type":"string"},"type":"array"}],"minLength":1,"title":"Input","description":"Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model (call `/v1/models` endpoint to get the `max_context_length` by model) and cannot be an empty string."},"model":{"type":"string","minLength":1,"title":"Model","description":"ID of the model to use. Call `/v1/models` endpoint to get the list of available models, only `text-embeddings-inference` model type is supported."},"dimensions":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Dimensions","description":"The number of dimensions the resulting output embeddings should have."},"encoding_format":{"$ref":"#/components/schemas/EncodingFormat","description":"The format of the output embeddings.","default":"float"}},"additionalProperties":true,"type":"object","required":["input","model"],"title":"CreateEmbeddingsBody"},"CreateKey":{"properties":{"name":{"type":"string","title":"Name"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["name"],"title":"CreateKey"},"CreateKeyBody":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name of the key.","examples":["key-1"]},"user":{"type":"integer","title":"User","description":"User ID to create the token for another user (by default, the current user). Required CREATE_USER permission."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Expiration time, as Unix timestamp. If None, the key never expires."}},"additionalProperties":true,"type":"object","required":["name","user"],"title":"CreateKeyBody"},"CreateOCR":{"properties":{"bbox_annotation_format":{"anyOf":[{"$ref":"#/components/schemas/ResponseFormat"},{"type":"null"}],"description":"Specify the format that the model must output for the bounding boxes. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide."},"document":{"anyOf":[{"$ref":"#/components/schemas/DocumentURLChunk"},{"$ref":"#/components/schemas/ImageURLChunk"}],"title":"Document","description":"Document to run OCR on."},"document_annotation_format":{"anyOf":[{"$ref":"#/components/schemas/ResponseFormat"},{"type":"null"}],"description":"Specify the format that the model must output for the document. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide."},"document_annotation_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Annotation Prompt","description":"Optional prompt to guide the model in extracting structured output from the entire document. A document_annotation_format must be provided."},"extract_footer":{"type":"boolean","title":"Extract Footer","description":"Whether to extract the footer of the document.","default":false},"extract_header":{"type":"boolean","title":"Extract Header","description":"Whether to extract the header of the document.","default":false},"image_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Limit","description":"Max images to extract"},"image_min_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Min Size","description":"Minimum height and width of image to extract"},"include_image_base64":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Image Base64","description":"Include image URLs in response"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"The model to use for the OCR."},"pages":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Pages","description":"Specific pages to process. Accepts a list of integers or a string of comma-separated numbers and ranges (e.g. '0,1,2' or '0-5' or '0,2-4'). Page numbers start from 0."},"table_format":{"anyOf":[{"type":"string","enum":["markdown","html"]},{"type":"null"}],"title":"Table Format","description":"Format for table extraction: 'markdown' (default) or 'html'."}},"additionalProperties":true,"type":"object","required":["document"],"title":"CreateOCR"},"CreateProviderBody":{"properties":{"type":{"$ref":"#/components/schemas/ProviderType","description":"Model provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"Model provider API url. The url must only contain the domain name (without `/v1` suffix for example). Depends of the model provider type, the url can be optional (Albert, OpenAI)."},"key":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Key","description":"Model provider API key."},"basic_auth":{"anyOf":[{"$ref":"#/components/schemas/BasicAuth"},{"type":"null"}],"description":"Model provider basic authentication."},"timeout":{"type":"integer","title":"Timeout","description":"Timeout for the model provider requests, after user receive an 503 error (model is too busy).","default":300},"model_name":{"type":"string","title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR"},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/Metric"},{"type":"null"}],"description":"The metric to use for the quality of service policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the model to create the provider for (router ID, eg. 123)."}},"additionalProperties":true,"type":"object","required":["type","model_name","router_id"],"title":"CreateProviderBody"},"CreateProviderResponse":{"properties":{"id":{"type":"integer","title":"Id","description":"Provider ID."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the router that owns the provider."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the provider."},"type":{"$ref":"#/components/schemas/ProviderType","description":"Provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"Provider API url. The url must only contain the domain name (without `/v1` suffix for example)."},"key":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Key","description":"Provider API key."},"basic_auth":{"anyOf":[{"$ref":"#/components/schemas/BasicAuth"},{"type":"null"}],"description":"Provider basic authentication."},"timeout":{"type":"integer","maximum":3600.0,"minimum":1.0,"title":"Timeout","description":"Timeout for the provider requests, after user receive an 500 error (model is too busy)."},"model_name":{"type":"string","minLength":1,"title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR","examples":["WOR"]},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the QoS policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"created":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","router_id","user_id","type","timeout","model_name"],"title":"CreateProviderResponse"},"CreateRerankBody":{"properties":{"query":{"type":"string","minLength":1,"title":"Query","description":"The search query to use for the reranking. `query` and `prompt` cannot both be provided."},"documents":{"items":{"type":"string","minLength":1},"type":"array","title":"Documents"},"model":{"type":"string","minLength":1,"title":"Model","description":"The model to use for the reranking, call `/v1/models` endpoint to get the list of available models, only `text-classification` model type is supported."},"top_n":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Top N","description":"The number of top results to return. If set to None, all results will be returned."}},"additionalProperties":true,"type":"object","required":["query","documents","model"],"title":"CreateRerankBody"},"CreateRoleBody":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"Name of the role.","examples":["my-role"]},"permissions":{"anyOf":[{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array"},{"type":"null"}],"title":"Permissions","description":"List of permissions."},"limits":{"anyOf":[{"items":{"$ref":"#/components/schemas/Limit"},"type":"array"},{"type":"null"}],"title":"Limits","description":"List of limits."}},"additionalProperties":true,"type":"object","title":"CreateRoleBody"},"CreateRouterBody":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name of the model router.","examples":["model-router-1"]},"type":{"$ref":"#/components/schemas/ModelType-Input","description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"$ref":"#/components/schemas/RouterLoadBalancingStrategy","description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","default":"shuffle"},"cost_prompt_tokens":{"type":"number","minimum":0.0,"title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)","default":0.0},"cost_completion_tokens":{"type":"number","minimum":0.0,"title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)","default":0.0}},"additionalProperties":true,"type":"object","required":["name","type"],"title":"CreateRouterBody"},"CreateToken":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"user":{"type":"integer","title":"User","description":"User ID to create the token for another user (by default, the current user). Required CREATE_USER permission."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["name","user"],"title":"CreateToken"},"CreateUserBody":{"properties":{"email":{"type":"string","maxLength":254,"minLength":1,"title":"Email","description":"The user email."},"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The user name."},"password":{"type":"string","maxLength":72,"minLength":6,"title":"Password","description":"The user password."},"role":{"type":"integer","title":"Role","description":"The role ID."},"organization_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization Id","description":"The organization ID."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The budget."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The expiration timestamp."},"priority":{"type":"integer","minimum":0.0,"title":"Priority","description":"The user priority. Higher value means higher priority.","default":0}},"additionalProperties":true,"type":"object","required":["email","password","role"],"title":"CreateUserBody"},"Custom":{"properties":{"input":{"type":"string","title":"Input"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["input","name"],"title":"Custom","description":"The custom tool that the model called."},"DocumentURLChunk":{"properties":{"document_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Name","description":"The filename of the document."},"document_url":{"type":"string","title":"Document Url","description":"The URL of the document."},"type":{"type":"string","const":"document_url","title":"Type","description":"The type of the document.","default":"document_url"}},"additionalProperties":true,"type":"object","required":["document_url"],"title":"DocumentURLChunk"},"Embedding":{"properties":{"embedding":{"items":{"type":"number"},"type":"array","title":"Embedding"},"index":{"type":"integer","title":"Index"},"object":{"type":"string","const":"embedding","title":"Object"}},"additionalProperties":true,"type":"object","required":["embedding","index","object"],"title":"Embedding","description":"Represents an embedding vector returned by embedding endpoint."},"EmbeddingsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Embedding"},"type":"array","title":"Data"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"list","title":"Object","description":"The type of object returned.","default":"list"},"usage":{"$ref":"#/components/schemas/api__domain__usage__entities__Usage","description":"Usage information for the request."},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"A unique identifier for the request."}},"additionalProperties":true,"type":"object","required":["data","model"],"title":"EmbeddingsResponse"},"EncodingFormat":{"type":"string","enum":["float","base64"],"title":"EncodingFormat"},"EndpointUsage":{"type":"string","enum":["/v1/audio/transcriptions","/v1/chat/completions","/v1/embeddings","/v1/ocr","/v1/rerank","/v1/search"],"title":"EndpointUsage"},"Function":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"Function","description":"The function that the model called."},"FunctionCall":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"FunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HostingZone":{"type":"string","enum":["ABW","AFG","AGO","AIA","ALA","ALB","AND","ARE","ARG","ARM","ASM","ATA","ATF","ATG","AUS","AUT","AZE","BDI","BEL","BEN","BES","BFA","BGD","BGR","BHR","BHS","BIH","BLM","BLR","BLZ","BMU","BOL","BRA","BRB","BRN","BTN","BVT","BWA","CAF","CAN","CCK","CHE","CHL","CHN","CIV","CMR","COD","COG","COK","COL","COM","CPV","CRI","CUB","CUW","CXR","CYM","CYP","CZE","DEU","DJI","DMA","DNK","DOM","DZA","ECU","EGY","ERI","ESH","ESP","EST","ETH","FIN","FJI","FLK","FRA","FRO","FSM","GAB","GBR","GEO","GGY","GHA","GIB","GIN","GLP","GMB","GNB","GNQ","GRC","GRD","GRL","GTM","GUF","GUM","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN","IMN","IND","IOT","IRL","IRN","IRQ","ISL","ISR","ITA","JAM","JEY","JOR","JPN","KAZ","KEN","KGZ","KHM","KIR","KNA","KOR","KWT","LAO","LBN","LBR","LBY","LCA","LIE","LKA","LSO","LTU","LUX","LVA","MAC","MAF","MAR","MCO","MDA","MDG","MDV","MEX","MHL","MKD","MLI","MLT","MMR","MNE","MNG","MNP","MOZ","MRT","MSR","MTQ","MUS","MWI","MYS","MYT","NAM","NCL","NER","NFK","NGA","NIC","NIU","NLD","NOR","NPL","NRU","NZL","OMN","PAK","PAN","PCN","PER","PHL","PLW","PNG","POL","PRI","PRK","PRT","PRY","PSE","PYF","QAT","REU","ROU","RUS","RWA","SAU","SDN","SEN","SGP","SGS","SHN","SJM","SLB","SLE","SLV","SMR","SOM","SPM","SRB","SSD","STP","SUR","SVK","SVN","SWE","SWZ","SXM","SYC","SYR","TCA","TCD","TGO","THA","TJK","TKL","TKM","TLS","TON","TTO","TUN","TUR","TUV","TWN","TZA","UGA","UKR","UMI","URY","USA","UZB","VAT","VCT","VEN","VGB","VIR","VNM","VUT","WLF","WOR","WSM","YEM","ZAF","ZMB","ZWE"],"title":"HostingZone"},"ImageURL":{"properties":{"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"The detail of the image."},"url":{"type":"string","title":"Url","description":"The URL of the image."}},"additionalProperties":true,"type":"object","required":["url"],"title":"ImageURL"},"ImageURLChunk":{"properties":{"image_url":{"anyOf":[{"$ref":"#/components/schemas/ImageURL"},{"type":"string"}],"title":"Image Url","description":"The URL of the image to OCR."},"type":{"type":"string","const":"image_url","title":"Type","description":"The type of the image.","default":"image_url"}},"additionalProperties":true,"type":"object","required":["image_url"],"title":"ImageURLChunk"},"JsonSchema":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the JSON schema."},"schema":{"additionalProperties":true,"type":"object","title":"Schema","description":"The JSON schema definition."},"strict":{"type":"boolean","title":"Strict","description":"Whether to use strict mode.","default":false},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description of the schema."}},"additionalProperties":true,"type":"object","required":["name","schema"],"title":"JsonSchema"},"Key":{"properties":{"object":{"type":"string","const":"key","title":"Object","default":"key"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"token":{"type":"string","title":"Token"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires"},"created":{"type":"integer","title":"Created"}},"additionalProperties":true,"type":"object","required":["id","name","token","created"],"title":"Key"},"Keys":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Key"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Keys"},"Limit":{"properties":{"router_id":{"type":"integer","title":"Router Id","description":"The router ID."},"type":{"$ref":"#/components/schemas/LimitType","description":"The limit type."},"value":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Value","description":"The limit value."}},"additionalProperties":true,"type":"object","required":["router_id","type"],"title":"Limit"},"LimitType":{"type":"string","enum":["tpm","tpd","rpm","rpd"],"title":"LimitType"},"Metric":{"type":"string","enum":["ttft","latency","inflight","performance","normalized_latency"],"title":"Metric"},"MetricsUsage":{"properties":{"latency":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latency"},"ttft":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttft"}},"additionalProperties":true,"type":"object","title":"MetricsUsage"},"Model":{"properties":{"object":{"type":"string","const":"model","title":"Object","description":"Type of the object.","default":"model"},"id":{"type":"string","title":"Id","description":"The model identifier, which can be referenced in the API endpoints."},"type":{"anyOf":[{"$ref":"#/components/schemas/api__domain__model__entities__ModelType"},{"type":"null"}],"description":"The type of the model, which can be used to identify the model type.","examples":["text-generation"]},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"owned_by":{"type":"string","title":"Owned By","description":"The organization that owns the model."},"max_context_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Context Length","description":"Maximum amount of tokens a context could contains. Makes sure it is the same for all models."},"costs":{"$ref":"#/components/schemas/ModelCosts","description":"Costs of the model."}},"additionalProperties":true,"type":"object","required":["id","created","owned_by"],"title":"Model"},"ModelCosts":{"properties":{"prompt_tokens":{"type":"number","minimum":0.0,"title":"Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)","default":0.0},"completion_tokens":{"type":"number","minimum":0.0,"title":"Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)","default":0.0}},"additionalProperties":true,"type":"object","title":"ModelCosts"},"ModelType-Input":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-embeddings-inference","text-generation","text-classification"],"title":"ModelType"},"ModelsResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Model"},"type":"array","title":"Data","description":"List of models."}},"additionalProperties":true,"type":"object","required":["data"],"title":"ModelsResponse"},"Nullable_OCRPageDimensions_":{"anyOf":[{"$ref":"#/components/schemas/OCRPageDimensions"},{"type":"null"}]},"Nullable_int_":{"anyOf":[{"type":"integer"},{"type":"null"}]},"Nullable_str_":{"anyOf":[{"type":"string"},{"type":"null"}]},"OCR":{"properties":{"pages":{"items":{"$ref":"#/components/schemas/OCRPageObject"},"type":"array","title":"Pages"},"model":{"type":"string","title":"Model"},"usage_info":{"$ref":"#/components/schemas/OCRUsageInfo"},"document_annotation":{"$ref":"#/components/schemas/OptionalNullable_str_","default":"~?~unset~?~sentinel~?~"},"id":{"type":"string","title":"Id","description":"The ID of the OCR request."},"usage":{"anyOf":[{"$ref":"#/components/schemas/api__schemas__usage__Usage"},{"type":"null"}],"description":"Usage information for the request."}},"type":"object","required":["pages","model","usage_info","id"],"title":"OCR"},"OCRImageObject":{"properties":{"id":{"type":"string","title":"Id"},"top_left_x":{"$ref":"#/components/schemas/Nullable_int_"},"top_left_y":{"$ref":"#/components/schemas/Nullable_int_"},"bottom_right_x":{"$ref":"#/components/schemas/Nullable_int_"},"bottom_right_y":{"$ref":"#/components/schemas/Nullable_int_"},"image_base64":{"$ref":"#/components/schemas/OptionalNullable_str_","default":"~?~unset~?~sentinel~?~"},"image_annotation":{"$ref":"#/components/schemas/OptionalNullable_str_","default":"~?~unset~?~sentinel~?~"}},"type":"object","required":["id","top_left_x","top_left_y","bottom_right_x","bottom_right_y"],"title":"OCRImageObject"},"OCRPageDimensions":{"properties":{"dpi":{"type":"integer","title":"Dpi"},"height":{"type":"integer","title":"Height"},"width":{"type":"integer","title":"Width"}},"type":"object","required":["dpi","height","width"],"title":"OCRPageDimensions"},"OCRPageObject":{"properties":{"index":{"type":"integer","title":"Index"},"markdown":{"type":"string","title":"Markdown"},"images":{"items":{"$ref":"#/components/schemas/OCRImageObject"},"type":"array","title":"Images"},"dimensions":{"$ref":"#/components/schemas/Nullable_OCRPageDimensions_"},"tables":{"anyOf":[{"items":{"$ref":"#/components/schemas/OCRTableObject"},"type":"array"},{"type":"null"}],"title":"Tables"},"hyperlinks":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Hyperlinks"},"header":{"$ref":"#/components/schemas/OptionalNullable_str_","default":"~?~unset~?~sentinel~?~"},"footer":{"$ref":"#/components/schemas/OptionalNullable_str_","default":"~?~unset~?~sentinel~?~"}},"type":"object","required":["index","markdown","images","dimensions"],"title":"OCRPageObject"},"OCRTableObject":{"properties":{"id":{"type":"string","title":"Id"},"content":{"type":"string","title":"Content"},"format":{"type":"string","enum":["markdown","html"],"title":"Format"}},"type":"object","required":["id","content","format"],"title":"OCRTableObject"},"OCRUsageInfo":{"properties":{"pages_processed":{"type":"integer","title":"Pages Processed"},"doc_size_bytes":{"$ref":"#/components/schemas/OptionalNullable_int_","default":"~?~unset~?~sentinel~?~"}},"type":"object","required":["pages_processed"],"title":"OCRUsageInfo"},"OptionalNullable_int_":{"anyOf":[{"$ref":"#/components/schemas/Nullable_int_"},{"$ref":"#/components/schemas/Unset"},{"type":"null"}]},"OptionalNullable_str_":{"anyOf":[{"$ref":"#/components/schemas/Nullable_str_"},{"$ref":"#/components/schemas/Unset"},{"type":"null"}]},"Organization":{"properties":{"object":{"type":"string","const":"organization","title":"Object","default":"organization"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"users":{"type":"integer","title":"Users"},"created":{"type":"integer","title":"Created"},"updated":{"type":"integer","title":"Updated"}},"additionalProperties":true,"type":"object","required":["id","name","users"],"title":"Organization"},"OrganizationRequest":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"The organization name."}},"additionalProperties":true,"type":"object","required":["name"],"title":"OrganizationRequest"},"OrganizationUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The new organization name."}},"additionalProperties":true,"type":"object","title":"OrganizationUpdateRequest"},"Organizations":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Organization"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Organizations"},"OrganizationsResponse":{"properties":{"id":{"type":"integer","title":"Id"}},"additionalProperties":true,"type":"object","required":["id"],"title":"OrganizationsResponse"},"PermissionType":{"type":"string","enum":["admin","create_public_collection","read_metric","provide_models"],"title":"PermissionType"},"PromptTokensDetails":{"properties":{"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"cached_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Tokens"}},"additionalProperties":true,"type":"object","title":"PromptTokensDetails","description":"Breakdown of tokens used in the prompt."},"ProviderResponse":{"properties":{"object":{"type":"string","const":"provider","title":"Object","description":"Type of the object.","default":"provider"},"id":{"type":"integer","title":"Id","description":"provider ID."},"router_id":{"type":"integer","title":"Router Id","description":"ID of the router that owns the provider."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the provider."},"type":{"$ref":"#/components/schemas/ProviderType","description":"Provider type."},"url":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Url","description":"provider API url. The url must only contain the domain name (without `/v1` suffix for example)."},"timeout":{"type":"integer","title":"Timeout","description":"Timeout for the provider requests, after user receive an 500 error (model is too busy)."},"model_name":{"type":"string","minLength":1,"title":"Model Name","description":"Model name from the model provider."},"model_hosting_zone":{"$ref":"#/components/schemas/HostingZone","description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai","default":"WOR","examples":["WOR"]},"model_total_params":{"type":"integer","minimum":0.0,"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"model_active_params":{"type":"integer","minimum":0.0,"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai","default":0},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the QoS policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."},"created":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","router_id","user_id","type","timeout","model_name","qos_metric"],"title":"ProviderResponse"},"ProviderSortField":{"type":"string","enum":["id","model_name","created"],"title":"ProviderSortField"},"ProviderType":{"type":"string","enum":["albert","openai","mistral","tei","vllm"],"title":"ProviderType"},"ProvidersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of providers."},"offset":{"type":"integer","title":"Offset","description":"Offset of the providers list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the providers list."},"data":{"items":{"$ref":"#/components/schemas/ProviderResponse"},"type":"array","title":"Data","description":"List of providers."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"ProvidersResponse"},"QoSMetric":{"type":"string","enum":["ttft","latency","inflight","performance"],"title":"QoSMetric"},"RerankResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"id":{"type":"string","title":"Id","description":"A unique identifier for the request."},"results":{"items":{"$ref":"#/components/schemas/RerankResult"},"type":"array","title":"Results","description":"The list of reranked texts."},"model":{"type":"string","title":"Model","description":"The model used to generate the reranking."},"usage":{"$ref":"#/components/schemas/api__domain__usage__entities__Usage","description":"Usage information for the request."}},"additionalProperties":true,"type":"object","required":["id","results","model"],"title":"RerankResponse"},"RerankResult":{"properties":{"relevance_score":{"type":"number","title":"Relevance Score","description":"The relevance score of the reranked text."},"index":{"type":"integer","title":"Index","description":"The index of the reranked text."}},"additionalProperties":true,"type":"object","required":["relevance_score","index"],"title":"RerankResult"},"ResponseFormat":{"properties":{"type":{"type":"string","enum":["text","json_object","json_schema"],"title":"Type","description":"Specify the format that the model must output. By default it will use `{ \"type\": \"text\" }`. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message. Setting to `{ \"type\": \"json_schema\" }` enables JSON schema mode, which guarantees the message the model generates is in JSON and follows the schema you provide.","default":"text"},"json_schema":{"anyOf":[{"$ref":"#/components/schemas/JsonSchema"},{"type":"null"}],"description":"The JSON schema definition. Required when type is 'json_schema'."}},"additionalProperties":true,"type":"object","title":"ResponseFormat"},"RoleResponse":{"properties":{"object":{"type":"string","const":"role","title":"Object","description":"Type of the object.","default":"role"},"id":{"type":"integer","title":"Id","description":"ID of the role."},"name":{"type":"string","title":"Name","description":"Name of the role."},"permissions":{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array","title":"Permissions","description":"List of permissions."},"limits":{"items":{"$ref":"#/components/schemas/Limit"},"type":"array","title":"Limits","description":"List of limits."},"users":{"type":"integer","title":"Users","description":"Number of users assigned to the role."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","permissions","limits","users","created","updated"],"title":"RoleResponse"},"RolesResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of roles."},"offset":{"type":"integer","title":"Offset","description":"Offset of the roles list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the roles list."},"data":{"items":{"$ref":"#/components/schemas/RoleResponse"},"type":"array","title":"Data","description":"List of roles."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"RolesResponse"},"RouterLoadBalancingStrategy":{"type":"string","enum":["shuffle","least_busy"],"title":"RouterLoadBalancingStrategy"},"RouterResponse":{"properties":{"object":{"type":"string","const":"router","title":"Object","description":"Type of the object.","default":"router"},"id":{"type":"integer","title":"Id","description":"ID of the router."},"name":{"type":"string","title":"Name","description":"Name of the router."},"user_id":{"type":"integer","title":"User Id","description":"ID of the user that owns the router."},"type":{"$ref":"#/components/schemas/api__schemas__models__ModelType","description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array","title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"$ref":"#/components/schemas/RouterLoadBalancingStrategy","description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","examples":["least_busy"]},"vector_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Vector Size","description":"Dimension of the vectors, if the models are embeddings. Make sure it is the same for all models."},"max_context_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Context Length","description":"Maximum amount of tokens a context could contains. Make sure it is the same for all models."},"cost_prompt_tokens":{"type":"number","title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)"},"cost_completion_tokens":{"type":"number","title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)"},"providers":{"type":"integer","title":"Providers","description":"Number of providers in the router.","default":0},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","user_id","type","aliases","load_balancing_strategy","cost_prompt_tokens","cost_completion_tokens","created","updated"],"title":"RouterResponse"},"RoutersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of routers."},"offset":{"type":"integer","title":"Offset","description":"Offset of the routers list."},"limit":{"type":"integer","title":"Limit","description":"Limit of the routers list."},"data":{"items":{"$ref":"#/components/schemas/RouterResponse"},"type":"array","title":"Data","description":"List of routers."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"RoutersResponse"},"Segment":{"properties":{"id":{"type":"integer","title":"Id","description":"A unique identifier for the segment."},"type":{"type":"string","title":"Type","description":"The type of the segment.","default":"transcript.text.segment"},"text":{"type":"string","title":"Text","description":"The segment text."},"start":{"type":"number","title":"Start","description":"Start time of the segment in seconds."},"end":{"type":"number","title":"End","description":"End time of the segment in seconds."},"speaker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker","description":"Speaker label assigned by diarization, if available."}},"additionalProperties":true,"type":"object","required":["id","text","start","end"],"title":"Segment"},"SortField":{"type":"string","enum":["id","name","created"],"title":"SortField"},"SortOrder":{"type":"string","enum":["asc","desc"],"title":"SortOrder"},"Token":{"properties":{"object":{"type":"string","const":"token","title":"Object","default":"token"},"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"token":{"type":"string","title":"Token"},"user":{"type":"integer","title":"User"},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires"},"created":{"type":"integer","title":"Created"}},"additionalProperties":true,"type":"object","required":["id","name","token","user","created"],"title":"Token"},"Tokens":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Token"},"type":"array","title":"Data"}},"additionalProperties":true,"type":"object","required":["data"],"title":"Tokens"},"TokensResponse":{"properties":{"id":{"type":"integer","title":"Id"},"token":{"type":"string","title":"Token"}},"additionalProperties":true,"type":"object","required":["id","token"],"title":"TokensResponse"},"TopLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"}},"additionalProperties":true,"type":"object","required":["token","logprob"],"title":"TopLogprob"},"Unset":{"properties":{},"type":"object","title":"Unset"},"UpdateProviderBody":{"properties":{"router_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Router Id","description":"The ID of the new router to assign to the provider."},"timeout":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timeout","description":"Timeout for the model provider requests, after user receive an 500 error (model is too busy)."},"model_hosting_zone":{"anyOf":[{"$ref":"#/components/schemas/HostingZone"},{"type":"null"}],"description":"Model hosting zone using ISO 3166-1 alpha-3 code format (e.g., `WOR` for World, `FRA` for France, `USA` for United States). This determines the electricity mix used for carbon intensity calculations. For more information, see https://ecologits.ai"},"model_total_params":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Model Total Params","description":"Total params of the model in billions of parameters for carbon footprint computation. If not provided, the active params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai"},"model_active_params":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Model Active Params","description":"Active params of the model in billions of parameters for carbon footprint computation. If not provided, the total params will be used if provided, else carbon footprint will not be computed. For more information, see https://ecologits.ai"},"qos_metric":{"anyOf":[{"$ref":"#/components/schemas/QoSMetric"},{"type":"null"}],"description":"The metric to use for the quality of service policy. If not provided, no QoS policy is applied."},"qos_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Qos Limit","description":"The value to use for the quality of service. Depends of the metric, the value can be a percentile, a threshold, etc."}},"additionalProperties":true,"type":"object","title":"UpdateProviderBody"},"UpdateRouterBody":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"Name of the model router.","examples":["model-router-1"]},"type":{"anyOf":[{"$ref":"#/components/schemas/ModelType-Input"},{"type":"null"}],"description":"Type of the model router. It will be used to identify the model router type.","examples":["text-generation"]},"aliases":{"anyOf":[{"items":{"type":"string","maxLength":64,"minLength":1},"type":"array"},{"type":"null"}],"title":"Aliases","description":"Aliases of the model. It will be used to identify the model by users.","examples":[["model-alias","model-alias-2"]]},"load_balancing_strategy":{"anyOf":[{"$ref":"#/components/schemas/RouterLoadBalancingStrategy"},{"type":"null"}],"description":"Routing strategy for load balancing between providers of the model. It will be used to identify the model type.","examples":["least_busy"]},"cost_prompt_tokens":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cost Prompt Tokens","description":"Cost of a million prompt tokens (decrease user budget)"},"cost_completion_tokens":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cost Completion Tokens","description":"Cost of a million completion tokens (decrease user budget)"}},"additionalProperties":true,"type":"object","title":"UpdateRouterBody"},"UpdateUserInfo":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The user name."},"email":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"title":"Email","description":"The user email."},"current_password":{"anyOf":[{"type":"string","maxLength":72},{"type":"null"}],"title":"Current Password","description":"The current user password."},"password":{"anyOf":[{"type":"string","maxLength":72},{"type":"null"}],"title":"Password","description":"The new user password. If None, the user password is not changed."}},"additionalProperties":true,"type":"object","title":"UpdateUserInfo"},"UsageDetail":{"properties":{"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prompt Tokens","description":"Number of prompt tokens (e.g. input tokens)."},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completion Tokens","description":"Number of completion tokens (e.g. output tokens)."},"total_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens","description":"Total number of tokens (e.g. input and output tokens)."},"cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost","description":"Total cost of the request."},"impacts":{"$ref":"#/components/schemas/api__schemas__usage__EnvironmentalImpacts"},"metrics":{"$ref":"#/components/schemas/MetricsUsage"}},"additionalProperties":true,"type":"object","title":"UsageDetail"},"Usages":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Object type.","default":"list"},"data":{"items":{"$ref":"#/components/schemas/api__schemas__me__usage__Usage"},"type":"array","title":"Data","description":"List of usages."}},"additionalProperties":true,"type":"object","required":["data"],"title":"Usages"},"UserInfo":{"properties":{"object":{"type":"string","const":"userInfo","title":"Object","description":"The user info object type.","default":"userInfo"},"id":{"type":"integer","title":"Id","description":"The user ID."},"email":{"type":"string","title":"Email","description":"The user email."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The user name."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"The user organization ID."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The user budget. If None, the user has unlimited budget."},"permissions":{"items":{"$ref":"#/components/schemas/PermissionType"},"type":"array","title":"Permissions","description":"The user permissions."},"limits":{"items":{"$ref":"#/components/schemas/Limit"},"type":"array","title":"Limits","description":"The user rate limits."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The user expiration timestamp. If None, the user will never expire."},"priority":{"type":"integer","title":"Priority","description":"The user priority (higher = higher priority). This value influences scheduling/queue priority for non-streaming model invocations.","default":0},"created":{"type":"integer","title":"Created","description":"The user creation timestamp."},"updated":{"type":"integer","title":"Updated","description":"The user update timestamp."}},"additionalProperties":true,"type":"object","required":["id","email","permissions","limits","created","updated"],"title":"UserInfo"},"UserResponse":{"properties":{"object":{"type":"string","const":"user","title":"Object","description":"Type of the object.","default":"user"},"id":{"type":"integer","title":"Id","description":"ID of the user."},"email":{"type":"string","title":"Email","description":"Email of the user."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Name of the user."},"sub":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sub","description":"Subject identifier for SSO."},"iss":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Iss","description":"Issuer identifier for SSO."},"role":{"type":"integer","title":"Role","description":"ID of the role assigned to the user."},"organization_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization Id","description":"ID of the organization the user belongs to."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"Budget allocated to the user."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Expiration time of the user, as Unix timestamp."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."},"updated":{"type":"integer","title":"Updated","description":"Time of last update, as Unix timestamp."},"priority":{"type":"integer","title":"Priority","description":"Priority of the user. Higher value means higher priority."}},"additionalProperties":true,"type":"object","required":["id","email","role","created","updated","priority"],"title":"UserResponse"},"UserSortField":{"type":"string","enum":["id","email","created","updated"],"title":"UserSortField"},"UserUpdateRequest":{"properties":{"email":{"anyOf":[{"type":"string","maxLength":254,"minLength":1},{"type":"null"}],"title":"Email","description":"The new user email. If None, the user email is not changed."},"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name","description":"The new user name. If None, the user name is not changed."},"current_password":{"anyOf":[{"type":"string","maxLength":72,"minLength":1},{"type":"null"}],"title":"Current Password","description":"The current user password."},"password":{"anyOf":[{"type":"string","maxLength":72,"minLength":1},{"type":"null"}],"title":"Password","description":"The new user password. If None, the user password is not changed."},"role":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Role","description":"The new role ID. If None, the user role is not changed."},"organization":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization","description":"The new organization ID. If None, the user will be removed from the organization if he was in one."},"budget":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget","description":"The new budget. If None, the user will have no budget."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"The new expiration timestamp. If None, the user will never expire."},"priority":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Priority","description":"The new user priority. Higher value means higher priority. If None, unchanged."}},"additionalProperties":true,"type":"object","title":"UserUpdateRequest"},"UsersResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","description":"Type of the object.","default":"list"},"total":{"type":"integer","title":"Total","description":"Total number of users matching the query."},"offset":{"type":"integer","title":"Offset","description":"Number of users skipped."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of users returned."},"data":{"items":{"$ref":"#/components/schemas/UserResponse"},"type":"array","title":"Data","description":"List of users."}},"additionalProperties":true,"type":"object","required":["total","offset","limit","data"],"title":"UsersResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"api__domain__model__entities__ModelType":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-classification","text-embeddings-inference","text-generation"],"title":"ModelType"},"api__domain__usage__entities__EnvironmentalImpacts":{"properties":{"kWh":{"type":"number","title":"Kwh","default":0.0},"kgCO2eq":{"type":"number","title":"Kgco2Eq","default":0.0}},"additionalProperties":true,"type":"object","title":"EnvironmentalImpacts"},"api__domain__usage__entities__Usage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens","default":0},"completion_tokens":{"type":"integer","title":"Completion Tokens","default":0},"total_tokens":{"type":"integer","title":"Total Tokens","default":0},"cost":{"type":"number","title":"Cost","default":0.0},"impacts":{"$ref":"#/components/schemas/api__domain__usage__entities__EnvironmentalImpacts","default":{"kWh":0.0,"kgCO2eq":0.0}}},"additionalProperties":true,"type":"object","title":"Usage"},"api__infrastructure__fastapi__documentation__HTTPExceptionModel":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"detail":{"type":"string","title":"Detail"},"headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Headers"}},"type":"object","required":["status_code","detail"],"title":"HTTPExceptionModel"},"api__infrastructure__fastapi__schemas__admin__keys__CreateKeyResponse":{"properties":{"object":{"type":"string","const":"key","title":"Object","description":"Type of the object.","default":"key"},"id":{"type":"integer","title":"Id","description":"ID of the key."},"name":{"type":"string","title":"Name","description":"Name of the key."},"value":{"type":"string","title":"Value","description":"Value of the key."},"user":{"type":"integer","title":"User","description":"ID of the user that owns the key."},"expires":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires","description":"Time of expiration, as Unix timestamp. If None, the key never expires."},"created":{"type":"integer","title":"Created","description":"Time of creation, as Unix timestamp."}},"additionalProperties":true,"type":"object","required":["id","name","value","user","created"],"title":"CreateKeyResponse"},"api__schemas__exception__HTTPExceptionModel":{"properties":{"status_code":{"type":"integer","maximum":599.0,"minimum":100.0,"title":"Status Code","description":"HTTP status code to send to the client."},"detail":{"title":"Detail","description":"Any data to be sent to the client in the `detail` key of the JSON response."},"headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Headers","description":"Any headers to send to the client in the response."}},"type":"object","required":["status_code","detail","headers"],"title":"HTTPExceptionModel"},"api__schemas__me__keys__CreateKeyResponse":{"properties":{"id":{"type":"integer","title":"Id"},"token":{"type":"string","title":"Token"}},"additionalProperties":true,"type":"object","required":["id","token"],"title":"CreateKeyResponse"},"api__schemas__me__usage__Usage":{"properties":{"object":{"type":"string","const":"me.usage","title":"Object","description":"Object type.","default":"me.usage"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Model used for the request."},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key","description":"Key used for the request."},"endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint","description":"Endpoint used for the request."},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method","description":"Method used for the request."},"status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status","description":"Status code of the response."},"usage":{"$ref":"#/components/schemas/UsageDetail"},"created":{"type":"integer","title":"Created","description":"Timestamp in seconds"}},"additionalProperties":true,"type":"object","required":["created"],"title":"Usage"},"api__schemas__models__ModelType":{"type":"string","enum":["automatic-speech-recognition","image-text-to-text","image-to-text","text-embeddings-inference","text-generation","text-classification"],"title":"ModelType"},"api__schemas__usage__EnvironmentalImpacts":{"properties":{"kWh":{"type":"number","title":"Kwh","description":"Carbon footprint in kWh.","default":0.0},"kgCO2eq":{"type":"number","title":"Kgco2Eq","description":"Carbon footprint in kgCO2eq (global warming potential).","default":0.0}},"additionalProperties":true,"type":"object","title":"EnvironmentalImpacts"},"api__schemas__usage__Usage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens","description":"Number of prompt tokens (e.g. input tokens).","default":0},"completion_tokens":{"type":"integer","title":"Completion Tokens","description":"Number of completion tokens (e.g. output tokens).","default":0},"total_tokens":{"type":"integer","title":"Total Tokens","description":"Total number of tokens (e.g. input and output tokens).","default":0},"cost":{"type":"number","title":"Cost","description":"Total cost of the request.","default":0.0},"carbon":{"$ref":"#/components/schemas/CarbonFootprintUsage","deprecated":true},"impacts":{"$ref":"#/components/schemas/api__schemas__usage__EnvironmentalImpacts"},"requests":{"type":"integer","title":"Requests","description":"Number of model requests.","default":0}},"additionalProperties":true,"type":"object","title":"Usage"},"openai__types__chat__chat_completion__Choice":{"properties":{"finish_reason":{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]},"message":{"$ref":"#/components/schemas/ChatCompletionMessage"}},"additionalProperties":true,"type":"object","required":["finish_reason","index","message"],"title":"Choice"},"openai__types__chat__chat_completion_chunk__Choice":{"properties":{"delta":{"$ref":"#/components/schemas/ChoiceDelta"},"finish_reason":{"anyOf":[{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"]},{"type":"null"}],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["delta","index"],"title":"Choice"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}
\ No newline at end of file
diff --git a/docs/package-lock.json b/docs/package-lock.json
index 70973cae0..9be4d43b8 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -17,7 +17,7 @@
"astro-contributors": "^0.8.0",
"astro-mermaid": "^2.0.1",
"mermaid": "^11.14.0",
- "sharp": "^0.34.5",
+ "sharp": "^0.35.0",
"starlight-giscus": "^0.9.1",
"starlight-ion-theme": "^2.4.0",
"starlight-links-validator": "^0.24.0",
@@ -348,9 +348,9 @@
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz",
+ "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -967,9 +967,9 @@
"license": "CC0-1.0"
},
"node_modules/@iconify/tools/node_modules/svgo": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz",
- "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==",
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.4.tgz",
+ "integrity": "sha512-GsNRis4e8jxn2Y9ENz/8lbJ93CstG8svtMnuRaHbiF2LTJ5tK0/q3t/URPq9Zc7zVWBJnNnJMIp6bevK7bSmNg==",
"license": "MIT",
"dependencies": {
"commander": "^7.2.0",
@@ -1018,9 +1018,9 @@
}
},
"node_modules/@img/sharp-darwin-arm64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
- "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.0.tgz",
+ "integrity": "sha512-ZgaYEwaj+lx/5n4W8GmZ2IYz0PQHjN5eqRcfijWGB+2Aq7ZInZGa0qJyAn6DEtyLuWHRSrmWOqT9q3qqTBvmUQ==",
"cpu": [
"arm64"
],
@@ -1030,19 +1030,19 @@
"darwin"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ "@img/sharp-libvips-darwin-arm64": "1.3.0"
}
},
"node_modules/@img/sharp-darwin-x64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
- "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.0.tgz",
+ "integrity": "sha512-c1z9LFpKB0slQW3RchwBE8iSVzGp70TNjUUO9k4BZwwW4HH7JBGHeIy4b+kk4n/kcBASb9evKCE3/7Slmslgiw==",
"cpu": [
"x64"
],
@@ -1052,19 +1052,38 @@
"darwin"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-x64": "1.2.4"
+ "@img/sharp-libvips-darwin-x64": "1.3.0"
+ }
+ },
+ "node_modules/@img/sharp-freebsd-wasm32": {
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.0.tgz",
+ "integrity": "sha512-Li2KTev0H90kEtnJHkI9xQojXt1AqWmFBMXiPw5kqd1jQgP7gi5HVK/qC5Rmh/59NuAwUuPzzPITmX22NomYYQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.0"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
- "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.0.tgz",
+ "integrity": "sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==",
"cpu": [
"arm64"
],
@@ -1078,9 +1097,9 @@
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
- "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.0.tgz",
+ "integrity": "sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==",
"cpu": [
"x64"
],
@@ -1094,12 +1113,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
- "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.0.tgz",
+ "integrity": "sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==",
"cpu": [
"arm"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1110,12 +1132,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
- "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.0.tgz",
+ "integrity": "sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==",
"cpu": [
"arm64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1126,12 +1151,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
- "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.0.tgz",
+ "integrity": "sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==",
"cpu": [
"ppc64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1142,12 +1170,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-riscv64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
- "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.0.tgz",
+ "integrity": "sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==",
"cpu": [
"riscv64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1158,12 +1189,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
- "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.0.tgz",
+ "integrity": "sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==",
"cpu": [
"s390x"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1174,12 +1208,15 @@
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
- "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.0.tgz",
+ "integrity": "sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==",
"cpu": [
"x64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1190,12 +1227,15 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
- "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.0.tgz",
+ "integrity": "sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==",
"cpu": [
"arm64"
],
+ "libc": [
+ "musl"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1206,12 +1246,15 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
- "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.0.tgz",
+ "integrity": "sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==",
"cpu": [
"x64"
],
+ "libc": [
+ "musl"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1222,204 +1265,244 @@
}
},
"node_modules/@img/sharp-linux-arm": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
- "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.0.tgz",
+ "integrity": "sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==",
"cpu": [
"arm"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm": "1.2.4"
+ "@img/sharp-libvips-linux-arm": "1.3.0"
}
},
"node_modules/@img/sharp-linux-arm64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
- "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.0.tgz",
+ "integrity": "sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==",
"cpu": [
"arm64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm64": "1.2.4"
+ "@img/sharp-libvips-linux-arm64": "1.3.0"
}
},
"node_modules/@img/sharp-linux-ppc64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
- "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.0.tgz",
+ "integrity": "sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==",
"cpu": [
"ppc64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ "@img/sharp-libvips-linux-ppc64": "1.3.0"
}
},
"node_modules/@img/sharp-linux-riscv64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
- "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.0.tgz",
+ "integrity": "sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==",
"cpu": [
"riscv64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ "@img/sharp-libvips-linux-riscv64": "1.3.0"
}
},
"node_modules/@img/sharp-linux-s390x": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
- "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.0.tgz",
+ "integrity": "sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==",
"cpu": [
"s390x"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-s390x": "1.2.4"
+ "@img/sharp-libvips-linux-s390x": "1.3.0"
}
},
"node_modules/@img/sharp-linux-x64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
- "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.0.tgz",
+ "integrity": "sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==",
"cpu": [
"x64"
],
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-x64": "1.2.4"
+ "@img/sharp-libvips-linux-x64": "1.3.0"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
- "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.0.tgz",
+ "integrity": "sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==",
"cpu": [
"arm64"
],
+ "libc": [
+ "musl"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.0"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
- "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.0.tgz",
+ "integrity": "sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==",
"cpu": [
"x64"
],
+ "libc": [
+ "musl"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.0"
}
},
"node_modules/@img/sharp-wasm32": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
- "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.0.tgz",
+ "integrity": "sha512-9woLIFORERCr+6cWu87dQ22J34EExkhc73U1kZW0c+RclQqWetoodByp4dWZ/hN8/KVmTRAx2HOnUwib8AwZdA==",
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.11.0"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-webcontainers-wasm32": {
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.0.tgz",
+ "integrity": "sha512-t+kie1TOyaDM6Dho+f+y0VqIUNhYQaKCUahuZVi0E0frgdiaOaPsDxDW3wfKacUdaNBCnK/ZDBMg33ydvHj8uA==",
"cpu": [
"wasm32"
],
- "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "license": "Apache-2.0",
"optional": true,
"dependencies": {
- "@emnapi/runtime": "^1.7.0"
+ "@img/sharp-wasm32": "0.35.0"
},
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-arm64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
- "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.0.tgz",
+ "integrity": "sha512-M5eKxug0dabbaWgFKvPa3odNs2OpaP+81NASfGKkt4GcYXpNhSu7CaeYxWkLNV6vHmUp4hnCxnxrUyhUJhXbKA==",
"cpu": [
"arm64"
],
@@ -1429,16 +1512,16 @@
"win32"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
- "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.0.tgz",
+ "integrity": "sha512-z0+pZ03QCDvdVN0Ez9IX/yjWC19ikMlXrmdYMwYNLTh2BLPx3hXWPvyqWfquZ0BTO9O6GVOjIVoTcyyacMnWlQ==",
"cpu": [
"ia32"
],
@@ -1448,16 +1531,16 @@
"win32"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": "^20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
- "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.0.tgz",
+ "integrity": "sha512-feNnlz5ZHKr0MY1LPHvZQyJeBkbo4ctsn0D8FvA53VTw5TC63rfEL2UrWbkSBR19htSE7Mw78xYVwdJqoMWVHw==",
"cpu": [
"x64"
],
@@ -1467,7 +1550,7 @@
"win32"
],
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
@@ -2682,92 +2765,641 @@
"yargs-parser": "^22.0.0",
"zod": "^4.3.6"
},
- "bin": {
- "astro": "bin/astro.mjs"
+ "bin": {
+ "astro": "bin/astro.mjs"
+ },
+ "engines": {
+ "node": ">=22.12.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/astrodotbuild"
+ },
+ "optionalDependencies": {
+ "sharp": "^0.34.0"
+ }
+ },
+ "node_modules/astro-contributors": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/astro-contributors/-/astro-contributors-0.8.0.tgz",
+ "integrity": "sha512-oz1sZ8K8Yq6bbLbhGV8e5C5Tif9+UB4oeREAqkQ3ehh4+e1OP03RXaAf2JkIhzEr+0et986MOHUO1iYt1wGZeQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=22.12.0"
+ },
+ "peerDependencies": {
+ "astro": "^6.0.0"
+ }
+ },
+ "node_modules/astro-expressive-code": {
+ "version": "0.41.7",
+ "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz",
+ "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==",
+ "license": "MIT",
+ "dependencies": {
+ "rehype-expressive-code": "^0.41.7"
+ },
+ "peerDependencies": {
+ "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta"
+ }
+ },
+ "node_modules/astro-icon": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/astro-icon/-/astro-icon-1.1.5.tgz",
+ "integrity": "sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw==",
+ "license": "MIT",
+ "dependencies": {
+ "@iconify/tools": "^4.0.5",
+ "@iconify/types": "^2.0.0",
+ "@iconify/utils": "^2.1.30"
+ }
+ },
+ "node_modules/astro-icon/node_modules/@iconify/utils": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz",
+ "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@antfu/install-pkg": "^1.0.0",
+ "@antfu/utils": "^8.1.0",
+ "@iconify/types": "^2.0.0",
+ "debug": "^4.4.0",
+ "globals": "^15.14.0",
+ "kolorist": "^1.8.0",
+ "local-pkg": "^1.0.0",
+ "mlly": "^1.7.4"
+ }
+ },
+ "node_modules/astro-mermaid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/astro-mermaid/-/astro-mermaid-2.0.1.tgz",
+ "integrity": "sha512-JTyB62FMFJpwS/1yUplmrugL0yr0flBVYZw6mf3s7pVlh+CHCeZTXyj3KCCWtFhnPLAdM+PYld0D+gxN/SysLQ==",
+ "license": "MIT",
+ "dependencies": {
+ "import-meta-resolve": "^4.2.0",
+ "mdast-util-to-string": "^4.0.0",
+ "unist-util-visit": "^5.0.0"
+ },
+ "peerDependencies": {
+ "@mermaid-js/layout-elk": "^0.2.0",
+ "astro": ">=4",
+ "mermaid": "^10.0.0 || ^11.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@mermaid-js/layout-elk": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
},
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.4"
+ }
+ },
+ "node_modules/astro/node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=22.12.0",
- "npm": ">=9.6.5",
- "pnpm": ">=7.1.0"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/astrodotbuild"
+ "url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "sharp": "^0.34.0"
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
}
},
- "node_modules/astro-contributors": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/astro-contributors/-/astro-contributors-0.8.0.tgz",
- "integrity": "sha512-oz1sZ8K8Yq6bbLbhGV8e5C5Tif9+UB4oeREAqkQ3ehh4+e1OP03RXaAf2JkIhzEr+0et986MOHUO1iYt1wGZeQ==",
- "license": "MIT",
+ "node_modules/astro/node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=22.12.0"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependencies": {
- "astro": "^6.0.0"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
}
},
- "node_modules/astro-expressive-code": {
- "version": "0.41.7",
- "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz",
- "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==",
- "license": "MIT",
+ "node_modules/astro/node_modules/@img/sharp-wasm32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
"dependencies": {
- "rehype-expressive-code": "^0.41.7"
+ "@emnapi/runtime": "^1.7.0"
},
- "peerDependencies": {
- "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta"
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/astro-icon": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/astro-icon/-/astro-icon-1.1.5.tgz",
- "integrity": "sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw==",
- "license": "MIT",
- "dependencies": {
- "@iconify/tools": "^4.0.5",
- "@iconify/types": "^2.0.0",
- "@iconify/utils": "^2.1.30"
+ "node_modules/astro/node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/astro-icon/node_modules/@iconify/utils": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz",
- "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==",
- "license": "MIT",
- "dependencies": {
- "@antfu/install-pkg": "^1.0.0",
- "@antfu/utils": "^8.1.0",
- "@iconify/types": "^2.0.0",
- "debug": "^4.4.0",
- "globals": "^15.14.0",
- "kolorist": "^1.8.0",
- "local-pkg": "^1.0.0",
- "mlly": "^1.7.4"
+ "node_modules/astro/node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/astro-mermaid": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/astro-mermaid/-/astro-mermaid-2.0.1.tgz",
- "integrity": "sha512-JTyB62FMFJpwS/1yUplmrugL0yr0flBVYZw6mf3s7pVlh+CHCeZTXyj3KCCWtFhnPLAdM+PYld0D+gxN/SysLQ==",
- "license": "MIT",
+ "node_modules/astro/node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/astro/node_modules/sharp": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
"dependencies": {
- "import-meta-resolve": "^4.2.0",
- "mdast-util-to-string": "^4.0.0",
- "unist-util-visit": "^5.0.0"
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.7.3"
},
- "peerDependencies": {
- "@mermaid-js/layout-elk": "^0.2.0",
- "astro": ">=4",
- "mermaid": "^10.0.0 || ^11.0.0"
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependenciesMeta": {
- "@mermaid-js/layout-elk": {
- "optional": true
- }
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.5",
+ "@img/sharp-darwin-x64": "0.34.5",
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
+ "@img/sharp-libvips-linux-arm": "1.2.4",
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
+ "@img/sharp-libvips-linux-x64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+ "@img/sharp-linux-arm": "0.34.5",
+ "@img/sharp-linux-arm64": "0.34.5",
+ "@img/sharp-linux-ppc64": "0.34.5",
+ "@img/sharp-linux-riscv64": "0.34.5",
+ "@img/sharp-linux-s390x": "0.34.5",
+ "@img/sharp-linux-x64": "0.34.5",
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
+ "@img/sharp-linuxmusl-x64": "0.34.5",
+ "@img/sharp-wasm32": "0.34.5",
+ "@img/sharp-win32-arm64": "0.34.5",
+ "@img/sharp-win32-ia32": "0.34.5",
+ "@img/sharp-win32-x64": "0.34.5"
}
},
"node_modules/axobject-query": {
@@ -7783,9 +8415,9 @@
}
},
"node_modules/semver": {
- "version": "7.7.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -7813,47 +8445,47 @@
}
},
"node_modules/sharp": {
- "version": "0.34.5",
- "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
- "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
- "hasInstallScript": true,
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.0.tgz",
+ "integrity": "sha512-BqvG5XbwPZ4NV0DK90d86leEECMsoa8bO0nqnKWlBDYxri4GJ7c4EDInaF6q20lTh/mATmnDIKWJFfXnoVfH5g==",
"license": "Apache-2.0",
"dependencies": {
- "@img/colour": "^1.0.0",
+ "@img/colour": "^1.1.0",
"detect-libc": "^2.1.2",
- "semver": "^7.7.3"
+ "semver": "^7.8.4"
},
"engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ "node": ">=20.9.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-darwin-arm64": "0.34.5",
- "@img/sharp-darwin-x64": "0.34.5",
- "@img/sharp-libvips-darwin-arm64": "1.2.4",
- "@img/sharp-libvips-darwin-x64": "1.2.4",
- "@img/sharp-libvips-linux-arm": "1.2.4",
- "@img/sharp-libvips-linux-arm64": "1.2.4",
- "@img/sharp-libvips-linux-ppc64": "1.2.4",
- "@img/sharp-libvips-linux-riscv64": "1.2.4",
- "@img/sharp-libvips-linux-s390x": "1.2.4",
- "@img/sharp-libvips-linux-x64": "1.2.4",
- "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
- "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
- "@img/sharp-linux-arm": "0.34.5",
- "@img/sharp-linux-arm64": "0.34.5",
- "@img/sharp-linux-ppc64": "0.34.5",
- "@img/sharp-linux-riscv64": "0.34.5",
- "@img/sharp-linux-s390x": "0.34.5",
- "@img/sharp-linux-x64": "0.34.5",
- "@img/sharp-linuxmusl-arm64": "0.34.5",
- "@img/sharp-linuxmusl-x64": "0.34.5",
- "@img/sharp-wasm32": "0.34.5",
- "@img/sharp-win32-arm64": "0.34.5",
- "@img/sharp-win32-ia32": "0.34.5",
- "@img/sharp-win32-x64": "0.34.5"
+ "@img/sharp-darwin-arm64": "0.35.0",
+ "@img/sharp-darwin-x64": "0.35.0",
+ "@img/sharp-freebsd-wasm32": "0.35.0",
+ "@img/sharp-libvips-darwin-arm64": "1.3.0",
+ "@img/sharp-libvips-darwin-x64": "1.3.0",
+ "@img/sharp-libvips-linux-arm": "1.3.0",
+ "@img/sharp-libvips-linux-arm64": "1.3.0",
+ "@img/sharp-libvips-linux-ppc64": "1.3.0",
+ "@img/sharp-libvips-linux-riscv64": "1.3.0",
+ "@img/sharp-libvips-linux-s390x": "1.3.0",
+ "@img/sharp-libvips-linux-x64": "1.3.0",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.0",
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.0",
+ "@img/sharp-linux-arm": "0.35.0",
+ "@img/sharp-linux-arm64": "0.35.0",
+ "@img/sharp-linux-ppc64": "0.35.0",
+ "@img/sharp-linux-riscv64": "0.35.0",
+ "@img/sharp-linux-s390x": "0.35.0",
+ "@img/sharp-linux-x64": "0.35.0",
+ "@img/sharp-linuxmusl-arm64": "0.35.0",
+ "@img/sharp-linuxmusl-x64": "0.35.0",
+ "@img/sharp-webcontainers-wasm32": "0.35.0",
+ "@img/sharp-win32-arm64": "0.35.0",
+ "@img/sharp-win32-ia32": "0.35.0",
+ "@img/sharp-win32-x64": "0.35.0"
}
},
"node_modules/shebang-command": {
@@ -8172,9 +8804,9 @@
}
},
"node_modules/svgo": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
- "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz",
+ "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==",
"license": "MIT",
"dependencies": {
"commander": "^11.1.0",
@@ -8206,9 +8838,9 @@
}
},
"node_modules/tar": {
- "version": "7.5.13",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz",
- "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==",
+ "version": "7.5.21",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.21.tgz",
+ "integrity": "sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
@@ -8375,9 +9007,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "7.25.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz",
- "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==",
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.2.tgz",
+ "integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"
diff --git a/docs/package.json b/docs/package.json
index 380a3e5e1..d33c8cc3d 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -18,7 +18,7 @@
"astro": "^6.2.1",
"astro-mermaid": "^2.0.1",
"mermaid": "^11.14.0",
- "sharp": "^0.34.5",
+ "sharp": "^0.35.0",
"astro-contributors": "^0.8.0",
"starlight-giscus": "^0.9.1",
"starlight-ion-theme": "^2.4.0",
diff --git a/docs/redoc-static.html b/docs/redoc-static.html
index cb11060fb..4e90c3fb0 100644
--- a/docs/redoc-static.html
+++ b/docs/redoc-static.html
@@ -12,7 +12,7 @@
margin: 0;
}
-