diff --git a/.github/workflows/image-scan.yml b/.github/workflows/image-scan.yml index d769b6ab8af..47c1dd9de26 100644 --- a/.github/workflows/image-scan.yml +++ b/.github/workflows/image-scan.yml @@ -20,7 +20,6 @@ on: - backend/Dockerfile - backend/main.py - litellm-rust/** - - litellm/proxy/lens/** - docker/component_entrypoint.sh - docker/entrypoint.sh - litellm/proxy/prisma_migration.py @@ -131,7 +130,7 @@ jobs: persist-credentials: false - name: Build runtime image - run: docker build --build-arg LITELLM_RELEASE_TAG=v0.0.0-lens-ci -f "${{ matrix.dockerfile }}" -t litellm-runtime-scan:${{ github.sha }} . + run: docker build --build-arg LITELLM_RELEASE_TAG=v0.0.0-ci -f "${{ matrix.dockerfile }}" -t litellm-runtime-scan:${{ github.sha }} . - name: Tag the cached builder for Admin MCP schema setup run: docker build --target builder -f "${{ matrix.dockerfile }}" -t litellm-admin-mcp-schema:${{ github.sha }} . diff --git a/.github/workflows/test-rust.yml b/.github/workflows/test-rust.yml index cf9fed192f6..b894089bb97 100644 --- a/.github/workflows/test-rust.yml +++ b/.github/workflows/test-rust.yml @@ -6,10 +6,6 @@ on: - "litellm-rust/**" - "model_prices_and_context_window.json" - "litellm/rust_bridge/**" - - "scripts/generate_trace_types.py" - - "scripts/trace_codegen/**" - - "scripts/lens_assets/**" - - "litellm/tracing/**" - "tests/test_litellm_rust/**" - "litellm/integrations/custom_logger.py" - "litellm/litellm_core_utils/litellm_logging.py" @@ -41,10 +37,6 @@ on: - "litellm-rust/**" - "model_prices_and_context_window.json" - "litellm/rust_bridge/**" - - "scripts/generate_trace_types.py" - - "scripts/trace_codegen/**" - - "scripts/lens_assets/**" - - "litellm/tracing/**" - "tests/test_litellm_rust/**" - "litellm/integrations/custom_logger.py" - "litellm/litellm_core_utils/litellm_logging.py" @@ -158,10 +150,6 @@ jobs: with: version: "v0.18.0" - - name: Check generated trace contracts - working-directory: . - run: uv run scripts/generate_trace_types.py --check - - run: cargo nextest run --workspace --locked - run: cargo test --workspace --doc --locked diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index fb29a92e306..9f3c8922098 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -956,7 +956,6 @@ jobs: - shard: endpoints-and-responses test-path: |- tests/unit/proxy/test_proxy_server_exception_mapping.py - tests/unit/proxy/lens tests/unit/proxy/auth/test_models_fallback_endpoint.py tests/unit/proxy/common_utils/test_check_batch_cost.py tests/unit/proxy/common_utils/test_check_responses_cost.py @@ -979,16 +978,6 @@ jobs: timeout-minutes: 15 job-timeout-minutes: 60 dist: loadscope - - - shard: lens-python-310 - test-path: >- - tests/unit/proxy/lens - python-version: "3.10" - workers: 0 - reruns: 0 - timeout-minutes: 5 - job-timeout-minutes: 60 - dist: loadscope steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 timeout-minutes: 3 diff --git a/backend/routes/allowlist.py b/backend/routes/allowlist.py index 2d3ccf40175..f89ea55a8fe 100644 --- a/backend/routes/allowlist.py +++ b/backend/routes/allowlist.py @@ -86,9 +86,6 @@ BACKEND_PATH_PREFIXES: tuple[str, ...] = ( # Spend / analytics "/spend/", "/analytics/", - "/lens/", - "/v1/traces", - "/v1/logs", "/global/", "/user_agent", "/usage/", @@ -153,7 +150,6 @@ BACKEND_EXACT_PATHS: frozenset[str] = frozenset( { "/", "/routes", - "/lens", "/openapi.json", "/docs", "/docs/oauth2-redirect", diff --git a/codecov.yaml b/codecov.yaml index 521088868bd..6c954c829b5 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -70,10 +70,6 @@ flag_management: carryforward: false - name: responses-caching-types carryforward: false - - name: lens-python-310 - carryforward: false - - name: lens-postgres - carryforward: false - name: proxy-db-key-generation carryforward: false - name: proxy-db-auth-checks diff --git a/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/grafana_dashboard.json b/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/grafana_dashboard.json index cedbbd0f07b..996e440d77d 100644 --- a/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/grafana_dashboard.json +++ b/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/grafana_dashboard.json @@ -6563,87 +6563,6 @@ ], "title": "litellm_project_model_rate_limit_used_metric", "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 447 - }, - "id": 115, - "panels": [], - "title": "Agent tracing export (needs LITELLM_LENS_URL)", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Request records the Lens exporter delivered to the Lens service against the records it dropped before the service accepted them", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineWidth": 1, - "showPoints": "never", - "spanNulls": false - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 448 - }, - "id": 116, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "sum(rate(litellm_lens_export_rows_written_total[$__rate_interval]))", - "legendFormat": "written", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "sum(rate(litellm_lens_export_rows_dropped_total[$__rate_interval]))", - "legendFormat": "dropped", - "range": true, - "refId": "B" - } - ], - "title": "litellm_lens_export_rows_written and litellm_lens_export_rows_dropped rate", - "type": "timeseries" } ], "preload": false, diff --git a/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/readme.md b/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/readme.md index dcac5db6dc0..bcbbc4ebaf3 100644 --- a/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/readme.md +++ b/cookbook/litellm_proxy_server/grafana_dashboard/dashboard_all_metrics/readme.md @@ -1,10 +1,10 @@ # LiteLLM All Prometheus Metrics dashboard -Every `litellm_*` metric family the proxy can expose on `/metrics` (143 families across 98 panels), grouped into rows: proxy traffic, latency, spend and tokens, cache, LLM API deployments, key and team rate limits, budgets, guardrails, MCP, managed files and batches, users and teams, the Redis circuit breaker, the spend log cleanup job, the `prometheus_system` service callback metrics (per-service latency, request and failure rates, spend update queue sizes), project model rate limits, and the agent tracing export to Lens. Panel titles are the metric names so you can grep the JSON for the metric you care about +Every `litellm_*` metric family the proxy can expose on `/metrics`, grouped into rows: proxy traffic, latency, spend and tokens, cache, LLM API deployments, key and team rate limits, budgets, guardrails, MCP, managed files and batches, users and teams, the Redis circuit breaker, the spend log cleanup job, the `prometheus_system` service callback metrics (per-service latency, request and failure rates, spend update queue sizes), and project model rate limits. Panel titles are the metric names so you can grep the JSON for the metric you care about Import `grafana_dashboard.json` from **Dashboards > New > Import** and pick your Prometheus data source when prompted (the `DS_PROMETHEUS` variable). Counters are plotted as `rate()` over `$__rate_interval`, histograms as p50 / p95 / p99, gauges as the raw value grouped by the most useful label. Every query names the metric exactly as the proxy emits it (counters carry the `_total` suffix the Prometheus client adds), and `tests/unit/integrations/test_prometheus_metric_name_consistency.py` fails if a metric is renamed without updating this dashboard -The first eleven rows and the project model rate limits row need only `callbacks: ["prometheus"]`. The other rows and the `litellm_admission_*` panels are emitted by other subsystems and stay empty until those are on: the service callback row needs `service_callback: ["prometheus_system"]` in `litellm_settings`, the circuit breaker row needs a Redis cache, the cleanup row needs spend log retention, the agent tracing export row needs `LITELLM_LENS_URL`, and admission control needs its middleware enabled. Within the base rows, many panels only fill in once the matching feature is in use: budgets need keys, teams, users or orgs with `max_budget` set, cache panels need caching on, guardrail and MCP panels need those features configured, deployment health needs the router with more than one deployment or a failure to record, and `litellm_in_flight_requests` needs traffic at scrape time. An empty panel for a feature you do not use is expected +The first eleven rows and the project model rate limits row need only `callbacks: ["prometheus"]`. The other rows and the `litellm_admission_*` panels are emitted by other subsystems and stay empty until those are on: the service callback row needs `service_callback: ["prometheus_system"]` in `litellm_settings`, the circuit breaker row needs a Redis cache, the cleanup row needs spend log retention, and admission control needs its middleware enabled. Within the base rows, many panels only fill in once the matching feature is in use: budgets need keys, teams, users or orgs with `max_budget` set, cache panels need caching on, guardrail and MCP panels need those features configured, deployment health needs the router with more than one deployment or a failure to record, and `litellm_in_flight_requests` needs traffic at scrape time. An empty panel for a feature you do not use is expected ## Pre-requisites diff --git a/docker/docker-compose.tracing.yml b/docker/docker-compose.tracing.yml deleted file mode 100644 index d28d84e61dc..00000000000 --- a/docker/docker-compose.tracing.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: litellm-tracing - -services: - litellm: - build: - context: .. - target: runtime - args: - LITELLM_RELEASE_TAG: ${LITELLM_RELEASE_TAG:-} - command: ["--config", "/app/tracing-config.yaml", "--port", "4000"] - environment: - LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY:?set LITELLM_MASTER_KEY} - LITELLM_SALT_KEY: sk-local-tracing-salt-key - DATABASE_URL: postgresql://litellm:litellm@db:5432/litellm - STORE_MODEL_IN_DB: "True" - LITELLM_LENS_URL: ${LITELLM_LENS_URL:?set the Lens URL reachable from the gateway container} - LITELLM_LENS_PUBLIC_URL: ${LITELLM_LENS_PUBLIC_URL:?set the Lens URL reachable from your browser and agents} - LITELLM_LENS_SERVICE_TOKEN: ${LITELLM_LENS_SERVICE_TOKEN:?set LITELLM_LENS_SERVICE_TOKEN} - LENS_GATEWAY_SECRET: ${LENS_GATEWAY_SECRET:?set the same signing secret on Lens and the gateway} - OPENAI_API_KEY: ${OPENAI_API_KEY:-} - volumes: - - ./tracing-config.yaml:/app/tracing-config.yaml:ro - ports: - - "127.0.0.1:4002:4000" - depends_on: - db: - condition: service_healthy - - db: - image: postgres:16 - environment: - POSTGRES_DB: litellm - POSTGRES_USER: litellm - POSTGRES_PASSWORD: litellm - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - "127.0.0.1:15432:5432" - healthcheck: - test: ["CMD-SHELL", "pg_isready -U litellm -d litellm"] - interval: 5s - timeout: 5s - retries: 10 - -volumes: - postgres_data: diff --git a/docker/tracing-config.yaml b/docker/tracing-config.yaml deleted file mode 100644 index 7cdd10b4e35..00000000000 --- a/docker/tracing-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -model_list: - - model_name: gpt-6.1-sol - litellm_params: - model: openai/gpt-6.1-sol - api_key: os.environ/OPENAI_API_KEY - -general_settings: - master_key: os.environ/LITELLM_MASTER_KEY - tracing: - store: - type: lens diff --git a/gateway/routes/allowlist.py b/gateway/routes/allowlist.py index c2740ac1d41..1b51c739f26 100644 --- a/gateway/routes/allowlist.py +++ b/gateway/routes/allowlist.py @@ -79,8 +79,6 @@ GATEWAY_PATH_PREFIXES: tuple[str, ...] = ( "/v1/containers", "/containers", "/v1/evals", - "/v1/traces", - "/v1/logs", "/v1/memory", "/queue/chat/", # Google data plane (v1beta is the Google AI Studio version) diff --git a/helm/litellm-helm/README.md b/helm/litellm-helm/README.md index bc6e29632f1..1e5c7348112 100644 --- a/helm/litellm-helm/README.md +++ b/helm/litellm-helm/README.md @@ -255,9 +255,9 @@ it would need to update the `config.yaml` file which is a exposed ConfigMap, and therefore, read-only. This is a limitation of this helm chart, not the Admin UI itself. -## Connect Lens +## Removed Lens configuration -This chart does not deploy Lens. Deploy Lens from [its own chart](https://github.com/BerriAI/lens/tree/main/helm/lens), then set `lens.enabled: true`, `lens.url`, `lens.publicUrl`, `lens.gatewaySecret.name` and `lens.serviceTokenSecret.name`. The secret keys default to `gateway-secret` and `service-token`. Set `lens.service.name` when that Lens runs in this release's namespace and the chart ingress should route `/lens-ingest` to it. The old `lensWorker` values are no longer read, and enabling them fails the render +The external Lens integration has been removed. Existing `lens` and `lensWorker` values are ignored with a warning in the release notes. Remove these obsolete values when updating your configuration. ## Shutdown accounting diff --git a/helm/litellm-helm/templates/NOTES.txt b/helm/litellm-helm/templates/NOTES.txt index 017bbfa78bd..5b2174cb6e6 100644 --- a/helm/litellm-helm/templates/NOTES.txt +++ b/helm/litellm-helm/templates/NOTES.txt @@ -20,4 +20,8 @@ echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT {{- end }} -PDB: {{ if .Values.pdb.enabled }}enabled{{ else }}disabled{{ end }}. Configure via .Values.pdb.* \ No newline at end of file +PDB: {{ if .Values.pdb.enabled }}enabled{{ else }}disabled{{ end }}. Configure via .Values.pdb.* + +{{- if or (hasKey .Values "lens") (hasKey .Values "lensWorker") }} +WARNING: The Lens integration has been removed. lens and lensWorker values are ignored. Remove these obsolete values. +{{- end }} diff --git a/helm/litellm-helm/templates/_helpers.tpl b/helm/litellm-helm/templates/_helpers.tpl index 230d2acaeef..cceccd87261 100644 --- a/helm/litellm-helm/templates/_helpers.tpl +++ b/helm/litellm-helm/templates/_helpers.tpl @@ -371,29 +371,3 @@ shutdown drain window. value: {{ .drainTimeoutSeconds | quote }} {{- end }} {{- end -}} - -{{- define "litellm.lensConnectionEnv" -}} -{{- with .Values.lensWorker }} -{{- if or .enabled (and .mode (ne .mode "disabled")) }} -{{- fail "lensWorker was removed; deploy Lens from its own chart and set lens.* instead, see the chart README" }} -{{- end }} -{{- end }} -{{- with .Values.lens }} -{{- if .enabled }} -- name: LITELLM_LENS_URL - value: {{ required "lens.url is required when lens.enabled is true" .url | quote }} -- name: LITELLM_LENS_PUBLIC_URL - value: {{ required "lens.publicUrl is required when lens.enabled is true" .publicUrl | quote }} -- name: LENS_GATEWAY_SECRET - valueFrom: - secretKeyRef: - name: {{ required "lens.gatewaySecret.name is required when lens.enabled is true" .gatewaySecret.name | quote }} - key: {{ .gatewaySecret.key | quote }} -- name: LITELLM_LENS_SERVICE_TOKEN - valueFrom: - secretKeyRef: - name: {{ required "lens.serviceTokenSecret.name is required when lens.enabled is true" .serviceTokenSecret.name | quote }} - key: {{ .serviceTokenSecret.key | quote }} -{{- end }} -{{- end }} -{{- end -}} diff --git a/helm/litellm-helm/templates/deployment.yaml b/helm/litellm-helm/templates/deployment.yaml index a37193f0efa..623c44f7d64 100644 --- a/helm/litellm-helm/templates/deployment.yaml +++ b/helm/litellm-helm/templates/deployment.yaml @@ -56,7 +56,6 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: - {{- include "litellm.lensConnectionEnv" . | nindent 12 }} {{- include "litellm.proxyEnv" . | nindent 12 }} {{- if .Values.liteadmin.enabled }} - name: LITELLM_ADMIN_AGENT_URL diff --git a/helm/litellm-helm/templates/ingress.yaml b/helm/litellm-helm/templates/ingress.yaml index 3d6e3f4af7a..ea9ffcbb54c 100644 --- a/helm/litellm-helm/templates/ingress.yaml +++ b/helm/litellm-helm/templates/ingress.yaml @@ -44,20 +44,6 @@ spec: - host: {{ .host | quote }} http: paths: - {{- if and $.Values.lens.enabled $.Values.lens.service.name }} - - path: /lens-ingest - pathType: Prefix - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $.Values.lens.service.name }} - port: - number: {{ $.Values.lens.service.port }} - {{- else }} - serviceName: {{ $.Values.lens.service.name }} - servicePort: {{ $.Values.lens.service.port }} - {{- end }} - {{- end }} {{- range .paths }} - path: {{ .path }} {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} diff --git a/helm/litellm-helm/tests/lens_connection_tests.yaml b/helm/litellm-helm/tests/lens_connection_tests.yaml index e01e49d0ffc..9d0bcf96290 100644 --- a/helm/litellm-helm/tests/lens_connection_tests.yaml +++ b/helm/litellm-helm/tests/lens_connection_tests.yaml @@ -1,128 +1,35 @@ -suite: lens connection +suite: retired Lens configuration templates: - deployment.yaml - configmap-litellm.yaml - - ingress.yaml tests: - - it: connects the proxy to an external Lens + - it: renders deployment.yaml with ignored lens.enabled and no Lens secret references template: deployment.yaml set: lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service asserts: - - contains: + - notContains: path: spec.template.spec.containers[0].env content: name: LITELLM_LENS_URL - value: http://lens.lens.svc:4318 - - contains: - path: spec.template.spec.containers[0].env - content: - name: LITELLM_LENS_PUBLIC_URL - value: https://lens.example.com/lens-ingest - - contains: + any: true + - notContains: path: spec.template.spec.containers[0].env content: name: LENS_GATEWAY_SECRET - valueFrom: - secretKeyRef: - name: lens-gateway - key: gateway-secret - - contains: + any: true + - it: renders deployment.yaml with ignored lensWorker.enabled and no Lens secret references + template: deployment.yaml + set: + lensWorker.enabled: true + asserts: + - notContains: path: spec.template.spec.containers[0].env content: - name: LITELLM_LENS_SERVICE_TOKEN - valueFrom: - secretKeyRef: - name: lens-service - key: service-token - - - it: requires lens.url when Lens is enabled - template: deployment.yaml - set: - lens.enabled: true - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.url is required when lens.enabled is true - - - it: requires lens.publicUrl when Lens is enabled - template: deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.publicUrl is required when lens.enabled is true - - - it: requires lens.gatewaySecret.name when Lens is enabled - template: deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.gatewaySecret.name is required when lens.enabled is true - - - it: requires lens.serviceTokenSecret.name when Lens is enabled - template: deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - asserts: - - failedTemplate: - errorMessage: lens.serviceTokenSecret.name is required when lens.enabled is true - - - it: routes /lens-ingest to the named Lens service ahead of the host paths - template: ingress.yaml - set: - ingress.enabled: true - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - lens.service.name: existing-lens - asserts: - - equal: - path: spec.rules[0].http.paths[0].path - value: /lens-ingest - - contains: - path: spec.rules[0].http.paths - content: - path: /lens-ingest - pathType: Prefix - backend: - service: - name: existing-lens - port: - number: 4318 - - - it: leaves /lens-ingest off the ingress without a Lens service name - template: ingress.yaml - set: - ingress.enabled: true - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - exists: - path: spec.rules[0].http.paths - - notContains: - path: spec.rules[0].http.paths - content: - path: /lens-ingest + name: LITELLM_LENS_URL + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: LENS_GATEWAY_SECRET any: true diff --git a/helm/litellm-helm/values.yaml b/helm/litellm-helm/values.yaml index 9afce050261..85d9b69308c 100644 --- a/helm/litellm-helm/values.yaml +++ b/helm/litellm-helm/values.yaml @@ -660,17 +660,3 @@ serviceMonitor: namespaceSelector: matchNames: [] # - test-namespace - -lens: - enabled: false - url: "" - publicUrl: "" - service: - name: "" - port: 4318 - gatewaySecret: - name: "" - key: gateway-secret - serviceTokenSecret: - name: "" - key: service-token diff --git a/helm/litellm/README.md b/helm/litellm/README.md index d66bb3284bf..3fc63f0aaba 100644 --- a/helm/litellm/README.md +++ b/helm/litellm/README.md @@ -2,7 +2,7 @@ This chart deploys separate gateway, backend and UI services -This chart does not deploy Lens. Deploy Lens from [its own chart](https://github.com/BerriAI/lens/tree/main/helm/lens), then set `lens.enabled: true`, `lens.url`, `lens.publicUrl`, `lens.gatewaySecret.name` and `lens.serviceTokenSecret.name`. The secret keys default to `gateway-secret` and `service-token`. Set `lens.service.name` when that Lens runs in this release's namespace and the chart ingress should route `/lens-ingest` to it. The old `lensWorker` values are no longer read, and enabling them fails the render +The external Lens integration has been removed. Existing `lens` and `lensWorker` values are ignored with a warning in the release notes. Remove these obsolete values when updating your configuration. For an ingress with separate component hostnames, set all three `ingress.componentHosts` values, leave `ingress.host` and `ingress.extraPaths` empty, configure `ui.backendUrl` as the backend's public origin and `backend.gatewayUrl` as the gateway's public origin, and set `ui.publicUrl` to the browser-facing UI origin. The UI Deployment receives `LITELLM_BACKEND_URL` from `ui.backendUrl` only when `ingress.componentHosts` is configured. diff --git a/helm/litellm/templates/NOTES.txt b/helm/litellm/templates/NOTES.txt index 135dcb876e0..3ee699f835a 100644 --- a/helm/litellm/templates/NOTES.txt +++ b/helm/litellm/templates/NOTES.txt @@ -56,3 +56,7 @@ Reminders: - {component}.topologySpreadConstraints (standard k8s list, e.g. spread replicas across topology.kubernetes.io/zone) - Enable ingress.enabled=true to dispatch / → ui, gateway data-plane prefixes → gateway, and the catch-all → backend. + +{{- if or (hasKey .Values "lens") (hasKey .Values "lensWorker") }} +WARNING: The Lens integration has been removed. lens and lensWorker values are ignored. Remove these obsolete values. +{{- end }} diff --git a/helm/litellm/templates/_helpers.tpl b/helm/litellm/templates/_helpers.tpl index b704782f5d1..099509d85ea 100644 --- a/helm/litellm/templates/_helpers.tpl +++ b/helm/litellm/templates/_helpers.tpl @@ -600,29 +600,3 @@ shutdown drain window. value: {{ .drainTimeoutSeconds | quote }} {{- end }} {{- end -}} - -{{- define "litellm.lensConnectionEnv" -}} -{{- with .Values.lensWorker }} -{{- if or .enabled (and .mode (ne .mode "disabled")) }} -{{- fail "lensWorker was removed; deploy Lens from its own chart and set lens.* instead, see the chart README" }} -{{- end }} -{{- end }} -{{- with .Values.lens }} -{{- if .enabled }} -- name: LITELLM_LENS_URL - value: {{ required "lens.url is required when lens.enabled is true" .url | quote }} -- name: LITELLM_LENS_PUBLIC_URL - value: {{ required "lens.publicUrl is required when lens.enabled is true" .publicUrl | quote }} -- name: LENS_GATEWAY_SECRET - valueFrom: - secretKeyRef: - name: {{ required "lens.gatewaySecret.name is required when lens.enabled is true" .gatewaySecret.name | quote }} - key: {{ .gatewaySecret.key | quote }} -- name: LITELLM_LENS_SERVICE_TOKEN - valueFrom: - secretKeyRef: - name: {{ required "lens.serviceTokenSecret.name is required when lens.enabled is true" .serviceTokenSecret.name | quote }} - key: {{ .serviceTokenSecret.key | quote }} -{{- end }} -{{- end }} -{{- end -}} diff --git a/helm/litellm/templates/backend/deployment.yaml b/helm/litellm/templates/backend/deployment.yaml index 7db14ad87a5..450ec957c5e 100644 --- a/helm/litellm/templates/backend/deployment.yaml +++ b/helm/litellm/templates/backend/deployment.yaml @@ -59,7 +59,6 @@ spec: containerPort: 4001 protocol: TCP env: - {{- include "litellm.lensConnectionEnv" . | nindent 12 }} {{- if .Values.ui.publicUrl }} - name: LITELLM_CORS_ORIGINS value: {{ include "litellm.ui.publicOrigin" . | quote }} diff --git a/helm/litellm/templates/gateway/deployment.yaml b/helm/litellm/templates/gateway/deployment.yaml index 987109e361e..b849636274f 100644 --- a/helm/litellm/templates/gateway/deployment.yaml +++ b/helm/litellm/templates/gateway/deployment.yaml @@ -55,7 +55,6 @@ spec: containerPort: 4000 protocol: TCP env: - {{- include "litellm.lensConnectionEnv" . | nindent 12 }} {{- if .Values.ui.publicUrl }} - name: LITELLM_CORS_ORIGINS value: {{ include "litellm.ui.publicOrigin" . | quote }} diff --git a/helm/litellm/templates/ingress.yaml b/helm/litellm/templates/ingress.yaml index 9f778e78087..b8c965cc90f 100644 --- a/helm/litellm/templates/ingress.yaml +++ b/helm/litellm/templates/ingress.yaml @@ -166,15 +166,6 @@ spec: - host: {{ $componentHosts.gateway | quote }} http: paths: - {{- if and .Values.lens.enabled .Values.lens.service.name }} - - path: /lens-ingest - pathType: Prefix - backend: - service: - name: {{ .Values.lens.service.name }} - port: - number: {{ .Values.lens.service.port }} - {{- end }} - path: / pathType: Prefix backend: @@ -249,16 +240,6 @@ spec: port: number: {{ $gatewayPort }} {{- end }} - {{- if and .Values.lens.enabled .Values.lens.service.name }} - {{- $builtinPathKeys = append $builtinPathKeys "/lens-ingest|Prefix" }} - - path: /lens-ingest - pathType: Prefix - backend: - service: - name: {{ .Values.lens.service.name }} - port: - number: {{ .Values.lens.service.port }} - {{- end }} {{- /* --- Operator-supplied extra paths (ingress.extraPaths) --- Rendered after every built-in path so an entry can never take diff --git a/helm/litellm/tests/component_hosts_tests.yaml b/helm/litellm/tests/component_hosts_tests.yaml index b55b3b694a0..2ebbbcae964 100644 --- a/helm/litellm/tests/component_hosts_tests.yaml +++ b/helm/litellm/tests/component_hosts_tests.yaml @@ -73,7 +73,7 @@ tests: port: number: 4000 - - it: keeps Lens ingestion ahead of the gateway catch-all + - it: keeps the gateway catch-all when obsolete Lens values are supplied set: ingress.enabled: true ingress.componentHosts.ui: ui.example.com @@ -91,13 +91,10 @@ tests: asserts: - equal: path: spec.rules[2].http.paths[0].path - value: /lens-ingest + value: / - equal: path: spec.rules[2].http.paths[0].backend.service.name - value: existing-lens - - equal: - path: spec.rules[2].http.paths[1].path - value: / + value: RELEASE-NAME-litellm-gateway template: ingress.yaml - it: rejects a partial component host configuration diff --git a/helm/litellm/tests/lens_connection_tests.yaml b/helm/litellm/tests/lens_connection_tests.yaml index 2b7c32d50cc..35288d19bb7 100644 --- a/helm/litellm/tests/lens_connection_tests.yaml +++ b/helm/litellm/tests/lens_connection_tests.yaml @@ -1,166 +1,68 @@ -suite: lens connection +suite: retired Lens configuration templates: - gateway/deployment.yaml - backend/deployment.yaml - gateway/configmap.yaml - - ingress.yaml values: - ./values/required.yaml tests: - - it: connects the gateway to an external Lens + - it: renders gateway/deployment.yaml with ignored lens.enabled and no Lens secret references template: gateway/deployment.yaml set: lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service asserts: - - contains: + - notContains: path: spec.template.spec.containers[0].env content: name: LITELLM_LENS_URL - value: http://lens.lens.svc:4318 - - contains: - path: spec.template.spec.containers[0].env - content: - name: LITELLM_LENS_PUBLIC_URL - value: https://lens.example.com/lens-ingest - - contains: + any: true + - notContains: path: spec.template.spec.containers[0].env content: name: LENS_GATEWAY_SECRET - valueFrom: - secretKeyRef: - name: lens-gateway - key: gateway-secret - - contains: + any: true + - it: renders gateway/deployment.yaml with ignored lensWorker.enabled and no Lens secret references + template: gateway/deployment.yaml + set: + lensWorker.enabled: true + asserts: + - notContains: path: spec.template.spec.containers[0].env content: - name: LITELLM_LENS_SERVICE_TOKEN - valueFrom: - secretKeyRef: - name: lens-service - key: service-token - - - it: connects the backend to an external Lens + name: LITELLM_LENS_URL + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: LENS_GATEWAY_SECRET + any: true + - it: renders backend/deployment.yaml with ignored lens.enabled and no Lens secret references template: backend/deployment.yaml set: lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service asserts: - - contains: + - notContains: path: spec.template.spec.containers[0].env content: name: LITELLM_LENS_URL - value: http://lens.lens.svc:4318 - - contains: - path: spec.template.spec.containers[0].env - content: - name: LITELLM_LENS_PUBLIC_URL - value: https://lens.example.com/lens-ingest - - contains: + any: true + - notContains: path: spec.template.spec.containers[0].env content: name: LENS_GATEWAY_SECRET - valueFrom: - secretKeyRef: - name: lens-gateway - key: gateway-secret - - contains: + any: true + - it: renders backend/deployment.yaml with ignored lensWorker.enabled and no Lens secret references + template: backend/deployment.yaml + set: + lensWorker.enabled: true + asserts: + - notContains: path: spec.template.spec.containers[0].env content: - name: LITELLM_LENS_SERVICE_TOKEN - valueFrom: - secretKeyRef: - name: lens-service - key: service-token - - - it: requires lens.url when Lens is enabled - template: gateway/deployment.yaml - set: - lens.enabled: true - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.url is required when lens.enabled is true - - - it: requires lens.publicUrl when Lens is enabled - template: gateway/deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.publicUrl is required when lens.enabled is true - - - it: requires lens.gatewaySecret.name when Lens is enabled - template: gateway/deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.serviceTokenSecret.name: lens-service - asserts: - - failedTemplate: - errorMessage: lens.gatewaySecret.name is required when lens.enabled is true - - - it: requires lens.serviceTokenSecret.name when Lens is enabled - template: gateway/deployment.yaml - set: - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - asserts: - - failedTemplate: - errorMessage: lens.serviceTokenSecret.name is required when lens.enabled is true - - - it: routes /lens-ingest to the named Lens service on the single ingress host - template: ingress.yaml - set: - ingress.enabled: true - ingress.host: litellm.example.com - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - lens.service.name: existing-lens - asserts: - - contains: - path: spec.rules[0].http.paths - content: - path: /lens-ingest - pathType: Prefix - backend: - service: - name: existing-lens - port: - number: 4318 - - - it: leaves /lens-ingest off the ingress without a Lens service name - template: ingress.yaml - set: - ingress.enabled: true - ingress.host: litellm.example.com - lens.enabled: true - lens.url: http://lens.lens.svc:4318 - lens.publicUrl: https://lens.example.com/lens-ingest - lens.gatewaySecret.name: lens-gateway - lens.serviceTokenSecret.name: lens-service - asserts: - - exists: - path: spec.rules[0].http.paths - - notContains: - path: spec.rules[0].http.paths - content: - path: /lens-ingest + name: LITELLM_LENS_URL + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: LENS_GATEWAY_SECRET any: true diff --git a/helm/litellm/values.yaml b/helm/litellm/values.yaml index cb37656cb77..18fa3e2646a 100644 --- a/helm/litellm/values.yaml +++ b/helm/litellm/values.yaml @@ -643,17 +643,3 @@ ui: affinity: {} # Same shape as gateway.topologySpreadConstraints. topologySpreadConstraints: [] - -lens: - enabled: false - url: "" - publicUrl: "" - service: - name: "" - port: 4318 - gatewaySecret: - name: "" - key: gateway-secret - serviceTokenSecret: - name: "" - key: service-token diff --git a/litellm-rust/Cargo.lock b/litellm-rust/Cargo.lock index ed658e074ee..a974a604c73 100644 --- a/litellm-rust/Cargo.lock +++ b/litellm-rust/Cargo.lock @@ -4422,7 +4422,6 @@ dependencies = [ "litellm-storage-clickhouse", "litellm-token-counter", "litellm-tracing", - "prost", "pyo3", "pyo3-async-runtimes", "reqwest", diff --git a/litellm-rust/crates/python-bridge/Cargo.toml b/litellm-rust/crates/python-bridge/Cargo.toml index 48206d242e4..04641c85f80 100644 --- a/litellm-rust/crates/python-bridge/Cargo.toml +++ b/litellm-rust/crates/python-bridge/Cargo.toml @@ -64,7 +64,6 @@ litellm-model-catalog-refresh.workspace = true litellm-token-counter = { path = "../token-counter", default-features = false } indexmap = "2.14.0" pyo3 = { workspace = true, features = ["indexmap"] } -prost.workspace = true pyo3-async-runtimes.workspace = true reqwest.workspace = true serde_json.workspace = true diff --git a/litellm-rust/crates/python-bridge/src/lib.rs b/litellm-rust/crates/python-bridge/src/lib.rs index 7edf13035c1..a93b76276f8 100644 --- a/litellm-rust/crates/python-bridge/src/lib.rs +++ b/litellm-rust/crates/python-bridge/src/lib.rs @@ -89,8 +89,6 @@ mod _native { use crate::routes::responses::{ResponsesWebSocketConnection, aresponses, responses}; #[pymodule_export] use crate::routes::token_counter::TokenCounter; - #[pymodule_export] - use crate::routes::traces::trace_encode_error; #[cfg(feature = "huggingface")] #[pymodule_export] use crate::tokenizer::HuggingFaceEncoding; @@ -171,7 +169,6 @@ mod tests { "NativeClickHouseSpendConfig", "NativeClickHouseSpendStorage", "NativeDatabase", - "trace_encode_error", "bundled_model_cost_map", "NativeModelCostMap", "NativeModelCostMapState", diff --git a/litellm-rust/crates/python-bridge/src/routes/mod.rs b/litellm-rust/crates/python-bridge/src/routes/mod.rs index f51c755c33e..04fe6d4e210 100644 --- a/litellm-rust/crates/python-bridge/src/routes/mod.rs +++ b/litellm-rust/crates/python-bridge/src/routes/mod.rs @@ -7,7 +7,6 @@ pub(crate) mod messages; pub(crate) mod ocr; pub(crate) mod responses; pub(crate) mod token_counter; -pub(crate) mod traces; use litellm_callbacks_legacy_python::{LegacyLogging, LoggingOperation, PublicCall}; use litellm_host::{call::HostedCompletion, machine::Machine, protocol::Protocol}; diff --git a/litellm-rust/crates/python-bridge/src/routes/traces.rs b/litellm-rust/crates/python-bridge/src/routes/traces.rs deleted file mode 100644 index 8346cf37f87..00000000000 --- a/litellm-rust/crates/python-bridge/src/routes/traces.rs +++ /dev/null @@ -1,33 +0,0 @@ -use prost::Message; -use pyo3::{prelude::*, types::PyBytes}; - -#[derive(Message)] -struct OtlpErrorStatus { - #[prost(int32, tag = "1")] - code: i32, - #[prost(string, tag = "2")] - message: String, -} - -#[pyfunction] -pub fn trace_encode_error<'py>(py: Python<'py>, message: &str) -> Bound<'py, PyBytes> { - let status = OtlpErrorStatus { - code: 0, - message: message.to_owned(), - }; - PyBytes::new(py, &status.encode_to_vec()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[rstest::rstest] - fn error_status_preserves_otlp_wire_contract() { - Python::initialize(); - Python::attach(|py| { - let encoded = trace_encode_error(py, "invalid trace"); - assert_eq!(encoded.as_bytes(), b"\x12\x0dinvalid trace"); - }); - } -} diff --git a/litellm/constants.py b/litellm/constants.py index 8df92c46630..b41fd103de3 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -103,19 +103,6 @@ CLICKHOUSE_MAX_BUFFERED_ROWS: Final = get_env_int("CLICKHOUSE_MAX_BUFFERED_ROWS" CLICKHOUSE_MAX_RETRIES: Final = get_env_int("CLICKHOUSE_MAX_RETRIES", 3) DEFAULT_CLICKHOUSE_DATABASE: Final = "litellm" DEFAULT_AGENT_TRACING_RETENTION_DAYS: Final = 14 -OTLP_MAX_BODY_BYTES: Final = get_env_int("OTLP_MAX_BODY_BYTES", 16 * 1024 * 1024) -OTLP_MAX_ATTRIBUTE_VALUE_BYTES: Final = get_env_int("OTLP_MAX_ATTRIBUTE_VALUE_BYTES", 64 * 1024) -OTLP_RETRY_AFTER_SECONDS: Final = get_env_int("OTLP_RETRY_AFTER_SECONDS", 2) -TRACE_READ_RETRY_AFTER_SECONDS: Final = get_env_int("TRACE_READ_RETRY_AFTER_SECONDS", 2) -OTLP_MAX_CONCURRENT_INGESTS: Final = get_env_int("OTLP_MAX_CONCURRENT_INGESTS", 2) -AGENT_TRACING_INPUT_PREVIEW_CHARS: Final = get_env_int("AGENT_TRACING_INPUT_PREVIEW_CHARS", 240) -AGENT_TRACING_LIST_PAGE_SIZE: Final = get_env_int("AGENT_TRACING_LIST_PAGE_SIZE", 50) -AGENT_TRACING_AGENT_LIST_LIMIT: Final = get_env_int("AGENT_TRACING_AGENT_LIST_LIMIT", 500) -LENS_DATASET_MAX_CASES: Final = get_env_int("LENS_DATASET_MAX_CASES", 200) -LENS_DATASET_MAX_CASE_CHARS: Final = get_env_int("LENS_DATASET_MAX_CASE_CHARS", 20_000) -LENS_DATASET_TRACE_PAGE_SIZE: Final = 500 -LENS_FEEDBACK_MAX_COMMENT_CHARS: Final = 10_000 -LENS_FEEDBACK_MAX_SCORE: Final = 10 DEFAULT_S3_FLUSH_INTERVAL_SECONDS: Final = get_env_int("DEFAULT_S3_FLUSH_INTERVAL_SECONDS", 10) DEFAULT_S3_BATCH_SIZE: Final = get_env_int("DEFAULT_S3_BATCH_SIZE", 512) DEFAULT_S3_MAX_CONCURRENT_UPLOADS: Final = get_env_int("DEFAULT_S3_MAX_CONCURRENT_UPLOADS", 16) diff --git a/litellm/integrations/clickhouse/clickhouse_spend_logger.py b/litellm/integrations/clickhouse/clickhouse_spend_logger.py index ef7442143ca..5f5ba6ad18b 100644 --- a/litellm/integrations/clickhouse/clickhouse_spend_logger.py +++ b/litellm/integrations/clickhouse/clickhouse_spend_logger.py @@ -18,13 +18,12 @@ import litellm from litellm._logging import verbose_logger from litellm.constants import ROUTER_USAGE_COUNTED_TOKENS_METADATA_KEY, USAGE_BASED_ROUTING_COUNTED_TOKENS_METADATA_KEY from litellm.integrations.clickhouse.clickhouse_batch_logger import ClickHouseBatchLogger -from litellm.integrations.clickhouse.context import is_lens_analysis from litellm.integrations.clickhouse.schema import SPEND_LOGS_TABLE +from litellm.integrations.clickhouse.types import SpendLogPayload, SpendLogRecord from litellm.litellm_core_utils.core_helpers import require_attributes from litellm.litellm_core_utils.internal_call_metadata import logged_event_key from litellm.litellm_core_utils.llm_response_utils.get_headers import get_provider_request_id from litellm.litellm_core_utils.sensitive_data_masker import redact_credentials_in_payload -from litellm.tracing.types import SpendLogPayload, SpendLogRecord from litellm.types.utils import StandardLoggingPayload # litellm_logging.py rewrites cache-hit ids as f"{id}_cache_hit{time.time()}" @@ -34,7 +33,6 @@ _CACHE_HIT_SUFFIX: Final = re.compile(r"_cache_hit[0-9.]*$") _TRACEPARENT: Final = re.compile(r"^[0-9a-f]{2}-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$") _INVALID_TRACE_ID: Final = "0" * 32 _INVALID_SPAN_ID: Final = "0" * 16 -TRACE_INGEST_ROUTE: Final = "/v1/traces" _METADATA_MAPPING: Final = TypeAdapter(Mapping[str, object]) _METADATA_VALUE: Final = TypeAdapter(JsonValue) _INTERNAL_METADATA_KEYS: Final = frozenset( @@ -146,11 +144,6 @@ def _session_id(payload: StandardLoggingPayload | SpendLogPayload, kwargs: Mappi ) -def _is_trace_ingest(payload: StandardLoggingPayload) -> bool: - """OTLP exports to POST /v1/traces are not LLM requests; don't write them as spend rows.""" - return str(payload.get("call_type") or "").startswith(TRACE_INGEST_ROUTE) - - def spend_log_row_from_payload( payload: StandardLoggingPayload | SpendLogPayload, kwargs: Mapping[str, object] ) -> SpendLogRecord: @@ -224,7 +217,6 @@ def spend_log_row_from_payload( { **request_metadata, **metadata, - "litellm_lens_internal": is_lens_analysis(), **({} if track_end_user else {"user_api_key_end_user_id": None}), } ) @@ -246,7 +238,7 @@ class ClickHouseSpendLogger(ClickHouseBatchLogger): def _log(self, kwargs: Mapping[str, Any]) -> None: try: payload = kwargs.get("standard_logging_object") - if payload is None or _is_trace_ingest(payload): + if payload is None: return row: Final = spend_log_row_from_payload(payload, kwargs) self.enqueue([dict(row)]) diff --git a/litellm/integrations/clickhouse/context.py b/litellm/integrations/clickhouse/context.py deleted file mode 100644 index d7873f1e1aa..00000000000 --- a/litellm/integrations/clickhouse/context.py +++ /dev/null @@ -1,19 +0,0 @@ -from collections.abc import Iterator -from contextlib import contextmanager -from contextvars import ContextVar -from typing import Final - -_lens_analysis: Final = ContextVar("litellm_lens_analysis", default=False) - - -def is_lens_analysis() -> bool: - return _lens_analysis.get() - - -@contextmanager -def lens_analysis() -> Iterator[None]: - token: Final = _lens_analysis.set(True) - try: - yield - finally: - _lens_analysis.reset(token) diff --git a/litellm/tracing/types.py b/litellm/integrations/clickhouse/types.py similarity index 81% rename from litellm/tracing/types.py rename to litellm/integrations/clickhouse/types.py index 43490f285c2..cc01b38181a 100644 --- a/litellm/tracing/types.py +++ b/litellm/integrations/clickhouse/types.py @@ -1,29 +1,7 @@ from collections.abc import Mapping, Sequence -from datetime import datetime -from pydantic import ConfigDict, Field from typing_extensions import NotRequired, ReadOnly, TypedDict -from litellm.types.llms.base import LiteLLMBaseModel - - -class TraceAgent(LiteLLMBaseModel): - """One agent seen in the caller's traces, for picking which agent's runs to look at.""" - - model_config = ConfigDict(frozen=True) - - name: str - runs: int = Field(ge=0) - failed_runs: int = Field(ge=0) - last_seen: datetime - frameworks: tuple[str, ...] = () - - -class TraceAgentList(LiteLLMBaseModel): - model_config = ConfigDict(frozen=True) - - agents: tuple[TraceAgent, ...] - class SpendLogPayload(TypedDict, total=False): id: ReadOnly[str | None] diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html index 5be386c8fc1..6dae2b2c62a 100644 --- a/litellm/proxy/_experimental/out/404.html +++ b/litellm/proxy/_experimental/out/404.html @@ -1 +1 @@ -