Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
19630ac
fix: Docker Compose librechat.yaml absolute path
Vidminas Sep 14, 2026
097f678
feat: Add support for ministack bedrock
Vidminas Sep 14, 2026
0b2e49a
feat: minimal DynamoDB replacement for MongoDB
Vidminas Sep 15, 2026
e1d8311
feat: add config files for ministack
Vidminas Sep 15, 2026
fa1d602
build: speed up Docker API typecheck
Vidminas Sep 15, 2026
def82c0
feat: add DynamoDB file persistence and S3 storage
Vidminas Sep 17, 2026
d091d5d
feat: add minimal DynamoDB agent, ACL, and API key support
Vidminas Sep 17, 2026
c8ea517
refactor: use generic AWS_* env vars in ministack compose wiring
Vidminas Sep 17, 2026
cc93798
chore: disable extra features in config
Vidminas Sep 17, 2026
9260524
feat: migrate RAG from rag_api to Bedrock Knowledge Base with per-use…
Vidminas Sep 20, 2026
df4ce63
feat: implement Cognito user pool login
Vidminas Sep 24, 2026
4f3f651
chore: swap ollama granite for smaller qwen model
Vidminas Sep 24, 2026
ba4ebec
chore: gitignore root librechat.yaml, add copies
Vidminas Sep 24, 2026
f3487e4
style: rename project to plastic-ai
Vidminas Sep 24, 2026
fc65e0d
Revert "feat: add minimal DynamoDB agent, ACL, and API key support"
Vidminas Sep 29, 2026
5ead05e
Revert "feat: add DynamoDB file persistence and S3 storage"
Vidminas Sep 29, 2026
a28995f
Revert "feat: minimal DynamoDB replacement for MongoDB"
Vidminas Sep 29, 2026
a396233
Revert "feat: migrate RAG from rag_api to Bedrock Knowledge Base with…
Vidminas Sep 29, 2026
3058fa2
Merge remote-tracking branch 'upstream/main'
Vidminas Sep 29, 2026
8d35ed2
fix: restore rag_api compose wiring after the Bedrock KB revert
Vidminas Oct 1, 2026
0cda5d9
feat: connect to Amazon DocumentDB over TLS
Vidminas Oct 1, 2026
a62afc9
docs: describe running locally against Amazon DocumentDB
Vidminas Oct 1, 2026
64e0a03
feat: resolve Bedrock credentials from an AWS profile in local compose
Vidminas Oct 1, 2026
6d40e01
chore: keep ollama and ministack data out of the docker build context
Vidminas Oct 1, 2026
c64cab3
feat: add Nova Lite to the AWS Bedrock models
Vidminas Oct 1, 2026
6579641
feat: update librechat yaml config for sandbox and public deployments
Vidminas Oct 2, 2026
f36000b
feat: add langfuse and hyperdx observability
Vidminas Oct 3, 2026
fd03ddb
feat: add content-free usage analytics views to clickhouse
Vidminas Oct 6, 2026
add845b
feat: provision a hyperdx usage timeline and llm usage dashboard
Vidminas Oct 6, 2026
894d2fe
feat: add a langfuse admin password sync script
Vidminas Oct 6, 2026
8469f42
feat: offer open-weight bedrock models in the sandbox
Vidminas Oct 6, 2026
a3bba91
chore: force LF for files opentofu hashes
Vidminas Oct 7, 2026
b5bb0ad
docs: point infra/terraform references at terraform/
Vidminas Oct 7, 2026
d8b7fe3
feat: let provisioned hyperdx sources link to each other by name
Vidminas Oct 7, 2026
09e2b2f
feat: show conversations, feedback reasons and full traces in hyperdx
Vidminas Oct 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
# Specific patterns to ignore
data-node
meili_data*
ollama
ministack
librechat*
Dockerfile*
docs
Expand Down
69 changes: 68 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ PORT=3080
# HTTP_HEADERS_TIMEOUT_MS=80000
# HTTP_REQUEST_TIMEOUT_MS=300000

# Local MongoDB default. For Amazon DocumentDB 8.0+, use an instance-based cluster URI with
# `tls=true&retryWrites=false` and set MONGO_TLS_CA_FILE to the AWS CA bundle.
# Example: mongodb://user:password@cluster.example.docdb.amazonaws.com:27017/LibreChat?tls=true&retryWrites=false&replicaSet=rs0&readPreference=secondaryPreferred
# When tunnelling from the Docker API container, use host.docker.internal instead of 127.0.0.1.
MONGO_URI=mongodb://127.0.0.1:27017/LibreChat
# Path inside the API container. The override mounts ./certs/documentdb here.
MONGO_TLS_CA_FILE=
#The maximum number of connections in the connection pool. */
MONGO_MAX_POOL_SIZE=
#The minimum number of connections in the connection pool. */
Expand Down Expand Up @@ -495,6 +501,9 @@ ANTHROPIC_API_KEY=user_provided

# AWS Profile
# BEDROCK_AWS_PROFILE=your-profile-name
# Host directory containing the AWS config, credentials, and optional SSO cache.
# Docker Compose mounts this directory read-only at /home/node/.aws.
AWS_PROFILE_DIR=/home/your-user/.aws

# Static credentials (use only if profiles or IAM roles are not suitable)
# BEDROCK_AWS_ACCESS_KEY_ID=someAccessKey
Expand Down Expand Up @@ -889,6 +898,12 @@ ALLOW_EMAIL_LOGIN=true
# ALLOW_EMAIL_LOGIN_OVERRIDE=false # note: permits direct API email login while ALLOW_EMAIL_LOGIN=false; each use is logged
ALLOW_REGISTRATION=true
ALLOW_SOCIAL_LOGIN=false
# Local ministack Cognito provisioning names. The app resolves the generated pool id +
# client id by these names at startup when OPENID_ALLOW_INSECURE_REQUESTS is set, so
# OPENID_ISSUER / OPENID_CLIENT_ID below can stay as placeholders for local dev.
COGNITO_POOL_NAME=
COGNITO_CLIENT_NAME=

ALLOW_SOCIAL_REGISTRATION=false
ALLOW_PASSWORD_RESET=false
# ALLOW_ACCOUNT_DELETION=true # note: enabled by default if omitted/commented out
Expand Down Expand Up @@ -977,14 +992,22 @@ OPENID_AUDIENCE=
# the intended access-token audience during refresh. Usually matches OPENID_AUDIENCE.
OPENID_REFRESH_AUDIENCE=

OPENID_BUTTON_LABEL=
# Login-page button label for the OpenID/Cognito provider (empty -> "Continue with OpenID").
OPENID_BUTTON_LABEL=Continue with Cognito
OPENID_IMAGE_URL=
# Set to true to automatically redirect to the OpenID provider when a user visits the login page
# This will bypass the login form completely for users, only use this if OpenID is your only authentication method
OPENID_AUTO_REDIRECT=false
# Set to true to use PKCE (Proof Key for Code Exchange) for OpenID authentication.
# For public clients (no client secret), leave OPENID_CLIENT_SECRET empty and set this to true.
OPENID_USE_PKCE=false
# Allow OpenID discovery/token/JWKS over plain HTTP (local emulators such as ministack,
# issuer http://ministack:4566). Keep empty/false for real HTTPS providers like AWS Cognito.
OPENID_ALLOW_INSECURE_REQUESTS=
# Host-reachable base for browser-facing OpenID endpoints (authorize/logout) when using a
# local emulator whose discovery advertises a compose-network host. e.g. http://localhost:4566.
# Leave empty for real HTTPS providers.
OPENID_PUBLIC_ENDPOINT_URL=
#Set to true to reuse openid tokens for authentication management instead of using the mongodb session and the custom refresh token.
OPENID_REUSE_TOKENS=
#Max age a reused OpenID session token is served before LibreChat forces an IdP refresh. Default 900000 ms (15 min).
Expand Down Expand Up @@ -1454,3 +1477,47 @@ OPENWEATHER_API_KEY=

# Circuit breaker: max backoff cap (ms) for exponential backoff
# MCP_CB_MAX_BACKOFF_MS=300000

#=====================================================================#
# ministack / fork infra #
#=====================================================================#
# Docker Compose project namespace for the local ministack/fork stack.
# Prefixes container, network, and volume names so this stack stays
# isolated from other Compose projects on the same host.
COMPOSE_PROJECT_NAME=plastic-ai

#=====================================================================#
# Observability stack (fork, compose profile) #
#=====================================================================#
# Local Langfuse (GenAI traces) and HyperDX (browser activity), started with
# docker compose --profile observability up -d
# Every value below is a local-development placeholder: replace them, and never
# reuse them in a deployed environment (terraform/ generates its own).
#
# To send data to the local stack, also set these in the sections above:
# LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY any pk-lf-... / sk-lf-... pair; Langfuse is
# bootstrapped with the same pair
# LANGFUSE_BASE_URL=http://langfuse-web:3000
# RUM_ENABLED=true, RUM_AUTH_MODE=proxy, RUM_PROXY_TARGET_URL=http://otel-collector:4318
# RUM_PROXY_AUTHORIZATION shared token the collector checks
# Comment them out again when the profile is not running; otherwise every export
# fails (harmlessly, but noisily) against services that are not there.

# Host ports for the two UIs.
LANGFUSE_PORT=3100
HYPERDX_PORT=8080
# Langfuse admin login. Sign-up is disabled, so this is the only account.
LANGFUSE_INIT_USER_EMAIL=admin@example.com
LANGFUSE_INIT_USER_PASSWORD=change-me-local
# Langfuse internals. LANGFUSE_ENCRYPTION_KEY must be 64 hex characters (openssl rand -hex 32).
LANGFUSE_NEXTAUTH_SECRET=change-me-local
LANGFUSE_SALT=change-me-local
LANGFUSE_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
LANGFUSE_POSTGRES_PASSWORD=change-me-local
LANGFUSE_REDIS_AUTH=change-me-local
# Shared ClickHouse: the admin account Langfuse uses, and HyperDX's account, which is
# limited to the `hyperdx` database and the content-free `analytics` views
# (otel/clickhouse/hyperdx.xml).
CLICKHOUSE_USER=clickhouse
CLICKHOUSE_PASSWORD=change-me-local
HYPERDX_CLICKHOUSE_PASSWORD=change-me-local
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Force LF line endings for shell scripts and git hooks (required for cross-platform compatibility)
.husky/* text eol=lf
*.sh text eol=lf

# Files OpenTofu reads and hashes (image tags, task triggers): CRLF on one
# machine would change the hashes and redeploy on every apply from the other.
librechat.*.yaml text eol=lf
otel/** text eol=lf
20 changes: 10 additions & 10 deletions .github/ISSUE_TEMPLATE/BUG-REPORT.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ body:
attributes:
value: |
Thanks for taking the time to fill out this bug report!

Before submitting, please:
- Search existing [Issues and Discussions](https://github.com/LibreChat-AI/LibreChat/discussions) to see if your bug has already been reported
- Use [Discussions](https://github.com/LibreChat-AI/LibreChat/discussions) instead of Issues for:
Expand All @@ -26,14 +26,14 @@ body:
id: version-info
attributes:
label: Version Information
description: |
In LibreChat, open **Settings → About** and click **Copy diagnostics**, then paste the result here.
This captures the exact version, commit, branch, and build date so maintainers can pinpoint the build you're running.

If the About panel is unavailable (older version / self-hosted with it disabled), please provide as much of the following as possible instead:
- Docker: `docker images | grep librechat` (image tag) and `docker inspect <image> | grep -i "\"Commit\\|BUILD_"` if build args were set
- Source: `git rev-parse HEAD` and `git rev-parse --abbrev-ref HEAD`
placeholder: Paste the diagnostics block here
description: |
In LibreChat, open **Settings → About** and click **Copy diagnostics**, then paste the result here.
This captures the exact version, commit, branch, and build date so maintainers can pinpoint the build you're running.
If the About panel is unavailable (older version / self-hosted with it disabled), please provide as much of the following as possible instead:
- Docker: `docker images | grep librechat` (image tag) and `docker inspect <image> | grep -i "\"Commit\\|BUILD_"` if build args were set
- Source: `git rev-parse HEAD` and `git rev-parse --abbrev-ref HEAD`
placeholder: Paste the diagnostics block here
validations:
required: true
- type: textarea
Expand Down Expand Up @@ -90,4 +90,4 @@ body:
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/LibreChat-AI/LibreChat/blob/main/.github/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow this project's Code of Conduct
required: true
required: true
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ junit.xml
**/venv/

# docker override file
docker-compose.override.yaml
docker-compose.override.yml
# docker-compose.override.yaml
# docker-compose.override.yml

# meilisearch
meilisearch
Expand Down Expand Up @@ -193,3 +193,9 @@ scripts/activity-labels/results/
!e2e/lighthouse/librechat.yaml
/.lighthouse/
/e2e/lighthouse/.test-results/

# Infrastructure and development artifacts
.kiro/
infra/
/ministack/state/
/ollama/
42 changes: 42 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,48 @@ and keep it inside the feature; app-global preferences and shell state a feature
through props or a small host-supplied context rather than reached for through `~/store`; when a
consumer sits outside the feature you are changing, leave that atom on Recoil and pass it in. Passing
them in is what lets a feature move to its own workspace later without a rewrite, and it keeps the
Jotai conversion scoped to the state a feature owns. See the detailed policy in `CLAUDE.md` under
“Client State Ownership”.

## Upstream mergeability

This repository is a fork of upstream LibreChat, re-platformed onto ministack/AWS. Keep the fork as
close as possible to upstream so future upstream changes merge with minimal conflict. Prefer these
patterns, which are already the de-facto style across the migration; see `CLAUDE.md` under "Workspace
Boundaries" for the companion module-placement policy.

- **Comment out, do not delete.** When code is replaced or disabled, leave the upstream line in place
as a commented-out merge anchor so the three-way merge still lines up. This is the established
pattern: `api/db/connect.js` keeps the entire Mongoose connection block commented out, and
`api/server/routes/index.js` keeps `// const search = require('./search');` above each
`unsupported(...)` stub. `docker-compose.override.yml` keeps the legacy `MONGO_URI` and `RAG_API_URL`
values in comments beside their replacements.
- **Interleave new code with the old it replaces.** Put the new line directly adjacent to the
commented-out original so a reviewer can see exactly where a merged upstream change maps, rather than
moving the replacement to a distant block.
- **Make minimal changes.** Prefer the smallest edit that achieves the goal — env/config toggles and
additive wiring over rewrites. `ENDPOINTS=agents,bedrock` and `fileStrategy: "s3"` switch behavior
through configuration instead of editing the code paths they select.
- **Create new files instead of replacing existing ones** where practical, so upstream files stay
byte-close to their origin. The DynamoDB port lives in new `packages/data-schemas/src/dynamo/*` and
`packages/api/src/dynamo/*`; the Bedrock Knowledge Base in `packages/api/src/bedrock-kb/*`; the 501
profile in `packages/api/src/http/unsupported.ts` — none rewrite the upstream Mongoose models in
place.

## Configuration and Docker changes

When a change introduces new configuration, add every new variable to **both** `.env` and
`.env.example`, keyed the same, with the `.env.example` entry carrying a documenting comment and a
safe placeholder (never a real secret). The two files must stay in lockstep so a fresh checkout of
`.env.example` lists the same knobs the running `.env` uses.

Make all Docker changes in `docker-compose.override.yml`, never by editing the upstream
`docker-compose.yml`. The override file is where the fork adds and re-points services (new init
containers such as `dynamodb-init`/`s3-init`/`bedrock-kb-init`, ministack endpoints, and the
commented-out legacy `MONGO_URI`/`RAG_API_URL` anchors), which keeps the upstream compose file
byte-close to its origin and every fork-specific service additive. `docker-compose.override.yml.example`
is upstream LibreChat's commented override template, not a mirror of the fork's override — the fork's
active services live only in `docker-compose.override.yml`, so do not mirror them into the example.
Jotai conversion scoped to the state a feature owns. For persisted atoms, use the helpers in
`client/src/store/jotai-utils.ts`.

Expand Down
70 changes: 70 additions & 0 deletions Dockerfile.multi
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,76 @@ COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/d
COPY --from=data-schemas-build /app/packages/data-schemas/dist /app/packages/data-schemas/dist
RUN npm run build

# Typecheck API source copied into Docker's Linux filesystem
FROM base AS api-typecheck-run
WORKDIR /app
COPY packages/api ./packages/api
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
COPY --from=data-schemas-build /app/packages/data-schemas/dist /app/packages/data-schemas/dist
RUN npx tsc --noEmit -p packages/api/tsconfig.json && touch /tmp/api-typecheck

FROM scratch AS api-typecheck
COPY --from=api-typecheck-run /tmp/api-typecheck /api-typecheck

# Typecheck data-schemas source copied into Docker's Linux filesystem
FROM base AS data-schemas-typecheck-run
WORKDIR /app
COPY packages/data-schemas ./packages/data-schemas
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
RUN npx tsc --noEmit -p packages/data-schemas/tsconfig.json && touch /tmp/data-schemas-typecheck

FROM scratch AS data-schemas-typecheck
COPY --from=data-schemas-typecheck-run /tmp/data-schemas-typecheck /data-schemas-typecheck

# Run API package unit tests against source copied into Docker's Linux filesystem
FROM base AS api-test-run
WORKDIR /app
COPY config ./config
COPY packages/api ./packages/api
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
COPY --from=data-schemas-build /app/packages/data-schemas/dist /app/packages/data-schemas/dist
RUN npx jest --coverage=false --config packages/api/jest.config.mjs --rootDir packages/api \
--testPathPatterns="(src/files/rag\.spec\.ts$|src/storage/s3/)" \
&& touch /tmp/api-test

FROM scratch AS api-test
COPY --from=api-test-run /tmp/api-test /api-test

# Run legacy `/api` workspace unit tests against source copied into Docker's Linux filesystem
FROM base AS legacy-api-test-run
WORKDIR /app
COPY config ./config
COPY skill ./skill
COPY api ./api
COPY --from=data-provider-build /app/packages/data-provider/dist ./packages/data-provider/dist
COPY --from=data-schemas-build /app/packages/data-schemas/dist ./packages/data-schemas/dist
COPY --from=api-package-build /app/packages/api/dist ./packages/api/dist
WORKDIR /app/api
RUN npx cross-env NODE_ENV=test jest \
--testPathPatterns="(server/services/Files/(process|strategies)|test/app/clients/tools/util/fileSearch)" \
--testPathIgnorePatterns="integration" \
&& touch /tmp/legacy-api-test

FROM scratch AS legacy-api-test
COPY --from=legacy-api-test-run /tmp/legacy-api-test /legacy-api-test

# Run cognito-login-migration spec tests against source copied into Docker's Linux filesystem
FROM base AS cognito-login-test-run
WORKDIR /app
COPY config ./config
COPY skill ./skill
COPY api ./api
COPY --from=data-provider-build /app/packages/data-provider/dist ./packages/data-provider/dist
COPY --from=data-schemas-build /app/packages/data-schemas/dist ./packages/data-schemas/dist
COPY --from=api-package-build /app/packages/api/dist ./packages/api/dist
WORKDIR /app/api
RUN npx cross-env NODE_ENV=test jest \
--testPathPatterns="(server/routes/oauth|server/routes/cognito|strategies/openidStrategy|strategies/.*[Cc]ognito|server/cognitoLogin|test/cognito)" \
--testPathIgnorePatterns="integration" \
&& touch /tmp/cognito-login-test

FROM scratch AS cognito-login-test
COPY --from=cognito-login-test-run /tmp/cognito-login-test /cognito-login-test
# Build `client` package
FROM base AS client-package-build
WORKDIR /app/packages/client
Expand Down
3 changes: 3 additions & 0 deletions api/db/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const maxIdleTimeMS = parseInt(process.env.MONGO_MAX_IDLE_TIME_MS) || undefined;
const waitQueueTimeoutMS = parseInt(process.env.MONGO_WAIT_QUEUE_TIMEOUT_MS) || undefined;
/** Set to false to disable automatic index creation for all models associated with this connection. */
const autoIndex = optionalEnabled(process.env.MONGO_AUTO_INDEX);
/** CA bundle path for TLS connections such as Amazon DocumentDB. */
const tlsCAFile = process.env.MONGO_TLS_CA_FILE || undefined;

/** Set to `false` to disable Mongoose automatically calling `createCollection()` on every model created on this connection. */
const autoCreate = optionalEnabled(process.env.MONGO_AUTO_CREATE);
Expand Down Expand Up @@ -55,6 +57,7 @@ async function connectDb() {
...(maxIdleTimeMS ? { maxIdleTimeMS } : {}),
...(waitQueueTimeoutMS ? { waitQueueTimeoutMS } : {}),
...(autoIndex != undefined ? { autoIndex } : {}),
...(tlsCAFile ? { tlsCAFile } : {}),
...(autoCreate != undefined ? { autoCreate } : {}),
// useNewUrlParser: true,
// useUnifiedTopology: true,
Expand Down
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@anthropic-ai/vertex-sdk": "^0.16.0",
"@aws-sdk/client-bedrock-runtime": "^3.1013.0",
"@aws-sdk/client-cloudfront": "^3.1042.0",
"@aws-sdk/client-cognito-identity-provider": "^3.1013.0",
"@aws-sdk/client-s3": "^3.980.0",
"@aws-sdk/cloudfront-signer": "^3.1036.0",
"@aws-sdk/credential-providers": "^3.1045.0",
Expand Down
Loading
Loading