diff --git a/docs/configuration.md b/docs/configuration.md index a9fd5fa..f8e5900 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -94,6 +94,36 @@ Remote MCP lets coding agents use Currents tools over HTTP at `/mc | `OAUTH_JWKS_URL` | string | `/api/auth/jwks` | Where the API fetches its own signing keys to check access tokens. With a `.localhost` `APP_BASE_URL`, set `http://localhost:4000/api/auth/jwks`: the container cannot resolve `.localhost` names, so every token is rejected. Set the same when the container cannot reach or trust `APP_BASE_URL` (split DNS, an internal CA) | | `OAUTH_RATE_LIMIT_REGISTER_MAX`, `OAUTH_RATE_LIMIT_TOKEN_MAX`, `OAUTH_RATE_LIMIT_AUTHORIZE_MAX`, `OAUTH_RATE_LIMIT_USERINFO_MAX` | int | `5`, `20`, `30`, `60` | OAuth requests per client address per 60 seconds, on top of `BETTER_AUTH_RATE_LIMIT_MAX` | +### AI Explanations and Chat (Optional) + +The `ai-queue-worker` service runs the AI tasks (test explanations, chat) from the `ai-bmq` queue. `webhooks` does not run AI tasks. + +The service is off by default, because it needs an LLM endpoint you provide. AI stays off for an organization until an admin grants AI consent in its settings, so turn the worker on first: AI tasks requested without it wait in the queue and never finish. To turn it on, add to `.env`: + +```bash +COMPOSE_PROFILES=ai +AI_QUEUE_WORKER_ENABLED=true +``` + +- `COMPOSE_PROFILES=ai` starts `ai-queue-worker` with `docker compose up -d`. With TLS, set `COMPOSE_PROFILES=tls,ai` and run `docker compose up -d` without `--profile tls`: a `--profile` flag replaces `COMPOSE_PROFILES`, so `--profile tls` starts Traefik but not the worker. +- `AI_QUEUE_WORKER_ENABLED=true` has the scheduler build the MongoDB indexes for the AI collections, including the ones that expire old AI sessions. In `webhooks` it also starts the Slack AI answer worker, unless `SLACK_AI_CALLBACK_WORKER_ENABLED` is set. + +Then set the LLM endpoint below and run `docker compose up -d`. The worker reads these variables from `.env`, as do all services. + +To turn the worker off, remove `ai` from `COMPOSE_PROFILES` and run `docker compose rm -sf ai-queue-worker`. `docker compose up -d` does not stop a service whose profile is no longer listed, so the worker keeps running with its old settings. + +| Variable | Type | Default | Description | +|----------|------|---------|-------------| +| `LLM_PROVIDER_URL` | string | `http://localhost:4001/v1` | Base URL of an OpenAI-compatible API | +| `LLM_API_KEY` | string | _(empty)_ | API key for the LLM provider | +| `LLM_MODEL` | string | `gpt-6-luna` | Model for chat and run-analysis sessions | +| `LLM_EXPLANATION_MODEL` | string | `gpt-6-luna` | Model for test and error explanations | +| `LLM_REASONING_EFFORT` | string | `medium` | `none`, `low`, `medium` or `high`; any other value falls back to `medium` | +| `LLM_EXPLANATION_REASONING_EFFORT` | string | `LLM_REASONING_EFFORT` | Reasoning effort for explanations; same values | +| `EXPLANATION_TRACE_TOOLS` | bool | `false` | `true`: error explanations read the Playwright trace of the failed attempt | +| `AI_QUEUE_CONCURRENCY` | int | `5` | AI tasks run at the same time | +| `USE_MOCK_AI` | bool | `false` | Return mock answers without calling an LLM (testing) | + ### SAML SSO (Optional) Enable SAML single sign-on by setting the two required variables and mounting your IdP metadata file into `./data/sso`. See [Enable SAML SSO](sso-saml.md) for the full walkthrough. SSO turns on automatically once both required variables are set — there is no separate enable flag. diff --git a/docs/container-images.md b/docs/container-images.md index e521ed4..9689f62 100644 --- a/docs/container-images.md +++ b/docs/container-images.md @@ -36,7 +36,9 @@ Create an IAM role in your AWS account with the following policy: "arn:aws:ecr:us-east-1:513558712013:currents/on-prem/writer/*", "arn:aws:ecr:us-east-1:513558712013:repository/currents/on-prem/writer", "arn:aws:ecr:us-east-1:513558712013:currents/on-prem/webhooks/*", - "arn:aws:ecr:us-east-1:513558712013:repository/currents/on-prem/webhooks" + "arn:aws:ecr:us-east-1:513558712013:repository/currents/on-prem/webhooks", + "arn:aws:ecr:us-east-1:513558712013:currents/on-prem/ai-queue-worker/*", + "arn:aws:ecr:us-east-1:513558712013:repository/currents/on-prem/ai-queue-worker" ] } ] @@ -76,7 +78,7 @@ TARGET_REGISTRY=your-registry.example.com/currents TAG=staging # or specific version tag # List of Currents services -SERVICES="api director change-streams scheduler writer webhooks" +SERVICES="api director change-streams scheduler writer webhooks ai-queue-worker" # Pull, tag, and push each image for service in $SERVICES; do @@ -155,7 +157,7 @@ SOURCE_REGISTRY=ghcr.io/currents-dev/currents- TARGET_REGISTRY=your-registry.example.com/currents/ TAG=staging -SERVICES="api director change-streams scheduler writer webhooks" +SERVICES="api director change-streams scheduler writer webhooks ai-queue-worker" for service in $SERVICES; do docker pull ${SOURCE_REGISTRY}${service}:${TAG} diff --git a/on-prem/.env.example b/on-prem/.env.example index a32d50a..b24a3c2 100644 --- a/on-prem/.env.example +++ b/on-prem/.env.example @@ -184,6 +184,29 @@ OAUTH_DYNAMIC_CLIENT_REGISTRATION_ENABLED=true # OAUTH_RATE_LIMIT_AUTHORIZE_MAX=30 # OAUTH_RATE_LIMIT_USERINFO_MAX=60 +# ============================================================================= +# AI explanations and chat (Optional) +# ============================================================================= +# The ai-queue-worker service runs the AI tasks (test explanations, chat). It is +# off by default because it needs an LLM endpoint. Turn it on before an +# organization admin grants AI consent; without it, AI tasks wait in the queue. +# With TLS, set COMPOSE_PROFILES=tls,ai and start without --profile tls: a +# --profile flag replaces COMPOSE_PROFILES, and the worker would not start. +# To turn it off, remove ai from COMPOSE_PROFILES and run +# docker compose rm -sf ai-queue-worker: docker compose up -d leaves it running. +# COMPOSE_PROFILES=ai # Starts ai-queue-worker +# AI_QUEUE_WORKER_ENABLED=true # Scheduler builds the AI collections' indexes +# +# LLM_PROVIDER_URL is the base URL of an OpenAI-compatible API. +# LLM_PROVIDER_URL=https://llm.example.com/v1 +# LLM_API_KEY= +# LLM_MODEL= +# LLM_EXPLANATION_MODEL= +# LLM_REASONING_EFFORT= +# LLM_EXPLANATION_REASONING_EFFORT= +# EXPLANATION_TRACE_TOOLS= +# AI_QUEUE_CONCURRENCY=5 # AI tasks run at the same time + # ============================================================================= # SAML SSO (Optional) # ============================================================================= diff --git a/on-prem/CHANGELOG.md b/on-prem/CHANGELOG.md index 596e2b5..5811d21 100644 --- a/on-prem/CHANGELOG.md +++ b/on-prem/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Compose File Changes +- New service `ai-queue-worker` in all three compose files, in the `ai` profile, so it does not start unless you turn it on. It runs the AI tasks (test explanations, chat) from the `ai-bmq` queue. Regenerate your compose file if you use custom templates. + +### Added +- Image `ai-queue-worker`. To turn the worker on, pull or mirror it with the other images (see [Container Image Access](../docs/container-images.md)), and add the `currents/on-prem/ai-queue-worker` repository to your ECR policy. + +### Upgrade Notes +- `webhooks` no longer runs AI tasks, and `ai-queue-worker` is off by default. **If you use AI today, it stops at this upgrade until you turn the worker on:** add `COMPOSE_PROFILES=ai` to `.env` (`COMPOSE_PROFILES=tls,ai` with TLS, and then start without `--profile tls`, which replaces it), and keep `AI_QUEUE_WORKER_ENABLED=true` and your `LLM_*` settings, which the worker reads from the same `.env`. See AI Explanations and Chat in the [Configuration Reference](../docs/configuration.md). +- `AI_QUEUE_WORKER_ENABLED=true` has the scheduler build the MongoDB indexes for the AI collections. In `webhooks` it now only starts the Slack AI answer worker, and only when `SLACK_AI_CALLBACK_WORKER_ENABLED` is unset. + ## [2026-10-14-002] - 2026-10-27 Image-only update on `2026-10-14-001`: no compose file or environment variable changes. diff --git a/on-prem/README.md b/on-prem/README.md index 5b6fcc3..f099ddf 100644 --- a/on-prem/README.md +++ b/on-prem/README.md @@ -120,6 +120,7 @@ Utility for generating secrets and keys. - **write-worker** - Async write operations - **scheduler** - Scheduled tasks and startup migrations - **webhooks** - Webhook delivery service +- **ai-queue-worker** - Runs AI tasks (test explanations, chat) from the `ai-bmq` queue (enabled with the `ai` profile) #### Data Services (optional, based on profile) diff --git a/on-prem/docker-compose.cache.yml b/on-prem/docker-compose.cache.yml index 1e0564f..2f01ad2 100644 --- a/on-prem/docker-compose.cache.yml +++ b/on-prem/docker-compose.cache.yml @@ -147,6 +147,24 @@ services: redis: condition: service_started required: false + # Runs the AI tasks from the ai-bmq queue. Reads the LLM_* settings from .env. + ai-queue-worker: + image: ${DC_CURRENTS_IMAGE_REPOSITORY:-currents-}ai-queue-worker:${DC_CURRENTS_IMAGE_TAG:-staging} + restart: unless-stopped + # Off by default: it needs an LLM endpoint. Start it with COMPOSE_PROFILES=ai + # in .env (see docs/configuration.md). + profiles: + - ai + networks: + - default + env_file: + - .env + environment: + CURRENTS_ENV: onprem + depends_on: + redis: + condition: service_started + required: false traefik: hostname: traefik image: ${DC_TRAEFIK_IMAGE:-traefik:v3.3} diff --git a/on-prem/docker-compose.database.yml b/on-prem/docker-compose.database.yml index 158565c..3478bc1 100644 --- a/on-prem/docker-compose.database.yml +++ b/on-prem/docker-compose.database.yml @@ -169,6 +169,27 @@ services: redis: condition: service_started required: false + # Runs the AI tasks from the ai-bmq queue. Reads the LLM_* settings from .env. + ai-queue-worker: + image: ${DC_CURRENTS_IMAGE_REPOSITORY:-currents-}ai-queue-worker:${DC_CURRENTS_IMAGE_TAG:-staging} + restart: unless-stopped + # Off by default: it needs an LLM endpoint. Start it with COMPOSE_PROFILES=ai + # in .env (see docs/configuration.md). + profiles: + - ai + networks: + - default + env_file: + - .env + environment: + CURRENTS_ENV: onprem + depends_on: + mongodb: + condition: service_healthy + required: false + redis: + condition: service_started + required: false traefik: hostname: traefik image: ${DC_TRAEFIK_IMAGE:-traefik:v3.3} diff --git a/on-prem/docker-compose.full.yml b/on-prem/docker-compose.full.yml index 4262cca..9cf3f78 100644 --- a/on-prem/docker-compose.full.yml +++ b/on-prem/docker-compose.full.yml @@ -175,6 +175,28 @@ services: redis: condition: service_started required: false + # Runs the AI tasks from the ai-bmq queue. Reads the LLM_* settings from .env. + ai-queue-worker: + image: ${DC_CURRENTS_IMAGE_REPOSITORY:-currents-}ai-queue-worker:${DC_CURRENTS_IMAGE_TAG:-staging} + restart: unless-stopped + # Off by default: it needs an LLM endpoint. Start it with COMPOSE_PROFILES=ai + # in .env (see docs/configuration.md). + profiles: + - ai + networks: + - default + env_file: + - .env + environment: + CURRENTS_ENV: onprem + FILE_STORAGE_FORCE_PATH_STYLE: "true" + depends_on: + mongodb: + condition: service_healthy + required: false + redis: + condition: service_started + required: false # Enable RustFS storage routing in Traefik traefik: hostname: traefik diff --git a/on-prem/templates/compose.currents.yml b/on-prem/templates/compose.currents.yml index 1e8cc2e..7cff7fb 100644 --- a/on-prem/templates/compose.currents.yml +++ b/on-prem/templates/compose.currents.yml @@ -116,6 +116,21 @@ services: CURRENTS_ENV: onprem EMAIL_TRANSPORTER: smtp + # Runs the AI tasks from the ai-bmq queue. Reads the LLM_* settings from .env. + ai-queue-worker: + image: ${DC_CURRENTS_IMAGE_REPOSITORY:-currents-}ai-queue-worker:${DC_CURRENTS_IMAGE_TAG:-staging} + restart: unless-stopped + # Off by default: it needs an LLM endpoint. Start it with COMPOSE_PROFILES=ai + # in .env (see docs/configuration.md). + profiles: + - ai + networks: + - default + env_file: + - .env + environment: + CURRENTS_ENV: onprem + networks: default: null diff --git a/on-prem/templates/compose.mongodb.yml b/on-prem/templates/compose.mongodb.yml index e2cbbac..f476e66 100644 --- a/on-prem/templates/compose.mongodb.yml +++ b/on-prem/templates/compose.mongodb.yml @@ -86,3 +86,9 @@ services: mongodb: condition: service_healthy required: false + + ai-queue-worker: + depends_on: + mongodb: + condition: service_healthy + required: false diff --git a/on-prem/templates/compose.redis.yml b/on-prem/templates/compose.redis.yml index 6bb34fa..f705dd2 100644 --- a/on-prem/templates/compose.redis.yml +++ b/on-prem/templates/compose.redis.yml @@ -49,3 +49,9 @@ services: redis: condition: service_started required: false + + ai-queue-worker: + depends_on: + redis: + condition: service_started + required: false diff --git a/on-prem/templates/compose.rustfs.yml b/on-prem/templates/compose.rustfs.yml index 504ccb9..5043b89 100644 --- a/on-prem/templates/compose.rustfs.yml +++ b/on-prem/templates/compose.rustfs.yml @@ -153,3 +153,7 @@ services: webhooks: environment: FILE_STORAGE_FORCE_PATH_STYLE: "true" + + ai-queue-worker: + environment: + FILE_STORAGE_FORCE_PATH_STYLE: "true"