* ✨ feat(docker): run self-hosted Compose chats in Gateway Mode by default
- Add the lobehub-gateway service to docker-compose and wire the lobe service
to it; AGENT_GATEWAY_INTERNAL_URL keeps server pushes on the Compose network
while browsers use AGENT_GATEWAY_URL.
- S3_INTERNAL_ENDPOINT routes the server's own S3 requests to rustfs:9000 while
presigned URLs keep the browser-facing S3_ENDPOINT, which local mode sets to
localhost and the container cannot reach.
- setup.sh generates a per-deployment JWKS_KEY and gateway token and writes the
gateway URL for each deploy mode; the .env template drops the public JWKS key.
- Warn loudly at container startup when an upgraded stack lacks the gateway
settings or still uses the public example JWKS_KEY, and document the upgrade.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* 🔒 fix(docker): pass only the public JWK to the gateway container
The gateway only needs the public half of JWKS_KEY to verify browser
sessions, but it received the full private key set, so anyone able to read
the gateway environment could sign tokens LobeHub trusts. setup.sh now also
writes JWKS_PUBLIC_KEY (the same key without d/p/q/dp/dq/qi), Compose passes
only that to the gateway, and the startup check warns when it is missing,
still contains private fields, or does not match JWKS_KEY.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* ✨ feat(next): unify asset base URL and add crossOrigin
- Derive assetPrefix from ASSET_BASE_URL, falling back to the
deprecated NEXT_PUBLIC_ASSET_PREFIX so existing deploys keep working
- Set crossOrigin: 'anonymous' so a cross-origin asset host doesn't
degrade module preload or turn Sentry frames into opaque errors
* ✅ test(next): cover trailing-slash strip on legacy asset prefix fallback
* ♻️ refactor(pwa): serve app icons from /app-icons instead of /icons
The PWA manifest icons and the default user avatar sat under the generic
/icons prefix. Namespacing them under /app-icons makes ownership explicit
and keeps them clear of any other path a deployment may serve at the root.
Every reference and the Cache-Control header rule move with the directory.
* 🐛 fix(next): gate crossOrigin on a configured asset prefix
crossOrigin: 'anonymous' was set unconditionally, so any self-hosted deployment whose asset host does not return Access-Control-Allow-Origin would go from working script tags to ones the browser refuses to execute. Apply it only when an asset prefix is actually configured, and document the ACAO requirement alongside the new ASSET_BASE_URL key.
* ♻️ refactor(assets): serve app images from /app-images instead of /images
Same change as /icons, for the same reason: /images is a generic root
prefix, and namespacing the App's own assets under /app-images makes
ownership explicit. Every reference goes through the imageUrl helper or a
literal path, and the Cache-Control header rule moves with them so the
images do not silently lose immutable caching.
* 💄 style: refresh AIHubMix branding and links
- Correct brand casing to AIHubMix in all user-facing text (provider card,
18 locale files, docs pages, READMEs)
- Update third-party proxy table: official logo, direct console token link
- Add the missing 'Obtain OpenAI API Key' section to the English README
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* 💄 style: update AIHubMix table model examples to GPT-5.6 and Claude Fable 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: YuTengjing <ytj2713151713@gmail.com>
* 🐛 fix(tools): make TOOL_NAME_MAX_LENGTH=0 actually disable tool-name compression
`TOOL_NAME_MAX_LENGTH` (#17249) is read from `process.env` at module load in
`ToolNameResolver`, so it only ever applied to the gateway (server-run) path.
The default client-driven chat path builds the tool payload in the browser,
where the server env is invisible — deployments setting `0` still got opaque
`MD5HASH_…` tool names.
Ship the value to the client with the global server config and push it into the
context-engine module both on config load and at `createToolsEngine` (the client
mirror of `createServerToolsEngine`), before any tool name is generated.
Also adds the var to the `@lobechat/env` tools schema and documents it in the
self-hosting env docs (en + zh-CN).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ♻️ refactor(tools): parse TOOL_NAME_MAX_LENGTH through one shared function
Review follow-up: the env schema coerced the value with zod while
`ToolNameResolver` parsed `process.env` with `parseInt`, so the same env value
could mean two things on the two sides that generate tool names:
raw resolver (server) shipped to client
1e2 1 100
" " 64 (fallback) 0 → compression silently off on the client
2048 2048 throws
-5/abc 64 (fallback) throws
The last row is the worst: `@t3-oss/env-core` throws on validation failure, so a
typo'd value would take `getServerGlobalConfig()` down entirely, where before it
just fell back to 64.
Move the parse into `parseToolNameMaxLength` (`@lobechat/const/plugin`, a leaf
module both sides can import cheaply — importing context-engine here would drag
the database module graph into the config path) and have the resolver and the
global config both use it. Unset / unparseable / negative reads as "not
configured" and falls back to the default; no upper bound, matching the
resolver. Env schema now passes the raw string through.
Covered by a table test in `ToolNameResolver.config.test.ts` (parse semantics)
and one in `getServerGlobalConfig.test.ts` (the shipped value matches, and a
typo no longer throws).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ♻️ refactor(tools): keep the tool-name config out of the app-shell bundle
The client-side sync lived in `serverConfig`'s SWR success handler, which put a
static `@lobechat/context-engine` import into a store that every page creates —
including the lightweight auth / popup shells — dragging the engine's module
graph (down to `@lobechat/database`) into bundles that never generate a tool
name.
Keep the value as plain data in the server config and push it into the engine
from the sites that actually generate names, via `applyToolNameMaxLength()`:
`createToolsEngine` (the tools payload) and the agent-profile mention list,
whose generated names are written into the system prompt and so must match the
names sent to the model. `src/store/serverConfig` is now byte-identical to
canary.
Verified: SPA vite build passes (the `@lobechat/const/plugin` subpath resolves
in the client bundle); context-engine 445 tests, client-side 286 tests, server
globalConfig/tool-engine suites, and the full type-check all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 📝 docs: fix outdated content across the docs site
Audited docs/ against the current codebase and fixed stale content that
drifted after major refactors (Clerk/NextAuth → Better Auth, src/server →
apps/server, src/{config,envs,locales} → packages/*, model-bank updates).
- self-hosting/auth: mark removed NextAuth/Clerk pages with deprecation
warnings; fix microsoft/zitadel alias claims and the Logto callback path
- environment-variables & advanced: correct wrong defaults (S3_SET_ACL,
AI_IMAGE_DEFAULT_IMAGE_NUM, index/proxy URLs), drop non-existent env vars
and fictional feature flags, fix OIDC config guidance
- development: update refactored paths, Better Auth, .mjs configs, remove
the MSW section (msw is not a dependency)
- providers & model examples: replace retired model ids with in-bank ones;
fix comfyui frontmatter corruption
- usage: rename Moderator→Orchestrator, GTD→Task, correct shortcut keys,
channel capability tables, Feishu/Lark WebSocket mode
- platform/migration: fix dead links, docker service name, npx/npm → bun
EN and zh-CN pairs updated together.
* 📝 docs: fix Logto callback path and AUTH_SECRET deprecation guidance
- Revert Logto/Sealos callback URLs to /api/auth/callback/logto to match
the runtime SSO redirectURI override
- Narrow legacy auth Callout: AUTH_SECRET remains required for Better Auth;
mark NEXT_AUTH_SECRET as deprecated in zh-CN
* 📝 docs: refresh agent skills for locales, env, auth, and agentRun paths
Align OSS agent guidance with post-refactor layout:
- packages/locales/src/default + bun run i18n
- packages/env/src for env schemas (@/envs alias)
- spa-auth shell + src/routes/auth segments
- chat agentRun/transports/hetero instead of aiChat
* 📝 docs: document APP_URL as required for Better Auth base URL
Self-hosted auth uses appEnv.APP_URL as baseURL, not request-header
auto-detection. NEXT_PUBLIC_AUTH_URL remains deprecated.
* 📝 docs: note self-host search provider setup for web search
Built-in lobe-web-browsing needs no client plugin, but self-hosted
servers still require SEARCH_PROVIDERS / SEARXNG_URL (default SearXNG).
* 📝 docs: point feature guide welcome UI at AgentHome
Opening message/questions on the agent chat page live in
src/features/AgentHome, not Onboarding WelcomeMessage.
* 📝 docs: Remove Langfuse docs; enable pg_search
Delete Langfuse observability guides (langfuse.mdx and langfuse.zh-CN.mdx). Update Docker self-hosting docs to add `-c shared_preload_libraries=pg_search` to the ParadeDB docker run command and clarify that the ParadeDB image includes pgvector and pg_search and that pg_search must be explicitly enabled; apply the same clarification to the Chinese documentation.
* 📝 docs: Document 'video' capability in model list
Add a `video` entry to the extension capabilities table in docs/self-hosting/advanced/model-list.mdx and its Chinese translation (model-list.zh-CN.mdx) to document Video Comprehension support.
* 📝 docs: Add agent feature flags & update thread text
Add documentation entries for new system agent feature flags: generationTopic (AI image automatic topic naming), inputCompletion (input auto-completion suggestions), and promptRewrite (prompt optimization before generation). Also reword the thread/branch conversation entry to clarify automatic title generation. Apply the same updates to the Chinese localization file.
* 📝 docs: Document AGENT_GATEWAY_SERVICE_TOKEN env var
Add documentation for the AGENT_GATEWAY_SERVICE_TOKEN environment variable to the self-hosting environment variables pages (English and Chinese). The new entries specify that the variable is optional, describe it as the authentication token used between Gateway Mode and a self-deployed Agent Gateway, and include default (-) and example (`dev-secret`). Files changed: docs/self-hosting/environment-variables/basic.mdx and basic.zh-CN.mdx.
* ✨ feat(aihubmix): allow configuring the base URL via AIHUBMIX_PROXY_URL
Follow-up to #16328, which made the AiHubMix gateway configurable per-user in the UI. This adds the server-side environment-variable path (as asked in the review), mirroring the New API provider.
- packages/env/src/llm.ts: declare AIHUBMIX_PROXY_URL (schema + value)
- Dockerfile: pass AIHUBMIX_PROXY_URL through
- .env.example: document AIHUBMIX_PROXY_URL
The runtime already reads options.baseURL and <PROVIDER>_PROXY_URL is injected generically, so no further wiring is needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 📝 docs(aihubmix): document AIHUBMIX_PROXY_URL
Add the AIHUBMIX_PROXY_URL entry to the self-hosting model-provider env reference (EN + zh-CN), matching NEWAPI_PROXY_URL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 🔥 chore(agent-config): drop dead enableAutoCreateTopic feature
Drop enableAutoCreateTopic + autoCreateTopicThreshold end-to-end. No
business code consumed these fields anymore — only types, defaults,
locale copy, UI form items, agent-builder LLM prompts, and test
fixtures kept the dead config alive.
Sweep:
- types & zod schema (LobeAgentChatConfig, AgentChatConfigSchema, openapi)
- DEFAULT_AGENT_CHAT_CONFIG constant
- locale keys in default + 18 translations
- agent-builder system prompts & tool manifests
- AgentChat form items (auto-topic switch + threshold slider)
- test fixtures & integration tests (replaced sample boolean key in
parser tests with enableHistoryCount)
- docs/self-hosting env-var examples
- settings.test snapshot
dataImporter JSON fixtures keep the legacy keys on purpose — they
simulate historical user exports and the zod schema strips unknowns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(chat-input): move inputTemplate + autoScroll into Params popover
Surface the User Input Preprocessing template (inputTemplate) and
Auto-scroll During AI Response toggle (enableAutoScrollOnStreaming) in
the chat-input Params popover, alongside compression / history /
max_tokens. Drop the matching form items from AgentChat — the popover
is now the single entry point for these two agent-level preferences.
ControlRow's action prop becomes optional so inputTemplate can render
as a label + TextArea without a Switch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 refactor(agent-settings): drop AgentChat tab in favor of Params popover
Remove the now-redundant Chat Preferences tab from agent settings:
- delete src/features/AgentSetting/AgentChat/
- drop ChatSettingsTabs.Chat enum and its three registrations
(useCategory, AgentSettingsContent, profile Content)
- drop agentTab.chat locale key in default + 18 translations
- drop MessagesSquare / MessagesSquareIcon imports that became unused
History/compression/auto-scroll/inputTemplate already live in the
chat-input Params popover, so this tab carried no unique
functionality.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(chat-input): surface enableStreaming + reasoning_effort + disabledParams in Params popover
Bring the Model tab's controls into the chat-input Params popover so the
popover can become the single entry point for agent-level params.
- enableStreaming Switch at the top of Advanced (treats undefined as on,
matching `chatConfig.enableStreaming !== false` in chat service)
- reasoning_effort row after max_tokens (Select tied to
chatConfig.enableReasoningEffort / params.reasoning_effort, matching
the agentConfigResolver gating)
- per-model disabledParams filter on the 4 sampling sliders (e.g. Claude
Opus 4.7 hides temperature/top_p), via aiModelSelectors.modelDisabledParams
- max_tokens defaults to 4096 on toggle-on (parity with AgentModal),
matching the AgentModal UX
- drop the !enableAgentMode gate on Advanced so agent-mode users still
reach the model params once the Model tab is gone
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 refactor(agent-settings): drop AgentModal tab in favor of Params popover
Now that the chat-input Params popover surfaces enableStreaming,
reasoning_effort, the 4 sampling params (model-aware via
disabledParams), and max_tokens, the Model Settings tab carries no
unique behavior. Remove it:
- delete src/features/AgentSetting/AgentModal/ (index + ModelSelect)
- drop ChatSettingsTabs.Modal enum and its three registrations
(useCategory, AgentSettingsContent, profile Content)
- drop agentTab.modal locale key in default + 18 translations
- drop BrainCog / BrainIcon imports that became unused
- simplify the profile Content inbox-default fallback to Opening
(Content menu no longer carried Modal at all)
settingModel.* locale keys are kept — Controls still reads them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): keep !enableAgentMode gate on Advanced sampling params
Walk back the gate removal from the prior commit. Agent mode is meant
to manage temperature / top_p / penalties / reasoning_effort itself;
exposing user overrides there contradicts the design.
- Move enableStreaming out of Advanced into the common section so it
stays visible in both modes (streaming is a UI behavior, not a
sampling param).
- Re-wrap the SectionHeader + sampling sliders + max_tokens +
reasoning_effort with `{!enableAgentMode && (...)}`, restoring the
prior visibility rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(conversation): persist per-topic chat scroll position to localStorage
Restores scroll position when switching back to a topic, keyed by
messageMapKey(context). Falls back to scroll-to-bottom for new topics or
when the user was already at the bottom. Storage is capped at 500 entries
with 30-day expiry and silent fallback on quota errors.
Fixes LOBE-8251
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔨 chore(conversation): rename scroll snapshot storage prefix to LOBEHUB
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔨 chore(conversation): use LOBEHUB_SCROLL as scroll snapshot key prefix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(conversation): preserve scroll across draft-to-topic key transition
When a draft conversation (`*_new` key) gets promoted to a real topic via
onTopicCreated, the contextKey changes mid-stream for the same logical
conversation. Treating it as a topic switch loaded a missing snapshot and
fell back to scrollToIndex(end), yanking users away from content they
were reading.
Now we detect the draft-promotion shape, migrate the snapshot to the new
key, and skip the restore pass while data is already on screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 chore(settings): remove queryRewrite system agent
Removes the unused knowledge-base query rewrite system agent: settings UI in agent/service-model pages, type definition, default config, store selector, server env parser, locale strings across 18 languages, env-variable docs, and the now-orphan chainRewriteQuery prompt chain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add JWKS_KEY env variable with fallback to OIDC_JWKS_KEY
- Add signInternalJWT() and validateInternalJWT() in internalJwt.ts
- Use short-lived JWT (3s) with purpose claim to authenticate lambda → async calls
- Remove KEY_VAULTS_SECRET from Authorization header transmission
- Update OIDC provider to use JWKS_KEY from authEnv
- Update documentation for JWKS_KEY and desktop sync
* ✨ feat(config): add assetPrefix to nextConfig for environment variable support
* ✨ feat(docs): add NEXT_PUBLIC_ASSET_PREFIX environment variable for CDN support
✨ feat: enhance NewAPI with environment variables and fix routers compatibility
- Add NEWAPI_API_KEY and NEWAPI_PROXY_URL environment variable support
- Update documentation for NewAPI configuration options
- Fix routers baseURL handling to prevent duplicate version paths
- Remove /v1 baseURL requirement to avoid SDK compatibility issues
- Auto-detect model capabilities based on provider detection
- Support dynamic routing to correct provider endpoints
This resolves URL duplication issues like /v1beta/v1beta/ and ensures
proper routing to Anthropic, Google, OpenAI, and XAI endpoints.