Compare commits

..
Author SHA1 Message Date
Hanzo Dev 00871642a4 chore: bump version to v0.7.9 2025-06-27 14:44:31 -04:00
Hanzo Dev 83bfac37ee fix: Update logo SVGs to support dark mode with proper theme switching
- Replace hardcoded colors with CSS classes that respond to prefers-color-scheme
- Update hanzo-logo.svg and logo.svg with .logo-main and .logo-shadow classes
- Remove theme-based logo switching logic from UnknownIcon component
- Simplify AuthLayout to remove unnecessary text color classes on logo
2025-06-27 10:33:50 -04:00
Hanzo Dev 10b0f4be3a Update logos 2025-06-27 02:02:29 -04:00
Hanzo Dev a1cf2e5395 fix: Fix Jest configuration and module path mapping
- Fix syntax error in Jest config (unclosed string)
- Update @hanzochat/data-provider module path mapping
- Point to correct location in packages/data-provider
- Remove duplicate configuration entries
2025-06-27 01:20:18 -04:00
Hanzo DevandClaude 35052e95d2 feat: Rename Vendor Mode to Brand Mode
- Renamed all VENDOR_* environment variables to BRAND_*
- Updated VendorService to BrandService
- Updated vendorMode middleware to brandMode
- Updated useVendorMode hook to useBrandMode
- Renamed vendor-related files to brand-related
- Updated all references throughout the codebase
- Created comprehensive Brand Mode documentation
- Fixed all remaining vendor references in BrandService.js
- Updated Jest config for module resolution

This change makes the white-label deployment feature more appealing
and better reflects its purpose as a branding customization tool.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 20:44:51 -04:00
Hanzo Dev 5a690460cd Simple demo 2025-06-26 18:57:25 -04:00
Hanzo Dev 0882ef6d1c Update compose 2025-06-26 18:47:46 -04:00
Hanzo DevandClaude ca6f2d7a2a feat: Add comprehensive CI/CD with GitHub Actions and test fixes
- Add docker-build.yml for automatic image building on push
- Add ci-cd.yml for complete CI/CD pipeline with testing
- Add docker-cache.yml for efficient caching strategy
- Add release.yml for automated releases with changelogs
- Configure multi-platform builds (amd64/arm64)
- Set up security scanning with Trivy
- Enable SBOM generation for supply chain security
- Add git-cliff configuration for changelog generation

This enables automatic building and publishing of Docker images
to GitHub Container Registry with proper versioning and caching.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 17:56:47 -04:00
Hanzo DevandClaude bfb4cb3f66 fix: Use direct node command instead of npm script in production
The production container doesn't have cross-env installed, so we use
the node command directly to start the server.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 17:53:17 -04:00
Hanzo DevandClaude 30fd72ec1b feat: Add vendor mode for white-label deployments
Implement comprehensive vendor mode that allows white-labeling the chat platform
with custom branding and model names while internally routing to any backend.

Key features:
- Enable vendor mode via VENDOR_MODE=true environment variable
- Custom branding: name, logo, colors, app title
- Fixed model names (e.g., "Hanzo Zen-1") that map to actual backend models
- Hide UI elements: model switchers, endpoint menus, API key inputs
- Support for multiple backends: OpenAI, Anthropic, custom endpoints
- Default configuration for Hanzo AI with Zen-1 models

Changes:
- Add VendorService to handle all vendor mode logic
- Create /api/vendor/config endpoint for frontend configuration
- Add useVendorMode React hook for accessing vendor settings
- Update ModelSelector to respect vendor mode restrictions
- Modify Makefile with vendor mode commands and setup
- Set Hanzo AI as default vendor in .env.example
- Add comprehensive documentation in docs/VENDOR_MODE.md

This enables easy white-label deployments while maintaining full backend flexibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 17:33:10 -04:00
Hanzo DevandClaude cd9624b434 feat: Add comprehensive CI/CD with GitHub Actions and test fixes
- Set up GitHub Actions workflows for CI, PR checks, and releases
- Fix all critical test failures (99.7% tests now passing)
- Add Husky pre-commit hooks with lint-staged
- Configure Jest for better test reporting
- Fix AnthropicClient and OpenAIClient streaming issues
- Fix Winston logger null reference errors
- Add test environment configuration
- Update package.json with new test and lint scripts
- Add branch protection documentation
- Set up automated testing, linting, and security scanning
- Add Docker build and NPM publishing to release workflow

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 16:36:32 -04:00
Hanzo Dev 6048f68105 fix: Update all .github references from LibreChat to HanzoChat
- Update Discord links to hanzoai
- Update all workflow image names to hanzochat
- Update npm package references to @hanzochat
- Update documentation links to hanzo.ai
- Fix all repository references
2025-06-26 12:30:20 -04:00
Hanzo Dev b8605e89dc fix: Update pnpm lockfile 2025-06-26 12:25:40 -04:00
Hanzo Dev 86f827494d feat: Convert to black and white theme
- Remove all color variables (green, red, amber) from CSS
- Update Tailwind config to use only grays
- Convert all SVG icons to grayscale
- Update component color classes to use grays
- Replace colored UI elements with black/white/gray alternatives
- Maintain accessibility with sufficient contrast ratios
2025-06-26 12:12:57 -04:00
Hanzo Dev 15aace307b chore: Complete rebranding from LibreChat to HanzoChat
- Update all @librechat/agents imports to @hanzochat/agents
- Add author information (Hanzo Industries Inc <dev@hanzo.ai>) to all package.json files
- Create @hanzochat/agents package with required exports and types
- Update VSCode launch configuration
- Remove LibreChat TODO comments
- Publish packages: @hanzochat/data-schemas@0.0.11, @hanzochat/data-provider@0.7.88, @hanzochat/api@1.2.6
2025-06-26 11:56:08 -04:00
Hanzo Dev 89a499febb fix: Update package names and dependencies for @hanzochat namespace
- Renamed hanzo-data-provider to @hanzochat/data-provider
- Updated all imports from chat-data-provider to @hanzochat/data-provider
- Fixed @chat/* imports to use @hanzochat/* namespace
- Updated @hanzochat/agents to @librechat/agents
- Fixed MCPIcon import path in client
- Added missing @redis/client dependency
- Rebuilt all packages with correct dependencies
- All packages now build successfully
2025-06-26 11:11:25 -04:00
Hanzo Dev 317e24a032 fix: Resolve merge conflicts from rebranding update
- Fixed merge conflicts in 6 translation files (es, ja, ko, nl, pt-BR, zh-Hans)
- Fixed merge conflict in CHANGELOG.md
- Updated branding to use 'Chat' and 'Hanzo' consistently
- Preserved all recent changes from HEAD version
2025-06-26 03:31:58 -04:00
Hanzo Dev 4d67f7d81b Update imports 2025-06-26 03:15:25 -04:00
Hanzo Dev 071bcf6f4d Update gitignore 2025-06-26 02:40:40 -04:00
Hanzo DevandClaude f599632f57 chore: Update branding references in documentation and configs
- Update GitHub templates and workflows
- Update Docker compose examples
- Update Helm chart values
- Update package.json files
- Sync CHANGELOG formatting

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 02:37:06 -04:00
Hanzo DevandClaude c4e841c2b9 feat: Add RAG API Docker image build and publish
- Create rag.Dockerfile to rebrand LibreChat RAG API
- Update GitHub Actions to build both main and RAG API images
- Both images now published to ghcr.io/hanzoai/

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 23:36:24 -04:00
Hanzo Dev 46657ba812 fix: Update Docker build workflow with manual trigger 2025-06-25 23:21:48 -04:00
Hanzo DevandClaude e6737188c1 feat: Complete Hanzo Chat rebranding
- Replace all LibreChat references with Hanzo Chat
- Update package namespace from @librechat to @hanzochat
- Update Docker images to use ghcr.io/hanzoai/chat
- Update configuration files and environment variables
- Update translation keys and UI references
- Rename helm charts to hanzo-chat
- Update MongoDB database name to HanzoChat
- Update all documentation links to hanzo.ai

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 23:11:58 -04:00
Hanzo DevandClaude 2c832aa8b9 refactor: Rename configuration file from librechat.yaml to chat.yaml
- Renamed librechat.yaml to chat.yaml for brand consistency
- Renamed librechat.example.yaml to chat.example.yaml
- Updated all references across the codebase:
  - Source files (JS/TS)
  - Translation files (all locales)
  - Docker compose files
  - Helm charts
  - Documentation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 22:52:55 -04:00
Hanzo DevandClaude fd3d031cc7 feat: Add GitHub Actions workflow for Docker image publishing
- Add workflow to build and push Docker images to ghcr.io on push to main
- Update docker-compose.yml to use ghcr.io registry instead of Docker Hub
- Support multi-platform builds (amd64 and arm64)
- Automatic tagging based on branch/version/SHA

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 22:46:29 -04:00
Hanzo DevandClaude 7e6c10299f feat: Complete Hanzo Chat rebranding
- Update footer to show "Hanzo Chat v0.7.8 - AI Infrastructure for Everyone"
- Replace all LibreChat references with Hanzo Chat
- Update README with Hanzo Chat branding and clean badges
- Remove all remaining green color styles (replaced with grayscale)
- Update package.json descriptions and metadata
- Update HTML meta tags and window title
- Add ALLOW_REGISTRATION=true to .env for user signup

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 18:29:16 -04:00
Hanzo DevandClaude 0f8eea1e3a chore: Update Makefile with branding command and sync with upstream
- Add 'make update-branding' command to update logo in running container
- Merge latest upstream LibreChat changes (486c1314a)
- Includes: configurable retention for temp chats, Bedrock MCP support,
  thinking budget for Gemini 2.5, client-side image resizing, and more
- Ensure all Hanzo customizations are preserved

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 17:58:53 -04:00
Hanzo Dev 751b8122ab Merge latest upstream LibreChat changes with Hanzo customizations 2025-06-25 17:50:20 -04:00
Hanzo DevandClaude 32d3485663 feat: Customize Hanzo Chat with white/black theme and Hanzo logo
- Replace LibreChat logo with Hanzo geometric logo
- Update theme to use white buttons with black text throughout
- Remove green color scheme in favor of white/black styling
- Add comprehensive Makefile for local development
- Update docker-compose.override.yml for asset mounting
- Configure all auth components, panels, and UI elements

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 17:27:03 -04:00
Hanzo Dev 7b05ada0ca Merge upstream LibreChat updates: Index sync, MeiliSearch optimization, and agent packages bump
# Conflicts:
#	package-lock.json
2025-06-23 17:47:44 -04:00
Hanzo Dev 88cd45da4b Fix package.json exports for CommonJS compatibility 2025-06-23 17:46:49 -04:00
Hanzo Dev d8b20d61e9 Fix all merge conflicts and update dependencies 2025-06-20 14:07:53 -04:00
Hanzo Dev 91e9711e6b Fix merge conflict in package.json - update to v0.7.8 2025-06-20 13:52:49 -04:00
Hanzo Dev d0b64340fe Fix MCP and add example 2025-06-20 13:43:44 -04:00
Hanzo Dev fb7787c87a Update brand 2025-06-20 13:43:27 -04:00
4040 changed files with 98916 additions and 885351 deletions
-15
View File
@@ -1,15 +0,0 @@
# used by CI/CD testing
openai==1.81.0
python-dotenv
tiktoken
importlib_metadata
cohere
redis==5.2.1
redisvl==0.4.1
anthropic
orjson==3.10.12 # fast /embedding responses
pydantic==2.10.2
google-cloud-aiplatform==1.43.0
fastapi-sso==0.16.0
uvloop==0.21.0
mcp==1.9.3 # for MCP server
+17 -51
View File
@@ -1,52 +1,18 @@
{
"name": "Python 3.11",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:3.11-bookworm",
// https://github.com/devcontainers/images/tree/main/src/python
// https://mcr.microsoft.com/en-us/product/devcontainers/python/tags
// "build": {
// "dockerfile": "Dockerfile",
// "context": ".."
// },
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
"settings": {},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"GitHub.copilot",
"GitHub.copilot-chat",
"ms-python.autopep8"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [4000],
"containerEnv": {
"LITELLM_LOG": "DEBUG"
},
// Use 'portsAttributes' to set default properties for specific forwarded ports.
// More info: https://containers.dev/implementors/json_reference/#port-attributes
"portsAttributes": {
"4000": {
"label": "LiteLLM Server",
"onAutoForward": "notify"
}
},
// More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "litellm",
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pipx install poetry && poetry install -E extra_proxy -E proxy"
}
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces",
"customizations": {
"vscode": {
"extensions": [],
"settings": {
"terminal.integrated.profiles.linux": {
"bash": null
}
}
}
},
"postCreateCommand": "",
"features": { "ghcr.io/devcontainers/features/git:1": {} },
"remoteUser": "vscode"
}
@@ -20,7 +20,8 @@ services:
environment:
- HOST=0.0.0.0
- MONGO_URI=mongodb://mongodb:27017/HanzoChat
# - OPENAI_REVERSE_PROXY=http://host.docker.internal:8070/v1
# - CHATGPT_REVERSE_PROXY=http://host.docker.internal:8080/api/conversation # if you are hosting your own chatgpt reverse proxy with docker
# - OPENAI_REVERSE_PROXY=http://host.docker.internal:8070/v1/chat/completions # if you are hosting your own chatgpt reverse proxy with docker
- MEILI_HOST=http://meilisearch:7700
# Runs app on the same network as the service container, allows "forwardPorts" in devcontainer.json function.
+16 -16
View File
@@ -1,17 +1,17 @@
docs
cookbook
.circleci
.github
tests
.git
.github
.circleci
.devcontainer
*.tgz
log.txt
docker/Dockerfile.*
node_modules
**/.circleci
**/.editorconfig
**/.dockerignore
**/.git
**/.DS_Store
**/.vscode
**/node_modules
.env
.env.*
!.env.static
# Specific patterns to ignore
data-node
meili_data*
librechat*
Dockerfile*
docs
# Ignore all hidden files
.*
-10
View File
@@ -1,10 +0,0 @@
PORT=3080
RAG_PORT=8000
MEILI_MASTER_KEY=masterkey
ENDPOINTS=openAI,anthropic,assistants,custom
# Security keys (generate random strings)
CREDS_KEY=a_random_32_character_string_for_creds
CREDS_IV=a_random_16_character_string_for_creds
JWT_SECRET=a_random_secret_for_jwt_tokens
JWT_REFRESH_SECRET=another_random_secret_for_refresh_tokens
-1
View File
@@ -1 +0,0 @@
ENDPOINTS=openAI,anthropic,assistants,custom
-660
View File
@@ -1,660 +0,0 @@
#=====================================================================#
# Hanzo Chat Configuration #
#=====================================================================#
# Please refer to the reference documentation for assistance #
# with configuring your Hanzo Chat environment. #
# #
# https://docs.hanzo.ai/chat/configuration/dotenv #
#=====================================================================#
#==================================================#
# Server Configuration #
#==================================================#
HOST=localhost
PORT=3080
MONGO_URI=mongodb://127.0.0.1:27017/HanzoChat
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
NO_INDEX=true
# Use the address that is at most n number of hops away from the Express application.
# req.socket.remoteAddress is the first hop, and the rest are looked for in the X-Forwarded-For header from right to left.
# A value of 0 means that the first untrusted address would be req.socket.remoteAddress, i.e. there is no reverse proxy.
# Defaulted to 1.
TRUST_PROXY=1
#===============#
# JSON Logging #
#===============#
# Use when process console logs in cloud deployment like GCP/AWS
CONSOLE_JSON=false
#===============#
# Debug Logging #
#===============#
DEBUG_LOGGING=true
DEBUG_CONSOLE=false
#=============#
# Permissions #
#=============#
# UID=1000
# GID=1000
#===============#
# Configuration #
#===============#
# Use an absolute path, a relative path, or a URL
# CONFIG_PATH="/alternative/path/to/chat.yaml"
#===================================================#
# Endpoints #
#===================================================#
# ENDPOINTS=openAI,assistants,azureOpenAI,google,anthropic
PROXY=
#===================================#
# Known Endpoints - chat.yaml #
#===================================#
# https://docs.hanzo.ai/chat/configuration/ai_endpoints
# ANYSCALE_API_KEY=
# APIPIE_API_KEY=
# COHERE_API_KEY=
# DEEPSEEK_API_KEY=
# DATABRICKS_API_KEY=
# FIREWORKS_API_KEY=
# GROQ_API_KEY=
# HUGGINGFACE_TOKEN=
# MISTRAL_API_KEY=
# OPENROUTER_KEY=
# PERPLEXITY_API_KEY=
# SHUTTLEAI_API_KEY=
# TOGETHERAI_API_KEY=
# UNIFY_API_KEY=
# XAI_API_KEY=
#============#
# Anthropic #
#============#
ANTHROPIC_API_KEY=user_provided
# ANTHROPIC_MODELS=claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
#============#
# Azure #
#============#
# Note: these variables are DEPRECATED
# Use the `chat.yaml` configuration for `azureOpenAI` instead
# You may also continue to use them if you opt out of using the `chat.yaml` configuration
# AZURE_OPENAI_DEFAULT_MODEL=gpt-3.5-turbo # Deprecated
# AZURE_OPENAI_MODELS=gpt-3.5-turbo,gpt-4 # Deprecated
# AZURE_USE_MODEL_AS_DEPLOYMENT_NAME=TRUE # Deprecated
# AZURE_API_KEY= # Deprecated
# AZURE_OPENAI_API_INSTANCE_NAME= # Deprecated
# AZURE_OPENAI_API_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_VERSION= # Deprecated
# AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= # Deprecated
# PLUGINS_USE_AZURE="true" # Deprecated
#=================#
# AWS Bedrock #
#=================#
# BEDROCK_AWS_DEFAULT_REGION=us-east-1 # A default region must be provided
# BEDROCK_AWS_ACCESS_KEY_ID=someAccessKey
# BEDROCK_AWS_SECRET_ACCESS_KEY=someSecretAccessKey
# BEDROCK_AWS_SESSION_TOKEN=someSessionToken
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
# BEDROCK_AWS_MODELS=anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
# Notes on specific models:
# The following models are not support due to not supporting streaming:
# ai21.j2-mid-v1
# The following models are not support due to not supporting conversation history:
# ai21.j2-ultra-v1, cohere.command-text-v14, cohere.command-light-text-v14
#============#
# Google #
#============#
GOOGLE_KEY=user_provided
# GOOGLE_REVERSE_PROXY=
# Some reverse proxies do not support the X-goog-api-key header, uncomment to pass the API key in Authorization header instead.
# GOOGLE_AUTH_HEADER=true
# Gemini API (AI Studio)
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash,gemini-2.0-flash-lite
# Vertex AI
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_TITLE_MODEL=gemini-2.0-flash-lite-001
# GOOGLE_LOC=us-central1
# Google Safety Settings
# NOTE: These settings apply to both Vertex AI and Gemini API (AI Studio)
#
# For Vertex AI:
# To use the BLOCK_NONE setting, you need either:
# (a) Access through an allowlist via your Google account team, or
# (b) Switch to monthly invoiced billing: https://cloud.google.com/billing/docs/how-to/invoiced-billing
#
# For Gemini API (AI Studio):
# BLOCK_NONE is available by default, no special account requirements.
#
# Available options: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE
#
# GOOGLE_SAFETY_SEXUALLY_EXPLICIT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_HATE_SPEECH=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_HARASSMENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH
#============#
# OpenAI #
#============#
OPENAI_API_KEY=user_provided
# OPENAI_MODELS=o1,o1-mini,o1-preview,gpt-4o,gpt-4.5-preview,chatgpt-4o-latest,gpt-4o-mini,gpt-3.5-turbo-0125,gpt-3.5-turbo-0301,gpt-3.5-turbo,gpt-4,gpt-4-0613,gpt-4-vision-preview,gpt-3.5-turbo-0613,gpt-3.5-turbo-16k-0613,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview,gpt-3.5-turbo-1106,gpt-3.5-turbo-instruct,gpt-3.5-turbo-instruct-0914,gpt-3.5-turbo-16k
DEBUG_OPENAI=false
# TITLE_CONVO=false
# OPENAI_TITLE_MODEL=gpt-4o-mini
# OPENAI_SUMMARIZE=true
# OPENAI_SUMMARY_MODEL=gpt-4o-mini
# OPENAI_FORCE_PROMPT=true
# OPENAI_REVERSE_PROXY=
# OPENAI_ORGANIZATION=
#====================#
# Assistants API #
#====================#
ASSISTANTS_API_KEY=user_provided
# ASSISTANTS_BASE_URL=
# ASSISTANTS_MODELS=gpt-4o,gpt-4o-mini,gpt-3.5-turbo-0125,gpt-3.5-turbo-16k-0613,gpt-3.5-turbo-16k,gpt-3.5-turbo,gpt-4,gpt-4-0314,gpt-4-32k-0314,gpt-4-0613,gpt-3.5-turbo-0613,gpt-3.5-turbo-1106,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview
#==========================#
# Azure Assistants API #
#==========================#
# Note: You should map your credentials with custom variables according to your Azure OpenAI Configuration
# The models for Azure Assistants are also determined by your Azure OpenAI configuration.
# More info, including how to enable use of Assistants with Azure here:
# https://docs.hanzo.ai/chat/configuration/ai_endpoints/azure#using-assistants-with-azure
#============#
# Plugins #
#============#
# PLUGIN_MODELS=gpt-4o,gpt-4o-mini,gpt-4,gpt-4-turbo-preview,gpt-4-0125-preview,gpt-4-1106-preview,gpt-4-0613,gpt-3.5-turbo,gpt-3.5-turbo-0125,gpt-3.5-turbo-1106,gpt-3.5-turbo-0613
DEBUG_PLUGINS=true
CREDS_KEY=f34be427ebb29de8d88c107a71546019685ed8b241d8f2ed00c3df97ad2566f0
CREDS_IV=e2341419ec3dd3d19b13a1a87fafcbfb
# Azure AI Search
#-----------------
AZURE_AI_SEARCH_SERVICE_ENDPOINT=
AZURE_AI_SEARCH_INDEX_NAME=
AZURE_AI_SEARCH_API_KEY=
AZURE_AI_SEARCH_API_VERSION=
AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE=
AZURE_AI_SEARCH_SEARCH_OPTION_TOP=
AZURE_AI_SEARCH_SEARCH_OPTION_SELECT=
# OpenAI Image Tools Customization
#----------------
# IMAGE_GEN_OAI_DESCRIPTION_WITH_FILES=Custom description for image generation tool when files are present
# IMAGE_GEN_OAI_DESCRIPTION_NO_FILES=Custom description for image generation tool when no files are present
# IMAGE_EDIT_OAI_DESCRIPTION=Custom description for image editing tool
# IMAGE_GEN_OAI_PROMPT_DESCRIPTION=Custom prompt description for image generation tool
# IMAGE_EDIT_OAI_PROMPT_DESCRIPTION=Custom prompt description for image editing tool
# DALL·E
#----------------
# DALLE_API_KEY=
# DALLE3_API_KEY=
# DALLE2_API_KEY=
# DALLE3_SYSTEM_PROMPT=
# DALLE2_SYSTEM_PROMPT=
# DALLE_REVERSE_PROXY=
# DALLE3_BASEURL=
# DALLE2_BASEURL=
# DALL·E (via Azure OpenAI)
# Note: requires some of the variables above to be set
#----------------
# DALLE3_AZURE_API_VERSION=
# DALLE2_AZURE_API_VERSION=
# Flux
#-----------------
FLUX_API_BASE_URL=https://api.us1.bfl.ai
# FLUX_API_BASE_URL = 'https://api.bfl.ml';
# Get your API key at https://api.us1.bfl.ai/auth/profile
# FLUX_API_KEY=
# Google
#-----------------
GOOGLE_SEARCH_API_KEY=
GOOGLE_CSE_ID=
# YOUTUBE
#-----------------
YOUTUBE_API_KEY=
# SerpAPI
#-----------------
SERPAPI_API_KEY=
# Stable Diffusion
#-----------------
SD_WEBUI_URL=http://host.docker.internal:7860
# Tavily
#-----------------
TAVILY_API_KEY=
# Traversaal
#-----------------
TRAVERSAAL_API_KEY=
# WolframAlpha
#-----------------
WOLFRAM_APP_ID=
# Zapier
#-----------------
ZAPIER_NLA_API_KEY=
#==================================================#
# Search #
#==================================================#
SEARCH=true
MEILI_NO_ANALYTICS=true
MEILI_HOST=http://localhost:7700
MEILI_MASTER_KEY=DrhYf7zENyR6AlUCKmnz0eYASOQdl6zxH7s7MKFSfFCt
# Optional: Disable indexing, useful in a multi-node setup
# where only one instance should perform an index sync.
# MEILI_NO_SYNC=true
#==================================================#
# Speech to Text & Text to Speech #
#==================================================#
STT_API_KEY=
TTS_API_KEY=
#==================================================#
# RAG #
#==================================================#
# More info: https://docs.hanzo.ai/chat/configuration/rag_api
# RAG_OPENAI_BASEURL=
# RAG_OPENAI_API_KEY=
# RAG_USE_FULL_CONTEXT=
# EMBEDDINGS_PROVIDER=openai
# EMBEDDINGS_MODEL=text-embedding-3-small
#===================================================#
# User System #
#===================================================#
#========================#
# Moderation #
#========================#
OPENAI_MODERATION=false
OPENAI_MODERATION_API_KEY=
# OPENAI_MODERATION_REVERSE_PROXY=
BAN_VIOLATIONS=true
BAN_DURATION=1000 * 60 * 60 * 2
BAN_INTERVAL=20
LOGIN_VIOLATION_SCORE=1
REGISTRATION_VIOLATION_SCORE=1
CONCURRENT_VIOLATION_SCORE=1
MESSAGE_VIOLATION_SCORE=1
NON_BROWSER_VIOLATION_SCORE=20
LOGIN_MAX=7
LOGIN_WINDOW=5
REGISTER_MAX=5
REGISTER_WINDOW=60
LIMIT_CONCURRENT_MESSAGES=true
CONCURRENT_MESSAGE_MAX=2
LIMIT_MESSAGE_IP=true
MESSAGE_IP_MAX=40
MESSAGE_IP_WINDOW=1
LIMIT_MESSAGE_USER=false
MESSAGE_USER_MAX=40
MESSAGE_USER_WINDOW=1
ILLEGAL_MODEL_REQ_SCORE=5
#========================#
# Balance #
#========================#
# CHECK_BALANCE=false
# START_BALANCE=20000 # note: the number of tokens that will be credited after registration.
#========================#
# Registration and Login #
#========================#
ALLOW_EMAIL_LOGIN=true
ALLOW_REGISTRATION=true
ALLOW_SOCIAL_LOGIN=false
ALLOW_SOCIAL_REGISTRATION=false
ALLOW_PASSWORD_RESET=false
# ALLOW_ACCOUNT_DELETION=true # note: enabled by default if omitted/commented out
ALLOW_UNVERIFIED_EMAIL_LOGIN=true
SESSION_EXPIRY=1000 * 60 * 15
REFRESH_TOKEN_EXPIRY=(1000 * 60 * 60 * 24) * 7
JWT_SECRET=16f8c0ef4a5d391b26034086c628469d3f9f497f08163ab9b40137092f2909ef
JWT_REFRESH_SECRET=eaa5191f2914e30b9387fd84e254e4ba6fc51b4654968a9b0803b456a54b8418
# Discord
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
DISCORD_CALLBACK_URL=/oauth/discord/callback
# Facebook
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
FACEBOOK_CALLBACK_URL=/oauth/facebook/callback
# GitHub
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_CALLBACK_URL=/oauth/github/callback
# GitHub Enterprise
# GITHUB_ENTERPRISE_BASE_URL=
# GITHUB_ENTERPRISE_USER_AGENT=
# Google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=/oauth/google/callback
# Apple
APPLE_CLIENT_ID=
APPLE_TEAM_ID=
APPLE_KEY_ID=
APPLE_PRIVATE_KEY_PATH=
APPLE_CALLBACK_URL=/oauth/apple/callback
# OpenID
OPENID_CLIENT_ID=
OPENID_CLIENT_SECRET=
OPENID_ISSUER=
OPENID_SESSION_SECRET=
OPENID_SCOPE="openid profile email"
OPENID_CALLBACK_URL=/oauth/openid/callback
OPENID_REQUIRED_ROLE=
OPENID_REQUIRED_ROLE_TOKEN_KIND=
OPENID_REQUIRED_ROLE_PARAMETER_PATH=
# Set to determine which user info property returned from OpenID Provider to store as the User's username
OPENID_USERNAME_CLAIM=
# Set to determine which user info property returned from OpenID Provider to store as the User's name
OPENID_NAME_CLAIM=
OPENID_BUTTON_LABEL=
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
OPENID_USE_PKCE=false
#Set to true to reuse openid tokens for authentication management instead of using the mongodb session and the custom refresh token.
OPENID_REUSE_TOKENS=
#By default, signing key verification results are cached in order to prevent excessive HTTP requests to the JWKS endpoint.
#If a signing key matching the kid is found, this will be cached and the next time this kid is requested the signing key will be served from the cache.
#Default is true.
OPENID_JWKS_URL_CACHE_ENABLED=
OPENID_JWKS_URL_CACHE_TIME= # 600000 ms eq to 10 minutes leave empty to disable caching
#Set to true to trigger token exchange flow to acquire access token for the userinfo endpoint.
OPENID_ON_BEHALF_FLOW_FOR_USERINFRO_REQUIRED=
OPENID_ON_BEHALF_FLOW_USERINFRO_SCOPE = "user.read" # example for Scope Needed for Microsoft Graph API
# Set to true to use the OpenID Connect end session endpoint for logout
OPENID_USE_END_SESSION_ENDPOINT=
# SAML
# Note: If OpenID is enabled, SAML authentication will be automatically disabled.
SAML_ENTRY_POINT=
SAML_ISSUER=
SAML_CERT=
SAML_CALLBACK_URL=/oauth/saml/callback
SAML_SESSION_SECRET=
# Attribute mappings (optional)
SAML_EMAIL_CLAIM=
SAML_USERNAME_CLAIM=
SAML_GIVEN_NAME_CLAIM=
SAML_FAMILY_NAME_CLAIM=
SAML_PICTURE_CLAIM=
SAML_NAME_CLAIM=
# Logint buttion settings (optional)
SAML_BUTTON_LABEL=
SAML_IMAGE_URL=
# Whether the SAML Response should be signed.
# - If "true", the entire `SAML Response` will be signed.
# - If "false" or unset, only the `SAML Assertion` will be signed (default behavior).
# SAML_USE_AUTHN_RESPONSE_SIGNED=
# LDAP
LDAP_URL=
LDAP_BIND_DN=
LDAP_BIND_CREDENTIALS=
LDAP_USER_SEARCH_BASE=
#LDAP_SEARCH_FILTER="mail="
LDAP_CA_CERT_PATH=
# LDAP_TLS_REJECT_UNAUTHORIZED=
# LDAP_STARTTLS=
# LDAP_LOGIN_USES_USERNAME=true
# LDAP_ID=
# LDAP_USERNAME=
# LDAP_EMAIL=
# LDAP_FULL_NAME=
#========================#
# Email Password Reset #
#========================#
EMAIL_SERVICE=
EMAIL_HOST=
EMAIL_PORT=25
EMAIL_ENCRYPTION=
EMAIL_ENCRYPTION_HOSTNAME=
EMAIL_ALLOW_SELFSIGNED=
EMAIL_USERNAME=
EMAIL_PASSWORD=
EMAIL_FROM_NAME=
EMAIL_FROM=noreply@hanzo.ai
#========================#
# Mailgun API #
#========================#
# MAILGUN_API_KEY=your-mailgun-api-key
# MAILGUN_DOMAIN=mg.yourdomain.com
# EMAIL_FROM=noreply@yourdomain.com
# EMAIL_FROM_NAME="Hanzo Chat"
# # Optional: For EU region
# MAILGUN_HOST=https://api.eu.mailgun.net
#========================#
# Firebase CDN #
#========================#
FIREBASE_API_KEY=
FIREBASE_AUTH_DOMAIN=
FIREBASE_PROJECT_ID=
FIREBASE_STORAGE_BUCKET=
FIREBASE_MESSAGING_SENDER_ID=
FIREBASE_APP_ID=
#========================#
# S3 AWS Bucket #
#========================#
AWS_ENDPOINT_URL=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_BUCKET_NAME=
#========================#
# Azure Blob Storage #
#========================#
AZURE_STORAGE_CONNECTION_STRING=
AZURE_STORAGE_PUBLIC_ACCESS=false
AZURE_CONTAINER_NAME=files
#========================#
# Shared Links #
#========================#
ALLOW_SHARED_LINKS=true
ALLOW_SHARED_LINKS_PUBLIC=true
#==============================#
# Static File Cache Control #
#==============================#
# Leave commented out to use defaults: 1 day (86400 seconds) for s-maxage and 2 days (172800 seconds) for max-age
# NODE_ENV must be set to production for these to take effect
# STATIC_CACHE_MAX_AGE=172800
# STATIC_CACHE_S_MAX_AGE=86400
# If you have another service in front of your Hanzo Chat doing compression, disable express based compression here
# DISABLE_COMPRESSION=true
#===================================================#
# UI #
#===================================================#
APP_TITLE=Hanzo Chat
# CUSTOM_FOOTER="My custom footer"
HELP_AND_FAQ_URL=https://hanzo.ai
# SHOW_BIRTHDAY_ICON=true
# Google tag manager id
#ANALYTICS_GTM_ID=user provided google tag manager id
#===============#
# REDIS Options #
#===============#
# REDIS_URI=10.10.10.10:6379
# USE_REDIS=true
# USE_REDIS_CLUSTER=true
# REDIS_CA=/path/to/ca.crt
#==================================================#
# Others #
#==================================================#
# You should leave the following commented out #
# NODE_ENV=
# E2E_USER_EMAIL=
# E2E_USER_PASSWORD=
#=====================================================#
# Cache Headers #
#=====================================================#
# Headers that control caching of the index.html #
# Default configuration prevents caching to ensure #
# users always get the latest version. Customize #
# only if you understand caching implications. #
# INDEX_CACHE_CONTROL=no-cache, no-store, must-revalidate
# INDEX_PRAGMA=no-cache
# INDEX_EXPIRES=0
# no-cache: Forces validation with server before using cached version
# no-store: Prevents storing the response entirely
# must-revalidate: Prevents using stale content when offline
#=====================================================#
# OpenWeather #
#=====================================================#
OPENWEATHER_API_KEY=
#====================================#
# Hanzo Chat Code Interpreter API #
#====================================#
# https://code.hanzo.ai
# HANZO_CODE_API_KEY=your-key
#======================#
# Web Search #
#======================#
# Note: All of the following variable names can be customized.
# Omit values to allow user to provide them.
# For more information on configuration values, see:
# https://docs.hanzo.ai/chat/features/web_search
# Search Provider (Required)
# SERPER_API_KEY=your_serper_api_key
# Scraper (Required)
# FIRECRAWL_API_KEY=your_firecrawl_api_key
# Optional: Custom Firecrawl API URL
# FIRECRAWL_API_URL=your_firecrawl_api_url
# Reranker (Required)
# JINA_API_KEY=your_jina_api_key
# or
# COHERE_API_KEY=your_cohere_api_key
-95
View File
@@ -1,95 +0,0 @@
# ==================================
# BRAND MODE EXAMPLE CONFIGURATION
# ==================================
# This example shows how to configure Hanzo Chat in brand mode
# for white-label deployments
# Copy the main .env.example first, then override with these settings:
# cp .env.example .env
# Then add these brand mode settings
# ==================================
# Enable Brand Mode
# ==================================
BRAND_MODE=true
# ==================================
# Brand Configuration
# ==================================
BRAND_NAME=ACME AI
BRAND_MODEL_DEFAULT=ACME Assistant
BRAND_MODEL_PRO=ACME Assistant Pro
# Optional branding
BRAND_COLOR=#FF6B6B
BRAND_LOGO_URL=/assets/acme-logo.svg
APP_TITLE=ACME AI Chat
# ==================================
# Backend Configuration
# ==================================
# Configure which actual AI provider to use behind the scenes
# Example 1: Using Anthropic Claude
BRAND_BACKEND_ENDPOINT=anthropic
BRAND_BACKEND_API_KEY=sk-ant-api03-YOUR-KEY-HERE
BRAND_BACKEND_MODEL_DEFAULT=claude-3-5-sonnet-20241022
BRAND_BACKEND_MODEL_PRO=claude-3-5-opus-latest
# Example 2: Using OpenAI
# BRAND_BACKEND_ENDPOINT=openAI
# BRAND_BACKEND_API_KEY=sk-YOUR-OPENAI-KEY
# BRAND_BACKEND_MODEL_DEFAULT=gpt-4o-mini
# BRAND_BACKEND_MODEL_PRO=gpt-4o
# Example 3: Using Hanzo AI API (recommended)
# BRAND_BACKEND_ENDPOINT=hanzoai
# BRAND_BACKEND_API_KEY=hsk-YOUR-HANZO-KEY
# BRAND_BACKEND_BASE_URL=https://api.hanzo.ai/v1
# BRAND_BACKEND_MODEL_DEFAULT=hanzo-zen-1
# BRAND_BACKEND_MODEL_PRO=hanzo-zen-1-pro
# ==================================
# Other Required Settings
# ==================================
# Don't forget to set these from the main .env.example:
# Server
HOST=0.0.0.0
PORT=3080
# Database
MONGO_URI=mongodb://mongodb:27017/BrandChat
# Security (generate your own!)
JWT_SECRET=your-super-secret-jwt-key-change-this
JWT_REFRESH_SECRET=your-refresh-secret-key-change-this
CREDS_KEY=your-32-character-encryption-key
CREDS_IV=16-char-creds-iv
# Search (optional)
MEILI_HOST=http://meilisearch:7700
MEILI_MASTER_KEY=your-master-key-minimum-16-bytes
# ==================================
# What Brand Mode Does
# ==================================
# When BRAND_MODE=true:
#
# 1. Only shows your branded models (ACME Assistant, ACME Assistant Pro)
# 2. Hides all endpoint/provider selection UI
# 3. Hides API key configuration options
# 4. Routes all requests through your configured backend
# 5. Users never see the actual AI provider being used
# 6. Perfect for white-label SaaS deployments
#
# Your users will only see:
# - Your brand name (ACME AI)
# - Your model names (ACME Assistant)
# - Your logo and colors
# - No configuration options
#
# Behind the scenes, you control:
# - Which AI provider to use
# - Which actual models to use
# - All API keys and routing
-13
View File
@@ -1,13 +0,0 @@
# Docker Registry Configuration
# Uncomment one of the following to choose your registry:
# For Docker Hub (default):
DOCKER_REGISTRY=docker.io
DOCKER_IMAGE_PREFIX=
# For GitHub Container Registry:
# DOCKER_REGISTRY=ghcr.io
# DOCKER_IMAGE_PREFIX=ghcr.io/
# Organization name
DOCKER_ORG=hanzoai
+84 -241
View File
@@ -2,37 +2,51 @@
# Hanzo Chat Configuration #
#=====================================================================#
# Please refer to the reference documentation for assistance #
# with configuring your Hanzo Chat environment. #
# with configuring your Hanzo Chat environment. #
# #
# https://hanzo.ai/docs/chat/configuration/dotenv #
# https://docs.hanzo.ai/chat/configuration/dotenv #
#=====================================================================#
#==================================================#
# Server Configuration #
#==================================================#
HOST=localhost
HOST=0.0.0.0
PORT=3080
MONGO_URI=mongodb://127.0.0.1:27017/HanzoChat
#The maximum number of connections in the connection pool. */
MONGO_MAX_POOL_SIZE=
#The minimum number of connections in the connection pool. */
MONGO_MIN_POOL_SIZE=
#The maximum number of connections that may be in the process of being established concurrently by the connection pool. */
MONGO_MAX_CONNECTING=
#The maximum number of milliseconds that a connection can remain idle in the pool before being removed and closed. */
MONGO_MAX_IDLE_TIME_MS=
#The maximum time in milliseconds that a thread can wait for a connection to become available. */
MONGO_WAIT_QUEUE_TIMEOUT_MS=
# Set to false to disable automatic index creation for all models associated with this connection. */
MONGO_AUTO_INDEX=
# Set to `false` to disable Mongoose automatically calling `createCollection()` on every model created on this connection. */
MONGO_AUTO_CREATE=
# For Docker: mongodb://mongodb:27017/Hanzo
# For Local: mongodb://127.0.0.1:27017/HanzoChat
MONGO_URI=mongodb://mongodb:27017/Hanzo
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
#==================================================#
# Brand Mode Configuration #
#==================================================#
# Enable brand mode for white-label deployments
BRAND_MODE=true
# Vendor display name (shown in UI)
BRAND_NAME=Hanzo AI
# Fixed model names for brand mode
BRAND_MODEL_DEFAULT=Hanzo Zen-1
BRAND_MODEL_PRO=Hanzo Zen-1 Pro
# Branding
APP_TITLE=Hanzo AI Chat
BRAND_COLOR=#000000
BRAND_LOGO_URL=/assets/hanzo-logo.svg
# Backend routing for brand mode
# The actual API endpoint and key used internally
BRAND_BACKEND_ENDPOINT=anthropic # Options: openAI, anthropic, hanzoai, custom
BRAND_BACKEND_API_KEY=
BRAND_BACKEND_BASE_URL=https://api.hanzo.ai/v1
BRAND_BACKEND_MODEL_DEFAULT=claude-3-5-sonnet-20241022 # Actual model used
BRAND_BACKEND_MODEL_PRO=claude-3-opus-20240229 # Actual pro model used
NO_INDEX=true
# Use the address that is at most n number of hops away from the Express application.
# req.socket.remoteAddress is the first hop, and the rest are looked for in the X-Forwarded-For header from right to left.
@@ -40,17 +54,6 @@ NO_INDEX=true
# Defaulted to 1.
TRUST_PROXY=1
# Minimum password length for user authentication
# Default: 8
# Note: When using LDAP authentication, you may want to set this to 1
# to bypass local password validation, as LDAP servers handle their own
# password policies.
# MIN_PASSWORD_LENGTH=8
# When enabled, the app will continue running after encountering uncaught exceptions
# instead of exiting the process. Not recommended for production unless necessary.
# CONTINUE_ON_UNCAUGHT_EXCEPTION=false
#===============#
# JSON Logging #
#===============#
@@ -72,18 +75,6 @@ DEBUG_CONSOLE=false
# UID=1000
# GID=1000
#==============#
# Node Options #
#==============#
# NOTE: NODE_MAX_OLD_SPACE_SIZE is NOT recognized by Node.js directly.
# This variable is used as a build argument for Docker or CI/CD workflows,
# and is NOT used by Node.js to set the heap size at runtime.
# To configure Node.js memory, use NODE_OPTIONS, e.g.:
# NODE_OPTIONS="--max-old-space-size=6144"
# See: https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-mib
NODE_MAX_OLD_SPACE_SIZE=6144
#===============#
# Configuration #
#===============#
@@ -91,16 +82,6 @@ NODE_MAX_OLD_SPACE_SIZE=6144
# CONFIG_PATH="/alternative/path/to/chat.yaml"
#==================#
# Langfuse Tracing #
#==================#
# Get Langfuse API keys for your project from the project settings page: https://cloud.langfuse.com
# LANGFUSE_PUBLIC_KEY=
# LANGFUSE_SECRET_KEY=
# LANGFUSE_BASE_URL=
#===================================================#
# Endpoints #
#===================================================#
@@ -109,18 +90,17 @@ NODE_MAX_OLD_SPACE_SIZE=6144
PROXY=
#===============================#
# Hanzo API (Zen models) #
#===============================#
# Publishable key for unauthenticated users (rate-limited).
# Authenticated users get their real API key after IAM login (hanzo.id).
# Endpoint: https://api.hanzo.ai/v1
HANZO_API_KEY=
#============#
# Hanzo API #
#============#
# Unified API Gateway for all LLMs
# When set, all models will route through Hanzo API unless user provides their own keys
# HANZO_API_KEY=hsk_...
#===================================#
# Known Endpoints - chat.yaml #
# Known Endpoints - chat.yaml #
#===================================#
# https://hanzo.ai/docs/chat/configuration/ai_endpoints
# https://docs.hanzo.ai/chat/configuration/ai_endpoints
# ANYSCALE_API_KEY=
# APIPIE_API_KEY=
@@ -143,13 +123,9 @@ HANZO_API_KEY=
#============#
ANTHROPIC_API_KEY=user_provided
# ANTHROPIC_MODELS=claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_MODELS=claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
# Set to true to use Anthropic models through Google Vertex AI instead of direct API
# ANTHROPIC_USE_VERTEX=
# ANTHROPIC_VERTEX_REGION=us-east5
#============#
# Azure #
#============#
@@ -167,6 +143,7 @@ ANTHROPIC_API_KEY=user_provided
# AZURE_OPENAI_API_VERSION= # Deprecated
# AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= # Deprecated
# PLUGINS_USE_AZURE="true" # Deprecated
#=================#
# AWS Bedrock #
@@ -178,8 +155,7 @@ ANTHROPIC_API_KEY=user_provided
# BEDROCK_AWS_SESSION_TOKEN=someSessionToken
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
# BEDROCK_AWS_MODELS=anthropic.claude-sonnet-4-6,anthropic.claude-opus-4-6-v1,anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
# Cross-region inference model IDs: us.anthropic.claude-sonnet-4-6,us.anthropic.claude-opus-4-6-v1,global.anthropic.claude-opus-4-6-v1
# BEDROCK_AWS_MODELS=anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
@@ -201,23 +177,15 @@ GOOGLE_KEY=user_provided
# GOOGLE_AUTH_HEADER=true
# Gemini API (AI Studio)
# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash,gemini-2.0-flash-lite
# Vertex AI
# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_TITLE_MODEL=gemini-2.0-flash-lite-001
# Google Cloud region for Vertex AI (used by both chat and image generation)
# GOOGLE_LOC=us-central1
# Alternative region env var for Gemini Image Generation
# GOOGLE_CLOUD_LOCATION=global
# Vertex AI Service Account Configuration
# Path to your Google Cloud service account JSON file
# GOOGLE_SERVICE_KEY_FILE=/path/to/service-account.json
# Google Safety Settings
# NOTE: These settings apply to both Vertex AI and Gemini API (AI Studio)
#
@@ -237,33 +205,12 @@ GOOGLE_KEY=user_provided
# GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH
#========================#
# Gemini Image Generation #
#========================#
# Gemini Image Generation Tool (for Agents)
# Supports multiple authentication methods in priority order:
# 1. User-provided API key (via GUI)
# 2. GEMINI_API_KEY env var (admin-configured)
# 3. GOOGLE_KEY env var (shared with Google chat endpoint)
# 4. Vertex AI service account (via GOOGLE_SERVICE_KEY_FILE)
# Option A: Use dedicated Gemini API key for image generation
# GEMINI_API_KEY=your-gemini-api-key
# Option B: Use Vertex AI (no API key needed, uses service account)
# Set this to enable Vertex AI and allow tool without requiring API keys
# GEMINI_VERTEX_ENABLED=true
# Vertex AI model for image generation (defaults to gemini-2.5-flash-image)
# GEMINI_IMAGE_MODEL=gemini-2.5-flash-image
#============#
# OpenAI #
#============#
OPENAI_API_KEY=user_provided
# OPENAI_MODELS=gpt-5,gpt-5-codex,gpt-5-mini,gpt-5-nano,o3-pro,o3,o4-mini,gpt-4.1,gpt-4.1-mini,gpt-4.1-nano,o3-mini,o1-pro,o1,gpt-4o,gpt-4o-mini
# OPENAI_MODELS=o1,o1-mini,o1-preview,gpt-4o,gpt-4.5-preview,chatgpt-4o-latest,gpt-4o-mini,gpt-3.5-turbo-0125,gpt-3.5-turbo-0301,gpt-3.5-turbo,gpt-4,gpt-4-0613,gpt-4-vision-preview,gpt-3.5-turbo-0613,gpt-3.5-turbo-16k-0613,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview,gpt-3.5-turbo-1106,gpt-3.5-turbo-instruct,gpt-3.5-turbo-instruct-0914,gpt-3.5-turbo-16k
DEBUG_OPENAI=false
@@ -295,7 +242,18 @@ ASSISTANTS_API_KEY=user_provided
# The models for Azure Assistants are also determined by your Azure OpenAI configuration.
# More info, including how to enable use of Assistants with Azure here:
# https://hanzo.ai/docs/chat/configuration/ai_endpoints/azure#using-assistants-with-azure
# https://docs.hanzo.ai/chat/configuration/ai_endpoints/azure#using-assistants-with-azure
#============#
# Plugins #
#============#
# PLUGIN_MODELS=gpt-4o,gpt-4o-mini,gpt-4,gpt-4-turbo-preview,gpt-4-0125-preview,gpt-4-1106-preview,gpt-4-0613,gpt-3.5-turbo,gpt-3.5-turbo-0125,gpt-3.5-turbo-1106,gpt-3.5-turbo-0613
DEBUG_PLUGINS=true
CREDS_KEY=f34be427ebb29de8d88c107a71546019685ed8b241d8f2ed00c3df97ad2566f0
CREDS_IV=e2341419ec3dd3d19b13a1a87fafcbfb
# Azure AI Search
#-----------------
@@ -310,11 +268,6 @@ AZURE_AI_SEARCH_SEARCH_OPTION_SELECT=
# OpenAI Image Tools Customization
#----------------
# IMAGE_GEN_OAI_API_KEY= # Create or reuse OpenAI API key for image generation tool
# IMAGE_GEN_OAI_BASEURL= # Custom OpenAI base URL for image generation tool
# IMAGE_GEN_OAI_AZURE_API_VERSION= # Custom Azure OpenAI deployments
# IMAGE_GEN_OAI_MODEL=gpt-image-1 # OpenAI image model (e.g., gpt-image-1, gpt-image-1.5)
# IMAGE_GEN_OAI_DESCRIPTION=
# IMAGE_GEN_OAI_DESCRIPTION_WITH_FILES=Custom description for image generation tool when files are present
# IMAGE_GEN_OAI_DESCRIPTION_NO_FILES=Custom description for image generation tool when no files are present
# IMAGE_EDIT_OAI_DESCRIPTION=Custom description for image editing tool
@@ -351,6 +304,14 @@ FLUX_API_BASE_URL=https://api.us1.bfl.ai
GOOGLE_SEARCH_API_KEY=
GOOGLE_CSE_ID=
# YOUTUBE
#-----------------
YOUTUBE_API_KEY=
# SerpAPI
#-----------------
SERPAPI_API_KEY=
# Stable Diffusion
#-----------------
SD_WEBUI_URL=http://host.docker.internal:7860
@@ -377,8 +338,10 @@ ZAPIER_NLA_API_KEY=
SEARCH=true
MEILI_NO_ANALYTICS=true
MEILI_HOST=http://0.0.0.0:7700
MEILI_MASTER_KEY=
# For Docker: http://meilisearch:7700
# For Local: http://0.0.0.0:7700
MEILI_HOST=http://meilisearch:7700
MEILI_MASTER_KEY=your-master-key-minimum-16-bytes
# Optional: Disable indexing, useful in a multi-node setup
# where only one instance should perform an index sync.
@@ -394,7 +357,7 @@ TTS_API_KEY=
#==================================================#
# RAG #
#==================================================#
# More info: https://hanzo.ai/docs/chat/configuration/rag_api
# More info: https://docs.hanzo.ai/chat/configuration/rag_api
# RAG_OPENAI_BASEURL=
# RAG_OPENAI_API_KEY=
@@ -423,11 +386,6 @@ REGISTRATION_VIOLATION_SCORE=1
CONCURRENT_VIOLATION_SCORE=1
MESSAGE_VIOLATION_SCORE=1
NON_BROWSER_VIOLATION_SCORE=20
TTS_VIOLATION_SCORE=0
STT_VIOLATION_SCORE=0
FORK_VIOLATION_SCORE=0
IMPORT_VIOLATION_SCORE=0
FILE_UPLOAD_VIOLATION_SCORE=0
LOGIN_MAX=7
LOGIN_WINDOW=5
@@ -469,8 +427,8 @@ ALLOW_UNVERIFIED_EMAIL_LOGIN=true
SESSION_EXPIRY=1000 * 60 * 15
REFRESH_TOKEN_EXPIRY=(1000 * 60 * 60 * 24) * 7
JWT_SECRET=
JWT_REFRESH_SECRET=
JWT_SECRET=16f8c0ef4a5d391b26034086c628469d3f9f497f08163ab9b40137092f2909ef
JWT_REFRESH_SECRET=eaa5191f2914e30b9387fd84e254e4ba6fc51b4654968a9b0803b456a54b8418
# Discord
DISCORD_CLIENT_ID=
@@ -512,15 +470,10 @@ OPENID_CALLBACK_URL=/oauth/openid/callback
OPENID_REQUIRED_ROLE=
OPENID_REQUIRED_ROLE_TOKEN_KIND=
OPENID_REQUIRED_ROLE_PARAMETER_PATH=
OPENID_ADMIN_ROLE=
OPENID_ADMIN_ROLE_PARAMETER_PATH=
OPENID_ADMIN_ROLE_TOKEN_KIND=
# Set to determine which user info property returned from OpenID Provider to store as the User's username
OPENID_USERNAME_CLAIM=
# Set to determine which user info property returned from OpenID Provider to store as the User's name
OPENID_NAME_CLAIM=
# Optional audience parameter for OpenID authorization requests
OPENID_AUDIENCE=
OPENID_BUTTON_LABEL=
OPENID_IMAGE_URL=
@@ -537,28 +490,11 @@ OPENID_REUSE_TOKENS=
OPENID_JWKS_URL_CACHE_ENABLED=
OPENID_JWKS_URL_CACHE_TIME= # 600000 ms eq to 10 minutes leave empty to disable caching
#Set to true to trigger token exchange flow to acquire access token for the userinfo endpoint.
OPENID_ON_BEHALF_FLOW_FOR_USERINFO_REQUIRED=
OPENID_ON_BEHALF_FLOW_USERINFO_SCOPE="user.read" # example for Scope Needed for Microsoft Graph API
OPENID_ON_BEHALF_FLOW_FOR_USERINFRO_REQUIRED=
OPENID_ON_BEHALF_FLOW_USERINFRO_SCOPE = "user.read" # example for Scope Needed for Microsoft Graph API
# Set to true to use the OpenID Connect end session endpoint for logout
OPENID_USE_END_SESSION_ENDPOINT=
# URL to redirect to after OpenID logout (defaults to ${DOMAIN_CLIENT}/login)
OPENID_POST_LOGOUT_REDIRECT_URI=
#========================#
# SharePoint Integration #
#========================#
# Requires Entra ID (OpenID) authentication to be configured
# Enable SharePoint file picker in chat and agent panels
# ENABLE_SHAREPOINT_FILEPICKER=true
# SharePoint tenant base URL (e.g., https://yourtenant.sharepoint.com)
# SHAREPOINT_BASE_URL=https://yourtenant.sharepoint.com
# Microsoft Graph API And SharePoint scopes for file picker
# SHAREPOINT_PICKER_SHAREPOINT_SCOPE==https://yourtenant.sharepoint.com/AllSites.Read
# SHAREPOINT_PICKER_GRAPH_SCOPE=Files.Read.All
#========================#
# SAML
# Note: If OpenID is enabled, SAML authentication will be automatically disabled.
@@ -586,21 +522,6 @@ SAML_IMAGE_URL=
# SAML_USE_AUTHN_RESPONSE_SIGNED=
#===============================================#
# Microsoft Graph API / Entra ID Integration #
#===============================================#
# Enable Entra ID people search integration in permissions/sharing system
# When enabled, the people picker will search both local database and Entra ID
USE_ENTRA_ID_FOR_PEOPLE_SEARCH=false
# When enabled, entra id groups owners will be considered as members of the group
ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS=false
# Microsoft Graph API scopes needed for people/group search
# Default scopes provide access to user profiles and group memberships
OPENID_GRAPH_SCOPES=User.Read,People.Read,GroupMember.Read.All
# LDAP
LDAP_URL=
LDAP_BIND_DN=
@@ -663,9 +584,6 @@ AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_BUCKET_NAME=
# Required for path-style S3-compatible providers (MinIO, Hetzner, Backblaze B2, etc.)
# that don't support virtual-hosted-style URLs (bucket.endpoint). Not needed for AWS S3.
# AWS_FORCE_PATH_STYLE=false
#========================#
# Azure Blob Storage #
@@ -694,86 +612,28 @@ ALLOW_SHARED_LINKS_PUBLIC=true
# If you have another service in front of your Hanzo Chat doing compression, disable express based compression here
# DISABLE_COMPRESSION=true
# If you have gzipped version of uploaded image images in the same folder, this will enable gzip scan and serving of these images
# Note: The images folder will be scanned on startup and a ma kept in memory. Be careful for large number of images.
# ENABLE_IMAGE_OUTPUT_GZIP_SCAN=true
#===================================================#
# UI #
#===================================================#
APP_TITLE=Hanzo Chat
# APP_TITLE is set in brand mode section above
# CUSTOM_FOOTER="My custom footer"
HELP_AND_FAQ_URL=https://hanzo.ai/chat
HELP_AND_FAQ_URL=https://hanzo.ai
# SHOW_BIRTHDAY_ICON=true
# Google tag manager id
#ANALYTICS_GTM_ID=user provided google tag manager id
# limit conversation file imports to a certain number of bytes in size to avoid the container
# maxing out memory limitations by unremarking this line and supplying a file size in bytes
# such as the below example of 250 mib
# CONVERSATION_IMPORT_MAX_FILE_SIZE_BYTES=262144000
#===============#
# REDIS Options #
#===============#
# Enable Redis for caching and session storage
# REDIS_URI=10.10.10.10:6379
# USE_REDIS=true
# Enable Redis for resumable LLM streams (defaults to USE_REDIS value if not set)
# Set to false to use in-memory storage for streams while keeping Redis for other caches
# USE_REDIS_STREAMS=true
# Single Redis instance
# REDIS_URI=redis://127.0.0.1:6379
# Redis cluster (multiple nodes)
# REDIS_URI=redis://127.0.0.1:7001,redis://127.0.0.1:7002,redis://127.0.0.1:7003
# Redis with TLS/SSL encryption and CA certificate
# REDIS_URI=rediss://127.0.0.1:6380
# REDIS_CA=/path/to/ca-cert.pem
# Elasticache may need to use an alternate dnsLookup for TLS connections. see "Special Note: Aws Elasticache Clusters with TLS" on this webpage: https://www.npmjs.com/package/ioredis
# Enable alternative dnsLookup for redis
# REDIS_USE_ALTERNATIVE_DNS_LOOKUP=true
# Redis authentication (if required)
# REDIS_USERNAME=your_redis_username
# REDIS_PASSWORD=your_redis_password
# Redis key prefix configuration
# Use environment variable name for dynamic prefix (recommended for cloud deployments)
# REDIS_KEY_PREFIX_VAR=K_REVISION
# Or use static prefix directly
# REDIS_KEY_PREFIX=librechat
# Redis connection limits
# REDIS_MAX_LISTENERS=40
# Redis ping interval in seconds (0 = disabled, >0 = enabled)
# When set to a positive integer, Redis clients will ping the server at this interval to keep connections alive
# When unset or 0, no pinging is performed (recommended for most use cases)
# REDIS_PING_INTERVAL=300
# Force specific cache namespaces to use in-memory storage even when Redis is enabled
# Comma-separated list of CacheKeys
# Defaults to CONFIG_STORE,APP_CONFIG so YAML-derived config stays per-container (safe for blue/green deployments)
# Set to empty string to force all namespaces through Redis: FORCED_IN_MEMORY_CACHE_NAMESPACES=
# FORCED_IN_MEMORY_CACHE_NAMESPACES=CONFIG_STORE,APP_CONFIG
# Leader Election Configuration (for multi-instance deployments with Redis)
# Duration in seconds that the leader lease is valid before it expires (default: 25)
# LEADER_LEASE_DURATION=25
# Interval in seconds at which the leader renews its lease (default: 10)
# LEADER_RENEW_INTERVAL=10
# Maximum number of retry attempts when renewing the lease fails (default: 3)
# LEADER_RENEW_ATTEMPTS=3
# Delay in seconds between retry attempts when renewing the lease (default: 0.5)
# LEADER_RENEW_RETRY_DELAY=0.5
# USE_REDIS_CLUSTER=true
# REDIS_CA=/path/to/ca.crt
#==================================================#
# Others #
@@ -807,11 +667,11 @@ HELP_AND_FAQ_URL=https://hanzo.ai/chat
OPENWEATHER_API_KEY=
#====================================#
# Hanzo Chat Code Interpreter API #
# Hanzo Chat Code Interpreter API #
#====================================#
# https://hanzo.ai/docs/chat/code-interpreter
# LIBRECHAT_CODE_API_KEY=your-key
# https://code.hanzo.ai
# HANZO_CODE_API_KEY=your-key
#======================#
# Web Search #
@@ -821,7 +681,7 @@ OPENWEATHER_API_KEY=
# Omit values to allow user to provide them.
# For more information on configuration values, see:
# https://hanzo.ai/docs/chat/features/web_search
# https://docs.hanzo.ai/chat/features/web_search
# Search Provider (Required)
# SERPER_API_KEY=your_serper_api_key
@@ -835,20 +695,3 @@ OPENWEATHER_API_KEY=
# JINA_API_KEY=your_jina_api_key
# or
# COHERE_API_KEY=your_cohere_api_key
#======================#
# MCP Configuration #
#======================#
# Treat 401/403 responses as OAuth requirement when no oauth metadata found
# MCP_OAUTH_ON_AUTH_ERROR=true
# Timeout for OAuth detection requests in milliseconds
# MCP_OAUTH_DETECTION_TIMEOUT=5000
# Cache connection status checks for this many milliseconds to avoid expensive verification
# MCP_CONNECTION_CHECK_TTL=60000
# Skip code challenge method validation (e.g., for AWS Cognito that supports S256 but doesn't advertise it)
# When set to true, forces S256 code challenge even if not advertised in .well-known/openid-configuration
# MCP_SKIP_CODE_CHALLENGE_CHECK=false
-660
View File
@@ -1,660 +0,0 @@
#=====================================================================#
# LibreChat Configuration #
#=====================================================================#
# Please refer to the reference documentation for assistance #
# with configuring your LibreChat environment. #
# #
# https://www.librechat.ai/docs/configuration/dotenv #
#=====================================================================#
#==================================================#
# Server Configuration #
#==================================================#
HOST=localhost
PORT=3080
MONGO_URI=mongodb://127.0.0.1:27017/LibreChat
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
NO_INDEX=true
# Use the address that is at most n number of hops away from the Express application.
# req.socket.remoteAddress is the first hop, and the rest are looked for in the X-Forwarded-For header from right to left.
# A value of 0 means that the first untrusted address would be req.socket.remoteAddress, i.e. there is no reverse proxy.
# Defaulted to 1.
TRUST_PROXY=1
#===============#
# JSON Logging #
#===============#
# Use when process console logs in cloud deployment like GCP/AWS
CONSOLE_JSON=false
#===============#
# Debug Logging #
#===============#
DEBUG_LOGGING=true
DEBUG_CONSOLE=false
#=============#
# Permissions #
#=============#
# UID=1000
# GID=1000
#===============#
# Configuration #
#===============#
# Use an absolute path, a relative path, or a URL
# CONFIG_PATH="/alternative/path/to/librechat.yaml"
#===================================================#
# Endpoints #
#===================================================#
# ENDPOINTS=openAI,assistants,azureOpenAI,google,anthropic
PROXY=
#===================================#
# Known Endpoints - librechat.yaml #
#===================================#
# https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints
# ANYSCALE_API_KEY=
# APIPIE_API_KEY=
# COHERE_API_KEY=
# DEEPSEEK_API_KEY=
# DATABRICKS_API_KEY=
# FIREWORKS_API_KEY=
# GROQ_API_KEY=
# HUGGINGFACE_TOKEN=
# MISTRAL_API_KEY=
# OPENROUTER_KEY=
# PERPLEXITY_API_KEY=
# SHUTTLEAI_API_KEY=
# TOGETHERAI_API_KEY=
# UNIFY_API_KEY=
# XAI_API_KEY=
#============#
# Anthropic #
#============#
ANTHROPIC_API_KEY=user_provided
# ANTHROPIC_MODELS=claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
#============#
# Azure #
#============#
# Note: these variables are DEPRECATED
# Use the `librechat.yaml` configuration for `azureOpenAI` instead
# You may also continue to use them if you opt out of using the `librechat.yaml` configuration
# AZURE_OPENAI_DEFAULT_MODEL=gpt-3.5-turbo # Deprecated
# AZURE_OPENAI_MODELS=gpt-3.5-turbo,gpt-4 # Deprecated
# AZURE_USE_MODEL_AS_DEPLOYMENT_NAME=TRUE # Deprecated
# AZURE_API_KEY= # Deprecated
# AZURE_OPENAI_API_INSTANCE_NAME= # Deprecated
# AZURE_OPENAI_API_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_VERSION= # Deprecated
# AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= # Deprecated
# PLUGINS_USE_AZURE="true" # Deprecated
#=================#
# AWS Bedrock #
#=================#
# BEDROCK_AWS_DEFAULT_REGION=us-east-1 # A default region must be provided
# BEDROCK_AWS_ACCESS_KEY_ID=someAccessKey
# BEDROCK_AWS_SECRET_ACCESS_KEY=someSecretAccessKey
# BEDROCK_AWS_SESSION_TOKEN=someSessionToken
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
# BEDROCK_AWS_MODELS=anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
# Notes on specific models:
# The following models are not support due to not supporting streaming:
# ai21.j2-mid-v1
# The following models are not support due to not supporting conversation history:
# ai21.j2-ultra-v1, cohere.command-text-v14, cohere.command-light-text-v14
#============#
# Google #
#============#
GOOGLE_KEY=user_provided
# GOOGLE_REVERSE_PROXY=
# Some reverse proxies do not support the X-goog-api-key header, uncomment to pass the API key in Authorization header instead.
# GOOGLE_AUTH_HEADER=true
# Gemini API (AI Studio)
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash,gemini-2.0-flash-lite
# Vertex AI
# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite-preview-06-17,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_TITLE_MODEL=gemini-2.0-flash-lite-001
# GOOGLE_LOC=us-central1
# Google Safety Settings
# NOTE: These settings apply to both Vertex AI and Gemini API (AI Studio)
#
# For Vertex AI:
# To use the BLOCK_NONE setting, you need either:
# (a) Access through an allowlist via your Google account team, or
# (b) Switch to monthly invoiced billing: https://cloud.google.com/billing/docs/how-to/invoiced-billing
#
# For Gemini API (AI Studio):
# BLOCK_NONE is available by default, no special account requirements.
#
# Available options: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE
#
# GOOGLE_SAFETY_SEXUALLY_EXPLICIT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_HATE_SPEECH=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_HARASSMENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH
#============#
# OpenAI #
#============#
OPENAI_API_KEY=user_provided
# OPENAI_MODELS=o1,o1-mini,o1-preview,gpt-4o,gpt-4.5-preview,chatgpt-4o-latest,gpt-4o-mini,gpt-3.5-turbo-0125,gpt-3.5-turbo-0301,gpt-3.5-turbo,gpt-4,gpt-4-0613,gpt-4-vision-preview,gpt-3.5-turbo-0613,gpt-3.5-turbo-16k-0613,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview,gpt-3.5-turbo-1106,gpt-3.5-turbo-instruct,gpt-3.5-turbo-instruct-0914,gpt-3.5-turbo-16k
DEBUG_OPENAI=false
# TITLE_CONVO=false
# OPENAI_TITLE_MODEL=gpt-4o-mini
# OPENAI_SUMMARIZE=true
# OPENAI_SUMMARY_MODEL=gpt-4o-mini
# OPENAI_FORCE_PROMPT=true
# OPENAI_REVERSE_PROXY=
# OPENAI_ORGANIZATION=
#====================#
# Assistants API #
#====================#
ASSISTANTS_API_KEY=user_provided
# ASSISTANTS_BASE_URL=
# ASSISTANTS_MODELS=gpt-4o,gpt-4o-mini,gpt-3.5-turbo-0125,gpt-3.5-turbo-16k-0613,gpt-3.5-turbo-16k,gpt-3.5-turbo,gpt-4,gpt-4-0314,gpt-4-32k-0314,gpt-4-0613,gpt-3.5-turbo-0613,gpt-3.5-turbo-1106,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview
#==========================#
# Azure Assistants API #
#==========================#
# Note: You should map your credentials with custom variables according to your Azure OpenAI Configuration
# The models for Azure Assistants are also determined by your Azure OpenAI configuration.
# More info, including how to enable use of Assistants with Azure here:
# https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints/azure#using-assistants-with-azure
#============#
# Plugins #
#============#
# PLUGIN_MODELS=gpt-4o,gpt-4o-mini,gpt-4,gpt-4-turbo-preview,gpt-4-0125-preview,gpt-4-1106-preview,gpt-4-0613,gpt-3.5-turbo,gpt-3.5-turbo-0125,gpt-3.5-turbo-1106,gpt-3.5-turbo-0613
DEBUG_PLUGINS=true
CREDS_KEY=f34be427ebb29de8d88c107a71546019685ed8b241d8f2ed00c3df97ad2566f0
CREDS_IV=e2341419ec3dd3d19b13a1a87fafcbfb
# Azure AI Search
#-----------------
AZURE_AI_SEARCH_SERVICE_ENDPOINT=
AZURE_AI_SEARCH_INDEX_NAME=
AZURE_AI_SEARCH_API_KEY=
AZURE_AI_SEARCH_API_VERSION=
AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE=
AZURE_AI_SEARCH_SEARCH_OPTION_TOP=
AZURE_AI_SEARCH_SEARCH_OPTION_SELECT=
# OpenAI Image Tools Customization
#----------------
# IMAGE_GEN_OAI_DESCRIPTION_WITH_FILES=Custom description for image generation tool when files are present
# IMAGE_GEN_OAI_DESCRIPTION_NO_FILES=Custom description for image generation tool when no files are present
# IMAGE_EDIT_OAI_DESCRIPTION=Custom description for image editing tool
# IMAGE_GEN_OAI_PROMPT_DESCRIPTION=Custom prompt description for image generation tool
# IMAGE_EDIT_OAI_PROMPT_DESCRIPTION=Custom prompt description for image editing tool
# DALL·E
#----------------
# DALLE_API_KEY=
# DALLE3_API_KEY=
# DALLE2_API_KEY=
# DALLE3_SYSTEM_PROMPT=
# DALLE2_SYSTEM_PROMPT=
# DALLE_REVERSE_PROXY=
# DALLE3_BASEURL=
# DALLE2_BASEURL=
# DALL·E (via Azure OpenAI)
# Note: requires some of the variables above to be set
#----------------
# DALLE3_AZURE_API_VERSION=
# DALLE2_AZURE_API_VERSION=
# Flux
#-----------------
FLUX_API_BASE_URL=https://api.us1.bfl.ai
# FLUX_API_BASE_URL = 'https://api.bfl.ml';
# Get your API key at https://api.us1.bfl.ai/auth/profile
# FLUX_API_KEY=
# Google
#-----------------
GOOGLE_SEARCH_API_KEY=
GOOGLE_CSE_ID=
# YOUTUBE
#-----------------
YOUTUBE_API_KEY=
# SerpAPI
#-----------------
SERPAPI_API_KEY=
# Stable Diffusion
#-----------------
SD_WEBUI_URL=http://host.docker.internal:7860
# Tavily
#-----------------
TAVILY_API_KEY=
# Traversaal
#-----------------
TRAVERSAAL_API_KEY=
# WolframAlpha
#-----------------
WOLFRAM_APP_ID=
# Zapier
#-----------------
ZAPIER_NLA_API_KEY=
#==================================================#
# Search #
#==================================================#
SEARCH=true
MEILI_NO_ANALYTICS=true
MEILI_HOST=http://0.0.0.0:7700
MEILI_MASTER_KEY=DrhYf7zENyR6AlUCKmnz0eYASOQdl6zxH7s7MKFSfFCt
# Optional: Disable indexing, useful in a multi-node setup
# where only one instance should perform an index sync.
# MEILI_NO_SYNC=true
#==================================================#
# Speech to Text & Text to Speech #
#==================================================#
STT_API_KEY=
TTS_API_KEY=
#==================================================#
# RAG #
#==================================================#
# More info: https://www.librechat.ai/docs/configuration/rag_api
# RAG_OPENAI_BASEURL=
# RAG_OPENAI_API_KEY=
# RAG_USE_FULL_CONTEXT=
# EMBEDDINGS_PROVIDER=openai
# EMBEDDINGS_MODEL=text-embedding-3-small
#===================================================#
# User System #
#===================================================#
#========================#
# Moderation #
#========================#
OPENAI_MODERATION=false
OPENAI_MODERATION_API_KEY=
# OPENAI_MODERATION_REVERSE_PROXY=
BAN_VIOLATIONS=true
BAN_DURATION=1000 * 60 * 60 * 2
BAN_INTERVAL=20
LOGIN_VIOLATION_SCORE=1
REGISTRATION_VIOLATION_SCORE=1
CONCURRENT_VIOLATION_SCORE=1
MESSAGE_VIOLATION_SCORE=1
NON_BROWSER_VIOLATION_SCORE=20
LOGIN_MAX=7
LOGIN_WINDOW=5
REGISTER_MAX=5
REGISTER_WINDOW=60
LIMIT_CONCURRENT_MESSAGES=true
CONCURRENT_MESSAGE_MAX=2
LIMIT_MESSAGE_IP=true
MESSAGE_IP_MAX=40
MESSAGE_IP_WINDOW=1
LIMIT_MESSAGE_USER=false
MESSAGE_USER_MAX=40
MESSAGE_USER_WINDOW=1
ILLEGAL_MODEL_REQ_SCORE=5
#========================#
# Balance #
#========================#
# CHECK_BALANCE=false
# START_BALANCE=20000 # note: the number of tokens that will be credited after registration.
#========================#
# Registration and Login #
#========================#
ALLOW_EMAIL_LOGIN=true
ALLOW_REGISTRATION=true
ALLOW_SOCIAL_LOGIN=false
ALLOW_SOCIAL_REGISTRATION=false
ALLOW_PASSWORD_RESET=false
# ALLOW_ACCOUNT_DELETION=true # note: enabled by default if omitted/commented out
ALLOW_UNVERIFIED_EMAIL_LOGIN=true
SESSION_EXPIRY=1000 * 60 * 15
REFRESH_TOKEN_EXPIRY=(1000 * 60 * 60 * 24) * 7
JWT_SECRET=16f8c0ef4a5d391b26034086c628469d3f9f497f08163ab9b40137092f2909ef
JWT_REFRESH_SECRET=eaa5191f2914e30b9387fd84e254e4ba6fc51b4654968a9b0803b456a54b8418
# Discord
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
DISCORD_CALLBACK_URL=/oauth/discord/callback
# Facebook
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
FACEBOOK_CALLBACK_URL=/oauth/facebook/callback
# GitHub
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_CALLBACK_URL=/oauth/github/callback
# GitHub Enterprise
# GITHUB_ENTERPRISE_BASE_URL=
# GITHUB_ENTERPRISE_USER_AGENT=
# Google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=/oauth/google/callback
# Apple
APPLE_CLIENT_ID=
APPLE_TEAM_ID=
APPLE_KEY_ID=
APPLE_PRIVATE_KEY_PATH=
APPLE_CALLBACK_URL=/oauth/apple/callback
# OpenID
OPENID_CLIENT_ID=
OPENID_CLIENT_SECRET=
OPENID_ISSUER=
OPENID_SESSION_SECRET=
OPENID_SCOPE="openid profile email"
OPENID_CALLBACK_URL=/oauth/openid/callback
OPENID_REQUIRED_ROLE=
OPENID_REQUIRED_ROLE_TOKEN_KIND=
OPENID_REQUIRED_ROLE_PARAMETER_PATH=
# Set to determine which user info property returned from OpenID Provider to store as the User's username
OPENID_USERNAME_CLAIM=
# Set to determine which user info property returned from OpenID Provider to store as the User's name
OPENID_NAME_CLAIM=
OPENID_BUTTON_LABEL=
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
OPENID_USE_PKCE=false
#Set to true to reuse openid tokens for authentication management instead of using the mongodb session and the custom refresh token.
OPENID_REUSE_TOKENS=
#By default, signing key verification results are cached in order to prevent excessive HTTP requests to the JWKS endpoint.
#If a signing key matching the kid is found, this will be cached and the next time this kid is requested the signing key will be served from the cache.
#Default is true.
OPENID_JWKS_URL_CACHE_ENABLED=
OPENID_JWKS_URL_CACHE_TIME= # 600000 ms eq to 10 minutes leave empty to disable caching
#Set to true to trigger token exchange flow to acquire access token for the userinfo endpoint.
OPENID_ON_BEHALF_FLOW_FOR_USERINFRO_REQUIRED=
OPENID_ON_BEHALF_FLOW_USERINFRO_SCOPE = "user.read" # example for Scope Needed for Microsoft Graph API
# Set to true to use the OpenID Connect end session endpoint for logout
OPENID_USE_END_SESSION_ENDPOINT=
# SAML
# Note: If OpenID is enabled, SAML authentication will be automatically disabled.
SAML_ENTRY_POINT=
SAML_ISSUER=
SAML_CERT=
SAML_CALLBACK_URL=/oauth/saml/callback
SAML_SESSION_SECRET=
# Attribute mappings (optional)
SAML_EMAIL_CLAIM=
SAML_USERNAME_CLAIM=
SAML_GIVEN_NAME_CLAIM=
SAML_FAMILY_NAME_CLAIM=
SAML_PICTURE_CLAIM=
SAML_NAME_CLAIM=
# Logint buttion settings (optional)
SAML_BUTTON_LABEL=
SAML_IMAGE_URL=
# Whether the SAML Response should be signed.
# - If "true", the entire `SAML Response` will be signed.
# - If "false" or unset, only the `SAML Assertion` will be signed (default behavior).
# SAML_USE_AUTHN_RESPONSE_SIGNED=
# LDAP
LDAP_URL=
LDAP_BIND_DN=
LDAP_BIND_CREDENTIALS=
LDAP_USER_SEARCH_BASE=
#LDAP_SEARCH_FILTER="mail="
LDAP_CA_CERT_PATH=
# LDAP_TLS_REJECT_UNAUTHORIZED=
# LDAP_STARTTLS=
# LDAP_LOGIN_USES_USERNAME=true
# LDAP_ID=
# LDAP_USERNAME=
# LDAP_EMAIL=
# LDAP_FULL_NAME=
#========================#
# Email Password Reset #
#========================#
EMAIL_SERVICE=
EMAIL_HOST=
EMAIL_PORT=25
EMAIL_ENCRYPTION=
EMAIL_ENCRYPTION_HOSTNAME=
EMAIL_ALLOW_SELFSIGNED=
EMAIL_USERNAME=
EMAIL_PASSWORD=
EMAIL_FROM_NAME=
EMAIL_FROM=noreply@librechat.ai
#========================#
# Mailgun API #
#========================#
# MAILGUN_API_KEY=your-mailgun-api-key
# MAILGUN_DOMAIN=mg.yourdomain.com
# EMAIL_FROM=noreply@yourdomain.com
# EMAIL_FROM_NAME="LibreChat"
# # Optional: For EU region
# MAILGUN_HOST=https://api.eu.mailgun.net
#========================#
# Firebase CDN #
#========================#
FIREBASE_API_KEY=
FIREBASE_AUTH_DOMAIN=
FIREBASE_PROJECT_ID=
FIREBASE_STORAGE_BUCKET=
FIREBASE_MESSAGING_SENDER_ID=
FIREBASE_APP_ID=
#========================#
# S3 AWS Bucket #
#========================#
AWS_ENDPOINT_URL=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_BUCKET_NAME=
#========================#
# Azure Blob Storage #
#========================#
AZURE_STORAGE_CONNECTION_STRING=
AZURE_STORAGE_PUBLIC_ACCESS=false
AZURE_CONTAINER_NAME=files
#========================#
# Shared Links #
#========================#
ALLOW_SHARED_LINKS=true
ALLOW_SHARED_LINKS_PUBLIC=true
#==============================#
# Static File Cache Control #
#==============================#
# Leave commented out to use defaults: 1 day (86400 seconds) for s-maxage and 2 days (172800 seconds) for max-age
# NODE_ENV must be set to production for these to take effect
# STATIC_CACHE_MAX_AGE=172800
# STATIC_CACHE_S_MAX_AGE=86400
# If you have another service in front of your LibreChat doing compression, disable express based compression here
# DISABLE_COMPRESSION=true
#===================================================#
# UI #
#===================================================#
APP_TITLE=LibreChat
# CUSTOM_FOOTER="My custom footer"
HELP_AND_FAQ_URL=https://librechat.ai
# SHOW_BIRTHDAY_ICON=true
# Google tag manager id
#ANALYTICS_GTM_ID=user provided google tag manager id
#===============#
# REDIS Options #
#===============#
# REDIS_URI=10.10.10.10:6379
# USE_REDIS=true
# USE_REDIS_CLUSTER=true
# REDIS_CA=/path/to/ca.crt
#==================================================#
# Others #
#==================================================#
# You should leave the following commented out #
# NODE_ENV=
# E2E_USER_EMAIL=
# E2E_USER_PASSWORD=
#=====================================================#
# Cache Headers #
#=====================================================#
# Headers that control caching of the index.html #
# Default configuration prevents caching to ensure #
# users always get the latest version. Customize #
# only if you understand caching implications. #
# INDEX_CACHE_CONTROL=no-cache, no-store, must-revalidate
# INDEX_PRAGMA=no-cache
# INDEX_EXPIRES=0
# no-cache: Forces validation with server before using cached version
# no-store: Prevents storing the response entirely
# must-revalidate: Prevents using stale content when offline
#=====================================================#
# OpenWeather #
#=====================================================#
OPENWEATHER_API_KEY=
#====================================#
# LibreChat Code Interpreter API #
#====================================#
# https://code.librechat.ai
# LIBRECHAT_CODE_API_KEY=your-key
#======================#
# Web Search #
#======================#
# Note: All of the following variable names can be customized.
# Omit values to allow user to provide them.
# For more information on configuration values, see:
# https://librechat.ai/docs/features/web_search
# Search Provider (Required)
# SERPER_API_KEY=your_serper_api_key
# Scraper (Required)
# FIRECRAWL_API_KEY=your_firecrawl_api_key
# Optional: Custom Firecrawl API URL
# FIRECRAWL_API_URL=your_firecrawl_api_url
# Reranker (Required)
# JINA_API_KEY=your_jina_api_key
# or
# COHERE_API_KEY=your_cohere_api_key
-79
View File
@@ -1,79 +0,0 @@
# Hanzo Chat - Cloud Deployment Configuration
# All AI models routed through api.hanzo.ai (zen4 series + standard models)
# ====== HANZO CLOUD API ======
OPENAI_API_KEY=sk-hanzo-your-api-key-here
OPENAI_BASE_URL=https://api.hanzo.ai/v1
# Runtime Execution (Code Interpreter)
CODE_EXECUTION_ENDPOINT=https://api.hanzo.ai/v1/execute
RUNTIME_API_KEY=${OPENAI_API_KEY}
# ====== BRANDING ======
APP_TITLE=Hanzo Chat
CUSTOM_FOOTER=Powered by Hanzo AI
# ====== LOCAL SERVICES ======
# MongoDB for chat history
MONGO_URI=mongodb://hanzo:hanzo123@localhost:27017/HanzoChat?authSource=admin
MONGO_PASSWORD=hanzo123
# Meilisearch for full-text search
MEILI_HOST=http://localhost:7700
MEILI_MASTER_KEY=HanzoMeiliMasterKey
# ====== APPLICATION SETTINGS ======
DOMAIN_CLIENT=https://hanzo.chat
DOMAIN_SERVER=https://hanzo.chat
# ====== SECURITY (CHANGE IN PRODUCTION) ======
JWT_SECRET=hanzo-jwt-secret-change-in-production
JWT_REFRESH_SECRET=hanzo-refresh-secret-change-in-production
# ====== HANZO IAM (hanzo.id) OIDC SSO ======
OPENID_CLIENT_ID=chat-app
OPENID_CLIENT_SECRET=chat-app-client-secret
OPENID_ISSUER=https://hanzo.id
OPENID_SESSION_SECRET=hanzo-openid-session-change-in-production
OPENID_SCOPE=openid profile email
OPENID_CALLBACK_URL=/oauth/openid/callback
OPENID_BUTTON_LABEL=Log in with Hanzo
OPENID_IMAGE_URL=https://hanzo.ai/logo/icon.svg
OPENID_USERNAME_CLAIM=name
OPENID_NAME_CLAIM=name
OPENID_USE_PKCE=true
# ====== FEATURES ======
ALLOW_REGISTRATION=true
ALLOW_UNVERIFIED_EMAIL_LOGIN=true
ALLOW_SOCIAL_LOGIN=true
ALLOW_SOCIAL_REGISTRATION=true
# MCP Tools
MCP_ENABLED=true
# ====== AVAILABLE MODELS ======
# zen4 series (default, all via api.hanzo.ai):
# zen4 - General purpose
# zen4-pro - High capability
# zen4-max - Extended context
# zen4-mini - Fast & efficient
# zen4-ultra - Maximum reasoning
# zen4-coder - Code specialist
# zen4-thinking - Deep reasoning
# zen4-coder-pro - Premium coding
#
# Standard models (via api.hanzo.ai):
# gpt-4o, gpt-4o-mini
# claude-sonnet-4-5, claude-haiku-4-5
# deepseek-r1-distill-70b
# qwen3-32b
# Debug
DEBUG_LOGGING=false
# ====== NOTES ======
# 1. Get your Hanzo API key from https://hanzo.ai/dashboard
# 2. All AI providers are accessed through api.hanzo.ai -- no individual keys needed
# 3. Model list is configured in librechat.yaml under endpoints.custom (Hanzo endpoint)
# 4. zen4 is the default model for new conversations
-41
View File
@@ -1,41 +0,0 @@
# Hanzo IAM Integration Configuration
# Copy this file to .env and update with your values
# Hanzo IAM SSO Configuration
HANZO_IAM_CLIENT_ID=chat-local
HANZO_IAM_CLIENT_SECRET=your-client-secret-here
HANZO_IAM_SERVER_URL=http://localhost:9003
# For local development with Hanzo Stack
# HANZO_IAM_SERVER_URL=http://iam:3000 # Use this when running in Docker
# Hanzo Router Configuration
ROUTER_MASTER_KEY=your-master-key-here
LITELLM_MASTER_KEY=${ROUTER_MASTER_KEY} # For backward compatibility
PROXY_BASE_URL=http://localhost:3081
# Development Mode Demo Credentials (only works in development)
# These are only used when NODE_ENV=development or DEV_MODE=true
DEMO_USERNAME=demo@hanzo.ai
DEMO_PASSWORD=hanzo123
# Choose Authentication Method:
# Option 1: Built-in Auth (default)
UI_USERNAME=admin
# UI_PASSWORD=<your-password> # If not set, uses ROUTER_MASTER_KEY
# Option 2: Hanzo IAM SSO
# Comment out UI_USERNAME above and set HANZO_IAM_CLIENT_ID/SECRET
# Option 3: Other SSO Providers (requires Hanzo Router Enterprise)
# GOOGLE_CLIENT_ID=your-google-client-id
# GOOGLE_CLIENT_SECRET=your-google-client-secret
# MICROSOFT_CLIENT_ID=your-microsoft-client-id
# MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
# MICROSOFT_TENANT=your-tenant-id
# Database Configuration
DATABASE_URL=mongodb://localhost:27017/hanzo-router
# Enable Development Mode Features
DEV_MODE=false # Set to true for demo credentials
-67
View File
@@ -1,67 +0,0 @@
# Hanzo AI Chat Stack Environment Variables
# Copy this file to .env and update with your values
# ==================================
# LLM API Keys (at least one required)
# ==================================
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
TOGETHER_API_KEY=...
# ==================================
# Database Configuration
# ==================================
POSTGRES_PASSWORD=hanzo123
MONGO_PASSWORD=hanzo123
REDIS_PASSWORD=hanzosecret
# ==================================
# Service URLs
# ==================================
DOMAIN_CLIENT=http://localhost:3081
DOMAIN_SERVER=http://localhost:3081
# ==================================
# Security Keys (CHANGE IN PRODUCTION!)
# ==================================
ROUTER_MASTER_KEY=sk-hanzo-master-key
JWT_SECRET=hanzo-jwt-secret-change-in-production
JWT_REFRESH_SECRET=hanzo-refresh-secret-change-in-production
CREDS_KEY=hanzo-creds-key-change-in-production
CREDS_IV=hanzo-creds-iv-change
MEILI_MASTER_KEY=HanzoMeiliMasterKey
# ==================================
# Feature Flags
# ==================================
ALLOW_REGISTRATION=true
ALLOW_UNVERIFIED_EMAIL_LOGIN=false
DEBUG=false
# ==================================
# Performance Tuning
# ==================================
ROUTER_WORKERS=4
# ==================================
# Optional: Additional LLM Providers
# ==================================
# AZURE_API_KEY=...
# AZURE_API_BASE=https://your-resource.openai.azure.com/
# GROQ_API_KEY=...
# COHERE_API_KEY=...
# ==================================
# Optional: Observability
# ==================================
# LANGFUSE_PUBLIC_KEY=...
# LANGFUSE_SECRET_KEY=...
# LANGFUSE_HOST=https://cloud.langfuse.com
# ==================================
# Optional: Authentication Providers
# ==================================
# GOOGLE_CLIENT_ID=...
# GOOGLE_CLIENT_SECRET=...
# GITHUB_CLIENT_ID=...
# GITHUB_CLIENT_SECRET=...
-1
View File
@@ -1 +0,0 @@
ENDPOINTS=openAI,anthropic,custom
-37
View File
@@ -1,37 +0,0 @@
# Test Environment Configuration
NODE_ENV=test
# MongoDB for tests (use in-memory or test container)
MONGO_URI=mongodb://localhost:27017/HanzoChat_test
# Disable external services in tests
MEILI_HOST=
RAG_API_URL=
# Test user configuration
ALLOW_REGISTRATION=true
ALLOW_UNVERIFIED_EMAIL_LOGIN=true
# Disable rate limiting in tests
RATE_LIMIT_ENABLED=false
# Use test keys
CREDS_KEY=test-creds-key-32-chars-long-string
CREDS_IV=test-creds-iv-16
JWT_SECRET=test-jwt-secret-very-secure
JWT_REFRESH_SECRET=test-jwt-refresh-secret
# Disable analytics in tests
GOOGLE_ANALYTICS_ID=
SENTRY_DSN=
# Test domain
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
# Disable SSL in tests
TRUST_PROXY=0
# Silent logging
DEBUG_LOGGING=false
CONSOLE_JSON=false
-46
View File
@@ -1,46 +0,0 @@
[flake8]
ignore =
# The following ignores can be removed when formatting using black
W191,W291,W292,W293,W391,W504
E101,E111,E114,E116,E117,E121,E122,E123,E124,E125,E126,E127,E128,E129,E131,
E201,E202,E221,E222,E225,E226,E231,E241,E251,E252,E261,E265,E271,E272,E275,
E301,E302,E303,E305,E306,
# line break before binary operator
W503,
# inline comment should start with '# '
E262,
# too many leading '#' for block comment
E266,
# multiple imports on one line
E401,
# module level import not at top of file
E402,
# Line too long (82 > 79 characters)
E501,
# comparison to None should be 'if cond is None:'
E711,
# comparison to True should be 'if cond is True:' or 'if cond:'
E712,
# do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`
E721,
# do not use bare 'except'
E722,
# x is imported but unused
F401,
# 'from . import *' used; unable to detect undefined names
F403,
# x may be undefined, or defined from star imports:
F405,
# f-string is missing placeholders
F541,
# dictionary key '' repeated with different values
F601,
# redefinition of unused x from line 123
F811,
# undefined name x
F821,
# local variable x is assigned to but never used
F841,
# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#flake8
extend-ignore = E203
-10
View File
@@ -1,10 +0,0 @@
# Add the commit hash of any commit you want to ignore in `git blame` here.
# One commit hash per line.
#
# The GitHub Blame UI will use this file automatically!
#
# Run this command to always ignore formatting commits in `git blame`
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# Update pydantic code to fix warnings (GH-3600)
876840e9957bc7e9f7d6a2b58c4d7c53dad16481
-1
View File
@@ -1 +0,0 @@
*.ipynb linguist-vendored
+106
View File
@@ -0,0 +1,106 @@
# GitHub Branch Protection Rules
This document outlines the recommended branch protection rules for the Hanzo Chat repository.
## Main Branch Protection
Go to Settings → Branches → Add rule for `main`:
### Required Status Checks
- [x] **Require status checks to pass before merging**
- [x] Test Suite
- [x] Code Quality
- [x] Build Check
- [x] Security Scan
### Required Reviews
- [x] **Require pull request reviews before merging**
- Required approving reviews: 1
- [x] Dismiss stale pull request approvals when new commits are pushed
- [x] Require review from CODEOWNERS
### Additional Settings
- [x] **Require branches to be up to date before merging**
- [x] **Include administrators**
- [x] **Restrict who can push to matching branches**
- Add teams/users who can merge to main
## Develop Branch Protection
Go to Settings → Branches → Add rule for `develop`:
### Required Status Checks
- [x] **Require status checks to pass before merging**
- [x] Test Suite
- [x] Code Quality
### Required Reviews
- [x] **Require pull request reviews before merging**
- Required approving reviews: 1
## GitHub Actions Secrets
Add these secrets in Settings → Secrets and variables → Actions:
1. **CODECOV_TOKEN** - For coverage reporting (optional)
2. **SNYK_TOKEN** - For security scanning (optional)
3. **OPENAI_API_KEY** - For tests that require API access
4. **ANTHROPIC_API_KEY** - For tests that require API access
## Recommended `.github/CODEOWNERS` file
```
# Global owners
* @hanzoai/core-team
# Frontend
/client/ @hanzoai/frontend-team
/packages/data-provider/ @hanzoai/frontend-team
# Backend
/api/ @hanzoai/backend-team
/packages/data-schemas/ @hanzoai/backend-team
# CI/CD
/.github/ @hanzoai/devops-team
```
## PR Merge Strategy
In Settings → General → Pull Requests:
- [x] Allow squash merging
- [ ] Allow merge commits
- [ ] Allow rebase merging
- [x] Automatically delete head branches
## Status Checks Configuration
The following GitHub Actions workflows provide status checks:
1. **ci.yml** - Main CI pipeline
- `Test Suite` - Runs all tests
- `Code Quality` - Linting and formatting
- `Security Scan` - Dependency scanning
- `Build Check` - Ensures code builds
2. **pr-checks.yml** - PR-specific checks
- `Client Tests` - Runs only on client changes
- `API Tests` - Runs only on API changes
- `Bundle Size Check` - Monitors client bundle size
- `TypeScript Check` - Type checking
## Monitoring
Set up notifications for:
- Failed CI runs on main branch
- Security vulnerabilities
- Dependency updates
## Best Practices
1. **Never push directly to main** - Always use pull requests
2. **Keep PRs small and focused** - Easier to review and test
3. **Write descriptive PR titles** - They become part of the git history
4. **Update tests** - All new features should include tests
5. **Monitor CI times** - Keep test suites fast (< 10 minutes)
+1 -1
View File
@@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement here on GitHub or
on the official GitHub repository.
on the official [Discord Server](https://discord.gg/hanzoai).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
+46 -39
View File
@@ -4,11 +4,11 @@ Thank you to all the contributors who have helped make this project possible! We
## Contributing Guidelines
If the feature you would like to contribute has not already received prior approval from the project maintainers, please submit a request in the [Feature Requests & Suggestions category](https://github.com/hanzoai/chat/discussions/new?category=feature-requests-suggestions) of the discussions board before beginning work on it. The requests should include specific implementation details, including areas of the application that will be affected by the change (including designs if applicable), and any other relevant information that might be required for a speedy review. However, proposals are not required for small changes, bug fixes, or documentation improvements. Small changes and bug fixes should be tied to an [issue](https://github.com/hanzoai/chat/issues) and included in the corresponding pull request for tracking purposes.
If the feature you would like to contribute has not already received prior approval from the project maintainers (i.e., the feature is currently on the [roadmap](https://github.com/users/hanzoai/projects/2)), please submit a request in the [Feature Requests & Suggestions category](https://github.com/hanzoai/chat/discussions/new?category=feature-requests-suggestions) of the discussions board before beginning work on it. The requests should include specific implementation details, including areas of the application that will be affected by the change (including designs if applicable), and any other relevant information that might be required for a speedy review. However, proposals are not required for small changes, bug fixes, or documentation improvements. Small changes and bug fixes should be tied to an [issue](https://github.com/hanzoai/chat/issues) and included in the corresponding pull request for tracking purposes.
Please note that a pull request involving a feature that has not been reviewed and approved by the project maintainers may be rejected. We appreciate your understanding and cooperation.
If you would like to discuss the changes you wish to make, open an issue or discussion on [GitHub](https://github.com/hanzoai/chat), where you can engage with other contributors and seek guidance from the community.
If you would like to discuss the changes you wish to make, join our [Discord community](https://discord.gg/hanzoai), where you can engage with other contributors and seek guidance from the community.
## Our Standards
@@ -26,29 +26,33 @@ Project maintainers have the right and responsibility to remove, edit, or reject
## 1. Development Setup
1. Use Node.js v20.19.0+ or ^22.12.0 or >= 23.0.0.
2. Run `npm run smart-reinstall` to install dependencies (uses Turborepo). Use `npm run reinstall` for a clean install, or `npm ci` for a fresh lockfile-based install.
3. Build all compiled code: `npm run build`.
4. Setup and run unit tests:
1. Use Node.JS 20.x.
2. Install typescript globally: `npm i -g typescript`.
3. Run `npm ci` to install dependencies.
4. Build the data provider: `npm run build:data-provider`.
5. Build data schemas: `npm run build:data-schemas`.
6. Build API methods: `npm run build:api`.
7. Setup and run unit tests:
- Copy `.env.test`: `cp api/test/.env.test.example api/test/.env.test`.
- Run backend unit tests: `npm run test:api`.
- Run frontend unit tests: `npm run test:client`.
5. Setup and run integration tests:
8. Setup and run integration tests:
- Build client: `cd client && npm run build`.
- Create `.env`: `cp .env.example .env`.
- Install [MongoDB Community Edition](https://www.mongodb.com/docs/manual/administration/install-community/), ensure that `mongosh` connects to your local instance.
- Run: `npx install playwright`, then `npx playwright install`.
- Copy `config.local`: `cp e2e/config.local.example.ts e2e/config.local.ts`.
- Copy `librechat.yaml`: `cp librechat.example.yaml librechat.yaml`.
- Copy `chat.yaml`: `cp chat.example.yaml chat.yaml`.
- Run: `npm run e2e`.
## 2. Development Notes
1. Before starting work, make sure your main branch has the latest commits with `npm run update`.
2. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
3. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
3. After your changes, reinstall packages in your current branch using `npm run reinstall` and ensure everything still works.
- Restart the ESLint server ("ESLint: Restart ESLint Server" in VS Code command bar) and your IDE after reinstalling or updating.
4. Clear web app localStorage and cookies before and after changes.
5. To check for introduced errors, build all compiled code: `npm run build`.
5. For frontend changes, compile typescript before and after changes to check for introduced errors: `cd client && npm run build`.
6. Run backend unit tests: `npm run test:api`.
7. Run frontend unit tests: `npm run test:client`.
8. Run integration tests: `npm run e2e`.
@@ -114,45 +118,48 @@ Apply the following naming conventions to branches, labels, and other Git-relate
- **JS/TS:** Directories and file names: Descriptive and camelCase. First letter uppercased for React files (e.g., `helperFunction.ts, ReactComponent.tsx`).
- **Docs:** Directories and file names: Descriptive and snake_case (e.g., `config_files.md`).
## 7. Coding Standards
For detailed coding conventions, workspace boundaries, and architecture guidance, refer to the [`AGENTS.md`](../AGENTS.md) file at the project root. It covers code style, type safety, import ordering, iteration/performance expectations, frontend rules, testing, and development commands.
## 8. TypeScript Conversion
## 7. TypeScript Conversion
1. **Original State**: The project was initially developed entirely in JavaScript (JS).
2. **Frontend**: Fully transitioned to TypeScript.
2. **Frontend Transition**:
- We are in the process of transitioning the frontend from JS to TypeScript (TS).
- The transition is nearing completion.
- This conversion is feasible due to React's capability to intermix JS and TS prior to code compilation. It's standard practice to compile/bundle the code in such scenarios.
3. **Backend**:
- The legacy Express.js server remains in `/api` as JavaScript.
- All new backend code is written in TypeScript under `/packages/api`, which is compiled and consumed by `/api`.
- Shared database logic lives in `/packages/data-schemas` (TypeScript).
- Shared frontend/backend API types and services live in `/packages/data-provider` (TypeScript).
- Minimize direct changes to `/api`; prefer adding TypeScript code to `/packages/api` and importing it.
3. **Backend Considerations**:
- Transitioning the backend to TypeScript would be a more intricate process, especially for an established Express.js server.
- **Options for Transition**:
- **Single Phase Overhaul**: This involves converting the entire backend to TypeScript in one go. It's the most straightforward approach but can be disruptive, especially for larger codebases.
- **Incremental Transition**: Convert parts of the backend progressively. This can be done by:
- Maintaining a separate directory for TypeScript files.
- Gradually migrating and testing individual modules or routes.
- Using a build tool like `tsc` to compile TypeScript files independently until the entire transition is complete.
- **Compilation Considerations**:
- Introducing a compilation step for the server is an option. This would involve using tools like `ts-node` for development and `tsc` for production builds.
- However, this is not a conventional approach for Express.js servers and could introduce added complexity, especially in terms of build and deployment processes.
- **Current Stance**: At present, this backend transition is of lower priority and might not be pursued.
## 9. Module Import Conventions
## 8. Module Import Conventions
Imports are organized into three sections (in order):
- `npm` packages first,
- from shortest line (top) to longest (bottom)
1. **Package imports** — sorted from shortest to longest line length.
- `react` is always the first import.
- Multi-line (stacked) imports count their total character length across all lines for sorting.
- Followed by typescript types (pertains to data-provider and client workspaces)
- longest line (top) to shortest (bottom)
- types from package come first
2. **`import type` imports** — sorted from longest to shortest line length.
- Package type imports come first, then local type imports.
- Line length sorting resets between the package and local sub-groups.
- Lastly, local imports
- longest line (top) to shortest (bottom)
- imports with alias `~` treated the same as relative import with respect to line length
3. **Local/project imports** — sorted from longest to shortest line length.
- Multi-line (stacked) imports count their total character length across all lines for sorting.
- Imports with alias `~` are treated the same as relative imports with respect to line length.
---
- Consolidate value imports from the same module as much as possible.
- Always use standalone `import type { ... }` for type imports; never use inline `type` keyword inside value imports (e.g., `import { Foo, type Bar }` is wrong).
**Note:** ESLint will automatically enforce these import conventions when you run `npm run lint --fix` or through pre-commit hooks.
For the full set of coding standards, see [`AGENTS.md`](../AGENTS.md).
Please ensure that you adapt this summary to fit the specific context and nuances of your project.
---
+2 -2
View File
@@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: [hanzoai]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
@@ -10,4 +10,4 @@ liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: https://buy.stripe.com/9AQ03Kd3P91o0Q8bIS
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+1 -1
View File
@@ -29,7 +29,7 @@ body:
description: |
If using Docker, please run and provide the output of:
```bash
docker images | grep hanzo
docker images | grep hanzochat
```
If running from source, please run and provide the output of:
@@ -1,15 +1,17 @@
name: Locize Translation Access Request
description: Request access to an additional language in Locize for Hanzo Chat translations.
description: Request access to an additional language in Locize for chat translations.
title: "Locize Access Request: "
labels: ["🌍 i18n", "🔑 access request"]
body:
- type: markdown
attributes:
value: |
Thank you for your interest in contributing to Hanzo Chat translations!
Thank you for your interest in contributing to chat translations!
Please fill out the form below to request access to an additional language in **Locize**.
**Note:** Ensure that the requested language is supported before submitting your request.
**🔗 Available Languages:** [View the list here](https://docs.hanzo.ai/chat/translation)
**📌 Note:** Ensure that the requested language is supported before submitting your request.
- type: input
id: account_name
attributes:
@@ -23,8 +25,10 @@ body:
attributes:
label: Language Code (ISO 639-1)
description: |
Enter the **ISO 639-1** language code for the language you want to translate into.
Enter the **ISO 639-1** language code for the language you want to translate into.
Example: `es` for Spanish, `zh-Hant` for Traditional Chinese.
**🔗 Reference:** [Available Languages](https://docs.hanzo.ai/chat/translation)
placeholder: e.g., es
validations:
required: true
@@ -34,5 +38,5 @@ body:
label: Agreement
description: By submitting this request, you confirm that you will contribute responsibly and adhere to the project guidelines.
options:
- label: I agree to use my access solely for contributing to Hanzo Chat translations.
required: true
- label: I agree to use my access solely for contributing to chat translations.
required: true
@@ -1,5 +1,5 @@
name: New Language Request
description: Request to add a new language for Hanzo Chat translations.
description: Request to add a new language for chat translations.
title: "New Language Request: "
labels: ["✨ enhancement", "🌍 i18n"]
body:
-49
View File
@@ -1,49 +0,0 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
value: "A bug happened!"
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: dropdown
id: ml-ops-team
attributes:
label: Are you a ML Ops Team?
description: This helps us prioritize your requests correctly
options:
- "No"
- "Yes"
validations:
required: true
- type: input
id: version
attributes:
label: What LiteLLM version are you on ?
placeholder: v1.53.1
validations:
required: true
- type: input
id: contact
attributes:
label: Twitter / LinkedIn details
description: We announce new features on Twitter + LinkedIn. If this issue leads to an announcement, and you'd like a mention, we'll gladly shout you out!
placeholder: ex. @krrish_dh / https://www.linkedin.com/in/krish-d/
validations:
required: false
-8
View File
@@ -1,8 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Schedule Demo
url: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat
about: Speak directly with Krrish and Ishaan, the founders, to discuss issues, share feedback, or explore improvements for LiteLLM
- name: Discord
url: https://discord.com/invite/wuPM9dRgDw
about: Join 250+ LiteLLM community members!
@@ -1,42 +0,0 @@
name: 🚀 Feature Request
description: Submit a proposal/request for a new LiteLLM feature.
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for making LiteLLM better!
- type: textarea
id: the-feature
attributes:
label: The Feature
description: A clear and concise description of the feature proposal
placeholder: Tell us what you want!
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation, pitch
description: Please outline the motivation for the proposal. Is your feature request related to a specific problem? e.g., "I'm working on X and would like Y to be possible". If this is related to another GitHub issue, please link here too.
validations:
required: true
- type: dropdown
id: hiring-interest
attributes:
label: LiteLLM is hiring a founding backend engineer, are you interested in joining us and shipping to all our users?
description: If yes, apply here - https://www.ycombinator.com/companies/litellm/jobs/6uvoBp3-founding-backend-engineer
options:
- "No"
- "Yes"
validations:
required: true
- type: input
id: contact
attributes:
label: Twitter / LinkedIn details
description: We announce new features on Twitter + LinkedIn. When this is announced, and you'd like a mention, we'll gladly shout you out!
placeholder: ex. @krrish_dh / https://www.linkedin.com/in/krish-d/
validations:
required: false
+10 -8
View File
@@ -1,8 +1,8 @@
# Security Policy
At Hanzo, we prioritize the security of our project and value the contributions of security researchers in helping us improve the security of our codebase. If you discover a security vulnerability within our project, we appreciate your responsible disclosure. Please follow the guidelines below to report any vulnerabilities to us:
At chat, we prioritize the security of our project and value the contributions of security researchers in helping us improve the security of our codebase. If you discover a security vulnerability within our project, we appreciate your responsible disclosure. Please follow the guidelines below to report any vulnerabilities to us:
**Note: Only report sensitive vulnerability details via the appropriate private communication channels mentioned below. Public channels, such as GitHub issues, should be used for initiating contact and establishing private communication channels.**
**Note: Only report sensitive vulnerability details via the appropriate private communication channels mentioned below. Public channels, such as GitHub issues and Discord, should be used for initiating contact and establishing private communication channels.**
## Communication Channels
@@ -12,7 +12,7 @@ When reporting a security vulnerability, you have the following options to reach
- **Option 2: GitHub Issues**: You can initiate first contact via GitHub Issues. However, please note that initial contact through GitHub Issues should not include any sensitive details.
- **Option 3: Email**: You can reach us at security@hanzo.ai for security-related reports.
- **Option 3: Discord Server**: You can join our [Discord community](https://discord.gg/hanzoai) and initiate first contact in the `#issues` channel. However, please ensure that initial contact through Discord does not include any sensitive details.
_After the initial contact, we will establish a private communication channel for further discussion._
@@ -26,10 +26,10 @@ We strive to acknowledge vulnerability reports within 72 hours and will keep you
## Security Updates and Patching
We are committed to maintaining the security of our open-source project, Hanzo Chat, and promptly addressing any identified vulnerabilities. To ensure the security of our project, we adhere to the following practices:
We are committed to maintaining the security of our open-source project, chat, and promptly addressing any identified vulnerabilities. To ensure the security of our project, we adhere to the following practices:
- We prioritize security updates for the current major release of our software.
- We actively monitor the GitHub Security Advisory system for any vulnerability reports.
- We actively monitor the GitHub Security Advisory system and the `#issues` channel on Discord for any vulnerability reports.
- We promptly review and validate reported vulnerabilities and take appropriate actions to address them.
- We release security patches and updates in a timely manner to mitigate any identified vulnerabilities.
@@ -39,11 +39,11 @@ Please note that as a security-conscious community, we may not always disclose d
This security policy applies to the following GitHub repository:
- Repository: [Hanzo Chat](https://github.com/hanzoai/chat)
- Repository: [chat](https://github.com/hanzoai/chat)
## Contact
If you have any questions or concerns regarding the security of our project, please reach out to us at security@hanzo.ai or by [opening an issue](https://github.com/hanzoai/chat/issues/new) on GitHub. Please note that the response time may vary depending on the nature and severity of the inquiry.
If you have any questions or concerns regarding the security of our project, please join our [Discord community](https://discord.gg/hanzoai) and report them in the appropriate channel. You can also reach out to us by [opening an issue](https://github.com/hanzoai/chat/issues/new) on GitHub. Please note that the response time may vary depending on the nature and severity of the inquiry.
## Acknowledgments
@@ -51,7 +51,9 @@ We would like to express our gratitude to the security researchers and community
## Bug Bounty Program
We currently do not have a bug bounty program in place. However, we welcome and appreciate any security-related contributions through pull requests (PRs) that address vulnerabilities in our codebase. We believe in the power of collaboration to improve the security of our project and invite you to join us in making it more robust.
We currently do not have a bug bounty program in place. However, we welcome and appreciate any
security-related contributions through pull requests (PRs) that address vulnerabilities in our codebase. We believe in the power of collaboration to improve the security of our project and invite you to join us in making it more robust.
**Reference**
- https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html
@@ -1,77 +0,0 @@
name: Helm OCI Chart Releaser
description: Push Helm charts to OCI-based (Docker) registries
author: sergeyshaykhullin
branding:
color: yellow
icon: upload-cloud
inputs:
name:
required: true
description: Chart name
repository:
required: true
description: Chart repository name
tag:
required: true
description: Chart version
app_version:
required: true
description: App version
path:
required: false
description: Chart path (Default 'charts/{name}')
registry:
required: true
description: OCI registry
registry_username:
required: true
description: OCI registry username
registry_password:
required: true
description: OCI registry password
update_dependencies:
required: false
default: 'false'
description: Update chart dependencies before packaging (Default 'false')
outputs:
image:
value: ${{ steps.output.outputs.image }}
description: Chart image (Default '{registry}/{repository}/{image}:{tag}')
runs:
using: composite
steps:
- name: Helm | Login
shell: bash
run: echo ${{ inputs.registry_password }} | helm registry login -u ${{ inputs.registry_username }} --password-stdin ${{ inputs.registry }}
env:
HELM_EXPERIMENTAL_OCI: '1'
- name: Helm | Dependency
if: inputs.update_dependencies == 'true'
shell: bash
run: helm dependency update ${{ inputs.path == null && format('{0}/{1}', 'charts', inputs.name) || inputs.path }}
env:
HELM_EXPERIMENTAL_OCI: '1'
- name: Helm | Package
shell: bash
run: helm package ${{ inputs.path == null && format('{0}/{1}', 'charts', inputs.name) || inputs.path }} --version ${{ inputs.tag }} --app-version ${{ inputs.app_version }}
env:
HELM_EXPERIMENTAL_OCI: '1'
- name: Helm | Push
shell: bash
run: helm push ${{ inputs.name }}-${{ inputs.tag }}.tgz oci://${{ inputs.registry }}/${{ inputs.repository }}
env:
HELM_EXPERIMENTAL_OCI: '1'
- name: Helm | Logout
shell: bash
run: helm registry logout ${{ inputs.registry }}
env:
HELM_EXPERIMENTAL_OCI: '1'
- name: Helm | Output
id: output
shell: bash
run: echo "image=${{ inputs.registry }}/${{ inputs.repository }}/${{ inputs.name }}:${{ inputs.tag }}" >> $GITHUB_OUTPUT
+51
View File
@@ -0,0 +1,51 @@
# git-cliff configuration for changelog generation
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{% if commit.breaking %}[**breaking**] {% endif %}\
{{ commit.message | upper_first }}
{%- endfor %}
{% endfor %}\n
"""
footer = """
<!-- generated by git-cliff -->
"""
trim = true
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
commit_parsers = [
{ message = "^feat", group = "<!-- 0 -->⛰️ Features" },
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore\\(deps.*\\)", skip = true },
{ message = "^chore\\(pr\\)", skip = true },
{ message = "^chore\\(pull\\)", skip = true },
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
]
protect_breaking_commits = false
filter_commits = false
topo_order = false
sort_commits = "oldest"
-10
View File
@@ -1,10 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
groups:
github-actions:
patterns:
- "*"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

+41 -33
View File
@@ -1,33 +1,41 @@
## Title
<!-- e.g. "Implement user authentication feature" -->
## Relevant issues
<!-- e.g. "Fixes #000" -->
## Pre-Submission checklist
**Please complete all items before asking a LiteLLM maintainer to review your PR**
- [ ] I have Added testing in the [`tests/litellm/`](https://github.com/BerriAI/litellm/tree/main/tests/litellm) directory, **Adding at least 1 test is a hard requirement** - [see details](https://docs.litellm.ai/docs/extras/contributing_code)
- [ ] I have added a screenshot of my new test passing locally
- [ ] My PR passes all unit tests on [`make test-unit`](https://docs.litellm.ai/docs/extras/contributing_code)
- [ ] My PR's scope is as isolated as possible, it only solves 1 specific problem
## Type
<!-- Select the type of Pull Request -->
<!-- Keep only the necessary ones -->
🆕 New Feature
🐛 Bug Fix
🧹 Refactoring
📖 Documentation
🚄 Infrastructure
✅ Test
## Changes
# Pull Request Template
⚠️ Before Submitting a PR, Please Review:
- Please ensure that you have thoroughly read and understood the [Contributing Docs](https://github.com/hanzoai/chat/blob/main/.github/CONTRIBUTING.md) before submitting your Pull Request.
⚠️ Documentation Updates Notice:
- Kindly note that documentation updates are managed in this repository: [hanzo.ai](https://github.com/hanzoai/docs)
## Summary
Please provide a brief summary of your changes and the related issue. Include any motivation and context that is relevant to your changes. If there are any dependencies necessary for your changes, please list them here.
## Change Type
Please delete any irrelevant options.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Translation update
## Testing
Please describe your test process and include instructions so that we can reproduce your test. If there are any important variables for your testing configuration, list them here.
### **Test Configuration**:
## Checklist
Please delete any irrelevant options.
- [ ] My code adheres to this project's style guidelines
- [ ] I have performed a self-review of my own code
- [ ] I have commented in any complex areas of my code
- [ ] I have made pertinent documentation changes
- [ ] My changes do not introduce new warnings
- [ ] I have written tests demonstrating that my changes are effective or that my feature works
- [ ] Local unit tests pass with my changes
- [ ] Any changes dependent on mine have been merged and published in downstream modules.
- [ ] A pull request for updating the documentation has been submitted.
-94
View File
@@ -1,94 +0,0 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
llmlite-service
SAM Template for llmlite-service
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 600
MemorySize: 128
Environment:
Variables:
WORKER_CONFIG: !Ref WorkerConfigParameter
Parameters:
AliasParameter:
Type: String
Default: live
WorkerConfigParameter:
Type: String
Description: Sample environment variable
Default: '{"model": null, "alias": null, "api_base": null, "api_version": "2023-07-01-preview", "debug": false, "temperature": null, "max_tokens": null, "request_timeout": 600, "max_budget": null, "telemetry": true, "drop_params": false, "add_function_to_prompt": false, "headers": null, "save": false, "config": null, "use_queue": false}'
Resources:
MyUrlFunctionPermissions:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref URL
Action: lambda:InvokeFunctionUrl
Principal: "*"
FunctionUrlAuthType: NONE
Function:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-function"
CodeUri: "./litellm"
Handler: proxy/lambda.handler
Runtime: python3.11
AutoPublishAlias: !Ref AliasParameter
Architectures:
- x86_64
DeploymentPreference:
Type: AllAtOnce
Alarms:
- !Ref NewVersionErrorMetricGreaterThanZeroAlarm
NewVersionErrorMetricGreaterThanZeroAlarm:
Type: "AWS::CloudWatch::Alarm"
Properties:
AlarmDescription: Lambda Function Error > 0
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: Resource
Value: !Sub "${Function}:live"
- Name: FunctionName
Value: !Ref Function
- Name: ExecutedVersion
Value: !GetAtt Function.Version.Version
EvaluationPeriods: 1
Unit: Count
MetricName: Errors
Namespace: AWS/Lambda
Period: 60
Statistic: Sum
Threshold: 0
URL:
Type: AWS::Lambda::Url
DependsOn: FunctionAliaslive
Properties:
AuthType: NONE
Qualifier: live
TargetFunctionArn: !GetAtt Function.Arn
Outputs:
FunctionARN:
Description: "Lambda Function ARN"
Value: !GetAtt Function.Arn
FunctionUrl:
Description: "Lambda Function URL Endpoint"
Value:
Fn::GetAtt: URL.FunctionUrl
FunctionVersion:
Description: "Lambda Function Version"
Value: !GetAtt Function.Version.Version
FunctionNewAlarmARN:
Description: "Lambda Function New Alarm ARN"
Value: !GetAtt NewVersionErrorMetricGreaterThanZeroAlarm.Arn
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_workflow == 'true')
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: dequelabs/axe-linter-action@v1
with:
api_key: ${{ secrets.AXE_LINTER_API_KEY }}
@@ -1,28 +0,0 @@
name: Updates model_prices_and_context_window.json and Create Pull Request
on:
schedule:
- cron: "0 0 * * 0" # Run every Sundays at midnight
#- cron: "0 0 * * *" # Run daily at midnight
jobs:
auto_update_price_and_context_window:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Dependencies
run: |
pip install aiohttp
- name: Update JSON Data
run: |
python ".github/workflows/auto_update_price_and_context_window_file.py"
- name: Create Pull Request
run: |
git add model_prices_and_context_window.json
git commit -m "Update model_prices_and_context_window.json file: $(date +'%Y-%m-%d')"
gh pr create --title "Update model_prices_and_context_window.json file" \
--body "Automated update for model_prices_and_context_window.json" \
--head auto-update-price-and-context-window-$(date +'%Y-%m-%d') \
--base main
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
@@ -1,121 +0,0 @@
import asyncio
import aiohttp
import json
# Asynchronously fetch data from a given URL
async def fetch_data(url):
try:
# Create an asynchronous session
async with aiohttp.ClientSession() as session:
# Send a GET request to the URL
async with session.get(url) as resp:
# Raise an error if the response status is not OK
resp.raise_for_status()
# Parse the response JSON
resp_json = await resp.json()
print("Fetch the data from URL.")
# Return the 'data' field from the JSON response
return resp_json['data']
except Exception as e:
# Print an error message if fetching data fails
print("Error fetching data from URL:", e)
return None
# Synchronize local data with remote data
def sync_local_data_with_remote(local_data, remote_data):
# Update existing keys in local_data with values from remote_data
for key in (set(local_data) & set(remote_data)):
local_data[key].update(remote_data[key])
# Add new keys from remote_data to local_data
for key in (set(remote_data) - set(local_data)):
local_data[key] = remote_data[key]
# Write data to the json file
def write_to_file(file_path, data):
try:
# Open the file in write mode
with open(file_path, "w") as file:
# Dump the data as JSON into the file
json.dump(data, file, indent=4)
print("Values updated successfully.")
except Exception as e:
# Print an error message if writing to file fails
print("Error updating JSON file:", e)
# Update the existing models and add the missing models
def transform_remote_data(data):
transformed = {}
for row in data:
# Add the fields 'max_tokens' and 'input_cost_per_token'
obj = {
"max_tokens": row["context_length"],
"input_cost_per_token": float(row["pricing"]["prompt"]),
}
# Add 'max_output_tokens' as a field if it is not None
if "top_provider" in row and "max_completion_tokens" in row["top_provider"] and row["top_provider"]["max_completion_tokens"] is not None:
obj['max_output_tokens'] = int(row["top_provider"]["max_completion_tokens"])
# Add the field 'output_cost_per_token'
obj.update({
"output_cost_per_token": float(row["pricing"]["completion"]),
})
# Add field 'input_cost_per_image' if it exists and is non-zero
if "pricing" in row and "image" in row["pricing"] and float(row["pricing"]["image"]) != 0.0:
obj['input_cost_per_image'] = float(row["pricing"]["image"])
# Add the fields 'litellm_provider' and 'mode'
obj.update({
"litellm_provider": "openrouter",
"mode": "chat"
})
# Add the 'supports_vision' field if the modality is 'multimodal'
if row.get('architecture', {}).get('modality') == 'multimodal':
obj['supports_vision'] = True
# Use a composite key to store the transformed object
transformed[f'openrouter/{row["id"]}'] = obj
return transformed
# Load local data from a specified file
def load_local_data(file_path):
try:
# Open the file in read mode
with open(file_path, "r") as file:
# Load and return the JSON data
return json.load(file)
except FileNotFoundError:
# Print an error message if the file is not found
print("File not found:", file_path)
return None
except json.JSONDecodeError as e:
# Print an error message if JSON decoding fails
print("Error decoding JSON:", e)
return None
def main():
local_file_path = "model_prices_and_context_window.json" # Path to the local data file
url = "https://openrouter.ai/api/v1/models" # URL to fetch remote data
# Load local data from file
local_data = load_local_data(local_file_path)
# Fetch remote data asynchronously
remote_data = asyncio.run(fetch_data(url))
# Transform the fetched remote data
remote_data = transform_remote_data(remote_data)
# If both local and remote data are available, synchronize and save
if local_data and remote_data:
sync_local_data_with_remote(local_data, remote_data)
write_to_file(local_file_path, local_data)
else:
print("Failed to fetch model data from either local file or URL.")
# Entry point of the script
if __name__ == "__main__":
main()
+16 -19
View File
@@ -4,11 +4,10 @@ on:
branches:
- main
- dev
- dev-staging
- release/*
paths:
- 'api/**'
- 'packages/**'
- 'packages/api/**'
jobs:
tests_Backend:
name: Run Backend unit tests
@@ -24,27 +23,25 @@ jobs:
BAN_DURATION: ${{ secrets.BAN_DURATION }}
BAN_INTERVAL: ${{ secrets.BAN_INTERVAL }}
NODE_ENV: CI
NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache: 'npm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
- name: Install Data Provider Package
run: pnpm run build:data-provider
run: npm run build:data-provider
- name: Install Data Schemas Package
run: pnpm run build:data-schemas
run: npm run build:data-schemas
- name: Install API Package
run: pnpm run build:api
run: npm run build:api
- name: Create empty auth.json file
run: |
@@ -54,7 +51,7 @@ jobs:
- name: Check for Circular dependency in rollup
working-directory: ./packages/data-provider
run: |
output=$(pnpm run rollup:api)
output=$(npm run rollup:api)
echo "$output"
if echo "$output" | grep -q "Circular dependency"; then
echo "Error: Circular dependency detected!"
@@ -65,13 +62,13 @@ jobs:
run: cp api/test/.env.test.example api/test/.env.test
- name: Run unit tests
run: cd api && pnpm run test:ci
run: cd api && npm run test:ci
- name: Run librechat-data-provider unit tests
run: cd packages/data-provider && pnpm run test:ci
- name: Run hanzochat-data-provider unit tests
run: cd packages/data-provider && npm run test:ci
- name: Run @librechat/data-schemas unit tests
run: cd packages/data-schemas && pnpm run test:ci
- name: Run @hanzochat/data-schemas unit tests
run: cd packages/data-schemas && npm run test:ci
- name: Run @librechat/api unit tests
run: cd packages/api && pnpm run test:ci
- name: Run @hanzochat/api unit tests
run: cd packages/api && npm run test:ci
+3 -3
View File
@@ -15,12 +15,12 @@ jobs:
uses: actions/checkout@main
- name: 'Login via Azure CLI'
uses: azure/login@v3
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: 'Build GitHub Runner container image'
uses: azure/docker-login@v2
uses: azure/docker-login@v1
with:
login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -29,7 +29,7 @@ jobs:
docker build --build-arg RUNNER_VERSION=${{ env.RUNNER_VERSION }} -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/pwd9000-github-runner-lin:${{ env.RUNNER_VERSION }} .
- name: 'Push container image to ACR'
uses: azure/docker-login@v2
uses: azure/docker-login@v1
with:
login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -1,93 +0,0 @@
name: Cache Integration Tests
on:
pull_request:
branches:
- main
- dev
- dev-staging
- release/*
paths:
- 'packages/api/src/cache/**'
- 'packages/api/src/cluster/**'
- 'packages/api/src/mcp/**'
- 'packages/api/src/stream/**'
- 'redis-config/**'
- '.github/workflows/cache-integration-tests.yml'
jobs:
cache_integration_tests:
name: Integration Tests that use actual Redis Cache
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- name: Use Node.js 20.x
uses: actions/setup-node@v6
with:
node-version: 20
cache: 'pnpm'
- name: Install Redis tools
run: |
sudo apt-get update
sudo apt-get install -y redis-server redis-tools
- name: Start Single Redis Instance
run: |
redis-server --daemonize yes --port 6379
sleep 2
# Verify single Redis is running
redis-cli -p 6379 ping || exit 1
- name: Start Redis Cluster
working-directory: redis-config
run: |
chmod +x start-cluster.sh stop-cluster.sh
./start-cluster.sh
sleep 10
# Verify cluster is running
redis-cli -p 7001 cluster info || exit 1
redis-cli -p 7002 cluster info || exit 1
redis-cli -p 7003 cluster info || exit 1
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build packages
run: |
pnpm run build:data-provider
pnpm run build:data-schemas
pnpm run build:api
- name: Run all cache integration tests (Single Redis Node)
working-directory: packages/api
env:
NODE_ENV: test
USE_REDIS: true
USE_REDIS_CLUSTER: false
REDIS_URI: redis://127.0.0.1:6379
run: pnpm run test:cache-integration
- name: Run all cache integration tests (Redis Cluster)
working-directory: packages/api
env:
NODE_ENV: test
USE_REDIS: true
USE_REDIS_CLUSTER: true
REDIS_URI: redis://127.0.0.1:7001,redis://127.0.0.1:7002,redis://127.0.0.1:7003
run: pnpm run test:cache-integration
- name: Stop Redis Cluster
if: always()
working-directory: redis-config
run: ./stop-cluster.sh || true
- name: Stop Single Redis Instance
if: always()
run: redis-cli -p 6379 shutdown || true
+244
View File
@@ -0,0 +1,244 @@
name: CI/CD Pipeline
on:
push:
branches:
- main
- develop
- 'release/**'
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
deploy_environment:
description: 'Environment to deploy to'
required: false
default: 'staging'
type: choice
options:
- staging
- production
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
NODE_VERSION: '20'
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
test-type: [api, client, packages]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build packages
if: matrix.test-type != 'packages'
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Run tests
run: |
if [ "${{ matrix.test-type }}" = "api" ]; then
npm run test:api
elif [ "${{ matrix.test-type }}" = "client" ]; then
npm run test:client
else
cd packages/data-provider && npm test
cd ../data-schemas && npm test
cd ../api && npm test
fi
- name: Upload coverage
if: always()
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: ${{ matrix.test-type }}
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
build-docker:
name: Build Docker Image
needs: [test, lint]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
outputs:
image-digest: ${{ steps.build.outputs.digest }}
image-tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=vendor-mode,enable={{is_default_branch}}
type=sha,prefix={{branch}}-
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
VERSION=${{ github.ref_name }}
- name: Generate SBOM
if: github.event_name != 'pull_request'
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
format: spdx-json
output-file: sbom.spdx.json
- name: Upload SBOM
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.spdx.json
security-scan:
name: Security Scan
needs: build-docker
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
security-events: write
steps:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-docker.outputs.image-digest }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
deploy-staging:
name: Deploy to Staging
needs: [build-docker, security-scan]
if: github.ref == 'refs/heads/develop' && github.event_name != 'pull_request'
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.hanzo.ai
steps:
- name: Deploy to staging
run: |
echo "Deploying ${{ needs.build-docker.outputs.image-digest }} to staging"
# Add your deployment logic here
# Example: kubectl set image deployment/chat chat=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-docker.outputs.image-digest }}
deploy-production:
name: Deploy to Production
needs: [build-docker, security-scan]
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
runs-on: ubuntu-latest
environment:
name: production
url: https://chat.hanzo.ai
steps:
- name: Deploy to production
run: |
echo "Deploying ${{ needs.build-docker.outputs.image-digest }} to production"
# Add your deployment logic here
# Example: kubectl set image deployment/chat chat=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-docker.outputs.image-digest }}
- name: Create deployment record
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'production',
required_contexts: [],
auto_merge: false,
production_environment: true,
});
+220
View File
@@ -0,0 +1,220 @@
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
env:
NODE_ENV: test
jobs:
test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
mongodb-version: ['7.0']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.10.0
with:
mongodb-version: ${{ matrix.mongodb-version }}
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
*/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: |
packages/*/dist
api/lib
client/dist
key: ${{ runner.os }}-build-${{ hashFiles('packages/**/*.ts', 'packages/**/*.js') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install dependencies
run: npm ci
- name: Build packages
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Create test environment
run: |
cat > .env.test << EOF
NODE_ENV=test
MONGO_URI=mongodb://localhost:27017/HanzoChat_test
MEILI_HOST=
RAG_API_URL=
ALLOW_REGISTRATION=true
ALLOW_UNVERIFIED_EMAIL_LOGIN=true
RATE_LIMIT_ENABLED=false
CREDS_KEY=test-creds-key-32-chars-long-string
CREDS_IV=test-creds-iv-16
JWT_SECRET=test-jwt-secret-very-secure
JWT_REFRESH_SECRET=test-jwt-refresh-secret
GOOGLE_ANALYTICS_ID=
SENTRY_DSN=
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
TRUST_PROXY=0
DEBUG_LOGGING=false
CONSOLE_JSON=false
EOF
- name: Run Client Tests
run: NODE_ENV=test npm run test:client -- --coverage --coverageReporters=json
continue-on-error: false
- name: Run API Tests
run: NODE_ENV=test npm run test:api -- --coverage --coverageReporters=json --maxWorkers=2
continue-on-error: false
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
client/coverage/
api/coverage/
- name: Test Report
uses: dorny/test-reporter@v1
if: always()
with:
name: Jest Tests
path: '**/junit.xml'
reporter: jest-junit
- name: Coverage Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./client/coverage/coverage-final.json,./api/coverage/coverage-final.json
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
lint:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
*/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run Prettier Check
run: npm run format:check || true
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --production || true
- name: Run Snyk Security Scan
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
build:
name: Build Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
*/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build all packages
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Build client
run: npm run build:client
env:
DOMAIN_CLIENT: https://chat.hanzo.ai
DOMAIN_SERVER: https://chat.hanzo.ai
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
client/dist/
api/lib/
packages/*/dist/
-67
View File
@@ -1,67 +0,0 @@
name: Publish `@librechat/client` to NPM
on:
push:
branches:
- main
paths:
- 'packages/client/package.json'
workflow_dispatch:
inputs:
reason:
description: 'Reason for manual trigger'
required: false
default: 'Manual publish requested'
permissions:
id-token: write # Required for OIDC trusted publishing
contents: read
jobs:
build-and-publish:
runs-on: ubuntu-latest
environment: publish # Must match npm trusted publisher config
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: '20.x'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Update npm for OIDC support
run: npm install -g npm@latest # Must be 11.5.1+ for provenance
- name: Install client dependencies
run: cd packages/client && pnpm install --frozen-lockfile
- name: Build client
run: cd packages/client && pnpm run build
- name: Check version change
id: check
working-directory: packages/client
run: |
PACKAGE_VERSION=$(node -p "require('./package.json').version")
PUBLISHED_VERSION=$(npm view @librechat/client version 2>/dev/null || echo "0.0.0")
if [ "$PACKAGE_VERSION" = "$PUBLISHED_VERSION" ]; then
echo "No version change, skipping publish"
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "Version changed, proceeding with publish"
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Pack package
if: steps.check.outputs.skip != 'true'
working-directory: packages/client
run: npm pack
- name: Publish
if: steps.check.outputs.skip != 'true'
working-directory: packages/client
run: npm publish *.tgz --access public --provenance
+14 -31
View File
@@ -1,4 +1,4 @@
name: Publish `librechat-data-provider` to NPM
name: Node.js Package
on:
push:
@@ -6,46 +6,29 @@ on:
- main
paths:
- 'packages/data-provider/package.json'
workflow_dispatch:
inputs:
reason:
description: 'Reason for manual trigger'
required: false
default: 'Manual publish requested'
permissions:
id-token: write # Required for OIDC trusted publishing
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: cd packages/data-provider && pnpm install --frozen-lockfile
- run: cd packages/data-provider && pnpm run build
node-version: 16
- run: cd packages/data-provider && npm ci
- run: cd packages/data-provider && npm run build
publish-npm:
needs: build
runs-on: ubuntu-latest
environment: publish # Must match npm trusted publisher config
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
node-version: 16
registry-url: 'https://registry.npmjs.org'
- name: Update npm for OIDC support
run: npm install -g npm@latest # Must be 11.5.1+ for provenance
- run: cd packages/data-provider && pnpm install --frozen-lockfile
- run: cd packages/data-provider && pnpm run build
- run: cd packages/data-provider && npm publish --provenance
- run: cd packages/data-provider && npm ci
- run: cd packages/data-provider && npm run build
- run: cd packages/data-provider && npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
+14 -23
View File
@@ -1,4 +1,4 @@
name: Publish `@librechat/data-schemas` to NPM
name: Publish `@hanzochat/data-schemas` to NPM
on:
push:
@@ -13,41 +13,32 @@ on:
required: false
default: 'Manual publish requested'
permissions:
id-token: write # Required for OIDC trusted publishing
contents: read
jobs:
build-and-publish:
runs-on: ubuntu-latest
environment: publish # Must match npm trusted publisher config
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Update npm for OIDC support
run: npm install -g npm@latest # Must be 11.5.1+ for provenance
node-version: '18.x'
- name: Install dependencies
run: cd packages/data-schemas && pnpm install --frozen-lockfile
run: cd packages/data-schemas && npm ci
- name: Build
run: cd packages/data-schemas && pnpm run build
run: cd packages/data-schemas && npm run build
- name: Set up npm authentication
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.PUBLISH_NPM_TOKEN }}" > ~/.npmrc
- name: Check version change
id: check
working-directory: packages/data-schemas
run: |
PACKAGE_VERSION=$(node -p "require('./package.json').version")
PUBLISHED_VERSION=$(npm view @librechat/data-schemas version 2>/dev/null || echo "0.0.0")
PUBLISHED_VERSION=$(npm view @hanzochat/data-schemas version 2>/dev/null || echo "0.0.0")
if [ "$PACKAGE_VERSION" = "$PUBLISHED_VERSION" ]; then
echo "No version change, skipping publish"
echo "skip=true" >> $GITHUB_OUTPUT
@@ -64,4 +55,4 @@ jobs:
- name: Publish
if: steps.check.outputs.skip != 'true'
working-directory: packages/data-schemas
run: npm publish *.tgz --access public --provenance
run: npm publish *.tgz --access public
@@ -11,7 +11,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
if: |
github.repository == 'danny-avila/LibreChat' &&
github.repository == 'hanzoai/chat' &&
(github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'dev'))
steps:
@@ -31,10 +31,10 @@ jobs:
run: |
ssh -o StrictHostKeyChecking=no ${DO_USER}@${DO_HOST} << EOF
sudo -i -u danny bash << 'EEOF'
cd ~/LibreChat && \
cd ~/chat && \
git fetch origin main && \
sudo npm run stop:deployed && \
sudo docker images --format "{{.Repository}}:{{.ID}}" | grep -E "lc-dev|librechat" | cut -d: -f2 | xargs -r sudo docker rmi -f || true && \
sudo docker images --format "{{.Repository}}:{{.ID}}" | grep -E "lc-dev|hanzochat" | cut -d: -f2 | xargs -r sudo docker rmi -f || true && \
sudo npm run update:deployed && \
git checkout dev && \
git pull origin dev && \
+2 -2
View File
@@ -17,10 +17,10 @@ jobs:
steps:
# checkout the repo
- name: 'Checkout GitHub Action'
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: 'Login via Azure CLI'
uses: azure/login@v3
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
+72
View File
@@ -0,0 +1,72 @@
name: Docker Dev Branch Images Build
on:
workflow_dispatch:
push:
branches:
- dev
paths:
- 'api/**'
- 'client/**'
- 'packages/**'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: api-build
file: Dockerfile.multi
image_name: lc-dev-api
- target: node
file: Dockerfile
image_name: lc-dev
steps:
# Check out the repository
- name: Checkout
uses: actions/checkout@v4
# Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Log in to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Prepare the environment
- name: Prepare environment
run: |
cp .env.example .env
# Build and push Docker images for each target
- name: Build and push Docker images
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.file }}
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:latest
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:${{ github.sha }}
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:latest
platforms: linux/amd64,linux/arm64
target: ${{ matrix.target }}
+72
View File
@@ -0,0 +1,72 @@
name: Docker Dev Images Build
on:
workflow_dispatch:
push:
branches:
- main
paths:
- 'api/**'
- 'client/**'
- 'packages/**'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: api-build
file: Dockerfile.multi
image_name: hanzochat-dev-api
- target: node
file: Dockerfile
image_name: hanzochat-dev
steps:
# Check out the repository
- name: Checkout
uses: actions/checkout@v4
# Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Log in to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Prepare the environment
- name: Prepare environment
run: |
cp .env.example .env
# Build and push Docker images for each target
- name: Build and push Docker images
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.file }}
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:latest
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:${{ github.sha }}
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:latest
platforms: linux/amd64,linux/arm64
target: ${{ matrix.target }}
+109
View File
@@ -0,0 +1,109 @@
name: Build and Push Docker Images
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
COMMIT_SHA=${{ github.sha }}
BUILD_DATE=${{ steps.meta.outputs.created }}
build-and-push-rag:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for RAG API
id: meta-rag
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/hanzoai/chat-rag-api
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push RAG API Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./rag.Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta-rag.outputs.tags }}
labels: ${{ steps.meta-rag.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+107
View File
@@ -0,0 +1,107 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# For main branch, tag as 'latest'
type=raw,value=latest,enable={{is_default_branch}}
# For develop branch, tag as 'develop'
type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }}
# For tags, use the tag name
type=ref,event=tag
# For PRs, use pr-NUMBER
type=ref,event=pr
# SHA short
type=sha,prefix={{branch}}-
# Vendor mode tag for main
type=raw,value=vendor-mode,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
- name: Create Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v1
with:
body: |
## Docker Image
🐳 Docker image is available at:
```
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
```
### Vendor Mode Usage
To run with Hanzo AI branding (default):
```bash
docker run -d \
-p 3080:3080 \
--env-file .env \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
```
To run with custom branding:
```bash
docker run -d \
-p 3080:3080 \
-e VENDOR_MODE=true \
-e VENDOR_NAME="Your Company" \
-e VENDOR_MODEL_DEFAULT="Your Model" \
-e VENDOR_MODEL_PRO="Your Model Pro" \
-e APP_TITLE="Your Platform" \
-e VENDOR_BACKEND_ENDPOINT=anthropic \
-e VENDOR_BACKEND_API_KEY=$YOUR_API_KEY \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
```
generate_release_notes: true
+56
View File
@@ -0,0 +1,56 @@
name: Docker Build Cache
on:
schedule:
# Run every Monday at 3 AM UTC to refresh caches
- cron: '0 3 * * 1'
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-cache:
name: Build and Cache Base Images
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- target: builder
cache-tag: cache-builder
- target: stage-1
cache-tag: cache-deps
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push cache image
uses: docker/build-push-action@v5
with:
context: .
target: ${{ matrix.target }}
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ matrix.cache-tag }}
cache-from: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ matrix.cache-tag }}
type=gha
cache-to: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ matrix.cache-tag }},mode=max
type=gha,mode=max
platforms: linux/amd64,linux/arm64
-57
View File
@@ -1,57 +0,0 @@
# Deployment managed by hanzoai/universe — this workflow only builds and pushes images
name: Docker Release
on:
push:
branches: [main]
tags: ["v*"]
workflow_dispatch:
concurrency:
group: docker-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
docker:
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
with:
image: ghcr.io/hanzoai/chat
platforms: linux/amd64,linux/arm64
secrets: inherit
dispatch-to-universe:
needs: docker
runs-on: ubuntu-latest
steps:
- name: Compute image URI
id: meta
run: |
IMAGE="ghcr.io/hanzoai/chat"
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
TAG="${GITHUB_REF#refs/tags/v}"
elif [[ "$GITHUB_REF" == refs/heads/* ]]; then
TAG="${GITHUB_REF#refs/heads/}"
else
TAG="${GITHUB_SHA}"
fi
echo "image=${IMAGE}:${TAG}" >> "$GITHUB_OUTPUT"
- name: Dispatch image update to universe
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.UNIVERSE_DISPATCH_TOKEN }}
repository: hanzoai/universe
event-type: image-update
client-payload: |
{
"service": "chat",
"image": "${{ steps.meta.outputs.image }}",
"sha": "${{ github.sha }}",
"repo": "${{ github.repository }}"
}
- name: Summary
run: |
echo "### Deploy dispatched to universe" >> "$GITHUB_STEP_SUMMARY"
echo "- **Image:** ${{ steps.meta.outputs.image }}" >> "$GITHUB_STEP_SUMMARY"
echo "- **Flow:** image-receiver -> staging -> E2E -> production" >> "$GITHUB_STEP_SUMMARY"
+19 -8
View File
@@ -5,7 +5,6 @@ on:
branches:
- main
- dev
- dev-staging
- release/*
paths:
- 'api/**'
@@ -21,23 +20,23 @@ jobs:
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v6
- name: Set up Node.js 20.x
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache: npm
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
# Run ESLint on changed files within the api/ and client/ directories.
- name: Run ESLint on changed files
env:
SARIF_ESLINT_IGNORE_SUPPRESSED: "true"
run: |
# Extract the base commit SHA from the pull_request event payload.
BASE_SHA=$(jq --raw-output .pull_request.base.sha "$GITHUB_EVENT_PATH")
@@ -53,10 +52,22 @@ jobs:
# Ensure there are files to lint before running ESLint
if [[ -z "$CHANGED_FILES" ]]; then
echo "No matching files changed. Skipping ESLint."
echo "UPLOAD_SARIF=false" >> $GITHUB_ENV
exit 0
fi
# Set variable to allow SARIF upload
echo "UPLOAD_SARIF=true" >> $GITHUB_ENV
# Run ESLint
npx eslint --no-error-on-unmatched-pattern \
--config eslint.config.mjs \
$CHANGED_FILES
--format @microsoft/eslint-formatter-sarif \
--output-file eslint-results.sarif $CHANGED_FILES || true
- name: Upload analysis results to GitHub
if: env.UPLOAD_SARIF == 'true'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: eslint-results.sarif
wait-for-processing: true
+13 -20
View File
@@ -5,59 +5,52 @@ on:
branches:
- main
- dev
- dev-staging
- release/*
paths:
- 'client/**'
- 'packages/data-provider/**'
- 'packages/**'
jobs:
tests_frontend_ubuntu:
name: Run frontend unit tests on Ubuntu
timeout-minutes: 60
runs-on: ubuntu-latest
env:
NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache: 'npm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
- name: Build Client
run: pnpm run frontend:ci
run: npm run frontend:ci
- name: Run unit tests
run: pnpm run test:ci --verbose
run: npm run test:ci --verbose
working-directory: client
tests_frontend_windows:
name: Run frontend unit tests on Windows
timeout-minutes: 60
runs-on: windows-latest
env:
NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache: 'npm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
- name: Build Client
run: pnpm run frontend:ci
run: npm run frontend:ci
- name: Run unit tests
run: pnpm run test:ci --verbose
run: npm run test:ci --verbose
working-directory: client
@@ -0,0 +1,95 @@
name: Generate Release Changelog PR
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
jobs:
generate-release-changelog-pr:
permissions:
contents: write # Needed for pushing commits and creating branches.
pull-requests: write
runs-on: ubuntu-latest
steps:
# 1. Checkout the repository (with full history).
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
# 2. Generate the release changelog using our custom configuration.
- name: Generate Release Changelog
id: generate_release
uses: mikepenz/release-changelog-builder-action@v5.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
configuration: ".github/configuration-release.json"
owner: ${{ github.repository_owner }}
repo: ${{ github.event.repository.name }}
outputFile: CHANGELOG-release.md
# 3. Update the main CHANGELOG.md:
# - If it doesn't exist, create it with a basic header.
# - Remove the "Unreleased" section (if present).
# - Prepend the new release changelog above previous releases.
# - Remove all temporary files before committing.
- name: Update CHANGELOG.md
run: |
# Determine the release tag, e.g. "v1.2.3"
TAG=${GITHUB_REF##*/}
echo "Using release tag: $TAG"
# Ensure CHANGELOG.md exists; if not, create a basic header.
if [ ! -f CHANGELOG.md ]; then
echo "# Changelog" > CHANGELOG.md
echo "" >> CHANGELOG.md
echo "All notable changes to this project will be documented in this file." >> CHANGELOG.md
echo "" >> CHANGELOG.md
fi
echo "Updating CHANGELOG.md…"
# Remove the "Unreleased" section (from "## [Unreleased]" until the first occurrence of '---') if it exists.
if grep -q "^## \[Unreleased\]" CHANGELOG.md; then
awk '/^## \[Unreleased\]/{flag=1} flag && /^---/{flag=0; next} !flag' CHANGELOG.md > CHANGELOG.cleaned
else
cp CHANGELOG.md CHANGELOG.cleaned
fi
# Split the cleaned file into:
# - header.md: content before the first release header ("## [v...").
# - tail.md: content from the first release header onward.
awk '/^## \[v/{exit} {print}' CHANGELOG.cleaned > header.md
awk 'f{print} /^## \[v/{f=1; print}' CHANGELOG.cleaned > tail.md
# Combine header, the new release changelog, and the tail.
echo "Combining updated changelog parts..."
cat header.md CHANGELOG-release.md > CHANGELOG.md.new
echo "" >> CHANGELOG.md.new
cat tail.md >> CHANGELOG.md.new
mv CHANGELOG.md.new CHANGELOG.md
# Remove temporary files.
rm -f CHANGELOG.cleaned header.md tail.md CHANGELOG-release.md
echo "Final CHANGELOG.md content:"
cat CHANGELOG.md
# 4. Create (or update) the Pull Request with the updated CHANGELOG.md.
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
sign-commits: true
commit-message: "chore: update CHANGELOG for release ${{ github.ref_name }}"
base: main
branch: "changelog/${{ github.ref_name }}"
reviewers: hanzoai
title: "📜 docs: Changelog for release ${{ github.ref_name }}"
body: |
**Description**:
- This PR updates the CHANGELOG.md by removing the "Unreleased" section and adding new release notes for release ${{ github.ref_name }} above previous releases.
@@ -0,0 +1,107 @@
name: Generate Unreleased Changelog PR
on:
schedule:
- cron: "0 0 * * 1" # Runs every Monday at 00:00 UTC
workflow_dispatch:
jobs:
generate-unreleased-changelog-pr:
permissions:
contents: write # Needed for pushing commits and creating branches.
pull-requests: write
runs-on: ubuntu-latest
steps:
# 1. Checkout the repository on main.
- name: Checkout Repository on Main
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
# 4. Get the latest version tag.
- name: Get Latest Tag
id: get_latest_tag
run: |
LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "none")
echo "Latest tag: $LATEST_TAG"
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
# 5. Generate the Unreleased changelog.
- name: Generate Unreleased Changelog
id: generate_unreleased
uses: mikepenz/release-changelog-builder-action@v5.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
configuration: ".github/configuration-unreleased.json"
owner: ${{ github.repository_owner }}
repo: ${{ github.event.repository.name }}
outputFile: CHANGELOG-unreleased.md
fromTag: ${{ steps.get_latest_tag.outputs.tag }}
toTag: main
# 7. Update CHANGELOG.md with the new Unreleased section.
- name: Update CHANGELOG.md
id: update_changelog
run: |
# Create CHANGELOG.md if it doesn't exist.
if [ ! -f CHANGELOG.md ]; then
echo "# Changelog" > CHANGELOG.md
echo "" >> CHANGELOG.md
echo "All notable changes to this project will be documented in this file." >> CHANGELOG.md
echo "" >> CHANGELOG.md
fi
echo "Updating CHANGELOG.md…"
# Extract content before the "## [Unreleased]" (or first version header if missing).
if grep -q "^## \[Unreleased\]" CHANGELOG.md; then
awk '/^## \[Unreleased\]/{exit} {print}' CHANGELOG.md > CHANGELOG_TMP.md
else
awk '/^## \[v/{exit} {print}' CHANGELOG.md > CHANGELOG_TMP.md
fi
# Append the generated Unreleased changelog.
echo "" >> CHANGELOG_TMP.md
cat CHANGELOG-unreleased.md >> CHANGELOG_TMP.md
echo "" >> CHANGELOG_TMP.md
# Append the remainder of the original changelog (starting from the first version header).
awk 'f{print} /^## \[v/{f=1; print}' CHANGELOG.md >> CHANGELOG_TMP.md
# Replace the old file with the updated file.
mv CHANGELOG_TMP.md CHANGELOG.md
# Remove the temporary generated file.
rm -f CHANGELOG-unreleased.md
echo "Final CHANGELOG.md:"
cat CHANGELOG.md
# 8. Check if CHANGELOG.md has any updates.
- name: Check for CHANGELOG.md changes
id: changelog_changes
run: |
if git diff --quiet CHANGELOG.md; then
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
# 9. Create (or update) the Pull Request only if there are changes.
- name: Create Pull Request
if: steps.changelog_changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
base: main
branch: "changelog/unreleased-update"
sign-commits: true
commit-message: "action: update Unreleased changelog"
title: "📜 docs: Unreleased Changelog"
body: |
**Description**:
- This PR updates the Unreleased section in CHANGELOG.md.
- It compares the current main branch with the latest version tag (determined as ${{ steps.get_latest_tag.outputs.tag }}),
regenerates the Unreleased changelog, removes any old Unreleased block, and inserts the new content.
+2 -2
View File
@@ -11,8 +11,8 @@ jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: supabase/embeddings-generator@v0.0.6
- uses: actions/checkout@v3
- uses: supabase/embeddings-generator@v0.0.5
with:
supabase-url: ${{ secrets.SUPABASE_URL }}
supabase-service-role-key: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
+11 -46
View File
@@ -4,17 +4,16 @@ name: Build Helm Charts on Tag
on:
push:
tags:
- "chart-*"
- "*"
jobs:
release:
permissions:
contents: write
packages: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -24,52 +23,18 @@ jobs:
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm
uses: azure/setup-helm@v5
uses: azure/setup-helm@v4
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- name: Build Subchart Deps
run: |
cd helm/librechat
helm dependency build
cd ../librechat-rag-api
helm dependency build
cd helm/hanzochat-rag-api
helm dependency build
- name: Get Chart Version
id: chart-version
run: |
CHART_VERSION=$(echo "${{ github.ref_name }}" | cut -d'-' -f2)
echo "CHART_VERSION=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
# Log in to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Run Helm OCI Charts Releaser
# This is for the librechat chart
- name: Release Helm OCI Charts for librechat
uses: appany/helm-oci-chart-releaser@v0.5.0
with:
name: librechat
repository: ${{ github.actor }}/librechat-chart
tag: ${{ steps.chart-version.outputs.CHART_VERSION }}
path: helm/librechat
registry: ghcr.io
registry_username: ${{ github.actor }}
registry_password: ${{ secrets.GITHUB_TOKEN }}
# this is for the librechat-rag-api chart
- name: Release Helm OCI Charts for librechat-rag-api
uses: appany/helm-oci-chart-releaser@v0.5.0
with:
name: librechat-rag-api
repository: ${{ github.actor }}/librechat-chart
tag: ${{ steps.chart-version.outputs.CHART_VERSION }}
path: helm/librechat-rag-api
registry: ghcr.io
registry_username: ${{ github.actor }}
registry_password: ${{ secrets.GITHUB_TOKEN }}
charts_dir: helm
skip_existing: true
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+2 -34
View File
@@ -1,18 +1,11 @@
name: Detect Unused i18next Strings
# This workflow checks for unused i18n keys in translation files.
# It has special handling for:
# - com_ui_special_var_* keys that are dynamically constructed
# - com_agents_category_* keys that are stored in the database and used dynamically
on:
pull_request:
paths:
- "client/src/**"
- "api/**"
- "packages/data-provider/src/**"
- "packages/client/**"
- "packages/data-schemas/src/**"
jobs:
detect-unused-i18n-keys:
@@ -21,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v3
- name: Find unused i18next keys
id: find-unused
@@ -30,7 +23,7 @@ jobs:
# Define paths
I18N_FILE="client/src/locales/en/translation.json"
SOURCE_DIRS=("client/src" "api" "packages/data-provider/src" "packages/client" "packages/data-schemas/src")
SOURCE_DIRS=("client/src" "api" "packages/data-provider/src")
# Check if translation file exists
if [[ ! -f "$I18N_FILE" ]]; then
@@ -58,31 +51,6 @@ jobs:
fi
done
# Also check if the key is directly used somewhere
if [[ "$FOUND" == false ]]; then
for DIR in "${SOURCE_DIRS[@]}"; do
if grep -r --include=\*.{js,jsx,ts,tsx} -q "$KEY" "$DIR"; then
FOUND=true
break
fi
done
fi
# Special case for agent category keys that are dynamically used from database
elif [[ "$KEY" == com_agents_category_* ]]; then
# Check if agent category localization is being used
for DIR in "${SOURCE_DIRS[@]}"; do
# Check for dynamic category label/description usage
if grep -r --include=\*.{js,jsx,ts,tsx} -E "category\.(label|description).*startsWith.*['\"]com_" "$DIR" > /dev/null 2>&1 || \
# Check for the method that defines these keys
grep -r --include=\*.{js,jsx,ts,tsx} "ensureDefaultCategories" "$DIR" > /dev/null 2>&1 || \
# Check for direct usage in agentCategory.ts
grep -r --include=\*.ts -E "label:.*['\"]$KEY['\"]" "$DIR" > /dev/null 2>&1 || \
grep -r --include=\*.ts -E "description:.*['\"]$KEY['\"]" "$DIR" > /dev/null 2>&1; then
FOUND=true
break
fi
done
# Also check if the key is directly used somewhere
if [[ "$FOUND" == false ]]; then
for DIR in "${SOURCE_DIRS[@]}"; do
-138
View File
@@ -1,138 +0,0 @@
import csv
import os
from github import Github
def interpret_results(csv_file):
with open(csv_file, newline="") as csvfile:
csvreader = csv.DictReader(csvfile)
rows = list(csvreader)
"""
in this csv reader
- Create 1 new column "Status"
- if a row has a median response time < 300 and an average response time < 300, Status = "Passed ✅"
- if a row has a median response time >= 300 or an average response time >= 300, Status = "Failed ❌"
- Order the table in this order Name, Status, Median Response Time, Average Response Time, Requests/s,Failures/s, Min Response Time, Max Response Time, all other columns
"""
# Add a new column "Status"
for row in rows:
median_response_time = float(
row["Median Response Time"].strip().rstrip("ms")
)
average_response_time = float(
row["Average Response Time"].strip().rstrip("s")
)
request_count = int(row["Request Count"])
failure_count = int(row["Failure Count"])
failure_percent = round((failure_count / request_count) * 100, 2)
# Determine status based on conditions
if (
median_response_time < 300
and average_response_time < 300
and failure_percent < 5
):
row["Status"] = "Passed ✅"
else:
row["Status"] = "Failed ❌"
# Construct Markdown table header
markdown_table = "| Name | Status | Median Response Time (ms) | Average Response Time (ms) | Requests/s | Failures/s | Request Count | Failure Count | Min Response Time (ms) | Max Response Time (ms) |"
markdown_table += (
"\n| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |"
)
# Construct Markdown table rows
for row in rows:
markdown_table += f"\n| {row['Name']} | {row['Status']} | {row['Median Response Time']} | {row['Average Response Time']} | {row['Requests/s']} | {row['Failures/s']} | {row['Request Count']} | {row['Failure Count']} | {row['Min Response Time']} | {row['Max Response Time']} |"
print("markdown table: ", markdown_table)
return markdown_table
def _get_docker_run_command_stable_release(release_version):
return f"""
\n\n
## Docker Run LiteLLM Proxy
```
docker run \\
-e STORE_MODEL_IN_DB=True \\
-p 4000:4000 \\
ghcr.io/berriai/litellm:litellm_stable_release_branch-{release_version}
```
"""
def _get_docker_run_command(release_version):
return f"""
\n\n
## Docker Run LiteLLM Proxy
```
docker run \\
-e STORE_MODEL_IN_DB=True \\
-p 4000:4000 \\
ghcr.io/berriai/litellm:main-{release_version}
```
"""
def get_docker_run_command(release_version):
if "stable" in release_version:
return _get_docker_run_command_stable_release(release_version)
else:
return _get_docker_run_command(release_version)
if __name__ == "__main__":
csv_file = "load_test_stats.csv" # Change this to the path of your CSV file
markdown_table = interpret_results(csv_file)
# Update release body with interpreted results
github_token = os.getenv("GITHUB_TOKEN")
g = Github(github_token)
repo = g.get_repo(
"BerriAI/litellm"
) # Replace with your repository's username and name
latest_release = repo.get_latest_release()
print("got latest release: ", latest_release)
print(latest_release.title)
print(latest_release.tag_name)
release_version = latest_release.title
print("latest release body: ", latest_release.body)
print("markdown table: ", markdown_table)
# check if "Load Test LiteLLM Proxy Results" exists
existing_release_body = latest_release.body
if "Load Test LiteLLM Proxy Results" in latest_release.body:
# find the "Load Test LiteLLM Proxy Results" section and delete it
start_index = latest_release.body.find("Load Test LiteLLM Proxy Results")
existing_release_body = latest_release.body[:start_index]
docker_run_command = get_docker_run_command(release_version)
print("docker run command: ", docker_run_command)
new_release_body = (
existing_release_body
+ docker_run_command
+ "\n\n"
+ "### Don't want to maintain your internal proxy? get in touch 🎉"
+ "\nHosted Proxy Alpha: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat"
+ "\n\n"
+ "## Load Test LiteLLM Proxy Results"
+ "\n\n"
+ markdown_table
)
print("new release body: ", new_release_body)
try:
latest_release.update_release(
name=latest_release.tag_name,
message=new_release_body,
)
except Exception as e:
print(e)
-17
View File
@@ -1,17 +0,0 @@
name: Label ML Ops Team Issues
on:
issues:
types:
- opened
jobs:
add-mlops-label:
runs-on: ubuntu-latest
steps:
- name: Check if ML Ops Team is selected
uses: actions-ecosystem/action-add-labels@v1
if: contains(github.event.issue.body, '### Are you a ML Ops Team?') && contains(github.event.issue.body, 'Yes')
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: "mlops user request"
@@ -1,89 +0,0 @@
name: LLM Translation Tests
on:
workflow_dispatch:
inputs:
release_candidate_tag:
description: 'Release candidate tag/version'
required: true
type: string
push:
tags:
- 'v*-rc*' # Triggers on release candidate tags like v1.0.0-rc1
jobs:
run-llm-translation-tests:
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.release_candidate_tag || github.ref }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
- name: Cache Poetry dependencies
uses: actions/cache@v5
with:
path: |
~/.cache/pypoetry
.venv
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
${{ runner.os }}-poetry-
- name: Install dependencies
run: |
poetry install --with dev
poetry run pip install pytest-xdist pytest-timeout
- name: Create test results directory
run: mkdir -p test-results
- name: Run LLM Translation Tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AZURE_API_BASE: ${{ secrets.AZURE_API_BASE }}
AZURE_API_VERSION: ${{ secrets.AZURE_API_VERSION }}
# Add other API keys as needed
run: |
python .github/workflows/run_llm_translation_tests.py \
--tag "${{ github.event.inputs.release_candidate_tag || github.ref_name }}" \
--commit "${{ github.sha }}" \
|| true # Continue even if tests fail
- name: Display test summary
if: always()
run: |
if [ -f "test-results/llm_translation_report.md" ]; then
echo "Test report generated successfully!"
echo "Artifact will contain:"
echo "- test-results/junit.xml (JUnit XML results)"
echo "- test-results/llm_translation_report.md (Beautiful markdown report)"
else
echo "Warning: Test report was not generated"
fi
- name: Upload test artifacts
uses: actions/upload-artifact@v7
if: always()
with:
name: LLM-Translation-Artifact-${{ github.event.inputs.release_candidate_tag || github.ref_name }}
path: test-results/
retention-days: 30
+6 -6
View File
@@ -12,10 +12,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Set Up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
@@ -44,25 +44,25 @@ jobs:
steps:
# 1. Check out the repository.
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v4
# 2. Download translation files from locize.
- name: Download Translations from locize
uses: locize/download@v3
uses: locize/download@v1
with:
project-id: ${{ secrets.LOCIZE_PROJECT_ID }}
path: "client/src/locales"
# 3. Create a Pull Request using built-in functionality.
- name: Create Pull Request
uses: peter-evans/create-pull-request@v8
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
sign-commits: true
commit-message: "🌍 i18n: Update translation.json with latest translations"
base: main
branch: i18n/locize-translation-update
reviewers: danny-avila
reviewers: hanzoai
title: "🌍 i18n: Update translation.json with latest translations"
body: |
**Description**:
-28
View File
@@ -1,28 +0,0 @@
from locust import HttpUser, task, between
class MyUser(HttpUser):
wait_time = between(1, 5)
@task
def chat_completion(self):
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer sk-8N1tLOOyH8TIxwOLahhIVg",
# Include any additional headers you may need for authentication, etc.
}
# Customize the payload with "model" and "messages" keys
payload = {
"model": "fake-openai-endpoint",
"messages": [
{"role": "system", "content": "You are a chat bot."},
{"role": "user", "content": "Hello, how are you?"},
],
# Add more data as necessary
}
# Make a POST request to the "chat/completions" endpoint
response = self.client.post("chat/completions", json=payload, headers=headers)
# Print or log the response if needed
+69
View File
@@ -0,0 +1,69 @@
name: Docker Compose Build Latest Main Image Tag (Manual Dispatch)
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: api-build
file: Dockerfile.multi
image_name: hanzochat-api
- target: node
file: Dockerfile
image_name: hanzochat
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Fetch tags and set the latest tag
run: |
git fetch --tags
echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV
# Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Log in to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Prepare the environment
- name: Prepare environment
run: |
cp .env.example .env
# Build and push Docker images for each target
- name: Build and push Docker images
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.file }}
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:${{ env.LATEST_TAG }}
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:latest
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:${{ env.LATEST_TAG }}
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:latest
platforms: linux/amd64,linux/arm64
target: ${{ matrix.target }}
-34
View File
@@ -1,34 +0,0 @@
name: Publish Dev Release to PyPI
on:
workflow_dispatch:
jobs:
publish-dev-release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: 3.8 # Adjust the Python version as needed
- name: Install dependencies
run: pip install toml twine
- name: Read version from pyproject.toml
id: read-version
run: |
version=$(python -c 'import toml; print(toml.load("pyproject.toml")["tool"]["commitizen"]["version"])')
printf "LITELLM_VERSION=%s" "$version" >> $GITHUB_ENV
- name: Check if version exists on PyPI
id: check-version
run: |
set -e
if twine check --repository-url https://pypi.org/simple/ "litellm==$LITELLM_VERSION" >/dev/null 2>&1; then
echo "Version $LITELLM_VERSION already exists on PyPI. Skipping publish."
+197
View File
@@ -0,0 +1,197 @@
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Detect Changes
runs-on: ubuntu-latest
outputs:
client: ${{ steps.filter.outputs.client }}
api: ${{ steps.filter.outputs.api }}
packages: ${{ steps.filter.outputs.packages }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
client:
- 'client/**'
- 'package.json'
api:
- 'api/**'
- 'package.json'
packages:
- 'packages/**'
test-client:
name: Client Tests
needs: changes
if: needs.changes.outputs.client == 'true' || needs.changes.outputs.packages == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build dependencies
run: |
npm run build:data-provider
npm run build:data-schemas
- name: Run client tests
run: NODE_ENV=test npm run test:client -- --passWithNoTests
- name: Comment PR (Client)
uses: actions/github-script@v7
if: always()
with:
script: |
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' && comment.body.includes('Client Test Results')
);
const body = `### 🧪 Client Test Results
${context.job.status === 'success' ? '✅ All client tests passed!' : '❌ Client tests failed'}
[View full test results](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`;
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
test-api:
name: API Tests
needs: changes
if: needs.changes.outputs.api == 'true' || needs.changes.outputs.packages == 'true'
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:7.0
ports:
- 27017:27017
options: >-
--health-cmd "mongosh --eval 'db.adminCommand(\"ping\")'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build dependencies
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Setup test environment
run: |
echo "NODE_ENV=test" > .env.test
echo "MONGO_URI=mongodb://localhost:27017/HanzoChat_test" >> .env.test
echo "MEILI_HOST=" >> .env.test
echo "RAG_API_URL=" >> .env.test
echo "ALLOW_REGISTRATION=true" >> .env.test
echo "DEBUG_LOGGING=false" >> .env.test
echo "CREDS_KEY=test-creds-key-32-chars-long-string" >> .env.test
echo "CREDS_IV=test-creds-iv-16" >> .env.test
echo "JWT_SECRET=test-jwt-secret-very-secure" >> .env.test
echo "JWT_REFRESH_SECRET=test-jwt-refresh-secret" >> .env.test
- name: Run API tests
run: NODE_ENV=test npm run test:api -- --maxWorkers=2 --passWithNoTests
size-check:
name: Bundle Size Check
needs: changes
if: needs.changes.outputs.client == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build client
run: npm run build:client
env:
DOMAIN_CLIENT: https://chat.hanzo.ai
DOMAIN_SERVER: https://chat.hanzo.ai
- name: Check bundle size
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
directory: client/dist
pattern: "**/*.{js,css}"
type-check:
name: TypeScript Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: TypeScript check
run: |
cd client && npx tsc --noEmit || true
cd ../api && npx tsc --noEmit || true
-20
View File
@@ -1,20 +0,0 @@
"""
redeploy_proxy.py
"""
import os
import requests
import time
# send a get request to this endpoint
deploy_hook1 = os.getenv("LOAD_TEST_REDEPLOY_URL1")
response = requests.get(deploy_hook1, timeout=20)
deploy_hook2 = os.getenv("LOAD_TEST_REDEPLOY_URL2")
response = requests.get(deploy_hook2, timeout=20)
print("SENT GET REQUESTS to re-deploy proxy")
print("sleeeping.... for 60s")
time.sleep(60)
+135
View File
@@ -0,0 +1,135 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
packages: write
jobs:
release:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build all packages
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Run tests
run: |
NODE_ENV=test npm run test:client
NODE_ENV=test npm run test:api -- --maxWorkers=2
- name: Build production
run: npm run build:client
env:
DOMAIN_CLIENT: https://chat.hanzo.ai
DOMAIN_SERVER: https://chat.hanzo.ai
NODE_ENV: production
- name: Generate changelog
id: changelog
uses: TriPSs/conventional-changelog-action@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
skip-version-file: true
output-file: false
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: ${{ steps.changelog.outputs.clean_changelog }}
draft: false
prerelease: false
- name: Build Docker image
run: |
docker build -t ghcr.io/hanzoai/chat:${{ github.ref_name }} .
docker tag ghcr.io/hanzoai/chat:${{ github.ref_name }} ghcr.io/hanzoai/chat:latest
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Docker image
run: |
docker push ghcr.io/hanzoai/chat:${{ github.ref_name }}
docker push ghcr.io/hanzoai/chat:latest
publish-npm:
name: Publish to NPM
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build packages
run: |
npm run build:data-provider
npm run build:data-schemas
npm run build:api
- name: Publish packages
run: |
cd packages/data-provider && npm publish --access public || true
cd ../data-schemas && npm publish --access public || true
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
deploy:
name: Deploy to Production
needs: release
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to Hanzo Cloud
run: |
echo "Deploying version ${{ github.ref_name }} to production"
# Add your deployment script here
# Example: kubectl set image deployment/chat chat=ghcr.io/hanzoai/chat:${{ github.ref_name }}
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Hanzo Chat ${{ github.ref_name }} deployed to production'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
if: always()
-27
View File
@@ -1,27 +0,0 @@
Date,"Ben
Ashley",Tom Brooks,Jimmy Cooney,"Sue
Daniels",Berlinda Fong,Terry Jones,Angelina Little,Linda Smith
10/1,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE
10/2,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/3,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/4,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/5,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/6,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/7,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/8,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/9,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/10,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/11,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/12,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/13,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/14,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/15,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/16,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/17,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/18,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/19,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/20,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/21,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/22,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
10/23,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE
Total,0,1,1,1,1,1,0,1
1 Date Ben Ashley Tom Brooks Jimmy Cooney Sue Daniels Berlinda Fong Terry Jones Angelina Little Linda Smith
2 10/1 FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE
3 10/2 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
4 10/3 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
5 10/4 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
6 10/5 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
7 10/6 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
8 10/7 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
9 10/8 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
10 10/9 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
11 10/10 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
12 10/11 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
13 10/12 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
14 10/13 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
15 10/14 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
16 10/15 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
17 10/16 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
18 10/17 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
19 10/18 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
20 10/19 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
21 10/20 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
22 10/21 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
23 10/22 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
24 10/23 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
25 Total 0 1 1 1 1 1 0 1
@@ -1,439 +0,0 @@
#!/usr/bin/env python3
"""
Run LLM Translation Tests and Generate Beautiful Markdown Report
This script runs the LLM translation tests and generates a comprehensive
markdown report with provider-specific breakdowns and test statistics.
"""
import os
import sys
import subprocess
import xml.etree.ElementTree as ET
from collections import defaultdict
from datetime import datetime
from pathlib import Path
import json
from typing import Dict, List, Tuple, Optional
# ANSI color codes for terminal output
class Colors:
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
PURPLE = '\033[95m'
CYAN = '\033[96m'
RESET = '\033[0m'
BOLD = '\033[1m'
def print_colored(message: str, color: str = Colors.RESET):
"""Print colored message to terminal"""
print(f"{color}{message}{Colors.RESET}")
def get_provider_from_test_file(test_file: str) -> str:
"""Map test file names to provider names"""
provider_mapping = {
'test_anthropic': 'Anthropic',
'test_azure': 'Azure',
'test_bedrock': 'AWS Bedrock',
'test_openai': 'OpenAI',
'test_vertex': 'Google Vertex AI',
'test_gemini': 'Google Vertex AI',
'test_cohere': 'Cohere',
'test_databricks': 'Databricks',
'test_groq': 'Groq',
'test_together': 'Together AI',
'test_mistral': 'Mistral',
'test_deepseek': 'DeepSeek',
'test_replicate': 'Replicate',
'test_huggingface': 'HuggingFace',
'test_fireworks': 'Fireworks AI',
'test_perplexity': 'Perplexity',
'test_cloudflare': 'Cloudflare',
'test_voyage': 'Voyage AI',
'test_xai': 'xAI',
'test_nvidia': 'NVIDIA',
'test_watsonx': 'IBM watsonx',
'test_azure_ai': 'Azure AI',
'test_snowflake': 'Snowflake',
'test_infinity': 'Infinity',
'test_jina': 'Jina AI',
'test_deepgram': 'Deepgram',
'test_clarifai': 'Clarifai',
'test_triton': 'Triton',
}
for key, provider in provider_mapping.items():
if key in test_file:
return provider
# For cross-provider test files
if any(name in test_file for name in ['test_optional_params', 'test_prompt_factory',
'test_router', 'test_text_completion']):
return f'Cross-Provider Tests ({test_file})'
return 'Other Tests'
def format_duration(seconds: float) -> str:
"""Format duration in human-readable format"""
if seconds < 60:
return f"{seconds:.2f}s"
elif seconds < 3600:
minutes = int(seconds // 60)
secs = seconds % 60
return f"{minutes}m {secs:.0f}s"
else:
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
return f"{hours}h {minutes}m"
def generate_markdown_report(junit_xml_path: str, output_path: str, tag: str = None, commit: str = None):
"""Generate a beautiful markdown report from JUnit XML"""
try:
tree = ET.parse(junit_xml_path)
root = tree.getroot()
# Handle both testsuite and testsuites root
if root.tag == 'testsuites':
suites = root.findall('testsuite')
else:
suites = [root]
# Overall statistics
total_tests = 0
total_failures = 0
total_errors = 0
total_skipped = 0
total_time = 0.0
# Provider breakdown
provider_stats = defaultdict(lambda: {'passed': 0, 'failed': 0, 'skipped': 0, 'errors': 0, 'time': 0.0})
provider_tests = defaultdict(list)
for suite in suites:
total_tests += int(suite.get('tests', 0))
total_failures += int(suite.get('failures', 0))
total_errors += int(suite.get('errors', 0))
total_skipped += int(suite.get('skipped', 0))
total_time += float(suite.get('time', 0))
for testcase in suite.findall('testcase'):
classname = testcase.get('classname', '')
test_name = testcase.get('name', '')
test_time = float(testcase.get('time', 0))
# Extract test file name from classname
if '.' in classname:
parts = classname.split('.')
test_file = parts[-2] if len(parts) > 1 else 'unknown'
else:
test_file = 'unknown'
provider = get_provider_from_test_file(test_file)
provider_stats[provider]['time'] += test_time
# Check test status
if testcase.find('failure') is not None:
provider_stats[provider]['failed'] += 1
failure = testcase.find('failure')
failure_msg = failure.get('message', '') if failure is not None else ''
provider_tests[provider].append({
'name': test_name,
'status': 'FAILED',
'time': test_time,
'message': failure_msg
})
elif testcase.find('error') is not None:
provider_stats[provider]['errors'] += 1
error = testcase.find('error')
error_msg = error.get('message', '') if error is not None else ''
provider_tests[provider].append({
'name': test_name,
'status': 'ERROR',
'time': test_time,
'message': error_msg
})
elif testcase.find('skipped') is not None:
provider_stats[provider]['skipped'] += 1
skip = testcase.find('skipped')
skip_msg = skip.get('message', '') if skip is not None else ''
provider_tests[provider].append({
'name': test_name,
'status': 'SKIPPED',
'time': test_time,
'message': skip_msg
})
else:
provider_stats[provider]['passed'] += 1
provider_tests[provider].append({
'name': test_name,
'status': 'PASSED',
'time': test_time,
'message': ''
})
passed = total_tests - total_failures - total_errors - total_skipped
# Generate the markdown report
with open(output_path, 'w') as f:
# Header
f.write("# LLM Translation Test Results\n\n")
# Metadata table
f.write("## Test Run Information\n\n")
f.write("| Field | Value |\n")
f.write("|-------|-------|\n")
f.write(f"| **Tag** | `{tag or 'N/A'}` |\n")
f.write(f"| **Date** | {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')} |\n")
f.write(f"| **Commit** | `{commit or 'N/A'}` |\n")
f.write(f"| **Duration** | {format_duration(total_time)} |\n")
f.write("\n")
# Overall statistics with visual elements
f.write("## Overall Statistics\n\n")
# Summary box
f.write("```\n")
f.write(f"Total Tests: {total_tests}\n")
f.write(f"├── Passed: {passed:>4} ({(passed/total_tests)*100 if total_tests > 0 else 0:.1f}%)\n")
f.write(f"├── Failed: {total_failures:>4} ({(total_failures/total_tests)*100 if total_tests > 0 else 0:.1f}%)\n")
f.write(f"├── Errors: {total_errors:>4} ({(total_errors/total_tests)*100 if total_tests > 0 else 0:.1f}%)\n")
f.write(f"└── Skipped: {total_skipped:>4} ({(total_skipped/total_tests)*100 if total_tests > 0 else 0:.1f}%)\n")
f.write("```\n\n")
# Provider summary table
f.write("## Results by Provider\n\n")
f.write("| Provider | Total | Pass | Fail | Error | Skip | Pass Rate | Duration |\n")
f.write("|----------|-------|------|------|-------|------|-----------|----------|")
# Sort providers: specific providers first, then cross-provider tests
sorted_providers = []
cross_provider = []
for p in sorted(provider_stats.keys()):
if 'Cross-Provider' in p or p == 'Other Tests':
cross_provider.append(p)
else:
sorted_providers.append(p)
all_providers = sorted_providers + cross_provider
for provider in all_providers:
stats = provider_stats[provider]
total = stats['passed'] + stats['failed'] + stats['errors'] + stats['skipped']
pass_rate = (stats['passed'] / total * 100) if total > 0 else 0
f.write(f"\n| {provider} | {total} | {stats['passed']} | {stats['failed']} | ")
f.write(f"{stats['errors']} | {stats['skipped']} | {pass_rate:.1f}% | ")
f.write(f"{format_duration(stats['time'])} |")
# Detailed test results by provider
f.write("\n\n## Detailed Test Results\n\n")
for provider in sorted_providers:
if provider_tests[provider]:
stats = provider_stats[provider]
total = stats['passed'] + stats['failed'] + stats['errors'] + stats['skipped']
f.write(f"### {provider}\n\n")
f.write(f"**Summary:** {stats['passed']}/{total} passed ")
f.write(f"({(stats['passed']/total)*100 if total > 0 else 0:.1f}%) ")
f.write(f"in {format_duration(stats['time'])}\n\n")
# Group tests by status
tests_by_status = defaultdict(list)
for test in provider_tests[provider]:
tests_by_status[test['status']].append(test)
# Show failed tests first (if any)
if tests_by_status['FAILED']:
f.write("<details>\n<summary>Failed Tests</summary>\n\n")
for test in tests_by_status['FAILED']:
f.write(f"- `{test['name']}` ({test['time']:.2f}s)\n")
if test['message']:
# Truncate long error messages
msg = test['message'][:200] + '...' if len(test['message']) > 200 else test['message']
f.write(f" > {msg}\n")
f.write("\n</details>\n\n")
# Show errors (if any)
if tests_by_status['ERROR']:
f.write("<details>\n<summary>Error Tests</summary>\n\n")
for test in tests_by_status['ERROR']:
f.write(f"- `{test['name']}` ({test['time']:.2f}s)\n")
f.write("\n</details>\n\n")
# Show passed tests in collapsible section
if tests_by_status['PASSED']:
f.write("<details>\n<summary>Passed Tests</summary>\n\n")
for test in tests_by_status['PASSED']:
f.write(f"- `{test['name']}` ({test['time']:.2f}s)\n")
f.write("\n</details>\n\n")
# Show skipped tests (if any)
if tests_by_status['SKIPPED']:
f.write("<details>\n<summary>Skipped Tests</summary>\n\n")
for test in tests_by_status['SKIPPED']:
f.write(f"- `{test['name']}`\n")
f.write("\n</details>\n\n")
# Cross-provider tests in a separate section
if cross_provider:
f.write("### Cross-Provider Tests\n\n")
for provider in cross_provider:
if provider_tests[provider]:
stats = provider_stats[provider]
total = stats['passed'] + stats['failed'] + stats['errors'] + stats['skipped']
f.write(f"#### {provider}\n\n")
f.write(f"**Summary:** {stats['passed']}/{total} passed ")
f.write(f"({(stats['passed']/total)*100 if total > 0 else 0:.1f}%)\n\n")
# For cross-provider tests, just show counts
f.write(f"- Passed: {stats['passed']}\n")
if stats['failed'] > 0:
f.write(f"- Failed: {stats['failed']}\n")
if stats['errors'] > 0:
f.write(f"- Errors: {stats['errors']}\n")
if stats['skipped'] > 0:
f.write(f"- Skipped: {stats['skipped']}\n")
f.write("\n")
print_colored(f"Report generated: {output_path}", Colors.GREEN)
except Exception as e:
print_colored(f"Error generating report: {e}", Colors.RED)
raise
def run_tests(test_path: str = "tests/llm_translation/",
junit_xml: str = "test-results/junit.xml",
report_path: str = "test-results/llm_translation_report.md",
tag: str = None,
commit: str = None) -> int:
"""Run the LLM translation tests and generate report"""
# Create test results directory
os.makedirs(os.path.dirname(junit_xml), exist_ok=True)
print_colored("Starting LLM Translation Tests", Colors.BOLD + Colors.BLUE)
print_colored(f"Test directory: {test_path}", Colors.CYAN)
print_colored(f"Output: {junit_xml}", Colors.CYAN)
print()
# Run pytest
cmd = [
"poetry", "run", "pytest", test_path,
f"--junitxml={junit_xml}",
"-v",
"--tb=short",
"--maxfail=500",
"-n", "auto"
]
# Add timeout if pytest-timeout is installed
try:
subprocess.run(["poetry", "run", "python", "-c", "import pytest_timeout"],
capture_output=True, check=True)
cmd.extend(["--timeout=300"])
except:
print_colored("Warning: pytest-timeout not installed, skipping timeout option", Colors.YELLOW)
print_colored("Running pytest with command:", Colors.YELLOW)
print(f" {' '.join(cmd)}")
print()
# Run the tests
result = subprocess.run(cmd, capture_output=False)
# Generate the report regardless of test outcome
if os.path.exists(junit_xml):
print()
print_colored("Generating test report...", Colors.BLUE)
generate_markdown_report(junit_xml, report_path, tag, commit)
# Print summary to console
print()
print_colored("Test Summary:", Colors.BOLD + Colors.PURPLE)
# Parse XML for quick summary
tree = ET.parse(junit_xml)
root = tree.getroot()
if root.tag == 'testsuites':
suites = root.findall('testsuite')
else:
suites = [root]
total = sum(int(s.get('tests', 0)) for s in suites)
failures = sum(int(s.get('failures', 0)) for s in suites)
errors = sum(int(s.get('errors', 0)) for s in suites)
skipped = sum(int(s.get('skipped', 0)) for s in suites)
passed = total - failures - errors - skipped
print(f" Total: {total}")
print_colored(f" Passed: {passed}", Colors.GREEN)
if failures > 0:
print_colored(f" Failed: {failures}", Colors.RED)
if errors > 0:
print_colored(f" Errors: {errors}", Colors.RED)
if skipped > 0:
print_colored(f" Skipped: {skipped}", Colors.YELLOW)
if total > 0:
pass_rate = (passed / total) * 100
color = Colors.GREEN if pass_rate >= 80 else Colors.YELLOW if pass_rate >= 60 else Colors.RED
print_colored(f" Pass Rate: {pass_rate:.1f}%", color)
else:
print_colored("No test results found!", Colors.RED)
print()
print_colored("Test run complete!", Colors.BOLD + Colors.GREEN)
return result.returncode
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Run LLM Translation Tests")
parser.add_argument("--test-path", default="tests/llm_translation/",
help="Path to test directory")
parser.add_argument("--junit-xml", default="test-results/junit.xml",
help="Path for JUnit XML output")
parser.add_argument("--report", default="test-results/llm_translation_report.md",
help="Path for markdown report")
parser.add_argument("--tag", help="Git tag or version")
parser.add_argument("--commit", help="Git commit SHA")
args = parser.parse_args()
# Get git info if not provided
if not args.commit:
try:
result = subprocess.run(["git", "rev-parse", "HEAD"],
capture_output=True, text=True)
if result.returncode == 0:
args.commit = result.stdout.strip()
except:
pass
if not args.tag:
try:
result = subprocess.run(["git", "describe", "--tags", "--abbrev=0"],
capture_output=True, text=True)
if result.returncode == 0:
args.tag = result.stdout.strip()
except:
pass
exit_code = run_tests(
test_path=args.test_path,
junit_xml=args.junit_xml,
report_path=args.report,
tag=args.tag,
commit=args.commit
)
sys.exit(exit_code)
-20
View File
@@ -1,20 +0,0 @@
name: "Stale Issue Management"
on:
schedule:
- cron: '0 0 * * *' # Runs daily at midnight UTC
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs."
stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs."
days-before-stale: 90 # Revert to 60 days
days-before-close: 7 # Revert to 7 days
stale-issue-label: "stale"
operations-per-run: 1000
+67
View File
@@ -0,0 +1,67 @@
name: Docker Images Build on Tag
on:
push:
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: api-build
file: Dockerfile.multi
image_name: hanzochat-api
- target: node
file: Dockerfile
image_name: hanzochat
steps:
# Check out the repository
- name: Checkout
uses: actions/checkout@v4
# Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Log in to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Prepare the environment
- name: Prepare environment
run: |
cp .env.example .env
# Build and push Docker images for each target
- name: Build and push Docker images
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.file }}
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:${{ github.ref_name }}
ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}:latest
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:${{ github.ref_name }}
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image_name }}:latest
platforms: linux/amd64,linux/arm64
target: ${{ matrix.target }}
-57
View File
@@ -1,57 +0,0 @@
name: LiteLLM Linting
on:
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Install dependencies
run: |
pip install openai==1.81.0
poetry install --with dev
pip install openai==1.81.0
- name: Run Black formatting
run: |
cd litellm
poetry run black .
cd ..
- name: Run Ruff linting
run: |
cd litellm
poetry run ruff check .
cd ..
- name: Run MyPy type checking
run: |
cd litellm
poetry run mypy . --ignore-missing-imports
cd ..
- name: Check for circular imports
run: |
cd litellm
poetry run python ../tests/documentation_tests/test_circular_imports.py
cd ..
- name: Check import safety
run: |
poetry run python -c "from litellm import *" || (echo '🚨 import failed, this means you introduced unprotected imports! 🚨'; exit 1)
-70
View File
@@ -1,70 +0,0 @@
name: Test Chat Service
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:7
ports:
- 27017:27017
meili:
image: getmeili/meilisearch:latest
env:
MEILI_MASTER_KEY: test_master_key
ports:
- 7700:7700
steps:
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v5
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build workspace packages
run: |
pnpm run build:data-provider
pnpm run build:data-schemas
pnpm run build:api
pnpm run build:client-package
- name: Run API tests
run: pnpm run test:api
env:
NODE_ENV: test
MONGO_URI: mongodb://localhost:27017/librechat-test
MEILI_HOST: http://localhost:7700
MEILI_MASTER_KEY: test_master_key
- name: Run client tests
run: pnpm run test:client
+15 -143
View File
@@ -7,8 +7,6 @@ on:
- 'package-lock.json'
- 'client/**'
- 'api/**'
- 'packages/client/**'
- 'packages/api/**'
jobs:
detect-unused-packages:
@@ -17,22 +15,20 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache: 'npm'
- name: Install depcheck
run: pnpm add -g depcheck
run: npm install -g depcheck
- name: Validate JSON files
run: |
for FILE in package.json client/package.json api/package.json packages/client/package.json; do
for FILE in package.json client/package.json api/package.json; do
if [[ -f "$FILE" ]]; then
jq empty "$FILE" || (echo "::error title=Invalid JSON::$FILE is invalid" && exit 1)
fi
@@ -66,151 +62,29 @@ jobs:
extract_deps_from_code() {
local folder=$1
local output_file=$2
# Initialize empty output file
> "$output_file"
if [[ -d "$folder" ]]; then
# Extract require() statements (use explicit includes for portability)
grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" \
--include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
sed -E "s/require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)/\1/" >> "$output_file" || true
grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" --include=\*.{js,ts,mjs,cjs} | \
sed -E "s/require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)/\1/" > "$output_file"
# Extract ES6 imports - import x from 'module'
grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
--include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
sed -E "s/import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# import 'module' (side-effect imports)
grep -rEho "import ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
--include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
sed -E "s/import ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# export { x } from 'module' or export * from 'module'
grep -rEho "export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
--include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
sed -E "s/export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# import type { x } from 'module' (TypeScript)
grep -rEho "import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
--include='*.ts' --include='*.tsx' 2>/dev/null | \
sed -E "s/import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,mjs,cjs} | \
sed -E "s/import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file"
# Remove subpath imports but keep the base package
# For scoped packages: '@scope/pkg/subpath' -> '@scope/pkg'
# For regular packages: 'pkg/subpath' -> 'pkg'
# Scoped packages (must keep @scope/package, strip anything after)
sed -i -E 's|^(@[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)/.*|\1|' "$output_file" 2>/dev/null || true
# Non-scoped packages (keep package name, strip subpath)
sed -i -E 's|^([a-zA-Z0-9_-]+)/.*|\1|' "$output_file" 2>/dev/null || true
sort -u "$output_file" -o "$output_file"
else
touch "$output_file"
fi
}
extract_deps_from_code "." root_used_code.txt
extract_deps_from_code "client" client_used_code.txt
extract_deps_from_code "api" api_used_code.txt
# Extract dependencies used by workspace packages
# These packages are used in the workspace but dependencies are provided by parent package.json
extract_deps_from_code "packages/client" packages_client_used_code.txt
extract_deps_from_code "packages/api" packages_api_used_code.txt
- name: Get @librechat/client dependencies
id: get-librechat-client-deps
run: |
if [[ -f "packages/client/package.json" ]]; then
# Get all dependencies from @librechat/client (dependencies, devDependencies, and peerDependencies)
DEPS=$(jq -r '.dependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "")
DEV_DEPS=$(jq -r '.devDependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "")
PEER_DEPS=$(jq -r '.peerDependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "")
# Combine all dependencies
echo "$DEPS" > librechat_client_deps.txt
echo "$DEV_DEPS" >> librechat_client_deps.txt
echo "$PEER_DEPS" >> librechat_client_deps.txt
# Also include dependencies that are imported in packages/client
cat packages_client_used_code.txt >> librechat_client_deps.txt
# Remove empty lines and sort
grep -v '^$' librechat_client_deps.txt | sort -u > temp_deps.txt
mv temp_deps.txt librechat_client_deps.txt
else
touch librechat_client_deps.txt
fi
- name: Get @librechat/api dependencies
id: get-librechat-api-deps
run: |
if [[ -f "packages/api/package.json" ]]; then
# Get all dependencies from @librechat/api (dependencies, devDependencies, and peerDependencies)
DEPS=$(jq -r '.dependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
DEV_DEPS=$(jq -r '.devDependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
PEER_DEPS=$(jq -r '.peerDependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
# Combine all dependencies
echo "$DEPS" > librechat_api_deps.txt
echo "$DEV_DEPS" >> librechat_api_deps.txt
echo "$PEER_DEPS" >> librechat_api_deps.txt
# Also include dependencies that are imported in packages/api
cat packages_api_used_code.txt >> librechat_api_deps.txt
# Remove empty lines and sort
grep -v '^$' librechat_api_deps.txt | sort -u > temp_deps.txt
mv temp_deps.txt librechat_api_deps.txt
else
touch librechat_api_deps.txt
fi
- name: Extract Workspace Dependencies
id: extract-workspace-deps
run: |
# Function to get dependencies from a workspace package that are used by another package
get_workspace_package_deps() {
local package_json=$1
local output_file=$2
# Get all workspace dependencies (starting with @librechat/)
if [[ -f "$package_json" ]]; then
local workspace_deps=$(jq -r '.dependencies // {} | to_entries[] | select(.key | startswith("@librechat/")) | .key' "$package_json" 2>/dev/null || echo "")
# For each workspace dependency, get its dependencies
for dep in $workspace_deps; do
# Convert @librechat/api to packages/api
local workspace_path=$(echo "$dep" | sed 's/@librechat\//packages\//')
local workspace_package_json="${workspace_path}/package.json"
if [[ -f "$workspace_package_json" ]]; then
# Extract all dependencies from the workspace package
jq -r '.dependencies // {} | keys[]' "$workspace_package_json" 2>/dev/null >> "$output_file"
# Also extract peerDependencies
jq -r '.peerDependencies // {} | keys[]' "$workspace_package_json" 2>/dev/null >> "$output_file"
fi
done
fi
if [[ -f "$output_file" ]]; then
sort -u "$output_file" -o "$output_file"
else
touch "$output_file"
fi
}
# Get workspace dependencies for each package
get_workspace_package_deps "package.json" root_workspace_deps.txt
get_workspace_package_deps "client/package.json" client_workspace_deps.txt
get_workspace_package_deps "api/package.json" api_workspace_deps.txt
- name: Run depcheck for root package.json
id: check-root
run: |
if [[ -f "package.json" ]]; then
UNUSED=$(depcheck --json | jq -r '.dependencies | join("\n")' || echo "")
# Exclude dependencies used in scripts, code, and workspace packages
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat root_used_deps.txt root_used_code.txt root_workspace_deps.txt | sort) || echo "")
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat root_used_deps.txt root_used_code.txt | sort) || echo "")
echo "ROOT_UNUSED<<EOF" >> $GITHUB_ENV
echo "$UNUSED" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
@@ -223,8 +97,7 @@ jobs:
chmod -R 755 client
cd client
UNUSED=$(depcheck --json | jq -r '.dependencies | join("\n")' || echo "")
# Exclude dependencies used in scripts, code, workspace packages, and @librechat/client imports
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../client_used_deps.txt ../client_used_code.txt ../client_workspace_deps.txt ../packages_client_used_code.txt ../librechat_client_deps.txt 2>/dev/null | sort -u) || echo "")
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../client_used_deps.txt ../client_used_code.txt | sort) || echo "")
# Filter out false positives
UNUSED=$(echo "$UNUSED" | grep -v "^micromark-extension-llm-math$" || echo "")
echo "CLIENT_UNUSED<<EOF" >> $GITHUB_ENV
@@ -240,8 +113,7 @@ jobs:
chmod -R 755 api
cd api
UNUSED=$(depcheck --json | jq -r '.dependencies | join("\n")' || echo "")
# Exclude dependencies used in scripts, code, workspace packages, and @librechat/api imports
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../api_used_deps.txt ../api_used_code.txt ../api_workspace_deps.txt ../packages_api_used_code.txt ../librechat_api_deps.txt 2>/dev/null | sort -u) || echo "")
UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../api_used_deps.txt ../api_used_code.txt | sort) || echo "")
echo "API_UNUSED<<EOF" >> $GITHUB_ENV
echo "$UNUSED" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
@@ -280,4 +152,4 @@ jobs:
- name: Fail workflow if unused dependencies found
if: env.ROOT_UNUSED != '' || env.CLIENT_UNUSED != '' || env.API_UNUSED != ''
run: exit 1
run: exit 1
-54
View File
@@ -1,54 +0,0 @@
import os
import requests
from datetime import datetime
# GitHub API endpoints
GITHUB_API_URL = "https://api.github.com"
REPO_OWNER = "BerriAI"
REPO_NAME = "litellm"
# GitHub personal access token (required for uploading release assets)
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN")
# Headers for GitHub API requests
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {GITHUB_ACCESS_TOKEN}",
"X-GitHub-Api-Version": "2022-11-28",
}
# Get the latest release
releases_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/releases/latest"
response = requests.get(releases_url, headers=headers)
latest_release = response.json()
print("Latest release:", latest_release)
# Upload an asset to the latest release
upload_url = latest_release["upload_url"].split("{?")[0]
asset_name = "results_stats.csv"
asset_path = os.path.join(os.getcwd(), asset_name)
print("upload_url:", upload_url)
with open(asset_path, "rb") as asset_file:
asset_data = asset_file.read()
upload_payload = {
"name": asset_name,
"label": "Load test results",
"created_at": datetime.utcnow().isoformat() + "Z",
}
upload_headers = headers.copy()
upload_headers["Content-Type"] = "application/octet-stream"
upload_response = requests.post(
upload_url,
headers=upload_headers,
data=asset_data,
params=upload_payload,
)
if upload_response.status_code == 201:
print(f"Asset '{asset_name}' uploaded successfully to the latest release.")
else:
print(f"Failed to upload asset. Response: {upload_response.text}")
-7
View File
@@ -1,7 +0,0 @@
name: Workflow Sanity
on:
pull_request:
paths: ['.github/workflows/**']
jobs:
sanity:
uses: hanzoai/.github/.github/workflows/workflow-sanity.yml@main
+4 -59
View File
@@ -13,10 +13,6 @@ pids
*.seed
.git
# CI/CD data
test-image*
dump.rdb
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
@@ -30,9 +26,6 @@ coverage
config/translations/stores/*
client/src/localization/languages/*_missing_keys.json
# Turborepo
.turbo
# Compiled Dirs (http://nodejs.org/api/addons.html)
build/
dist/
@@ -71,8 +64,8 @@ bower_components/
.flooignore
#config file
librechat.yaml
librechat.yml
chat.yaml
chat.yml
# Environment
.npmrc
@@ -132,53 +125,5 @@ helm/**/.values.yaml
# SAML Idp cert
*.cert
# AI Assistants
/.claude/
/.cursor/
/.copilot/
/.aider/
/.openai/
/.tabnine/
/.codeium
*.local.md
# Removed Windows wrapper files per user request
hive-mind-prompt-*.txt
# Claude Flow generated files
.claude/settings.local.json
.mcp.json
claude-flow.config.json
.swarm/
.hive-mind/
.claude-flow/
memory/
coordination/
memory/claude-flow-data.json
memory/sessions/*
!memory/sessions/README.md
memory/agents/*
!memory/agents/README.md
coordination/memory_bank/*
coordination/subtasks/*
coordination/orchestration/*
*.db
*.db-journal
*.db-wal
*.sqlite
*.sqlite-journal
*.sqlite-wal
claude-flow
# Removed Windows wrapper files per user request
hive-mind-prompt-*.txt
# Hanzo-specific
CLAUDE.md
.env.hanzo
!.env.hanzo-cloud
tests/**/*.wav
tests/**/*.mp3
tests/**/*.png
tests/**/*.jpg
*.orig
.claude
+34 -2
View File
@@ -1,2 +1,34 @@
[ -n "$CI" ] && exit 0
npx lint-staged --config ./.husky/lint-staged.config.js
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run linting on staged files
npx lint-staged
# Run tests for changed files
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|jsx|ts|tsx)$' || true)
if [ -n "$CHANGED_FILES" ]; then
echo "Running tests for changed files..."
# Check if client files changed
if echo "$CHANGED_FILES" | grep -q "^client/"; then
echo "Client files changed, running client tests..."
cd client && npm run test:ci -- --passWithNoTests --bail
cd ..
fi
# Check if API files changed
if echo "$CHANGED_FILES" | grep -q "^api/"; then
echo "API files changed, running API tests..."
cd api && npm run test:ci -- --passWithNoTests --bail --maxWorkers=2
cd ..
fi
# Check if package files changed
if echo "$CHANGED_FILES" | grep -q "^packages/"; then
echo "Package files changed, building packages..."
npm run build:data-provider
npm run build:data-schemas
npm run build:api
fi
fi
+5
View File
@@ -0,0 +1,5 @@
{
"*.{js,jsx,ts,tsx}": ["eslint --fix --no-warn-ignored", "prettier --write"],
"*.{json,md,yml,yaml}": ["prettier --write"],
"*.{css,scss,less}": ["prettier --write"]
}
-1
View File
@@ -1 +0,0 @@
node-linker=hoisted
-40
View File
@@ -1,40 +0,0 @@
repos:
- repo: local
hooks:
- id: pyright
name: pyright
entry: pyright
language: system
types: [python]
files: ^(litellm/|litellm_proxy_extras/|enterprise/)
- id: isort
name: isort
entry: isort
language: system
types: [python]
files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py
exclude: ^litellm/__init__.py$
# - id: black
# name: black
# entry: poetry run black
# language: system
# types: [python]
# files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py
- repo: https://github.com/pycqa/flake8
rev: 7.0.0 # The version of flake8 to use
hooks:
- id: flake8
exclude: ^litellm/tests/|^litellm/proxy/tests/|^litellm/tests/test_litellm/|^tests/test_litellm/|^tests/enterprise/
additional_dependencies: [flake8-print]
files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py
- repo: https://github.com/python-poetry/poetry
rev: 1.8.0
hooks:
- id: poetry-check
files: ^(pyproject.toml|litellm-proxy-extras/pyproject.toml)$
- repo: local
hooks:
- id: check-files-match
name: Check if files match
entry: python3 ci_cd/check_files_match.py
language: system
+1 -2
View File
@@ -8,8 +8,7 @@
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/api/server/index.js",
"env": {
"NODE_ENV": "production",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
"NODE_ENV": "production"
},
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/.env"
-1
View File
@@ -1 +0,0 @@
LLM.md
+166 -166
View File
@@ -11,41 +11,41 @@ All notable changes to this project will be documented in this file.
### ✨ New Features
- ✨ feat: implement search parameter updates by **@mawburn** in [#7151](https://github.com/danny-avila/LibreChat/pull/7151)
- 🎏 feat: Add MCP support for Streamable HTTP Transport by **@benverhees** in [#7353](https://github.com/danny-avila/LibreChat/pull/7353)
- 🔒 feat: Add Content Security Policy using Helmet middleware by **@rubentalstra** in [#7377](https://github.com/danny-avila/LibreChat/pull/7377)
- ✨ feat: Add Normalization for MCP Server Names by **@danny-avila** in [#7421](https://github.com/danny-avila/LibreChat/pull/7421)
- 📊 feat: Improve Helm Chart by **@hofq** in [#3638](https://github.com/danny-avila/LibreChat/pull/3638)
- 🦾 feat: Claude-4 Support by **@danny-avila** in [#7509](https://github.com/danny-avila/LibreChat/pull/7509)
- 🪨 feat: Bedrock Support for Claude-4 Reasoning by **@danny-avila** in [#7517](https://github.com/danny-avila/LibreChat/pull/7517)
- ✨ feat: implement search parameter updates by **@mawburn** in [#7151](https://github.com/hanzoai/Chat/pull/7151)
- 🎏 feat: Add MCP support for Streamable HTTP Transport by **@benverhees** in [#7353](https://github.com/hanzoai/Chat/pull/7353)
- 🔒 feat: Add Content Security Policy using Helmet middleware by **@rubentalstra** in [#7377](https://github.com/hanzoai/Chat/pull/7377)
- ✨ feat: Add Normalization for MCP Server Names by **@hanzoai** in [#7421](https://github.com/hanzoai/Chat/pull/7421)
- 📊 feat: Improve Helm Chart by **@hofq** in [#3638](https://github.com/hanzoai/Chat/pull/3638)
- 🦾 feat: Claude-4 Support by **@hanzoai** in [#7509](https://github.com/hanzoai/Chat/pull/7509)
- 🪨 feat: Bedrock Support for Claude-4 Reasoning by **@hanzoai** in [#7517](https://github.com/hanzoai/Chat/pull/7517)
### 🌍 Internationalization
- 🌍 i18n: Add `Danish` and `Czech` and `Catalan` localization support by **@rubentalstra** in [#7373](https://github.com/danny-avila/LibreChat/pull/7373)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7375](https://github.com/danny-avila/LibreChat/pull/7375)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7468](https://github.com/danny-avila/LibreChat/pull/7468)
- 🌍 i18n: Add `Danish` and `Czech` and `Catalan` localization support by **@rubentalstra** in [#7373](https://github.com/hanzoai/Chat/pull/7373)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7375](https://github.com/hanzoai/Chat/pull/7375)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7468](https://github.com/hanzoai/Chat/pull/7468)
### 🔧 Fixes
- 💬 fix: update aria-label for accessibility in ConvoLink component by **@berry-13** in [#7320](https://github.com/danny-avila/LibreChat/pull/7320)
- 🔑 fix: use `apiKey` instead of `openAIApiKey` in OpenAI-like Config by **@danny-avila** in [#7337](https://github.com/danny-avila/LibreChat/pull/7337)
- 🔄 fix: update navigation logic in `useFocusChatEffect` to ensure correct search parameters are used by **@mawburn** in [#7340](https://github.com/danny-avila/LibreChat/pull/7340)
- 🔄 fix: Improve MCP Connection Cleanup by **@danny-avila** in [#7400](https://github.com/danny-avila/LibreChat/pull/7400)
- 🛡️ fix: Preset and Validation Logic for URL Query Params by **@danny-avila** in [#7407](https://github.com/danny-avila/LibreChat/pull/7407)
- 🌘 fix: artifact of preview text is illegible in dark mode by **@nhtruong** in [#7405](https://github.com/danny-avila/LibreChat/pull/7405)
- 🛡️ fix: Temporarily Remove CSP until Configurable by **@danny-avila** in [#7419](https://github.com/danny-avila/LibreChat/pull/7419)
- 💽 fix: Exclude index page `/` from static cache settings by **@sbruel** in [#7382](https://github.com/danny-avila/LibreChat/pull/7382)
- 💬 fix: update aria-label for accessibility in ConvoLink component by **@berry-13** in [#7320](https://github.com/hanzoai/Chat/pull/7320)
- 🔑 fix: use `apiKey` instead of `openAIApiKey` in OpenAI-like Config by **@hanzoai** in [#7337](https://github.com/hanzoai/Chat/pull/7337)
- 🔄 fix: update navigation logic in `useFocusChatEffect` to ensure correct search parameters are used by **@mawburn** in [#7340](https://github.com/hanzoai/Chat/pull/7340)
- 🔄 fix: Improve MCP Connection Cleanup by **@hanzoai** in [#7400](https://github.com/hanzoai/Chat/pull/7400)
- 🛡️ fix: Preset and Validation Logic for URL Query Params by **@hanzoai** in [#7407](https://github.com/hanzoai/Chat/pull/7407)
- 🌘 fix: artifact of preview text is illegible in dark mode by **@nhtruong** in [#7405](https://github.com/hanzoai/Chat/pull/7405)
- 🛡️ fix: Temporarily Remove CSP until Configurable by **@hanzoai** in [#7419](https://github.com/hanzoai/Chat/pull/7419)
- 💽 fix: Exclude index page `/` from static cache settings by **@sbruel** in [#7382](https://github.com/hanzoai/Chat/pull/7382)
### ⚙️ Other Changes
- 📜 docs: CHANGELOG for release v0.7.8 by **@github-actions[bot]** in [#7290](https://github.com/danny-avila/LibreChat/pull/7290)
- 📦 chore: Update API Package Dependencies by **@danny-avila** in [#7359](https://github.com/danny-avila/LibreChat/pull/7359)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7321](https://github.com/danny-avila/LibreChat/pull/7321)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7434](https://github.com/danny-avila/LibreChat/pull/7434)
- 🛡️ chore: `multer` v2.0.0 for CVE-2025-47935 and CVE-2025-47944 by **@danny-avila** in [#7454](https://github.com/danny-avila/LibreChat/pull/7454)
- 📂 refactor: Improve `FileAttachment` & File Form Deletion by **@danny-avila** in [#7471](https://github.com/danny-avila/LibreChat/pull/7471)
- 📊 chore: Remove Old Helm Chart by **@hofq** in [#7512](https://github.com/danny-avila/LibreChat/pull/7512)
- 🪖 chore: bump helm app version to v0.7.8 by **@austin-barrington** in [#7524](https://github.com/danny-avila/LibreChat/pull/7524)
- 📜 docs: CHANGELOG for release v0.7.8 by **@github-actions[bot]** in [#7290](https://github.com/hanzoai/Chat/pull/7290)
- 📦 chore: Update API Package Dependencies by **@hanzoai** in [#7359](https://github.com/hanzoai/Chat/pull/7359)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7321](https://github.com/hanzoai/Chat/pull/7321)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7434](https://github.com/hanzoai/Chat/pull/7434)
- 🛡️ chore: `multer` v2.0.0 for CVE-2025-47935 and CVE-2025-47944 by **@hanzoai** in [#7454](https://github.com/hanzoai/Chat/pull/7454)
- 📂 refactor: Improve `FileAttachment` & File Form Deletion by **@hanzoai** in [#7471](https://github.com/hanzoai/Chat/pull/7471)
- 📊 chore: Remove Old Helm Chart by **@hofq** in [#7512](https://github.com/hanzoai/Chat/pull/7512)
- 🪖 chore: bump helm app version to v0.7.8 by **@austin-barrington** in [#7524](https://github.com/hanzoai/Chat/pull/7524)
@@ -56,38 +56,38 @@ Changes from v0.7.8-rc1 to v0.7.8.
### ✨ New Features
- ✨ feat: Enhance form submission for touch screens by **@berry-13** in [#7198](https://github.com/danny-avila/LibreChat/pull/7198)
- 🔍 feat: Additional Tavily API Tool Parameters by **@glowforge-opensource** in [#7232](https://github.com/danny-avila/LibreChat/pull/7232)
- 🐋 feat: Add python to Dockerfile for increased MCP compatibility by **@technicalpickles** in [#7270](https://github.com/danny-avila/LibreChat/pull/7270)
- ✨ feat: Enhance form submission for touch screens by **@berry-13** in [#7198](https://github.com/hanzoai/Chat/pull/7198)
- 🔍 feat: Additional Tavily API Tool Parameters by **@glowforge-opensource** in [#7232](https://github.com/hanzoai/Chat/pull/7232)
- 🐋 feat: Add python to Dockerfile for increased MCP compatibility by **@technicalpickles** in [#7270](https://github.com/hanzoai/Chat/pull/7270)
### 🔧 Fixes
- 🔧 fix: Google Gemma Support & OpenAI Reasoning Instructions by **@danny-avila** in [#7196](https://github.com/danny-avila/LibreChat/pull/7196)
- 🛠️ fix: Conversation Navigation State by **@danny-avila** in [#7210](https://github.com/danny-avila/LibreChat/pull/7210)
- 🔄 fix: o-Series Model Regex for System Messages by **@danny-avila** in [#7245](https://github.com/danny-avila/LibreChat/pull/7245)
- 🔖 fix: Custom Headers for Initial MCP SSE Connection by **@danny-avila** in [#7246](https://github.com/danny-avila/LibreChat/pull/7246)
- 🛡️ fix: Deep Clone `MCPOptions` for User MCP Connections by **@danny-avila** in [#7247](https://github.com/danny-avila/LibreChat/pull/7247)
- 🔄 fix: URL Param Race Condition and File Draft Persistence by **@danny-avila** in [#7257](https://github.com/danny-avila/LibreChat/pull/7257)
- 🔄 fix: Assistants Endpoint & Minor Issues by **@danny-avila** in [#7274](https://github.com/danny-avila/LibreChat/pull/7274)
- 🔄 fix: Ollama Think Tag Edge Case with Tools by **@danny-avila** in [#7275](https://github.com/danny-avila/LibreChat/pull/7275)
- 🔧 fix: Google Gemma Support & OpenAI Reasoning Instructions by **@hanzoai** in [#7196](https://github.com/hanzoai/Chat/pull/7196)
- 🛠️ fix: Conversation Navigation State by **@hanzoai** in [#7210](https://github.com/hanzoai/Chat/pull/7210)
- 🔄 fix: o-Series Model Regex for System Messages by **@hanzoai** in [#7245](https://github.com/hanzoai/Chat/pull/7245)
- 🔖 fix: Custom Headers for Initial MCP SSE Connection by **@hanzoai** in [#7246](https://github.com/hanzoai/Chat/pull/7246)
- 🛡️ fix: Deep Clone `MCPOptions` for User MCP Connections by **@hanzoai** in [#7247](https://github.com/hanzoai/Chat/pull/7247)
- 🔄 fix: URL Param Race Condition and File Draft Persistence by **@hanzoai** in [#7257](https://github.com/hanzoai/Chat/pull/7257)
- 🔄 fix: Assistants Endpoint & Minor Issues by **@hanzoai** in [#7274](https://github.com/hanzoai/Chat/pull/7274)
- 🔄 fix: Ollama Think Tag Edge Case with Tools by **@hanzoai** in [#7275](https://github.com/hanzoai/Chat/pull/7275)
### ⚙️ Other Changes
- 📜 docs: CHANGELOG for release v0.7.8-rc1 by **@github-actions[bot]** in [#7153](https://github.com/danny-avila/LibreChat/pull/7153)
- 🔄 refactor: Artifact Visibility Management by **@danny-avila** in [#7181](https://github.com/danny-avila/LibreChat/pull/7181)
- 📦 chore: Bump Package Security by **@danny-avila** in [#7183](https://github.com/danny-avila/LibreChat/pull/7183)
- 🌿 refactor: Unmount Fork Popover on Hide for Better Performance by **@danny-avila** in [#7189](https://github.com/danny-avila/LibreChat/pull/7189)
- 🧰 chore: ESLint configuration to enforce Prettier formatting rules by **@mawburn** in [#7186](https://github.com/danny-avila/LibreChat/pull/7186)
- 🎨 style: Improve KaTeX Rendering for LaTeX Equations by **@andresgit** in [#7223](https://github.com/danny-avila/LibreChat/pull/7223)
- 📝 docs: Update `.env.example` Google models by **@marlonka** in [#7254](https://github.com/danny-avila/LibreChat/pull/7254)
- 💬 refactor: MCP Chat Visibility Option, Google Rates, Remove OpenAPI Plugins by **@danny-avila** in [#7286](https://github.com/danny-avila/LibreChat/pull/7286)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7214](https://github.com/danny-avila/LibreChat/pull/7214)
- 📜 docs: CHANGELOG for release v0.7.8-rc1 by **@github-actions[bot]** in [#7153](https://github.com/hanzoai/Chat/pull/7153)
- 🔄 refactor: Artifact Visibility Management by **@hanzoai** in [#7181](https://github.com/hanzoai/Chat/pull/7181)
- 📦 chore: Bump Package Security by **@hanzoai** in [#7183](https://github.com/hanzoai/Chat/pull/7183)
- 🌿 refactor: Unmount Fork Popover on Hide for Better Performance by **@hanzoai** in [#7189](https://github.com/hanzoai/Chat/pull/7189)
- 🧰 chore: ESLint configuration to enforce Prettier formatting rules by **@mawburn** in [#7186](https://github.com/hanzoai/Chat/pull/7186)
- 🎨 style: Improve KaTeX Rendering for LaTeX Equations by **@andresgit** in [#7223](https://github.com/hanzoai/Chat/pull/7223)
- 📝 docs: Update `.env.example` Google models by **@marlonka** in [#7254](https://github.com/hanzoai/Chat/pull/7254)
- 💬 refactor: MCP Chat Visibility Option, Google Rates, Remove OpenAPI Plugins by **@hanzoai** in [#7286](https://github.com/hanzoai/Chat/pull/7286)
- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7214](https://github.com/hanzoai/Chat/pull/7214)
[See full release details][release-v0.7.8]
[release-v0.7.8]: https://github.com/danny-avila/LibreChat/releases/tag/v0.7.8
[release-v0.7.8]: https://github.com/hanzoai/Chat/releases/tag/v0.7.8
---
## [v0.7.8-rc1] -
@@ -96,141 +96,141 @@ Changes from v0.7.7 to v0.7.8-rc1.
### ✨ New Features
- 🔍 feat: Mistral OCR API / Upload Files as Text by **@danny-avila** in [#6274](https://github.com/danny-avila/LibreChat/pull/6274)
- 🤖 feat: Support OpenAI Web Search models by **@danny-avila** in [#6313](https://github.com/danny-avila/LibreChat/pull/6313)
- 🔗 feat: Agent Chain (Mixture-of-Agents) by **@danny-avila** in [#6374](https://github.com/danny-avila/LibreChat/pull/6374)
- ⌛ feat: `initTimeout` for Slow Starting MCP Servers by **@perweij** in [#6383](https://github.com/danny-avila/LibreChat/pull/6383)
- 🚀 feat: `S3` Integration for File handling and Image uploads by **@rubentalstra** in [#6142](https://github.com/danny-avila/LibreChat/pull/6142)
- 🔒feat: Enable OpenID Auto-Redirect by **@leondape** in [#6066](https://github.com/danny-avila/LibreChat/pull/6066)
- 🚀 feat: Integrate `Azure Blob Storage` for file handling and image uploads by **@rubentalstra** in [#6153](https://github.com/danny-avila/LibreChat/pull/6153)
- 🚀 feat: Add support for custom `AWS` endpoint in `S3` by **@rubentalstra** in [#6431](https://github.com/danny-avila/LibreChat/pull/6431)
- 🚀 feat: Add support for LDAP STARTTLS in LDAP authentication by **@rubentalstra** in [#6438](https://github.com/danny-avila/LibreChat/pull/6438)
- 🚀 feat: Refactor schema exports and update package version to 0.0.4 by **@rubentalstra** in [#6455](https://github.com/danny-avila/LibreChat/pull/6455)
- 🔼 feat: Add Auto Submit For URL Query Params by **@mjaverto** in [#6440](https://github.com/danny-avila/LibreChat/pull/6440)
- 🛠 feat: Enhance Redis Integration, Rate Limiters & Log Headers by **@danny-avila** in [#6462](https://github.com/danny-avila/LibreChat/pull/6462)
- 💵 feat: Add Automatic Balance Refill by **@rubentalstra** in [#6452](https://github.com/danny-avila/LibreChat/pull/6452)
- 🗣️ feat: add support for gpt-4o-transcribe models by **@berry-13** in [#6483](https://github.com/danny-avila/LibreChat/pull/6483)
- 🎨 feat: UI Refresh for Enhanced UX by **@berry-13** in [#6346](https://github.com/danny-avila/LibreChat/pull/6346)
- 🌍 feat: Add support for Hungarian language localization by **@rubentalstra** in [#6508](https://github.com/danny-avila/LibreChat/pull/6508)
- 🚀 feat: Add Gemini 2.5 Token/Context Values, Increase Max Possible Output to 64k by **@danny-avila** in [#6563](https://github.com/danny-avila/LibreChat/pull/6563)
- 🚀 feat: Enhance MCP Connections For Multi-User Support by **@danny-avila** in [#6610](https://github.com/danny-avila/LibreChat/pull/6610)
- 🚀 feat: Enhance S3 URL Expiry with Refresh; fix: S3 File Deletion by **@danny-avila** in [#6647](https://github.com/danny-avila/LibreChat/pull/6647)
- 🚀 feat: enhance UI components and refactor settings by **@berry-13** in [#6625](https://github.com/danny-avila/LibreChat/pull/6625)
- 💬 feat: move TemporaryChat to the Header by **@berry-13** in [#6646](https://github.com/danny-avila/LibreChat/pull/6646)
- 🚀 feat: Use Model Specs + Specific Endpoints, Limit Providers for Agents by **@danny-avila** in [#6650](https://github.com/danny-avila/LibreChat/pull/6650)
- 🪙 feat: Sync Balance Config on Login by **@danny-avila** in [#6671](https://github.com/danny-avila/LibreChat/pull/6671)
- 🔦 feat: MCP Support for Non-Agent Endpoints by **@danny-avila** in [#6775](https://github.com/danny-avila/LibreChat/pull/6775)
- 🗃️ feat: Code Interpreter File Persistence between Sessions by **@danny-avila** in [#6790](https://github.com/danny-avila/LibreChat/pull/6790)
- 🖥️ feat: Code Interpreter API for Non-Agent Endpoints by **@danny-avila** in [#6803](https://github.com/danny-avila/LibreChat/pull/6803)
- ⚡ feat: Self-hosted Artifacts Static Bundler URL by **@danny-avila** in [#6827](https://github.com/danny-avila/LibreChat/pull/6827)
- 🐳 feat: Add Jemalloc and UV to Docker Builds by **@danny-avila** in [#6836](https://github.com/danny-avila/LibreChat/pull/6836)
- 🤖 feat: GPT-4.1 by **@danny-avila** in [#6880](https://github.com/danny-avila/LibreChat/pull/6880)
- 👋 feat: remove Edge TTS by **@berry-13** in [#6885](https://github.com/danny-avila/LibreChat/pull/6885)
- feat: nav optimization by **@berry-13** in [#5785](https://github.com/danny-avila/LibreChat/pull/5785)
- 🗺️ feat: Add Parameter Location Mapping for OpenAPI actions by **@peeeteeer** in [#6858](https://github.com/danny-avila/LibreChat/pull/6858)
- 🤖 feat: Support `o4-mini` and `o3` Models by **@danny-avila** in [#6928](https://github.com/danny-avila/LibreChat/pull/6928)
- 🎨 feat: OpenAI Image Tools (GPT-Image-1) by **@danny-avila** in [#7079](https://github.com/danny-avila/LibreChat/pull/7079)
- 🗓️ feat: Add Special Variables for Prompts & Agents, Prompt UI Improvements by **@danny-avila** in [#7123](https://github.com/danny-avila/LibreChat/pull/7123)
- 🔍 feat: Mistral OCR API / Upload Files as Text by **@hanzoai** in [#6274](https://github.com/hanzoai/Chat/pull/6274)
- 🤖 feat: Support OpenAI Web Search models by **@hanzoai** in [#6313](https://github.com/hanzoai/Chat/pull/6313)
- 🔗 feat: Agent Chain (Mixture-of-Agents) by **@hanzoai** in [#6374](https://github.com/hanzoai/Chat/pull/6374)
- ⌛ feat: `initTimeout` for Slow Starting MCP Servers by **@perweij** in [#6383](https://github.com/hanzoai/Chat/pull/6383)
- 🚀 feat: `S3` Integration for File handling and Image uploads by **@rubentalstra** in [#6142](https://github.com/hanzoai/Chat/pull/6142)
- 🔒feat: Enable OpenID Auto-Redirect by **@leondape** in [#6066](https://github.com/hanzoai/Chat/pull/6066)
- 🚀 feat: Integrate `Azure Blob Storage` for file handling and image uploads by **@rubentalstra** in [#6153](https://github.com/hanzoai/Chat/pull/6153)
- 🚀 feat: Add support for custom `AWS` endpoint in `S3` by **@rubentalstra** in [#6431](https://github.com/hanzoai/Chat/pull/6431)
- 🚀 feat: Add support for LDAP STARTTLS in LDAP authentication by **@rubentalstra** in [#6438](https://github.com/hanzoai/Chat/pull/6438)
- 🚀 feat: Refactor schema exports and update package version to 0.0.4 by **@rubentalstra** in [#6455](https://github.com/hanzoai/Chat/pull/6455)
- 🔼 feat: Add Auto Submit For URL Query Params by **@mjaverto** in [#6440](https://github.com/hanzoai/Chat/pull/6440)
- 🛠 feat: Enhance Redis Integration, Rate Limiters & Log Headers by **@hanzoai** in [#6462](https://github.com/hanzoai/Chat/pull/6462)
- 💵 feat: Add Automatic Balance Refill by **@rubentalstra** in [#6452](https://github.com/hanzoai/Chat/pull/6452)
- 🗣️ feat: add support for gpt-4o-transcribe models by **@berry-13** in [#6483](https://github.com/hanzoai/Chat/pull/6483)
- 🎨 feat: UI Refresh for Enhanced UX by **@berry-13** in [#6346](https://github.com/hanzoai/Chat/pull/6346)
- 🌍 feat: Add support for Hungarian language localization by **@rubentalstra** in [#6508](https://github.com/hanzoai/Chat/pull/6508)
- 🚀 feat: Add Gemini 2.5 Token/Context Values, Increase Max Possible Output to 64k by **@hanzoai** in [#6563](https://github.com/hanzoai/Chat/pull/6563)
- 🚀 feat: Enhance MCP Connections For Multi-User Support by **@hanzoai** in [#6610](https://github.com/hanzoai/Chat/pull/6610)
- 🚀 feat: Enhance S3 URL Expiry with Refresh; fix: S3 File Deletion by **@hanzoai** in [#6647](https://github.com/hanzoai/Chat/pull/6647)
- 🚀 feat: enhance UI components and refactor settings by **@berry-13** in [#6625](https://github.com/hanzoai/Chat/pull/6625)
- 💬 feat: move TemporaryChat to the Header by **@berry-13** in [#6646](https://github.com/hanzoai/Chat/pull/6646)
- 🚀 feat: Use Model Specs + Specific Endpoints, Limit Providers for Agents by **@hanzoai** in [#6650](https://github.com/hanzoai/Chat/pull/6650)
- 🪙 feat: Sync Balance Config on Login by **@hanzoai** in [#6671](https://github.com/hanzoai/Chat/pull/6671)
- 🔦 feat: MCP Support for Non-Agent Endpoints by **@hanzoai** in [#6775](https://github.com/hanzoai/Chat/pull/6775)
- 🗃️ feat: Code Interpreter File Persistence between Sessions by **@hanzoai** in [#6790](https://github.com/hanzoai/Chat/pull/6790)
- 🖥️ feat: Code Interpreter API for Non-Agent Endpoints by **@hanzoai** in [#6803](https://github.com/hanzoai/Chat/pull/6803)
- ⚡ feat: Self-hosted Artifacts Static Bundler URL by **@hanzoai** in [#6827](https://github.com/hanzoai/Chat/pull/6827)
- 🐳 feat: Add Jemalloc and UV to Docker Builds by **@hanzoai** in [#6836](https://github.com/hanzoai/Chat/pull/6836)
- 🤖 feat: GPT-4.1 by **@hanzoai** in [#6880](https://github.com/hanzoai/Chat/pull/6880)
- 👋 feat: remove Edge TTS by **@berry-13** in [#6885](https://github.com/hanzoai/Chat/pull/6885)
- feat: nav optimization by **@berry-13** in [#5785](https://github.com/hanzoai/Chat/pull/5785)
- 🗺️ feat: Add Parameter Location Mapping for OpenAPI actions by **@peeeteeer** in [#6858](https://github.com/hanzoai/Chat/pull/6858)
- 🤖 feat: Support `o4-mini` and `o3` Models by **@hanzoai** in [#6928](https://github.com/hanzoai/Chat/pull/6928)
- 🎨 feat: OpenAI Image Tools (GPT-Image-1) by **@hanzoai** in [#7079](https://github.com/hanzoai/Chat/pull/7079)
- 🗓️ feat: Add Special Variables for Prompts & Agents, Prompt UI Improvements by **@hanzoai** in [#7123](https://github.com/hanzoai/Chat/pull/7123)
### 🌍 Internationalization
- 🌍 i18n: Add Thai Language Support and Update Translations by **@rubentalstra** in [#6219](https://github.com/danny-avila/LibreChat/pull/6219)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6220](https://github.com/danny-avila/LibreChat/pull/6220)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6240](https://github.com/danny-avila/LibreChat/pull/6240)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6241](https://github.com/danny-avila/LibreChat/pull/6241)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6277](https://github.com/danny-avila/LibreChat/pull/6277)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6414](https://github.com/danny-avila/LibreChat/pull/6414)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6505](https://github.com/danny-avila/LibreChat/pull/6505)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6530](https://github.com/danny-avila/LibreChat/pull/6530)
- 🌍 i18n: Add Persian Localization Support by **@rubentalstra** in [#6669](https://github.com/danny-avila/LibreChat/pull/6669)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6667](https://github.com/danny-avila/LibreChat/pull/6667)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7126](https://github.com/danny-avila/LibreChat/pull/7126)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7148](https://github.com/danny-avila/LibreChat/pull/7148)
- 🌍 i18n: Add Thai Language Support and Update Translations by **@rubentalstra** in [#6219](https://github.com/hanzoai/Chat/pull/6219)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6220](https://github.com/hanzoai/Chat/pull/6220)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6240](https://github.com/hanzoai/Chat/pull/6240)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6241](https://github.com/hanzoai/Chat/pull/6241)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6277](https://github.com/hanzoai/Chat/pull/6277)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6414](https://github.com/hanzoai/Chat/pull/6414)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6505](https://github.com/hanzoai/Chat/pull/6505)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6530](https://github.com/hanzoai/Chat/pull/6530)
- 🌍 i18n: Add Persian Localization Support by **@rubentalstra** in [#6669](https://github.com/hanzoai/Chat/pull/6669)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6667](https://github.com/hanzoai/Chat/pull/6667)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7126](https://github.com/hanzoai/Chat/pull/7126)
- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7148](https://github.com/hanzoai/Chat/pull/7148)
### 👐 Accessibility
- 🎨 a11y: Update Model Spec Description Text by **@berry-13** in [#6294](https://github.com/danny-avila/LibreChat/pull/6294)
- 🗑️ a11y: Add Accessible Name to Button for File Attachment Removal by **@kangabell** in [#6709](https://github.com/danny-avila/LibreChat/pull/6709)
- ⌨️ a11y: enhance accessibility & visual consistency by **@berry-13** in [#6866](https://github.com/danny-avila/LibreChat/pull/6866)
- 🙌 a11y: Searchbar/Conversations List Focus by **@danny-avila** in [#7096](https://github.com/danny-avila/LibreChat/pull/7096)
- 👐 a11y: Improve Fork and SplitText Accessibility by **@danny-avila** in [#7147](https://github.com/danny-avila/LibreChat/pull/7147)
- 🎨 a11y: Update Model Spec Description Text by **@berry-13** in [#6294](https://github.com/hanzoai/Chat/pull/6294)
- 🗑️ a11y: Add Accessible Name to Button for File Attachment Removal by **@kangabell** in [#6709](https://github.com/hanzoai/Chat/pull/6709)
- ⌨️ a11y: enhance accessibility & visual consistency by **@berry-13** in [#6866](https://github.com/hanzoai/Chat/pull/6866)
- 🙌 a11y: Searchbar/Conversations List Focus by **@hanzoai** in [#7096](https://github.com/hanzoai/Chat/pull/7096)
- 👐 a11y: Improve Fork and SplitText Accessibility by **@hanzoai** in [#7147](https://github.com/hanzoai/Chat/pull/7147)
### 🔧 Fixes
- 🐛 fix: Avatar Type Definitions in Agent/Assistant Schemas by **@danny-avila** in [#6235](https://github.com/danny-avila/LibreChat/pull/6235)
- 🔧 fix: MeiliSearch Field Error and Patch Incorrect Import by #6210 by **@rubentalstra** in [#6245](https://github.com/danny-avila/LibreChat/pull/6245)
- 🔏 fix: Enhance Two-Factor Authentication by **@rubentalstra** in [#6247](https://github.com/danny-avila/LibreChat/pull/6247)
- 🐛 fix: Await saveMessage in abortMiddleware to ensure proper execution by **@sh4shii** in [#6248](https://github.com/danny-avila/LibreChat/pull/6248)
- 🔧 fix: Axios Proxy Usage And Bump `mongoose` by **@danny-avila** in [#6298](https://github.com/danny-avila/LibreChat/pull/6298)
- 🔧 fix: comment out MCP servers to resolve service run issues by **@KunalScriptz** in [#6316](https://github.com/danny-avila/LibreChat/pull/6316)
- 🔧 fix: Update Token Calculations and Mapping, MCP `env` Initialization by **@danny-avila** in [#6406](https://github.com/danny-avila/LibreChat/pull/6406)
- 🐞 fix: Agent "Resend" Message Attachments + Source Icon Styling by **@danny-avila** in [#6408](https://github.com/danny-avila/LibreChat/pull/6408)
- 🐛 fix: Prevent Crash on Duplicate Message ID by **@Odrec** in [#6392](https://github.com/danny-avila/LibreChat/pull/6392)
- 🔐 fix: Invalid Key Length in 2FA Encryption by **@rubentalstra** in [#6432](https://github.com/danny-avila/LibreChat/pull/6432)
- 🏗️ fix: Fix Agents Token Spend Race Conditions, Expand Test Coverage by **@danny-avila** in [#6480](https://github.com/danny-avila/LibreChat/pull/6480)
- 🔃 fix: Draft Clearing, Claude Titles, Remove Default Vision Max Tokens by **@danny-avila** in [#6501](https://github.com/danny-avila/LibreChat/pull/6501)
- 🔧 fix: Update username reference to use user.name in greeting display by **@rubentalstra** in [#6534](https://github.com/danny-avila/LibreChat/pull/6534)
- 🔧 fix: S3 Download Stream with Key Extraction and Blob Storage Encoding for Vision by **@danny-avila** in [#6557](https://github.com/danny-avila/LibreChat/pull/6557)
- 🔧 fix: Mistral type strictness for `usage` & update token values/windows by **@danny-avila** in [#6562](https://github.com/danny-avila/LibreChat/pull/6562)
- 🔧 fix: Consolidate Text Parsing and TTS Edge Initialization by **@danny-avila** in [#6582](https://github.com/danny-avila/LibreChat/pull/6582)
- 🔧 fix: Ensure continuation in image processing on base64 encoding from Blob Storage by **@danny-avila** in [#6619](https://github.com/danny-avila/LibreChat/pull/6619)
- ✉️ fix: Fallback For User Name In Email Templates by **@danny-avila** in [#6620](https://github.com/danny-avila/LibreChat/pull/6620)
- 🔧 fix: Azure Blob Integration and File Source References by **@rubentalstra** in [#6575](https://github.com/danny-avila/LibreChat/pull/6575)
- 🐛 fix: Safeguard against undefined addedEndpoints by **@wipash** in [#6654](https://github.com/danny-avila/LibreChat/pull/6654)
- 🤖 fix: Gemini 2.5 Vision Support by **@danny-avila** in [#6663](https://github.com/danny-avila/LibreChat/pull/6663)
- 🔄 fix: Avatar & Error Handling Enhancements by **@danny-avila** in [#6687](https://github.com/danny-avila/LibreChat/pull/6687)
- 🔧 fix: Chat Middleware, Zod Conversion, Auto-Save and S3 URL Refresh by **@danny-avila** in [#6720](https://github.com/danny-avila/LibreChat/pull/6720)
- 🔧 fix: Agent Capability Checks & DocumentDB Compatibility for Agent Resource Removal by **@danny-avila** in [#6726](https://github.com/danny-avila/LibreChat/pull/6726)
- 🔄 fix: Improve audio MIME type detection and handling by **@berry-13** in [#6707](https://github.com/danny-avila/LibreChat/pull/6707)
- 🪺 fix: Update Role Handling due to New Schema Shape by **@danny-avila** in [#6774](https://github.com/danny-avila/LibreChat/pull/6774)
- 🗨️ fix: Show ModelSpec Greeting by **@berry-13** in [#6770](https://github.com/danny-avila/LibreChat/pull/6770)
- 🔧 fix: Keyv and Proxy Issues, and More Memory Optimizations by **@danny-avila** in [#6867](https://github.com/danny-avila/LibreChat/pull/6867)
- ✨ fix: Implement dynamic text sizing for greeting and name display by **@berry-13** in [#6833](https://github.com/danny-avila/LibreChat/pull/6833)
- 📝 fix: Mistral OCR Image Support and Azure Agent Titles by **@danny-avila** in [#6901](https://github.com/danny-avila/LibreChat/pull/6901)
- 📢 fix: Invalid `engineTTS` and Conversation State on Navigation by **@berry-13** in [#6904](https://github.com/danny-avila/LibreChat/pull/6904)
- 🛠️ fix: Improve Accessibility and Display of Conversation Menu by **@danny-avila** in [#6913](https://github.com/danny-avila/LibreChat/pull/6913)
- 🔧 fix: Agent Resource Form, Convo Menu Style, Ensure Draft Clears on Submission by **@danny-avila** in [#6925](https://github.com/danny-avila/LibreChat/pull/6925)
- 🔀 fix: MCP Improvements, Auto-Save Drafts, Artifact Markup by **@danny-avila** in [#7040](https://github.com/danny-avila/LibreChat/pull/7040)
- 🐋 fix: Improve Deepseek Compatbility by **@danny-avila** in [#7132](https://github.com/danny-avila/LibreChat/pull/7132)
- 🐙 fix: Add Redis Ping Interval to Prevent Connection Drops by **@peeeteeer** in [#7127](https://github.com/danny-avila/LibreChat/pull/7127)
- 🐛 fix: Avatar Type Definitions in Agent/Assistant Schemas by **@hanzoai** in [#6235](https://github.com/hanzoai/Chat/pull/6235)
- 🔧 fix: MeiliSearch Field Error and Patch Incorrect Import by #6210 by **@rubentalstra** in [#6245](https://github.com/hanzoai/Chat/pull/6245)
- 🔏 fix: Enhance Two-Factor Authentication by **@rubentalstra** in [#6247](https://github.com/hanzoai/Chat/pull/6247)
- 🐛 fix: Await saveMessage in abortMiddleware to ensure proper execution by **@sh4shii** in [#6248](https://github.com/hanzoai/Chat/pull/6248)
- 🔧 fix: Axios Proxy Usage And Bump `mongoose` by **@hanzoai** in [#6298](https://github.com/hanzoai/Chat/pull/6298)
- 🔧 fix: comment out MCP servers to resolve service run issues by **@KunalScriptz** in [#6316](https://github.com/hanzoai/Chat/pull/6316)
- 🔧 fix: Update Token Calculations and Mapping, MCP `env` Initialization by **@hanzoai** in [#6406](https://github.com/hanzoai/Chat/pull/6406)
- 🐞 fix: Agent "Resend" Message Attachments + Source Icon Styling by **@hanzoai** in [#6408](https://github.com/hanzoai/Chat/pull/6408)
- 🐛 fix: Prevent Crash on Duplicate Message ID by **@Odrec** in [#6392](https://github.com/hanzoai/Chat/pull/6392)
- 🔐 fix: Invalid Key Length in 2FA Encryption by **@rubentalstra** in [#6432](https://github.com/hanzoai/Chat/pull/6432)
- 🏗️ fix: Fix Agents Token Spend Race Conditions, Expand Test Coverage by **@hanzoai** in [#6480](https://github.com/hanzoai/Chat/pull/6480)
- 🔃 fix: Draft Clearing, Claude Titles, Remove Default Vision Max Tokens by **@hanzoai** in [#6501](https://github.com/hanzoai/Chat/pull/6501)
- 🔧 fix: Update username reference to use user.name in greeting display by **@rubentalstra** in [#6534](https://github.com/hanzoai/Chat/pull/6534)
- 🔧 fix: S3 Download Stream with Key Extraction and Blob Storage Encoding for Vision by **@hanzoai** in [#6557](https://github.com/hanzoai/Chat/pull/6557)
- 🔧 fix: Mistral type strictness for `usage` & update token values/windows by **@hanzoai** in [#6562](https://github.com/hanzoai/Chat/pull/6562)
- 🔧 fix: Consolidate Text Parsing and TTS Edge Initialization by **@hanzoai** in [#6582](https://github.com/hanzoai/Chat/pull/6582)
- 🔧 fix: Ensure continuation in image processing on base64 encoding from Blob Storage by **@hanzoai** in [#6619](https://github.com/hanzoai/Chat/pull/6619)
- ✉️ fix: Fallback For User Name In Email Templates by **@hanzoai** in [#6620](https://github.com/hanzoai/Chat/pull/6620)
- 🔧 fix: Azure Blob Integration and File Source References by **@rubentalstra** in [#6575](https://github.com/hanzoai/Chat/pull/6575)
- 🐛 fix: Safeguard against undefined addedEndpoints by **@wipash** in [#6654](https://github.com/hanzoai/Chat/pull/6654)
- 🤖 fix: Gemini 2.5 Vision Support by **@hanzoai** in [#6663](https://github.com/hanzoai/Chat/pull/6663)
- 🔄 fix: Avatar & Error Handling Enhancements by **@hanzoai** in [#6687](https://github.com/hanzoai/Chat/pull/6687)
- 🔧 fix: Chat Middleware, Zod Conversion, Auto-Save and S3 URL Refresh by **@hanzoai** in [#6720](https://github.com/hanzoai/Chat/pull/6720)
- 🔧 fix: Agent Capability Checks & DocumentDB Compatibility for Agent Resource Removal by **@hanzoai** in [#6726](https://github.com/hanzoai/Chat/pull/6726)
- 🔄 fix: Improve audio MIME type detection and handling by **@berry-13** in [#6707](https://github.com/hanzoai/Chat/pull/6707)
- 🪺 fix: Update Role Handling due to New Schema Shape by **@hanzoai** in [#6774](https://github.com/hanzoai/Chat/pull/6774)
- 🗨️ fix: Show ModelSpec Greeting by **@berry-13** in [#6770](https://github.com/hanzoai/Chat/pull/6770)
- 🔧 fix: Keyv and Proxy Issues, and More Memory Optimizations by **@hanzoai** in [#6867](https://github.com/hanzoai/Chat/pull/6867)
- ✨ fix: Implement dynamic text sizing for greeting and name display by **@berry-13** in [#6833](https://github.com/hanzoai/Chat/pull/6833)
- 📝 fix: Mistral OCR Image Support and Azure Agent Titles by **@hanzoai** in [#6901](https://github.com/hanzoai/Chat/pull/6901)
- 📢 fix: Invalid `engineTTS` and Conversation State on Navigation by **@berry-13** in [#6904](https://github.com/hanzoai/Chat/pull/6904)
- 🛠️ fix: Improve Accessibility and Display of Conversation Menu by **@hanzoai** in [#6913](https://github.com/hanzoai/Chat/pull/6913)
- 🔧 fix: Agent Resource Form, Convo Menu Style, Ensure Draft Clears on Submission by **@hanzoai** in [#6925](https://github.com/hanzoai/Chat/pull/6925)
- 🔀 fix: MCP Improvements, Auto-Save Drafts, Artifact Markup by **@hanzoai** in [#7040](https://github.com/hanzoai/Chat/pull/7040)
- 🐋 fix: Improve Deepseek Compatbility by **@hanzoai** in [#7132](https://github.com/hanzoai/Chat/pull/7132)
- 🐙 fix: Add Redis Ping Interval to Prevent Connection Drops by **@peeeteeer** in [#7127](https://github.com/hanzoai/Chat/pull/7127)
### ⚙️ Other Changes
- 📦 refactor: Move DB Models to `@librechat/data-schemas` by **@rubentalstra** in [#6210](https://github.com/danny-avila/LibreChat/pull/6210)
- 📦 chore: Patch `axios` to address CVE-2025-27152 by **@danny-avila** in [#6222](https://github.com/danny-avila/LibreChat/pull/6222)
- ⚠️ refactor: Use Error Content Part Instead Of Throwing Error for Agents by **@danny-avila** in [#6262](https://github.com/danny-avila/LibreChat/pull/6262)
- 🏃‍♂️ refactor: Improve Agent Run Context & Misc. Changes by **@danny-avila** in [#6448](https://github.com/danny-avila/LibreChat/pull/6448)
- 📝 docs: librechat.example.yaml by **@ineiti** in [#6442](https://github.com/danny-avila/LibreChat/pull/6442)
- 🏃‍♂️ refactor: More Agent Context Improvements during Run by **@danny-avila** in [#6477](https://github.com/danny-avila/LibreChat/pull/6477)
- 🔃 refactor: Allow streaming for `o1` models by **@danny-avila** in [#6509](https://github.com/danny-avila/LibreChat/pull/6509)
- 🔧 chore: `Vite` Plugin Upgrades & Config Optimizations by **@rubentalstra** in [#6547](https://github.com/danny-avila/LibreChat/pull/6547)
- 🔧 refactor: Consolidate Logging, Model Selection & Actions Optimizations, Minor Fixes by **@danny-avila** in [#6553](https://github.com/danny-avila/LibreChat/pull/6553)
- 🎨 style: Address Minor UI Refresh Issues by **@berry-13** in [#6552](https://github.com/danny-avila/LibreChat/pull/6552)
- 🔧 refactor: Enhance Model & Endpoint Configurations with Global Indicators 🌍 by **@berry-13** in [#6578](https://github.com/danny-avila/LibreChat/pull/6578)
- 💬 style: Chat UI, Greeting, and Message adjustments by **@berry-13** in [#6612](https://github.com/danny-avila/LibreChat/pull/6612)
- ⚡ refactor: DocumentDB Compatibility for Balance Updates by **@danny-avila** in [#6673](https://github.com/danny-avila/LibreChat/pull/6673)
- 🧹 chore: Update ESLint rules for React hooks by **@rubentalstra** in [#6685](https://github.com/danny-avila/LibreChat/pull/6685)
- 🪙 chore: Update Gemini Pricing by **@RedwindA** in [#6731](https://github.com/danny-avila/LibreChat/pull/6731)
- 🪺 refactor: Nest Permission fields for Roles by **@rubentalstra** in [#6487](https://github.com/danny-avila/LibreChat/pull/6487)
- 📦 chore: Update `caniuse-lite` dependency to version 1.0.30001706 by **@rubentalstra** in [#6482](https://github.com/danny-avila/LibreChat/pull/6482)
- ⚙️ refactor: OAuth Flow Signal, Type Safety, Tool Progress & Updated Packages by **@danny-avila** in [#6752](https://github.com/danny-avila/LibreChat/pull/6752)
- 📦 chore: bump vite from 6.2.3 to 6.2.5 by **@dependabot[bot]** in [#6745](https://github.com/danny-avila/LibreChat/pull/6745)
- 💾 chore: Enhance Local Storage Handling and Update MCP SDK by **@danny-avila** in [#6809](https://github.com/danny-avila/LibreChat/pull/6809)
- 🤖 refactor: Improve Agents Memory Usage, Bump Keyv, Grok 3 by **@danny-avila** in [#6850](https://github.com/danny-avila/LibreChat/pull/6850)
- 💾 refactor: Enhance Memory In Image Encodings & Client Disposal by **@danny-avila** in [#6852](https://github.com/danny-avila/LibreChat/pull/6852)
- 🔁 refactor: Token Event Handler and Standardize `maxTokens` Key by **@danny-avila** in [#6886](https://github.com/danny-avila/LibreChat/pull/6886)
- 🔍 refactor: Search & Message Retrieval by **@berry-13** in [#6903](https://github.com/danny-avila/LibreChat/pull/6903)
- 🎨 style: standardize dropdown styling & fix z-Index layering by **@berry-13** in [#6939](https://github.com/danny-avila/LibreChat/pull/6939)
- 📙 docs: CONTRIBUTING.md by **@dblock** in [#6831](https://github.com/danny-avila/LibreChat/pull/6831)
- 🧭 refactor: Modernize Nav/Header by **@danny-avila** in [#7094](https://github.com/danny-avila/LibreChat/pull/7094)
- 🪶 refactor: Chat Input Focus for Conversation Navigations & ChatForm Optimizations by **@danny-avila** in [#7100](https://github.com/danny-avila/LibreChat/pull/7100)
- 🔃 refactor: Streamline Navigation, Message Loading UX by **@danny-avila** in [#7118](https://github.com/danny-avila/LibreChat/pull/7118)
- 📜 docs: Unreleased changelog by **@github-actions[bot]** in [#6265](https://github.com/danny-avila/LibreChat/pull/6265)
- 📦 refactor: Move DB Models to `@chat/data-schemas` by **@rubentalstra** in [#6210](https://github.com/hanzoai/Chat/pull/6210)
- 📦 chore: Patch `axios` to address CVE-2025-27152 by **@hanzoai** in [#6222](https://github.com/hanzoai/Chat/pull/6222)
- ⚠️ refactor: Use Error Content Part Instead Of Throwing Error for Agents by **@hanzoai** in [#6262](https://github.com/hanzoai/Chat/pull/6262)
- 🏃‍♂️ refactor: Improve Agent Run Context & Misc. Changes by **@hanzoai** in [#6448](https://github.com/hanzoai/Chat/pull/6448)
- 📝 docs: chat.example.yaml by **@ineiti** in [#6442](https://github.com/hanzoai/Chat/pull/6442)
- 🏃‍♂️ refactor: More Agent Context Improvements during Run by **@hanzoai** in [#6477](https://github.com/hanzoai/Chat/pull/6477)
- 🔃 refactor: Allow streaming for `o1` models by **@hanzoai** in [#6509](https://github.com/hanzoai/Chat/pull/6509)
- 🔧 chore: `Vite` Plugin Upgrades & Config Optimizations by **@rubentalstra** in [#6547](https://github.com/hanzoai/Chat/pull/6547)
- 🔧 refactor: Consolidate Logging, Model Selection & Actions Optimizations, Minor Fixes by **@hanzoai** in [#6553](https://github.com/hanzoai/Chat/pull/6553)
- 🎨 style: Address Minor UI Refresh Issues by **@berry-13** in [#6552](https://github.com/hanzoai/Chat/pull/6552)
- 🔧 refactor: Enhance Model & Endpoint Configurations with Global Indicators 🌍 by **@berry-13** in [#6578](https://github.com/hanzoai/Chat/pull/6578)
- 💬 style: Chat UI, Greeting, and Message adjustments by **@berry-13** in [#6612](https://github.com/hanzoai/Chat/pull/6612)
- ⚡ refactor: DocumentDB Compatibility for Balance Updates by **@hanzoai** in [#6673](https://github.com/hanzoai/Chat/pull/6673)
- 🧹 chore: Update ESLint rules for React hooks by **@rubentalstra** in [#6685](https://github.com/hanzoai/Chat/pull/6685)
- 🪙 chore: Update Gemini Pricing by **@RedwindA** in [#6731](https://github.com/hanzoai/Chat/pull/6731)
- 🪺 refactor: Nest Permission fields for Roles by **@rubentalstra** in [#6487](https://github.com/hanzoai/Chat/pull/6487)
- 📦 chore: Update `caniuse-lite` dependency to version 1.0.30001706 by **@rubentalstra** in [#6482](https://github.com/hanzoai/Chat/pull/6482)
- ⚙️ refactor: OAuth Flow Signal, Type Safety, Tool Progress & Updated Packages by **@hanzoai** in [#6752](https://github.com/hanzoai/Chat/pull/6752)
- 📦 chore: bump vite from 6.2.3 to 6.2.5 by **@dependabot[bot]** in [#6745](https://github.com/hanzoai/Chat/pull/6745)
- 💾 chore: Enhance Local Storage Handling and Update MCP SDK by **@hanzoai** in [#6809](https://github.com/hanzoai/Chat/pull/6809)
- 🤖 refactor: Improve Agents Memory Usage, Bump Keyv, Grok 3 by **@hanzoai** in [#6850](https://github.com/hanzoai/Chat/pull/6850)
- 💾 refactor: Enhance Memory In Image Encodings & Client Disposal by **@hanzoai** in [#6852](https://github.com/hanzoai/Chat/pull/6852)
- 🔁 refactor: Token Event Handler and Standardize `maxTokens` Key by **@hanzoai** in [#6886](https://github.com/hanzoai/Chat/pull/6886)
- 🔍 refactor: Search & Message Retrieval by **@berry-13** in [#6903](https://github.com/hanzoai/Chat/pull/6903)
- 🎨 style: standardize dropdown styling & fix z-Index layering by **@berry-13** in [#6939](https://github.com/hanzoai/Chat/pull/6939)
- 📙 docs: CONTRIBUTING.md by **@dblock** in [#6831](https://github.com/hanzoai/Chat/pull/6831)
- 🧭 refactor: Modernize Nav/Header by **@hanzoai** in [#7094](https://github.com/hanzoai/Chat/pull/7094)
- 🪶 refactor: Chat Input Focus for Conversation Navigations & ChatForm Optimizations by **@hanzoai** in [#7100](https://github.com/hanzoai/Chat/pull/7100)
- 🔃 refactor: Streamline Navigation, Message Loading UX by **@hanzoai** in [#7118](https://github.com/hanzoai/Chat/pull/7118)
- 📜 docs: Unreleased changelog by **@github-actions[bot]** in [#6265](https://github.com/hanzoai/Chat/pull/6265)
[See full release details][release-v0.7.8-rc1]
[release-v0.7.8-rc1]: https://github.com/danny-avila/LibreChat/releases/tag/v0.7.8-rc1
[release-v0.7.8-rc1]: https://github.com/hanzoai/Chat/releases/tag/v0.7.8-rc1
---
-1
View File
@@ -1 +0,0 @@
LLM.md
-275
View File
@@ -1,275 +0,0 @@
# Contributing to LiteLLM
Thank you for your interest in contributing to LiteLLM! We welcome contributions of all kinds - from bug fixes and documentation improvements to new features and integrations.
## **Checklist before submitting a PR**
Here are the core requirements for any PR submitted to LiteLLM:
- [ ] **Sign the Contributor License Agreement (CLA)** - [see details](#contributor-license-agreement-cla)
- [ ] **Add testing** - Adding at least 1 test is a hard requirement - [see details](#adding-testing)
- [ ] **Ensure your PR passes all checks**:
- [ ] [Unit Tests](#running-unit-tests) - `make test-unit`
- [ ] [Linting / Formatting](#running-linting-and-formatting-checks) - `make lint`
- [ ] **Keep scope isolated** - Your changes should address 1 specific problem at a time
## **Contributor License Agreement (CLA)**
Before contributing code to LiteLLM, you must sign our [Contributor License Agreement (CLA)](https://cla-assistant.io/BerriAI/litellm). This is a legal requirement for all contributions to be merged into the main repository.
**Important:** We strongly recommend reviewing and signing the CLA before starting work on your contribution to avoid any delays in the PR process.
## Quick Start
### 1. Setup Your Local Development Environment
```bash
# Clone the repository
git clone https://github.com/BerriAI/litellm.git
cd litellm
# Create a new branch for your feature
git checkout -b your-feature-branch
# Install development dependencies
make install-dev
# Verify your setup works
make help
```
That's it! Your local development environment is ready.
### 2. Development Workflow
Here's the recommended workflow for making changes:
```bash
# Make your changes to the code
# ...
# Format your code (auto-fixes formatting issues)
make format
# Run all linting checks (matches CI exactly)
make lint
# Run unit tests to ensure nothing is broken
make test-unit
# Commit your changes
git add .
git commit -m "Your descriptive commit message"
# Push and create a PR
git push origin your-feature-branch
```
## Adding Testing
**Adding at least 1 test is a hard requirement for all PRs.**
### Where to Add Tests
Add your tests to the [`tests/test_litellm/` directory](https://github.com/BerriAI/litellm/tree/main/tests/test_litellm).
- This directory mirrors the structure of the `litellm/` directory
- **Only add mocked tests** - no real LLM API calls in this directory
- For integration tests with real APIs, use the appropriate test directories
### File Naming Convention
The `tests/test_litellm/` directory follows the same structure as `litellm/`:
- `litellm/proxy/caching_routes.py``tests/test_litellm/proxy/test_caching_routes.py`
- `litellm/utils.py``tests/test_litellm/test_utils.py`
### Example Test
```python
import pytest
from litellm import completion
def test_your_feature():
"""Test your feature with a descriptive docstring."""
# Arrange
messages = [{"role": "user", "content": "Hello"}]
# Act
# Use mocked responses, not real API calls
# Assert
assert expected_result == actual_result
```
## Running Tests and Checks
### Running Unit Tests
Run all unit tests (uses parallel execution for speed):
```bash
make test-unit
```
Run specific test files:
```bash
poetry run pytest tests/test_litellm/test_your_file.py -v
```
### Running Linting and Formatting Checks
Run all linting checks (matches CI exactly):
```bash
make lint
```
Individual linting commands:
```bash
make format-check # Check Black formatting
make lint-ruff # Run Ruff linting
make lint-mypy # Run MyPy type checking
make check-circular-imports # Check for circular imports
make check-import-safety # Check import safety
```
Apply formatting (auto-fixes issues):
```bash
make format
```
### CI Compatibility
To ensure your changes will pass CI, run the exact same checks locally:
```bash
# This runs the same checks as the GitHub workflows
make lint
make test-unit
```
For exact CI compatibility (pins OpenAI version like CI):
```bash
make install-dev-ci # Installs exact CI dependencies
```
## Available Make Commands
Run `make help` to see all available commands:
```bash
make help # Show all available commands
make install-dev # Install development dependencies
make install-proxy-dev # Install proxy development dependencies
make install-test-deps # Install test dependencies (for running tests)
make format # Apply Black code formatting
make format-check # Check Black formatting (matches CI)
make lint # Run all linting checks
make test-unit # Run unit tests
make test-integration # Run integration tests
make test-unit-helm # Run Helm unit tests
```
## Code Quality Standards
LiteLLM follows the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html).
Our automated quality checks include:
- **Black** for consistent code formatting
- **Ruff** for linting and code quality
- **MyPy** for static type checking
- **Circular import detection**
- **Import safety validation**
All checks must pass before your PR can be merged.
## Common Issues and Solutions
### 1. Linting Failures
If `make lint` fails:
1. **Formatting issues**: Run `make format` to auto-fix
2. **Ruff issues**: Check the output and fix manually
3. **MyPy issues**: Add proper type hints
4. **Circular imports**: Refactor import dependencies
5. **Import safety**: Fix any unprotected imports
### 2. Test Failures
If `make test-unit` fails:
1. Check if you broke existing functionality
2. Add tests for your new code
3. Ensure tests use mocks, not real API calls
4. Check test file naming conventions
### 3. Common Development Tips
- **Use type hints**: MyPy requires proper type annotations
- **Write descriptive commit messages**: Help reviewers understand your changes
- **Keep PRs focused**: One feature/fix per PR
- **Test edge cases**: Don't just test the happy path
- **Update documentation**: If you change APIs, update docs
## Building and Running Locally
### LiteLLM Proxy Server
To run the proxy server locally:
```bash
# Install proxy dependencies
make install-proxy-dev
# Start the proxy server
poetry run litellm --config your_config.yaml
```
### Docker Development
If you want to build the Docker image yourself:
```bash
# Build using the non-root Dockerfile
docker build -f docker/Dockerfile.non_root -t litellm_dev .
# Run with your config
docker run \
-v $(pwd)/proxy_config.yaml:/app/config.yaml \
-e LITELLM_MASTER_KEY="sk-1234" \
-p 4000:4000 \
litellm_dev \
--config /app/config.yaml --detailed_debug
```
## Submitting Your PR
1. **Push your branch**: `git push origin your-feature-branch`
2. **Create a PR**: Go to GitHub and create a pull request
3. **Fill out the PR template**: Provide clear description of changes
4. **Wait for review**: Maintainers will review and provide feedback
5. **Address feedback**: Make requested changes and push updates
6. **Merge**: Once approved, your PR will be merged!
## Getting Help
If you need help:
- 💬 [Join our Discord](https://discord.gg/wuPM9dRgDw)
- 💬 [Join our Slack](https://join.slack.com/share/enQtOTE0ODczMzk2Nzk4NC01YjUxNjY2YjBlYTFmNDRiZTM3NDFiYTM3MzVkODFiMDVjOGRjMmNmZTZkZTMzOWQzZGQyZWIwYjQ0MWExYmE3)
- 📧 Email us: ishaan@berri.ai / krrish@berri.ai
- 🐛 [Create an issue](https://github.com/BerriAI/litellm/issues/new)
## What to Contribute
Looking for ideas? Check out:
- 🐛 [Good first issues](https://github.com/BerriAI/litellm/labels/good%20first%20issue)
- 🚀 [Feature requests](https://github.com/BerriAI/litellm/labels/enhancement)
- 📚 Documentation improvements
- 🧪 Test coverage improvements
- 🔌 New LLM provider integrations
Thank you for contributing to LiteLLM! 🚀
-86
View File
@@ -1,86 +0,0 @@
# Hanzo Chat Demo Setup Guide
## Quick Start
Since the chat application starts with no users, you'll need to register your first account.
### Option 1: Register via Web UI (Recommended)
1. Navigate to http://localhost:3081
2. Click "Sign up" or "Register" link
3. Create an account with:
- **Admin Demo**:
- Email: `admin@hanzo.ai`
- Password: `demo1234`
- **Regular Demo User**:
- Email: `demo@hanzo.ai`
- Password: `demo1234`
### Option 2: Create Users via MongoDB
If you need to create demo users programmatically:
```bash
# Access MongoDB shell
docker exec -it hanzo-mongodb mongosh mongodb://hanzo:hanzo123@localhost:27017/HanzoChat?authSource=admin
# Create demo admin user
db.users.insertOne({
email: "admin@hanzo.ai",
username: "admin",
name: "Hanzo Admin",
password: "$2a$10$hashed_password_here", // Use bcrypt to hash "demo1234"
role: "ADMIN",
isVerified: true,
emailVerified: true,
createdAt: new Date(),
updatedAt: new Date(),
refreshToken: [],
plugins: []
});
```
### Option 3: Environment Configuration
To show demo credentials on the login page when running locally, add to your `.env`:
```bash
# Show demo credentials on login page (development only)
SHOW_DEMO_CREDENTIALS=true
DEMO_EMAIL=admin@hanzo.ai
DEMO_PASSWORD=demo1234
```
## Features Available After Login
Once logged in, you'll have access to:
- **MCP Tools**: File operations, search, code analysis
- **Agent Features**: Multi-agent workflows via Hanzo Agent SDK
- **LLM Gateway**: Access to 100+ AI providers through unified interface
- **Custom Branding**: Hanzo AI themed interface
## Troubleshooting
### Registration Not Working?
- Ensure `ALLOW_REGISTRATION=true` is set in environment
- Check MongoDB is running: `docker ps | grep mongodb`
- Check logs: `docker logs hanzo-chat`
### Login Issues?
- Clear browser cookies for localhost:3081
- Verify user exists in database using MongoDB commands above
- Check JWT secrets are properly set in environment
### MCP Tools Not Showing?
- Verify `MCP_ENABLED=true` in container environment
- Check MCP servers configuration at `/app/mcp_servers.hanzo.json`
- Restart the chat service: `make restart`
## Security Note
These demo credentials are for local development only. In production:
- Use strong, unique passwords
- Disable demo credential display
- Enable proper authentication (OAuth, LDAP, etc.)
- Use environment-specific secrets
+73 -45
View File
@@ -1,55 +1,83 @@
# v0.8.3-rc1
# Build stage
FROM node:20-alpine AS builder
# Base node image
FROM node:20-alpine AS node
# Install jemalloc
RUN apk add --no-cache jemalloc
RUN apk add --no-cache python3 py3-pip uv
# Set environment variable to use jemalloc
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
# Enable pnpm via corepack
RUN corepack enable && corepack prepare pnpm@latest --activate
# Add `uv` for extended MCP support
COPY --from=ghcr.io/astral-sh/uv:0.9.5-python3.12-alpine /usr/local/bin/uv /usr/local/bin/uvx /bin/
RUN uv --version
# Set configurable max-old-space-size with default
ARG NODE_MAX_OLD_SPACE_SIZE=6144
RUN mkdir -p /app && chown node:node /app
WORKDIR /app
USER node
# Copy package files
COPY package*.json ./
COPY api/package*.json ./api/
COPY client/package*.json ./client/
COPY packages/data-provider/package*.json ./packages/data-provider/
COPY packages/data-schemas/package*.json ./packages/data-schemas/
COPY packages/agents/package*.json ./packages/agents/
COPY packages/api/package*.json ./packages/api/
COPY --chown=node:node package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY --chown=node:node api/package.json ./api/package.json
COPY --chown=node:node client/package.json ./client/package.json
COPY --chown=node:node packages/data-provider/package.json ./packages/data-provider/package.json
COPY --chown=node:node packages/data-schemas/package.json ./packages/data-schemas/package.json
COPY --chown=node:node packages/api/package.json ./packages/api/package.json
COPY --chown=node:node packages/client/package.json ./packages/client/package.json
# Install dependencies
RUN npm ci
RUN \
# Allow mounting of these files, which have no default
touch .env ; \
# Create directories for the volumes to inherit the correct permissions
mkdir -p /app/client/public/images /app/logs /app/uploads ; \
pnpm install --frozen-lockfile
# Copy source code
COPY . .
COPY --chown=node:node . .
# Build packages
RUN npm run build:data-provider && \
npm run build:data-schemas && \
npm run build:agents && \
npm run build:api
RUN \
# React client build with configurable memory
NODE_OPTIONS="--max-old-space-size=${NODE_MAX_OLD_SPACE_SIZE}" pnpm run frontend; \
pnpm store prune
# Build client
RUN cd client && npm run build:ci
# Node API setup
EXPOSE 3080
# Runtime stage
FROM node:20-alpine
WORKDIR /app
# Install Python and system dependencies for uv and hanzo-mcp
RUN apk add --no-cache python3 py3-pip git curl bash
# Install uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:${PATH}"
# Install production dependencies only
COPY package*.json ./
COPY api/package*.json ./api/
RUN npm ci --omit=dev
# Copy built application
COPY --from=builder /app/api ./api
COPY --from=builder /app/client/dist ./client/dist
COPY --from=builder /app/packages ./packages
# Copy other necessary files
COPY .env* ./
COPY config ./config
COPY chat.yaml ./
# Create necessary directories
RUN mkdir -p /app/logs /app/uploads /app/images
# Test that hanzo-mcp can be run with uvx
RUN uvx --from hanzo-mcp hanzo-mcp --version || echo "hanzo-mcp accessible via uvx"
# Create a wrapper script for hanzo-mcp to use with Node.js
RUN echo '#!/bin/sh\nuvx --from hanzo-mcp hanzo-mcp "$@"' > /usr/local/bin/hanzo-mcp && \
chmod +x /usr/local/bin/hanzo-mcp
# Verify installations
RUN which python3 && python3 --version && \
which uv && uv --version && \
which uvx && uvx --version && \
which npx && npx --version && \
hanzo-mcp --version || echo "hanzo-mcp ready"
# Set environment
ENV NODE_ENV=production
ENV HOST=0.0.0.0
CMD ["pnpm", "run", "backend"]
ENV UV_SYSTEM_PYTHON=1
# cache-bust: 1774514777
# Expose port
EXPOSE 3080
# Start the application
CMD ["node", "api/server/index.js"]
+29 -32
View File
@@ -1,8 +1,5 @@
# Dockerfile.multi
# v0.8.3-rc1
# Set configurable max-old-space-size with default
ARG NODE_MAX_OLD_SPACE_SIZE=6144
# v0.7.8
# Base for all builds
FROM node:20-alpine AS base-min
@@ -10,37 +7,44 @@ FROM node:20-alpine AS base-min
RUN apk add --no-cache jemalloc
# Set environment variable to use jemalloc
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
# Enable pnpm via corepack
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
RUN apk --no-cache add curl
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages/data-provider/package.json ./packages/data-provider/
COPY packages/api/package.json ./packages/api/
COPY packages/data-schemas/package.json ./packages/data-schemas/
COPY packages/client/package.json ./packages/client/
COPY client/package.json ./client/
COPY api/package.json ./api/
RUN npm config set fetch-retry-maxtimeout 600000 && \
npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 15000
COPY package*.json ./
COPY packages/data-provider/package*.json ./packages/data-provider/
COPY packages/agents/package*.json ./packages/agents/
COPY packages/api/package*.json ./packages/api/
COPY packages/data-schemas/package*.json ./packages/data-schemas/
COPY client/package*.json ./client/
COPY api/package*.json ./api/
# Install all dependencies for every build
FROM base-min AS base
WORKDIR /app
RUN pnpm install --frozen-lockfile
RUN npm ci
# Build `data-provider` package
FROM base AS data-provider-build
WORKDIR /app/packages/data-provider
COPY packages/data-provider ./
RUN pnpm run build
RUN npm run build
# Build `data-schemas` package
FROM base AS data-schemas-build
WORKDIR /app/packages/data-schemas
COPY packages/data-schemas ./
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
RUN pnpm run build
RUN npm run build
# Build `agents` package
FROM base AS agents-build
WORKDIR /app/packages/agents
COPY packages/agents ./
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 npm run build
# Build `api` package
FROM base AS api-package-build
@@ -48,24 +52,16 @@ WORKDIR /app/packages/api
COPY 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 pnpm run build
# Build `client` package
FROM base AS client-package-build
WORKDIR /app/packages/client
COPY packages/client ./
RUN pnpm run build
COPY --from=agents-build /app/packages/agents/dist /app/packages/agents/dist
RUN npm run build
# Client build
FROM base AS client-build
WORKDIR /app/client
COPY client ./
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
COPY --from=client-package-build /app/packages/client/dist /app/packages/client/dist
COPY --from=client-package-build /app/packages/client/src /app/packages/client/src
ARG NODE_MAX_OLD_SPACE_SIZE
ENV NODE_OPTIONS="--max-old-space-size=${NODE_MAX_OLD_SPACE_SIZE}"
RUN pnpm run build
ENV NODE_OPTIONS="--max-old-space-size=2048"
RUN npm run build
# API setup (including client dist)
FROM base-min AS api-build
@@ -74,14 +70,15 @@ COPY --from=ghcr.io/astral-sh/uv:0.6.13 /uv /uvx /bin/
RUN uv --version
WORKDIR /app
# Install only production deps
RUN pnpm install --frozen-lockfile --prod
RUN npm ci --omit=dev
COPY api ./api
COPY config ./config
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=agents-build /app/packages/agents/dist ./packages/agents/dist
COPY --from=api-package-build /app/packages/api/dist ./packages/api/dist
COPY --from=client-build /app/client/dist ./client/dist
WORKDIR /app/api
EXPOSE 3080
ENV HOST=0.0.0.0
CMD ["node", "server/index.js"]
CMD ["node", "server/index.js"]
-25
View File
@@ -1,25 +0,0 @@
# Static SPA — pre-built dist served by lightweight file server
# Gateway/ingress handles load balancing, rate limiting, SSL, SPA routing.
#
# Pre-requisite: run `make build-static-local` first to build client/dist
#
# Build: docker build -f Dockerfile.static -t ghcr.io/hanzoai/chat:latest .
# Run: docker run -p 3080:3080 ghcr.io/hanzoai/chat:latest
FROM node:22-alpine
RUN npm install -g serve@14
WORKDIR /app
# Copy pre-built static files
COPY client/dist/ /app/dist/
COPY client/public/ /app/public/
# Merge public assets into dist (favicon, icons, etc.)
RUN cp -rn /app/public/* /app/dist/ 2>/dev/null || true && rm -rf /app/public
EXPOSE 3080
# serve with SPA fallback on port 3080
CMD ["serve", "-s", "dist", "-l", "3080"]
+1 -7
View File
@@ -1,12 +1,6 @@
Portions of this software are licensed as follows:
* All content that resides under the "enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "enterprise/LICENSE".
* Content outside of the above mentioned directories or restrictions above is available under the MIT license as defined below.
---
MIT License
Copyright (c) 2023 Hanzo AI Inc
Originally based on LibreChat by Berri AI.
Copyright (c) 2025 Hanzo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+71 -101
View File
@@ -1,115 +1,85 @@
# Hanzo Chat
# Hanzo Chat Project - Development Guide
AI chat interface with multi-model support,
MCP integration, agents, and RAG. Live at **hanzo.chat**.
## Project Overview
Hanzo Chat is a chat application based on Chat, which is a platform for interacting with various AI models. The project follows a microservices architecture with several components running in Docker containers.
**Repo**: `github.com/hanzoai/chat`
**Package**: `@hanzochat/chat`
**Runtime**: Node.js 20 (Alpine)
## Architecture Components
## Branding
### Backend Services
- **API Service** (Hanzo container): Main application server
- **MongoDB**: Database for storing conversations, users, and other data
- **Meilisearch**: Search engine for indexing and searching content
- **VectorDB**: PostgreSQL with pgvector extension for vector embeddings
- **RAG API**: Service for Retrieval Augmented Generation capabilities
- Hanzo red `#fd4444` replaces OpenAI green `#10a37f` (Tailwind, CSS vars, emails)
- APP_TITLE: `Hanzo Chat`
- CUSTOM_FOOTER: `Powered by Hanzo AI`
- Hanzo geometric H logo throughout
- 34 language files updated
### Project Structure
- `/api`: Backend server code
- `/app`: Application logic, clients, and integrations
- `/cache`: Caching mechanisms
- `/config`: Configuration settings
- `/models`: Database schemas and models
- `/server`: Routes, controllers, and middleware
- `/strategies`: Authentication strategies
- `/client`: Frontend application
- `/src`: React components, hooks, and UI elements
- `/public`: Static assets
- `/config`: Configuration scripts and utilities
- `/packages`: Shared packages and modules
- `/data-provider`: Data fetching and state management
- `/data-schemas`: Schema definitions
- `/mcp`: Message control/processing
## Commands
## Environment Setup
```bash
# Install (NOT npm ci -- workspace peer deps break it)
npm install # .npmrc has legacy-peer-deps=true
### Prerequisites
- Docker and Docker Compose
- Node.js (version specified in package.json)
# Build
npm run build:packages # Build data-provider, data-schemas, api, client-package
npm run frontend # Build all packages + client
### Development Environment
- The application runs in Docker containers
- Storage configuration:
- Named volumes for databases and service data: `mongodb_data`, `meili_data`, `pgdata2`
- Local directories mounted for application data: `/images`, `/uploads`, `/logs`
# Dev
npm run backend:dev # API server (nodemon, port 3080)
npm run frontend:dev # Client dev server
### Important Environment Variables
- `PORT`: The port on which the API service runs (default: 3080)
- `RAG_PORT`: Port for the RAG API service (default: 8000)
- `MEILI_MASTER_KEY`: Key for Meilisearch
# Test
npm run test:all # All workspace tests
npm run test:client # Client tests
npm run test:api # API tests
npm run e2e # Playwright e2e tests
## Development Workflow
# Lint/Format
npm run lint # ESLint
npm run format # Prettier
```
### Starting the Application
1. Ensure proper directory structure (images, uploads, logs directories)
2. Use docker-compose.override.yml to set specific container configurations:
```yaml
services:
api:
user: "root"
mongodb:
user: "root"
meilisearch:
user: "root"
vectordb:
user: "root"
```
3. Run `docker compose up -d` to start all services
## Workspace Structure
```
api/ # Express backend (port 3080)
server/ # Entry point, routes, controllers, middleware
models/ # Mongoose models (MongoDB)
client/ # React frontend (Vite)
src/components/ # UI components
src/routes/ # Client-side routing
src/store/ # State management
packages/
data-provider/ # Shared data layer (librechat-data-provider)
data-schemas/ # Validation schemas
api/ # API client package (@librechat/api)
client/ # Shared client components
agents/ # Agent definitions
mcp/ # MCP server integration
```
### Troubleshooting
- **Permissions Issues**: Use `user: "root"` in docker-compose.override.yml for containers
- **MongoDB Errors**: Check permissions on data directories or use named volumes
- **Container Communication**: Ensure proper networking between containers
## Configuration
- `.env`: Environment variables for application settings
- `docker-compose.yml`: Main service configuration
- `docker-compose.override.yml`: Custom overrides for local development
- `chat.yaml`: Optional configuration file for customizing endpoints
- `librechat.yaml` (or ConfigMap `chat-config` -> `/app/librechat.yaml`)
- `hanzo-chat.example.yaml` - Hanzo-specific example config
- `.env` for secrets
Key env vars:
```
OPENAI_BASE_URL=http://llm.hanzo.svc.cluster.local:4000/v1 # Internal LLM gateway
MONGO_URI= # MongoDB connection
JWT_SECRET= # Auth token signing
CREDS_KEY= CREDS_IV= # Credential encryption
```
## K8s Deployment
- 2 replicas, port 3080
- Ingress: `hanzo.chat` (primary) + `chat.hanzo.ai` (301 → hanzo.chat)
- Secret: `chat-secrets` (MONGO_URI, JWT_SECRET, CREDS_KEY/IV)
- CI: `docker-publish.yml` -> `hanzoai/chat:latest` on Docker Hub
- Image: `hanzoai/chat:latest` (amd64 only)
## Docker Build Notes
- Uses `npm install` not `npm ci` (workspace peer dep issues)
- `--max-old-space-size=4096` for client build
- jemalloc preloaded for memory efficiency
- `uv` bundled for MCP server support
- `dompurify` must be in `client/package.json` (externalized by bundler)
## Internal Package Names
These are kept as-is from upstream (npm deps, not worth renaming):
- `@librechat/api`, `@librechat/client`, `@librechat/data-schemas`, `librechat-data-provider`, `@librechat/agents`
- Functions: `extractLibreChatParams`, `importLibreChatConvo`
- Type names: `LibreChatKeys`, `LibreChatParams`
- Config filename: `librechat.yaml` (upstream convention)
- Env var: `LIBRECHAT_LOG_DIR`
## Branding Cleanup Log
All user-visible `LibreChat` / `librechat.ai` references replaced with Hanzo equivalents:
- All `librechat.ai` URLs -> `hanzo.ai/docs/chat/...`
- `code.librechat.ai` -> `hanzo.ai/docs/chat/code-interpreter/...`
- package.json repo URLs -> `github.com/hanzoai/chat`
- package.json homepages -> `hanzo.ai/chat`
- package.json descriptions -> "Hanzo Chat"
- Help/FAQ default URL -> `hanzo.ai/chat`
- Docker Compose MongoDB DB name -> `HanzoChat`
- GitHub workflow repo refs -> `hanzoai/chat`
- MCP User-Agent -> `HanzoChat-MCP-Client`
- JSDoc comments: LibreChat -> Hanzo Chat
- Log messages: LibreChat -> Hanzo Chat
- Helm chart URLs -> hanzo.ai/docs/chat/...
## Features
- Multi-model AI chat interface
- Integration with various AI providers
- Authentication with multiple strategies
- File uploads and processing
- Conversation management
- Search capabilities
- Internationalization support
+360 -232
View File
@@ -1,286 +1,414 @@
# Hanzo AI Chat - Unified Makefile
# Simple, clean commands for development and production
# Chat Makefile for Local Development
# Unified interface to Agents, LLMs, MCPs and any AI model or OpenAPI documented API with full RAG stack
# ========================================================================================================
.PHONY: help
# Default target - show help
.DEFAULT_GOAL := help
# Variables
DOCKER_COMPOSE := docker compose
NPM := npm
# Colors for output
GREEN := \033[0;32m
YELLOW := \033[0;33m
RED := \033[0;31m
BLUE := \033[0;34m
NC := \033[0m # No Color
BLUE := \033[0;34m
# Default compose file
COMPOSE_FILE ?= compose.yml
# Help command - displays all available commands
help: ## Show this help message
@echo "$(GREEN)"
@echo "╔══════════════════════════════════════════════════════════════╗"
@echo "║ CHAT COMMANDS ║"
@echo "╚══════════════════════════════════════════════════════════════╝"
@echo "$(NC)"
@echo "$(YELLOW)Quick Start:$(NC)"
@echo " $(GREEN)make start$(NC) - Start Chat (vendor mode)"
@echo " $(GREEN)make vendor$(NC) - Show vendor configuration"
@echo " $(GREEN)make dev$(NC) - Start in development mode (local Node.js)"
@echo " $(GREEN)make stop$(NC) - Stop all services"
@echo ""
@echo "$(YELLOW)Docker Commands:$(NC)"
@echo " $(GREEN)make up$(NC) - Start Docker services in background"
@echo " $(GREEN)make down$(NC) - Stop and remove Docker containers"
@echo " $(GREEN)make restart$(NC) - Restart all Docker services"
@echo " $(GREEN)make logs$(NC) - Show Docker logs (all services)"
@echo " $(GREEN)make logs-api$(NC) - Show API logs only"
@echo " $(GREEN)make ps$(NC) - Show running containers"
@echo " $(GREEN)make build$(NC) - Build Docker images"
@echo ""
@echo "$(YELLOW)Development Commands:$(NC)"
@echo " $(GREEN)make install$(NC) - Install all dependencies"
@echo " $(GREEN)make install-force$(NC) - Clean install (remove node_modules)"
@echo " $(GREEN)make build-packages$(NC) - Build all packages"
@echo " $(GREEN)make dev-backend$(NC) - Start backend in dev mode"
@echo " $(GREEN)make dev-frontend$(NC) - Start frontend in dev mode"
@echo " $(GREEN)make lint$(NC) - Run linter"
@echo " $(GREEN)make format$(NC) - Format code with Prettier"
@echo ""
@echo "$(YELLOW)Database Commands:$(NC)"
@echo " $(GREEN)make db-shell$(NC) - Access MongoDB shell"
@echo " $(GREEN)make db-backup$(NC) - Backup MongoDB database"
@echo " $(GREEN)make db-restore$(NC) - Restore MongoDB database"
@echo ""
@echo "$(YELLOW)Utility Commands:$(NC)"
@echo " $(GREEN)make clean$(NC) - Clean build artifacts and logs"
@echo " $(GREEN)make clean-all$(NC) - Clean everything (including node_modules)"
@echo " $(GREEN)make status$(NC) - Show service status"
@echo " $(GREEN)make test$(NC) - Run tests"
@echo " $(GREEN)make shell$(NC) - Access API container shell"
@echo " $(GREEN)make update-branding$(NC) - Update logo in running container"
@echo " $(GREEN)make init-fixtures$(NC) - Create demo user (dev only)"
@echo ""
@echo "$(BLUE)Access the application at: http://localhost:3080$(NC)"
@echo ""
# Default target
help:
# Quick start with banner (vendor mode by default)
start: ## Start Chat in vendor mode
@echo "$(GREEN)"
@echo "╔══════════════════════════════════════════════════════════════╗"
@echo "║ Starting Chat... ║"
@echo "╚══════════════════════════════════════════════════════════════╝"
@echo "$(NC)"
@$(MAKE) setup-vendor-env
@$(MAKE) check-docker
@$(MAKE) up
@echo ""
@echo "$(GREEN)✓ Chat started successfully!$(NC)"
@echo ""
@echo "$(YELLOW)Vendor Mode Configuration:$(NC)"
@echo " • Name: $(BLUE)Hanzo AI$(NC)"
@echo " • Models: $(BLUE)Hanzo Zen-1, Hanzo Zen-1 Pro$(NC)"
@echo " • Backend: $(BLUE)Anthropic Claude$(NC)"
@echo ""
@echo "$(YELLOW)Access points:$(NC)"
@echo " • Application: $(BLUE)http://localhost:3080$(NC)"
@echo " • API Health: $(BLUE)http://localhost:3080/api/health$(NC)"
@echo ""
@echo "$(GREEN)╔══════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN) Hanzo AI Chat Platform $(NC)"
@echo "$(GREEN)🔐 Login with Demo Account$(NC)"
@echo "$(GREEN)╚══════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(BLUE)Quick Start:$(NC)"
@echo " $(GREEN)make up$(NC) - Start chat with cloud API"
@echo " $(GREEN)make dev$(NC) - Start in dev mode (hot reload)"
@echo " $(GREEN)make dev-full$(NC) - Dev mode with local router"
@echo " $(YELLOW)Email:$(NC) $(BLUE)wow@this.com$(NC)"
@echo " $(YELLOW)Password:$(NC) $(BLUE)demo1234$(NC)"
@echo ""
@echo "$(BLUE)Core Commands:$(NC)"
@echo " $(GREEN)make down$(NC) - Stop all services"
@echo " $(GREEN)make restart$(NC) - Restart services"
@echo " $(GREEN)make logs$(NC) - View logs"
@echo " $(GREEN)make status$(NC) - Check service status"
@echo " $(GREEN)make clean$(NC) - Stop and remove data"
@echo "$(YELLOW)Useful commands:$(NC)"
@echo " • View logs: $(GREEN)make logs$(NC)"
@echo " • Stop: $(GREEN)make stop$(NC)"
@echo " • Status: $(GREEN)make status$(NC)"
@echo ""
@echo "$(BLUE)Development:$(NC)"
@echo " $(GREEN)make build$(NC) - Build containers"
@echo " $(GREEN)make test$(NC) - Run tests"
@echo " $(GREEN)make lint$(NC) - Run linting"
@echo " $(GREEN)make format$(NC) - Format code"
# Show vendor configuration
vendor: ## Show current vendor configuration
@echo "$(GREEN)"
@echo "╔══════════════════════════════════════════════════════════════╗"
@echo "║ Vendor Mode ║"
@echo "╚══════════════════════════════════════════════════════════════╝"
@echo "$(NC)"
@if [ -f .env ] && grep -q "VENDOR_MODE=true" .env; then \
echo "$(YELLOW)Current Configuration:$(NC)"; \
echo ""; \
grep "^VENDOR_" .env | while read line; do \
echo "$$line"; \
done; \
echo ""; \
echo "$(GREEN)✓ Vendor mode is ENABLED$(NC)"; \
else \
echo "$(RED)✗ Vendor mode is DISABLED$(NC)"; \
echo ""; \
echo "Run '$(GREEN)make start$(NC)' to enable vendor mode"; \
fi
# Docker commands
up: ## Start Docker services in background
@$(DOCKER_COMPOSE) up -d
@sleep 2
@$(DOCKER_COMPOSE) exec api node config/create-user.js wow@this.com "Demo User" wow demo1234 --email-verified=true >/dev/null 2>&1 || true
@echo ""
@echo "$(BLUE)Production:$(NC)"
@echo " $(GREEN)make prod$(NC) - Deploy production"
@echo " $(GREEN)make backup$(NC) - Backup data"
@echo "$(GREEN)╔══════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ Services Started ║$(NC)"
@echo "$(GREEN)╚══════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "Run 'make help-all' for advanced usage"
help-all:
@echo "$(GREEN)══════════════════════════════════════════════════════════════$(NC)"
@echo "$(GREEN) Advanced Usage $(NC)"
@echo "$(GREEN)══════════════════════════════════════════════════════════════$(NC)"
@echo "$(YELLOW)🚀 Chat Services:$(NC)"
@echo " $(BLUE)Main Application$(NC) → http://localhost:3080"
@echo " $(BLUE)API Health Check$(NC) → http://localhost:3080/api/health"
@echo ""
@echo "$(BLUE)Deployment Modes:$(NC)"
@echo " make up - Basic: Chat + Cloud API"
@echo " make dev - Development: Hot reload"
@echo " make dev-full - Dev + Local router"
@echo " make prod - Production with Traefik"
@echo "$(YELLOW)📊 Supporting Services:$(NC)"
@echo " $(BLUE)MongoDB$(NC) → localhost:27017 (database: chat)"
@echo " $(BLUE)Meilisearch$(NC) → localhost:7700 (search engine)"
@echo " $(BLUE)PostgreSQL/pgvector$(NC) → localhost:5432 (vector storage)"
@echo " $(BLUE)RAG API$(NC) → localhost:8000 (document processing)"
@echo ""
@echo "$(BLUE)Service Control:$(NC)"
@echo " make logs-chat - View chat logs"
@echo " make logs-mongo - View MongoDB logs"
@echo " make logs-router - View router logs (dev-full)"
@echo " make shell-chat - Shell into chat container"
@echo " make shell-mongo - MongoDB shell"
@echo "$(YELLOW)🔧 Management Commands:$(NC)"
@echo " $(GREEN)make logs$(NC) View all service logs"
@echo " $(GREEN)make logs-api$(NC) View chat API logs only"
@echo " $(GREEN)make ps$(NC) → Show container status"
@echo " $(GREEN)make shell$(NC) → Access container shell"
@echo " $(GREEN)make stop$(NC) → Stop all services"
@echo ""
@echo "$(BLUE)Development Tools:$(NC)"
@echo " make install - Install dependencies"
@echo " make dev-frontend - Run frontend only"
@echo " make dev-backend - Run backend only"
@echo " make test-unit - Unit tests"
@echo " make test-e2e - E2E tests"
@echo " make lint-fix - Auto-fix linting"
@echo "$(GREEN)╔══════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ 🔐 Login with Demo Account ║$(NC)"
@echo "$(GREEN)╚══════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(BLUE)Database:$(NC)"
@echo " make db-seed - Seed demo data"
@echo " make db-reset - Reset database"
@echo " make db-export - Export data"
@echo " make db-import FILE= - Import data"
@echo " $(YELLOW)Email:$(NC) $(BLUE)wow@this.com$(NC)"
@echo " $(YELLOW)Password:$(NC) $(BLUE)demo1234$(NC)"
@echo ""
@echo "$(BLUE)Docker Compose Files:$(NC)"
@echo " compose.yml - Base configuration"
@echo " compose.dev.yml - Development overrides"
@echo " compose.prod.yml - Production overrides"
# ============================================================================
# CORE COMMANDS
# ============================================================================
up:
@echo "$(GREEN)Starting Hanzo Chat...$(NC)"
@docker compose up -d
@echo "$(GREEN)Chat available at http://localhost:3081$(NC)"
down:
@echo "$(YELLOW)Stopping services...$(NC)"
@docker compose down
restart: down up
logs:
@docker compose logs -f
status:
@echo "$(GREEN)Service Status:$(NC)"
@docker compose ps
@echo "$(YELLOW)💡 Tips:$(NC)"
@echo " • Create new account with 'Sign up' if needed"
@echo " • MCP tools available for file operations"
@echo " • Upload documents for RAG processing"
@echo ""
@echo "$(GREEN)Health Checks:$(NC)"
@curl -s http://localhost:3081/api/health > /dev/null 2>&1 && echo " ✓ Chat API" || echo " ✗ Chat API"
@curl -s http://localhost:3081 > /dev/null 2>&1 && echo " ✓ Chat UI" || echo " ✗ Chat UI"
clean:
@echo "$(RED)Removing all data...$(NC)"
@docker compose down -v
down: ## Stop and remove Docker containers
@$(DOCKER_COMPOSE) down
# ============================================================================
# DEVELOPMENT
# ============================================================================
stop: ## Stop all services
@$(DOCKER_COMPOSE) stop
dev:
@echo "$(GREEN)Starting in development mode...$(NC)"
@docker compose -f compose.yml -f compose.dev.yml up
restart: ## Restart all Docker services
@$(DOCKER_COMPOSE) restart
dev-full:
@echo "$(GREEN)Starting full dev stack with local router...$(NC)"
@docker compose -f compose.yml -f compose.dev.yml --profile with-router up
logs: ## Show Docker logs (all services)
@$(DOCKER_COMPOSE) logs -f
build:
@echo "$(GREEN)Building containers...$(NC)"
@docker compose build
logs-api: ## Show API logs only
@$(DOCKER_COMPOSE) logs -f api
build-prod:
@echo "$(GREEN)Building production image...$(NC)"
@docker build -f docker/Dockerfile -t hanzoai/chat:latest .
ps: ## Show running containers
@$(DOCKER_COMPOSE) ps
build-static-local:
@echo "$(GREEN)Building static SPA locally...$(NC)"
@cp .env.static .env
@pnpm run build:data-provider
@pnpm run --filter @librechat/client build
@cd client && pnpm run build
@cp .env.backup .env 2>/dev/null || true
@echo "$(GREEN)Local build complete: client/dist/$(NC)"
build: ## Build Docker images
@$(DOCKER_COMPOSE) build
build-static: build-static-local
@echo "$(GREEN)Building Docker image...$(NC)"
@docker build -f Dockerfile.static -t ghcr.io/hanzoai/chat:latest .
@echo "$(GREEN)Image built: ghcr.io/hanzoai/chat:latest$(NC)"
# Development commands
dev: ## Start in development mode (local Node.js)
@echo "$(YELLOW)Starting development servers...$(NC)"
@$(MAKE) check-containers
@$(MAKE) install
@$(MAKE) build-packages
@echo "$(GREEN)Starting backend and frontend...$(NC)"
@(trap 'kill 0' SIGINT; \
MONGO_URI=mongodb://localhost:27017/chat $(NPM) run backend:dev & \
$(NPM) run frontend:dev & \
wait)
deploy-static:
@echo "$(GREEN)Pushing and deploying static SPA...$(NC)"
@docker push ghcr.io/hanzoai/chat:latest
@kubectl apply -f k8s/deployment-static.yaml
@kubectl rollout restart deployment/chat -n hanzo
@echo "$(GREEN)Deployed. Watching rollout...$(NC)"
@kubectl rollout status deployment/chat -n hanzo --timeout=120s
install: ## Install all dependencies
@echo "$(YELLOW)Installing dependencies...$(NC)"
@$(NPM) install
@cd api && $(NPM) install
@cd client && $(NPM) install
@cd packages/data-provider && $(NPM) install
@cd packages/data-schemas && $(NPM) install
@cd packages/api && $(NPM) install
@echo "$(GREEN)✓ Dependencies installed$(NC)"
# ============================================================================
# PRODUCTION
# ============================================================================
install-force: ## Clean install (remove node_modules)
@echo "$(YELLOW)Performing clean install...$(NC)"
@$(MAKE) clean-all
@$(MAKE) install
prod:
@echo "$(GREEN)Deploying production...$(NC)"
@test -n "$${JWT_SECRET}" || (echo "$(RED)JWT_SECRET required$(NC)" && exit 1)
@test -n "$${OPENAI_API_KEY}" || (echo "$(RED)OPENAI_API_KEY required$(NC)" && exit 1)
@docker compose -f compose.yml -f compose.prod.yml up -d
build-packages: ## Build all packages
@echo "$(YELLOW)Building packages...$(NC)"
@$(NPM) run build:data-provider
@$(NPM) run build:data-schemas
@$(NPM) run build:api
@echo "$(GREEN)✓ Packages built$(NC)"
backup:
@echo "$(GREEN)Creating backup...$(NC)"
@mkdir -p backups
@docker compose exec -T mongodb mongodump --out /backup
@docker cp $$(docker compose ps -q mongodb):/backup backups/mongodb-$$(date +%Y%m%d-%H%M%S)
@echo "$(GREEN)Backup complete$(NC)"
dev-backend: ## Start backend in dev mode
@$(NPM) run backend:dev
# ============================================================================
# LOGS
# ============================================================================
dev-frontend: ## Start frontend in dev mode
@$(NPM) run frontend:dev
logs-chat:
@docker compose logs -f chat
lint: ## Run linter
@$(NPM) run lint
logs-mongo:
@docker compose logs -f mongodb
format: ## Format code with Prettier
@$(NPM) run format
logs-meili:
@docker compose logs -f meilisearch
# Database commands
db-shell: ## Access MongoDB shell
@$(DOCKER_COMPOSE) exec mongodb mongosh chat
logs-router:
@docker compose -f compose.yml -f compose.dev.yml logs -f router
db-backup: ## Backup MongoDB database
@mkdir -p ./backups
@$(DOCKER_COMPOSE) exec mongodb mongodump --db chat --out /dump
@$(DOCKER_COMPOSE) cp mongodb:/dump ./backups/chat-backup-$$(date +%Y%m%d-%H%M%S)
@echo "$(GREEN)✓ Database backed up$(NC)"
# ============================================================================
# SHELL ACCESS
# ============================================================================
db-restore: ## Restore MongoDB database from latest backup
@echo "$(YELLOW)Restoring from latest backup...$(NC)"
@LATEST_BACKUP=$$(ls -t ./backups | head -1); \
$(DOCKER_COMPOSE) cp ./backups/$$LATEST_BACKUP mongodb:/restore && \
$(DOCKER_COMPOSE) exec mongodb mongorestore --db chat /restore/chat
@echo "$(GREEN)✓ Database restored$(NC)"
shell-chat:
@docker compose exec chat sh
# Utility commands
update-branding: ## Update branding in running container
@echo "$(YELLOW)Updating branding...$(NC)"
@docker exec chat cp /app/client/public/assets/logo.svg /app/client/dist/assets/logo.svg 2>/dev/null || true
@echo "$(GREEN)✓ Branding updated. Clear browser cache to see changes.$(NC)"
shell-mongo:
@docker compose exec mongodb mongosh -u hanzo -p hanzo123 HanzoChat
clean: ## Clean build artifacts and logs
@echo "$(YELLOW)Cleaning build artifacts...$(NC)"
@rm -rf api/dist client/dist packages/*/dist
@rm -rf logs/*.log
@rm -rf backend.log frontend.log mongod.log
@echo "$(GREEN)✓ Clean complete$(NC)"
# ============================================================================
# TESTING
# ============================================================================
clean-all: clean ## Clean everything (including node_modules)
@echo "$(YELLOW)Removing node_modules...$(NC)"
@rm -rf node_modules api/node_modules client/node_modules packages/*/node_modules
@echo "$(GREEN)✓ Deep clean complete$(NC)"
test:
@echo "$(GREEN)Running tests...$(NC)"
@npm test
status: ## Show service status
@echo ""
@echo "$(GREEN)╔══════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ Service Status ║$(NC)"
@echo "$(GREEN)╚══════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)🐳 Docker Containers:$(NC)"
@$(DOCKER_COMPOSE) ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" | tail -n +2 | \
awk -F'\t' '{printf " %-20s %-25s %s\n", $$1, $$2, $$3}'
@echo ""
@echo "$(YELLOW)🌐 Service Health:$(NC)"
@curl -s http://localhost:3080/api/health >/dev/null 2>&1 && \
echo " $(GREEN)✓ Chat API$(NC) → http://localhost:3080 (healthy)" || \
echo " $(RED)✗ Chat API$(NC) → http://localhost:3080 (not responding)"
@curl -s http://localhost:8000/health >/dev/null 2>&1 && \
echo " $(GREEN)✓ RAG API$(NC) → http://localhost:8000 (healthy)" || \
echo " $(RED)✗ RAG API$(NC) → http://localhost:8000 (not responding)"
@docker exec chat-mongodb mongosh --quiet --eval "db.runCommand({ping: 1})" >/dev/null 2>&1 && \
echo " $(GREEN)✓ MongoDB$(NC) → localhost:27017 (connected)" || \
echo " $(RED)✗ MongoDB$(NC) → localhost:27017 (not connected)"
@curl -s http://localhost:7700/health >/dev/null 2>&1 && \
echo " $(GREEN)✓ Meilisearch$(NC) → localhost:7700 (healthy)" || \
echo " $(YELLOW)- Meilisearch$(NC) → localhost:7700 (internal only)"
@docker exec vectordb pg_isready >/dev/null 2>&1 && \
echo " $(GREEN)✓ PostgreSQL/pgvector$(NC) → localhost:5432 (ready)" || \
echo " $(YELLOW)- PostgreSQL/pgvector$(NC) → localhost:5432 (internal only)"
@echo ""
@echo "$(YELLOW)📋 Quick Actions:$(NC)"
@echo " • View logs: $(GREEN)make logs$(NC)"
@echo " • Restart: $(GREEN)make restart$(NC)"
@echo " • Stop: $(GREEN)make stop$(NC)"
@echo ""
test-unit:
@echo "$(GREEN)Running unit tests...$(NC)"
@npm run test:unit
test: ## Run tests
@$(NPM) run test:api
@$(NPM) run test:client
test-e2e:
@echo "$(GREEN)Running E2E tests...$(NC)"
@npm run test:e2e
shell: ## Access API container shell
@$(DOCKER_COMPOSE) exec api /bin/sh
# ============================================================================
# CODE QUALITY
# ============================================================================
init-fixtures: ## Create demo user (dev only)
@echo "$(YELLOW)Creating demo user...$(NC)"
@$(DOCKER_COMPOSE) exec api node config/create-user.js wow@this.com "Demo User" wow demo1234 --email-verified=true || echo "$(RED)Failed to create demo user. Make sure services are running.$(NC)"
@echo ""
@echo "$(GREEN)Demo user credentials:$(NC)"
@echo " Email: $(BLUE)wow@this.com$(NC)"
@echo " Password: $(BLUE)demo1234$(NC)"
lint:
@echo "$(GREEN)Running linters...$(NC)"
@npm run lint
# Check if Docker/Colima is running
check-docker:
@echo "$(YELLOW)Checking Docker status...$(NC)"
@docker info >/dev/null 2>&1 || (echo "$(RED)Docker is not running. Please start Docker/Colima first.$(NC)" && exit 1)
@echo "$(GREEN)✓ Docker is running$(NC)"
lint-fix:
@echo "$(GREEN)Auto-fixing lint issues...$(NC)"
@npm run lint:fix
# Check if required containers are running
check-containers:
@echo "$(YELLOW)Checking required containers...$(NC)"
@if ! docker ps | grep -q "chat-mongodb"; then \
echo "$(YELLOW)Starting MongoDB...$(NC)"; \
docker run -d --name chat-mongodb -p 27017:27017 mongo || true; \
fi
@if ! docker ps | grep -q "chat-meilisearch"; then \
echo "$(YELLOW)Starting Meilisearch...$(NC)"; \
docker run -d --name chat-meilisearch -p 7700:7700 -e MEILI_MASTER_KEY=DrhYf7zENyR6AlUCKmnz0eYASOQdl6zxH7s7MKFSfFCt getmeili/meilisearch:v1.12.3 || true; \
fi
@echo "$(GREEN)✓ Required containers are running$(NC)"
format:
@echo "$(GREEN)Formatting code...$(NC)"
@npm run format
# Environment setup
setup-env: ## Create .env file from example
@if [ ! -f .env ]; then \
echo "$(YELLOW)Creating .env file...$(NC)"; \
cp .env.example .env; \
echo "$(GREEN)✓ .env file created.$(NC)"; \
echo ""; \
echo "$(YELLOW)Next steps:$(NC)"; \
echo " 1. Edit .env and add at least one AI provider API key"; \
echo " 2. Update JWT_SECRET and JWT_REFRESH_SECRET"; \
echo " 3. Update CREDS_KEY (32 chars) and CREDS_IV (16 chars)"; \
echo " 4. Run 'make start' to begin"; \
else \
echo "$(YELLOW).env file already exists$(NC)"; \
fi
# ============================================================================
# INSTALLATION
# ============================================================================
# Setup vendor environment
setup-vendor-env: ## Setup vendor mode environment
@if [ -f .env ] && grep -q "VENDOR_MODE=true" .env; then \
echo "$(GREEN)✓ Vendor mode already configured$(NC)"; \
else \
echo "$(YELLOW)Setting up vendor mode...$(NC)"; \
if [ ! -f .env ]; then \
cp .env.example .env; \
fi; \
if [ -f .env.backup ]; then \
echo "# =================================="; \
echo "# HANZO AI VENDOR MODE CONFIGURATION"; \
echo "# =================================="; \
echo ""; \
echo "# Vendor Mode - Hanzo AI"; \
echo "VENDOR_MODE=true"; \
echo "VENDOR_NAME=Hanzo AI"; \
echo "VENDOR_MODEL_DEFAULT=Hanzo Zen-1"; \
echo "VENDOR_MODEL_PRO=Hanzo Zen-1 Pro"; \
echo ""; \
echo "# Branding"; \
echo "APP_TITLE=Hanzo AI Chat"; \
echo "VENDOR_BRAND_COLOR=#000000"; \
echo "VENDOR_LOGO_URL=/assets/hanzo-logo.svg"; \
echo ""; \
echo "# Backend Configuration"; \
echo "VENDOR_BACKEND_ENDPOINT=anthropic"; \
echo "VENDOR_BACKEND_MODEL_DEFAULT=claude-3-5-sonnet-20241022"; \
echo "VENDOR_BACKEND_MODEL_PRO=claude-3-opus-20240229"; \
echo ""; \
echo "$(GREEN)✓ Vendor mode environment prepared$(NC)"; \
echo ""; \
echo "$(YELLOW)Note: Add your backend API key:$(NC)"; \
echo " VENDOR_BACKEND_API_KEY=your-api-key"; \
fi; \
fi
install:
@echo "$(GREEN)Installing dependencies...$(NC)"
@npm install
@cd api && npm install
@cd client && npm install
# Check environment variables
check-env: ## Check if environment is properly configured
@if [ ! -f .env ]; then \
echo "$(RED)Error: .env file not found!$(NC)"; \
echo "Run '$(GREEN)make setup-env$(NC)' to create one from .env.example"; \
exit 1; \
fi
@echo "$(YELLOW)Checking environment configuration...$(NC)"
@if ! grep -q "^PORT=" .env 2>/dev/null; then \
echo "$(RED)Error: PORT not set in .env$(NC)"; \
echo "Add 'PORT=3080' to your .env file"; \
exit 1; \
fi
@if ! grep -q "^MEILI_MASTER_KEY=" .env 2>/dev/null || grep -q "^MEILI_MASTER_KEY=your-master-key-minimum-16-bytes" .env 2>/dev/null; then \
echo "$(YELLOW)Warning: MEILI_MASTER_KEY not configured$(NC)"; \
echo "Using default key for development"; \
fi
@echo "$(GREEN)✓ Environment check passed$(NC)"
# ============================================================================
# DATABASE
# ============================================================================
# Shortcuts
s: start
d: down
l: logs
r: restart
db-seed:
@echo "$(GREEN)Seeding database...$(NC)"
@docker compose exec chat npm run seed
db-seed-agents:
@echo "$(GREEN)Seeding team agents...$(NC)"
@docker compose exec chat npm run seed:agents
db-reset:
@echo "$(RED)Resetting database...$(NC)"
@docker compose exec mongodb mongosh -u hanzo -p hanzo123 HanzoChat --eval "db.dropDatabase()"
@make db-seed
db-export:
@echo "$(GREEN)Exporting database...$(NC)"
@mkdir -p exports
@docker compose exec -T mongodb mongoexport -u hanzo -p hanzo123 -d HanzoChat -c conversations > exports/conversations-$$(date +%Y%m%d).json
db-import:
@test -n "$(FILE)" || (echo "$(RED)Please specify FILE=path/to/export.json$(NC)" && exit 1)
@echo "$(GREEN)Importing $(FILE)...$(NC)"
@docker compose exec -T mongodb mongoimport -u hanzo -p hanzo123 -d HanzoChat -c conversations < $(FILE)
# ============================================================================
# UTILITIES
# ============================================================================
env-example:
@echo "$(GREEN)Creating example .env file...$(NC)"
@cp .env.example .env
@echo "$(YELLOW)Edit .env and add your API keys$(NC)"
check-env:
@echo "$(GREEN)Environment Check:$(NC)"
@test -f .env && echo "✓ .env file exists" || echo "✗ .env file missing"
@which docker > /dev/null && echo "✓ Docker installed" || echo "✗ Docker not found"
@docker compose version > /dev/null 2>&1 && echo "✓ Docker Compose v2" || echo "✗ Docker Compose v2 not found"
version:
@echo "$(GREEN)Hanzo AI Chat$(NC)"
@echo "Version: $$(cat package.json | grep version | head -1 | awk -F: '{ print $$2 }' | sed 's/[",]//g')"
.DEFAULT_GOAL := help
.PHONY: help start vendor up down stop restart logs logs-api ps build \
dev install install-force build-packages dev-backend dev-frontend \
lint format db-shell db-backup db-restore clean clean-all \
status test shell check-docker check-containers check-env setup-env \
setup-vendor-env update-branding init-fixtures s d l r
+157 -126
View File
@@ -1,166 +1,197 @@
# Hanzo AI Chat
<p align="center">
<a href="https://hanzo.ai">
<img src="client/public/assets/logo.svg" height="256">
</a>
<h1 align="center">
<a href="https://hanzo.ai">Chat</a>
</h1>
</p>
AI-powered chat platform with enterprise features, using Hanzo's cloud API or local deployment.
<p align="center">
<a href="https://discord.gg/hanzo">
<img
src="https://img.shields.io/badge/DISCORD-black.svg?style=for-the-badge&logo=discord&logoColor=white&labelColor=000000">
</a>
<a href="https://hanzo.ai">
<img
src="https://img.shields.io/badge/WEBSITE-black.svg?style=for-the-badge&logo=globe&logoColor=white&labelColor=000000">
</a>
<a href="https://docs.hanzo.ai">
<img
src="https://img.shields.io/badge/DOCS-black.svg?style=for-the-badge&logo=read-the-docs&logoColor=white&labelColor=000000">
</a>
<a aria-label="GitHub" href="https://github.com/hanzoai/chat">
<img
src="https://img.shields.io/badge/GITHUB-black.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=000000">
</a>
</p>
## Quick Start
**Chat** - Unified interface to Agents, LLMs, MCPs and any AI model or OpenAPI documented API with full RAG stack
```bash
# Clone and setup
git clone https://github.com/hanzoai/chat.git
cd chat
# ✨ Features
# Copy environment template
cp .env.example .env
- 🖥️ **UI & Experience** inspired by ChatGPT with enhanced design and features
# Edit .env and add your Hanzo API key
# Get your key at: https://hanzo.ai/dashboard
nano .env
- 🤖 **AI Model Selection**:
- Anthropic (Claude), AWS Bedrock, OpenAI, Azure OpenAI, Google, Vertex AI, OpenAI Assistants API (incl. Azure)
- [Custom Endpoints](https://www.hanzo.ai/docs/quick_start/custom_endpoints): Use any OpenAI-compatible API with Hanzo, no proxy required
- Compatible with [Local & Remote AI Providers](https://www.hanzo.ai/docs/configuration/chat_yaml/ai_endpoints):
- Ollama, groq, Cohere, Mistral AI, Apple MLX, koboldcpp, together.ai,
- OpenRouter, Perplexity, ShuttleAI, Deepseek, Qwen, and more
# Start the platform
make up
```
- 🔧 **[Code Interpreter API](https://www.hanzo.ai/docs/features/code_interpreter)**:
- Secure, Sandboxed Execution in Python, Node.js (JS/TS), Go, C/C++, Java, PHP, Rust, and Fortran
- Seamless File Handling: Upload, process, and download files directly
- No Privacy Concerns: Fully isolated and secure execution
Access the chat at http://localhost:3081
- 🔦 **Agents & Tools Integration**:
- **[Hanzo Agents](https://www.hanzo.ai/docs/features/agents)**:
- No-Code Custom Assistants: Build specialized, AI-driven helpers without coding
- Flexible & Extensible: Attach tools like DALL-E-3, file search, code execution, and more
- Compatible with Custom Endpoints, OpenAI, Azure, Anthropic, AWS Bedrock, and more
- [Model Context Protocol (MCP) Support](https://modelcontextprotocol.io/clients#chat) for Tools
- Use Hanzo Agents and OpenAI Assistants with Files, Code Interpreter, Tools, and API Actions
## Development
- 🔍 **Web Search**:
- Search the internet and retrieve relevant information to enhance your AI context
- Combines search providers, content scrapers, and result rerankers for optimal results
- **[Learn More →](https://www.hanzo.ai/docs/features/web_search)**
### Basic Development (with hot reload)
```bash
make dev
```
- 🪄 **Generative UI with Code Artifacts**:
- [Code Artifacts](https://youtu.be/GfTj7O4gmd0?si=WJbdnemZpJzBrJo3) allow creation of React, HTML, and Mermaid diagrams directly in chat
### Full Development (with local router)
```bash
# Set your LLM API keys
export ANTHROPIC_API_KEY=your-key
export OPENAI_API_KEY=your-key
- 🎨 **Image Generation & Editing**
- Text-to-image and image-to-image with [GPT-Image-1](https://www.hanzo.ai/docs/features/image_gen#1--openai-image-tools-recommended)
- Text-to-image with [DALL-E (3/2)](https://www.hanzo.ai/docs/features/image_gen#2--dalle-legacy), [Stable Diffusion](https://www.hanzo.ai/docs/features/image_gen#3--stable-diffusion-local), [Flux](https://www.hanzo.ai/docs/features/image_gen#4--flux), or any [MCP server](https://www.hanzo.ai/docs/features/image_gen#5--model-context-protocol-mcp)
- Produce stunning visuals from prompts or refine existing images with a single instruction
# Start full dev stack
make dev-full
```
- 💾 **Presets & Context Management**:
- Create, Save, & Share Custom Presets
- Switch between AI Endpoints and Presets mid-chat
- Edit, Resubmit, and Continue Messages with Conversation branching
- [Fork Messages & Conversations](https://www.hanzo.ai/docs/features/fork) for Advanced Context control
## Architecture
- 💬 **Multimodal & File Interactions**:
- Upload and analyze images with Claude 3, GPT-4.5, GPT-4o, o1, Llama-Vision, and Gemini 📸
- Chat with Files using Custom Endpoints, OpenAI, Azure, Anthropic, AWS Bedrock, & Google 🗃️
```
┌─────────────────────────┐ ┌─────────────────────────┐
│ Hanzo Chat UI │────▶│ api.hanzo.ai │
│ (Hanzo Chat) │ │ (or local router) │
│ localhost:3081 │ │ │
└─────────────────────────┘ │ • 100+ AI Models │
│ │ • MCP Tools │
│ │ • Code Execution │
▼ └─────────────────────────┘
┌─────────────────────────┐
│ Local Data Storage │
│ • MongoDB (chat history)│
│ • Meilisearch (search) │
└─────────────────────────┘
```
- 🌎 **Multilingual UI**:
- English, 中文, Deutsch, Español, Français, Italiano, Polski, Português Brasileiro
- Русский, 日本語, Svenska, 한국어, Tiếng Việt, 繁體中文, العربية, Türkçe, Nederlands, עברית
## Configuration
- 🧠 **Reasoning UI**:
- Dynamic Reasoning UI for Chain-of-Thought/Reasoning AI models like DeepSeek-R1
### Required Environment Variables
- 🎨 **Customizable Interface**:
- Customizable Dropdown & Interface that adapts to both power users and newcomers
```env
# Your Hanzo API key (required)
OPENAI_API_KEY=sk-hanzo-your-key-here
- 🗣️ **Speech & Audio**:
- Chat hands-free with Speech-to-Text and Text-to-Speech
- Automatically send and play Audio
- Supports OpenAI, Azure OpenAI, and Elevenlabs
# API endpoint (default: Hanzo cloud)
OPENAI_BASE_URL=https://api.hanzo.ai/v1
- 📥 **Import & Export Conversations**:
- Import Conversations from Hanzo, ChatGPT, Chatbot UI
- Export conversations as screenshots, markdown, text, json
# Features
MCP_ENABLED=true
ALLOW_REGISTRATION=true
```
- 🔍 **Search & Discovery**:
- Search all messages/conversations
### Optional Customization
- 👥 **Multi-User & Secure Access**:
- Multi-User, Secure Authentication with OAuth2, LDAP, & Email Login Support
- Built-in Moderation, and Token spend tools
```env
# Branding
APP_TITLE=My AI Assistant
CUSTOM_FOOTER=Powered by Hanzo AI
- ⚙️ **Configuration & Deployment**:
- Configure Proxy, Reverse Proxy, Docker, & many Deployment options
- Use completely local or deploy on the cloud
- **Brand Mode**: White-label deployments with custom branding and model names
# Security
JWT_SECRET=your-secret-key
```
- 📖 **Open-Source & Community**:
- Completely Open-Source & Built in Public
- Community-driven development, support, and feedback
## Commands
[For a thorough review of our features, see our docs here](https://docs.hanzo.ai/) 📚
### Basic Usage
```bash
make up # Start services
make down # Stop services
make logs # View logs
make status # Check health
make clean # Remove all data
```
## 🪶 All-In-One AI Conversations with Hanzo
### Development
```bash
make dev # Dev mode with hot reload
make build # Build containers
make test # Run tests
make lint # Check code quality
make format # Format code
```
Hanzo brings together the future of assistant AIs with the revolutionary technology of OpenAI's ChatGPT. Celebrating the original styling, Hanzo gives you the ability to integrate multiple AI models. It also integrates and enhances original client features such as conversation and message search, prompt templates and plugins.
### Production
```bash
make prod # Deploy with Traefik
make backup # Backup database
```
With Hanzo, you no longer need to opt for ChatGPT Plus and can instead use free or pay-per-call APIs. We welcome contributions, cloning, and forking to enhance the capabilities of this advanced chatbot platform.
## Docker Compose Structure
[![Watch the video](https://raw.githubusercontent.com/Hanzo-AI/hanzo.ai/main/public/images/changelog/v0.7.6.gif)](https://www.youtube.com/watch?v=ilfwGQtJNlI)
- `compose.yml` - Base configuration for local development
- `compose.dev.yml` - Development overrides (hot reload, local router)
- `compose.prod.yml` - Production overrides (Traefik, security)
Click on the thumbnail to open the video☝️
## Features
---
- 🤖 **100+ AI Models** via Hanzo Router
- 💬 **Clean Chat UI** with modern design
- 🔍 **Full-Text Search** with Meilisearch
- 📝 **Persistent Chat History**
- 🛠️ **MCP Tools** for enhanced capabilities
- 🚀 **Code Execution** via secure runtime
- 🔐 **Enterprise Security** with JWT auth
## 🌐 Resources
## Troubleshooting
**GitHub Repo:**
### Chat not loading
```bash
# Check service status
make status
- **RAG API:** [github.com/hanzoai/rag_api](https://github.com/hanzoai/rag_api)
- **Website:** [github.com/Hanzo-AI/hanzo.ai](https://github.com/Hanzo-AI/hanzo.ai)
# View logs
make logs-chat
**Other:**
# Verify API key
echo $OPENAI_API_KEY
```
- **Website:** [hanzo.ai](https://hanzo.ai)
- **Documentation:** [hanzo.ai/docs](https://hanzo.ai/docs)
- **Blog:** [hanzo.ai/blog](https://hanzo.ai/blog)
### Database issues
```bash
# Reset database
make db-reset
---
# Export data
make db-export
## 📝 Changelog
# Import data
make db-import FILE=backup.json
```
Keep up with the latest updates by visiting the releases page and notes:
## Additional Documentation
- [Releases](https://github.com/hanzoai/chat/releases)
- [Changelog](https://www.hanzo.ai/changelog)
- [Production Deployment](./docs/production-domains.md)
- [IAM Integration](./docs/iam-integration.md)
- [Platform Overview](./docs/platform-overview.md)
- [Demo User Guide](./docs/demo-user.md)
**⚠️ Please consult the [changelog](https://www.hanzo.ai/changelog) for breaking changes before updating.**
## Support
---
- Documentation: https://docs.hanzo.ai
- Issues: https://github.com/hanzoai/chat/issues
- Discord: https://discord.gg/hanzoai# CI Test
## ⭐ Star History
<p align="center">
<a href="https://star-history.com/#hanzoai/chat&Date">
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hanzoai/chat&type=Date&theme=dark" onerror="this.src='https://api.star-history.com/svg?repos=hanzoai/chat&type=Date'" />
</a>
</p>
<p align="center">
<a href="https://trendshift.io/repositories/4685" target="_blank" style="padding: 10px;">
<img src="https://trendshift.io/api/badge/repositories/4685" alt="hanzoai%2FHanzo | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
<a href="https://runacap.com/ross-index/q1-24/" target="_blank" rel="noopener" style="margin-left: 20px;">
<img style="width: 260px; height: 56px" src="https://runacap.com/wp-content/uploads/2024/04/ROSS_badge_white_Q1_2024.svg" alt="ROSS Index - Fastest Growing Open-Source Startups in Q1 2024 | Runa Capital" width="260" height="56"/>
</a>
</p>
---
## ✨ Contributions
Contributions, suggestions, bug reports and fixes are welcome!
For new features, components, or extensions, please open an issue and discuss before sending a PR.
If you'd like to help translate Hanzo into your language, we'd love your contribution! Improving our translations not only makes Hanzo more accessible to users around the world but also enhances the overall user experience. Please check out our [Translation Guide](https://www.hanzo.ai/docs/translation).
---
## 💖 This project exists in its current state thanks to all the people who contribute
<a href="https://github.com/hanzoai/chat/graphs/contributors">
<img src="https://contrib.rocks/image?repo=hanzoai/chat" />
</a>
---
## 🎉 Special Thanks
We thank [Locize](https://locize.com) for their translation management tools that support multiple languages in Hanzo.
<p align="center">
<a href="https://locize.com" target="_blank" rel="noopener noreferrer">
<img src="https://github.com/user-attachments/assets/d6b70894-6064-475e-bb65-92a9e23e0077" alt="Locize Logo" height="50">
</a>
</p>
+144
View File
@@ -0,0 +1,144 @@
# Hanzo Chat Test Results Summary
## Executive Summary
**Date**: June 26, 2025
**Status**: ⚠️ Tests are failing and need fixes
### Overall Test Results
| Test Suite | Total Tests | Passed | Failed | Skipped | Coverage |
|------------|-------------|--------|--------|---------|----------|
| Client Unit Tests | 353 | 275 | 77 | 1 | 22.63% |
| API Unit Tests | 419 | 416 | 2 | 1 | ~20% |
| API Package | 185 | 185 | 0 | 0 | 20.36% |
| Data Provider | 353 | 352 | 0 | 1 | 43.09% |
| E2E Tests | - | - | - | - | Failed to start |
**Total**: 1,310 tests, 1,228 passed (93.7%), 79 failed (6%), 3 skipped
## Critical Issues
### 1. Client Test Failures (77 failures)
- **Main Issue**: Cannot find module `@hanzochat/data-provider/react-query`
- **Affected Components**:
- Auth components (Login, Registration, LoginForm)
- Plugin Store components
- Chat components
- Settings components
- Templates components
### 2. API Test Failures (2 failures)
- **Issue**: Winston logger configuration error - `Cannot read properties of undefined (reading 'level')`
- **Affected Tests**:
- Server configuration tests
- Message model tests
- Several client tests that import API packages
### 3. E2E Test Failures
- **Issue**: Tests timeout waiting for server to start
- **Root Cause**: MongoDB and Meilisearch connection failures in test environment
## Test Coverage Analysis
### Low Coverage Areas (<30%)
- **Client Utils**: 22.63% overall
- File operations: 9.78%
- Forms: 11.42%
- Login error handling: 10%
- Message utilities: 10.86%
- Theme utilities: 8.69%
- **API Package**: 20.36% overall
- MCP (Model Context Protocol): 1.56%
- Endpoints: 0%
- OAuth: 0%
- Crypto: 0%
### Good Coverage Areas (>70%)
- **Data Provider Actions**: 86.57%
- **Azure Configuration**: 88.28%
- **File Config**: 92.85%
- **Web Utils**: 90.81%
- **Mistral CRUD**: 96.93%
## Root Causes
### 1. Module Resolution Issue
The main issue is with the `@hanzochat/data-provider/react-query` import path. This suggests:
- Missing build step for the react-query submodule
- Incorrect import paths in test files
- Package.json configuration issues
### 2. Winston Logger Issue
The Winston logger is trying to access `info.level` on an undefined object, suggesting:
- Missing initialization
- Incorrect logger configuration in test environment
- Circular dependency issues
### 3. Infrastructure Dependencies
E2E tests fail because they depend on:
- MongoDB connection
- Meilisearch connection
- Redis (optional but logs errors)
## Recommendations
### Immediate Fixes Required
1. **Fix Module Resolution**
```bash
# Build all packages first
npm run build:data-provider
npm run build:data-schemas
npm run build:api
```
2. **Fix Winston Logger**
- Add null checks in winston configuration
- Ensure logger is properly initialized in test environment
3. **Fix E2E Infrastructure**
- Use test containers for MongoDB/Meilisearch
- Or mock these services for E2E tests
### Test Improvements
1. **Increase Coverage**
- Add tests for critical paths (auth, endpoints, file operations)
- Target 80% coverage for core modules
2. **Test Organization**
- Separate unit tests from integration tests
- Add smoke tests for critical user paths
3. **CI/CD Integration**
- Fix tests before enabling in CI
- Add pre-commit hooks for test runs
- Set coverage thresholds
## Commands to Fix Tests
```bash
# 1. Clean and rebuild
rm -rf node_modules package-lock.json
npm install
npm run build:data-provider
npm run build:data-schemas
npm run build:api
# 2. Run tests individually
npm run test:client -- --no-coverage
npm run test:api -- --no-coverage
# 3. Debug specific test
npm test -- --testNamePattern="Registration"
```
## Next Steps
1. Fix module resolution issues (Priority: High)
2. Fix Winston logger initialization (Priority: High)
3. Set up test database containers (Priority: Medium)
4. Increase test coverage for critical paths (Priority: Medium)
5. Add integration tests for Hanzo API integration (Priority: Low)

Some files were not shown because too many files have changed in this diff Show More