Compare commits

..

759 Commits

Author SHA1 Message Date
Arvin Xu 0f04463708 🐛 fix(desktop): persist gateway toggle state across app restarts (#13300)
🐛 fix: persist gateway toggle state across app restarts

The gateway auto-connect logic only checked if the user was logged in,
ignoring whether they had manually disabled the toggle. Added a
`gatewayEnabled` flag to the Electron store that is set on
connect/disconnect and checked before auto-connecting on startup.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:31:42 +08:00
Arvin Xu 093fa7bcae feat: support agent tasks system (#13289)
*  feat: agent task system — CLI, review rubrics, workspace, comments, brief tool split

support import md

Major changes:
- Split task CLI into modular files (task/, lifecycle, topic, doc, review, checkpoint, dep)
- Split builtin-tool-task into task + brief tools (conditional injection)
- Task review uses EvalBenchmarkRubric from @lobechat/eval-rubric
- Task workspace: documents auto-pin via Notebook, tree view with folders
- Task comments system (task_comments table)
- Task topics: dedicated TaskTopicModel with userId, handoff fields, review results
- Heartbeat timeout auto-detection in detail API
- Run idempotency (reject duplicate runs) + error rollback
- Topic cancel/delete by topicId only (no taskId needed)
- Integration tests for task router (13 tests)
- interruptOperation fix (string param, not object)
- Global TRPC error handler in CLI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

task document workflow

task handoff loop

🗃️ chore: consolidate task system migrations into single 0095

Merged 7 separate migrations (0095-0101) into one:
- tasks, briefs, task_comments, task_dependencies, task_documents, task_topics tables
- All fields including sort_order, resolved_action/comment, review fields
- Idempotent CREATE TABLE IF NOT EXISTS, DROP/ADD CONSTRAINT, CREATE INDEX IF NOT EXISTS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

fix interruptOperation

topic auto review workflow

topic handoff workflow

finish run topic and brief workflow

support task tool

improve task schema

update

 feat: add onComplete hook to task.run for completion callbacks

When agent execution completes, the hook:
- Updates task heartbeat
- Creates a result Brief (on success) with assistant content summary
- Creates an error Brief (on failure) with error message
- Supports both local (handler) and production (webhook) modes

Uses the new Agent Runtime Hooks system instead of raw stepCallbacks.

LOBE-6160 LOBE-6208

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Review system — LLM-as-Judge automated review

Task review uses an independent LLM call to evaluate topic output
quality against configurable criteria with pass/fail thresholds.

- TaskReviewService: structured LLM review via generateObject,
  auto-resolves model/provider from user's system agent defaults
- Model: getReviewConfig, updateReviewConfig on TaskModel
- Router: getReview, updateReview, runReview procedures
- CLI: `task review set/view/run` commands
- Auto-creates Brief with review results

LOBE-6165

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add TaskScheduler, multi-topic execution, and handoff context

- TaskScheduler: interface + Local implementation (setTimeout-based),
  following QueueService dual-mode pattern
- Multi-topic execution: `task run --topics N --delay S` runs N topics
  in sequence with optional delay between them
- Handoff context: buildTaskPrompt() queries previous topics by
  metadata.taskId and injects handoff summaries into the next topic's
  prompt (sliding window: latest full, older summaries only)
- Heartbeat auto-update between topics

LOBE-6161

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Heartbeat watchdog + heartbeat CLI

Watchdog scans running tasks with expired heartbeats, marks them as
failed, and creates urgent error Briefs. Heartbeat CLI allows manual
heartbeat reporting for testing.

- Model: refactored to use Drizzle operators (isNull, isNotNull, ne)
  instead of raw SQL where possible; fixed findStuckTasks to skip
  tasks without heartbeat data
- Router: heartbeat (manual report), watchdog (scan + fail + brief)
- Router: updateSchema now includes heartbeatInterval, heartbeatTimeout
- CLI: `task heartbeat <id>`, `task watchdog`, `task edit` with
  --heartbeat-timeout, --heartbeat-interval, --description

LOBE-6161

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

♻️ refactor: move CheckpointConfig to @lobechat/types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add task run — trigger agent execution for tasks

Task.run creates a topic, triggers AiAgentService.execAgent with task
context, and streams results via SSE. Supports both agentId and slug.

- Service: added taskId to ExecAgentParams, included in topic metadata
- Router: task.run procedure — resolves agent, builds prompt, calls execAgent,
  updates topic count and heartbeat
- CLI: `task run <id>` command with SSE streaming, --prompt, --verbose

LOBE-6160

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Checkpoint system for task review gates

Checkpoint allows configuring pause points in task execution flow.
Supports beforeIds (pause before subtask starts) and afterIds (pause
after subtask completes) on parent tasks.

- Model: CheckpointConfig type, getCheckpointConfig, updateCheckpointConfig,
  shouldPauseBeforeStart, shouldPauseAfterComplete
- Router: getCheckpoint, updateCheckpoint procedures; integrated with
  updateStatus for automatic checkpoint triggering
- CLI: `task checkpoint view/set` commands with --before, --after,
  --topic-before, --topic-after, --on-agent-request options
- Tests: 3 new checkpoint tests (37 total)

LOBE-6162

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add dependency unlocking on task completion

When a task completes, automatically check and unlock blocked tasks
whose dependencies are all satisfied (backlog → running). Also notify
when all subtasks of a parent are completed.

- Model: getUnlockedTasks, areAllSubtasksCompleted (Drizzle, no raw SQL)
- Router: updateStatus hook triggers unlocking on completion
- CLI: shows unlocked tasks and parent completion notification
- Tests: 3 new tests (34 total)

LOBE-6164

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Brief system — schema, model, router, CLI

Brief is a universal Agent-to-User reporting mechanism, not limited to
Tasks. CronJobs, Agents, and future systems can all produce Briefs.

- Schema: briefs table with polymorphic source (taskId, cronJobId, agentId)
- Model: BriefModel with CRUD, listUnresolved (Daily Brief), markRead, resolve
- Router: TRPC brief router with taskId identifier resolution
- CLI: `lh brief` command (list/view/read/resolve)
- Tests: 11 model tests
- Migration: 0096_add_briefs_table.sql

LOBE-6163

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Task system — schema, model, router, CLI

Implement the foundational Task system for managing long-running,
multi-topic agent tasks with subtask trees and dependency chains.

- Schema: tasks, task_dependencies, task_documents tables
- Model: TaskModel with CRUD, tree queries, heartbeat, dependencies, document pinning
- Router: TRPC task router with identifier/id resolution
- CLI: `lh task` command (list/view/create/edit/delete/start/pause/resume/complete/cancel/tree/dep)
- Tests: 31 model tests
- Migration: 0095_add_task_tables.sql

LOBE-6036 LOBE-6054

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* update

* 🐛 fix: update brief model import path and add raw-md vitest plugin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: eslint import sort in vitest config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: brief ID validation, auto-review retry, and continueTopicId operationId

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: task integration tests — create test agent for FK, fix children spread

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: task integration tests — correct identifier prefix and agent ID

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: remove unused toolsActivatorRuntime import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: create real topic in task integration tests to satisfy FK constraint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: type errors in task prompt tests, handoff schema, and activity mapping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: create real agent/topic/brief records in database model tests for FK constraints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:43:51 +08:00
lobehubbot aa48b856fb Merge remote-tracking branch 'origin/main' into canary 2026-03-26 09:05:30 +00:00
YuTengjing b4d27c7232 🗃️ db: add notification tables (#13295)
🗃️ db: add notification tables migration (UUID, with indexes)
2026-03-26 17:04:47 +08:00
Rdmclin2 dd192eda3e feat: bot support custom markdown render and context injection (#13294)
* feat: support  bot mardown format

* feat: support custom markdownRender and bot context inject

* feat: support custom PORT

* feat: telegram support html render

* feat: slack support markdown render

* chore: feishu and lark don't handle markdown for now
2026-03-26 16:52:35 +08:00
huangkairan c6b0f868ef 🐛 fix: skill page redirect & activeTab handling in Details component (#13255) 2026-03-26 15:39:43 +08:00
Arvin Xu 3bea920193 🔁 chore: sync main branch to canary (#13286)
## Summary
- Sync main branch (v2.1.44 + v2.1.45 releases, agent task system DB
schema) into canary
- Resolved Body.tsx merge conflict by keeping canary version
2026-03-26 15:03:02 +08:00
arvinxx ca16a40a44 Merge remote-tracking branch 'origin/main' into sync/main-to-canary-20260326-v2
# Conflicts:
#	src/routes/(main)/agent/channel/detail/Body.tsx
2026-03-26 15:01:04 +08:00
lobehubbot 59e19310fe 🔖 chore(release): release version v2.1.45 [skip ci] 2026-03-26 05:58:23 +00:00
Arvin Xu b005a9c73b 👷 build: add agent task system database schema (#13280)
* 🗃️ chore: add agent task system database schema

Add 6 new tables for the Agent Task System:
- tasks: core task with tree structure, heartbeat, scheduling
- task_dependencies: inter-task dependency graph (blocks/relates)
- task_documents: MVP workspace document pinning
- task_topics: topic tracking with handoff (jsonb) and review results
- task_comments: user/agent comments with author tracking (text id: cmt_)
- briefs: unresolved notification system (text id: brf_)

All sub-tables include userId FK for row-level user isolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add self-referential FK on tasks.parentTaskId (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use foreignKey() for self-referential parentTaskId to avoid TS circular inference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on task_topics.topic_id → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: resolve pre-existing TS type-check errors

- Fix i18next defaultValue type (string | null → string)
- Fix i18next options type mismatches
- Fix fieldTags.webhook possibly undefined

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on tasks.currentTopicId → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK constraints for assignee, author, topic, and parent fields

- tasks.assigneeUserId → users.id (ON DELETE SET NULL)
- tasks.assigneeAgentId → agents.id (ON DELETE SET NULL)
- tasks.parentTaskId → tasks.id (ON DELETE SET NULL)
- tasks.currentTopicId → topics.id (ON DELETE SET NULL)
- task_comments.authorUserId → users.id (ON DELETE SET NULL)
- task_comments.authorAgentId → agents.id (ON DELETE SET NULL)
- task_topics.topicId → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: change task_topics.topicId FK to ON DELETE CASCADE

Topic deleted → task_topic mapping row removed (not just nulled).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: use inline .references() for currentTopicId FK

No circular inference issue — only parentTaskId (self-ref) needs foreignKey().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on task_comments.briefId and topicId (ON DELETE SET NULL)

- task_comments.briefId → briefs.id (SET NULL)
- task_comments.topicId → topics.id (SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: merge briefs table into task.ts to fix circular dependency

brief.ts imported task.ts (briefs.taskId FK) and task.ts imported
brief.ts (taskComments.briefId FK), causing circular dependency error.
Merged briefs into task.ts since briefs are part of the task system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on tasks.createdByAgentId → agents.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:56:01 +08:00
Rdmclin2 2c657670fe 🐛 fix: skill import url and github address problem (#13261)
* chore: optimize github import placeholder and hint

* fix: support import a github hosted skill.md url

* fix:  reimport skill problem

* fix: github zip url file correctly resovled

* fix:  empty content

* fix: test case

* fix: regex lint
2026-03-26 11:28:31 +08:00
Rylan Cai 4dd271c968 feat(cli): support api key auth in cli (#13190)
*  support cli api key auth

* 🔒 reject invalid x-api-key without fallback auth

* ♻️ clean up cli api key auth diff

* ♻️ clean up cli auth command diff

* ♻️ clean up remaining cli auth diff

* ♻️ split stored auth token fields

* ♻️ trim connect auth surface

* ♻️ drop redundant jwt user id carry-over

* ♻️ trim auth test wording diff

* 🐛 fix api key model imports

* 🐛 fix api key util subpath import

* 🔐 chore(cli): use env-only api key auth

* ♻️ refactor(cli): simplify auth credential flow

*  feat: simplify cli api key login flow

* 🐛 fix(cli): prefer jwt for webapi auth

* ♻️ refactor(cli): trim auth http diff

* 🐛 fix(cli): skip api key auth expiry handling

* 🐛 fix(cli): restore non-jwt expiry handling

* ♻️ refactor(cli): trim connect auth expired diff

* ♻️ refactor(cli): trim login comment diff

* ♻️ refactor(cli): trim resolve token comment diff

* ♻️ refactor(cli): restore connect expiry flow

* ♻️ refactor(cli): trim login api key message

* 🐛 fix(cli): support api key gateway auth

* ♻️ refactor(cli): restore resolve token comment

* ♻️ refactor(cli): trim test-only auth diffs

* ♻️ refactor(cli): restore resolve token comments

*  test(cli): add api key expiry coverage

* 🐛 fix cli auth server resolution and gateway auth

* ♻️ prune auth fix diff noise

* ♻️ unify cli server url precedence

* ♻️ simplify device gateway auth tests

*  add gateway auth edge case coverage

*  remove low-value gateway auth test

* 🐛 fix api key context test mock typing
2026-03-26 10:11:38 +08:00
Arvin Xu b76db6bcbd 🐛 fix(memory): respect agent-level memory toggle when injecting memories (#13265)
* 🐛 fix(memory): respect agent-level memory toggle when injecting memories

When the user disables the memory toggle in ChatInput (which writes to
agent-level chatConfig.memory.enabled), the actual message-sending path
in chat/index.ts was only checking the user-level memoryEnabled setting,
completely ignoring the agent-level override.

This aligns the injection logic with useMemoryEnabled hook:
agent-level config takes priority, falls back to user-level setting.

Also fix pre-commit hook to use bunx instead of npx to ensure the
correct ESLint version (v10) is used in monorepo context.

Adds regression tests verifying all three priority scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update pre-commit

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 01:51:56 +08:00
Innei 84674b1e10 feat(builtin-tool-local-system): skip intervention for safe paths like /tmp (#13232)
*  feat(builtin-tool-local-system): skip intervention for safe paths like /tmp

Add SAFE_PATH_PREFIXES whitelist to bypass user confirmation for
file operations targeting ephemeral directories (/tmp, /var/tmp).

* Fix intervention audit tests

* Move fs checks into Electron
2026-03-26 01:38:36 +08:00
LobeHub Bot 1cb13d9f93 test: add unit tests for mcpStore selectors (#13240)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 01:19:27 +08:00
Arvin Xu 169f11b63b feat(desktop): add device gateway status indicator in titlebar (#13260)
* support desktop gateway

* support device mode

*  feat(desktop): add device gateway status indicator in titlebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  test(desktop): update getDeviceInfo test to include name and description fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): update gateway status copy to reference Gateway instead of cloud

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): translate Gateway to 网关 in zh-CN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): simplify description placeholder to Optional

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(desktop): use fixed title 'Connect to Gateway' in device popover

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 01:14:08 +08:00
Arvin Xu 2c7a3f934d 🐛 fix: use display messages for token counting in group chats (#13247)
* 🐛 fix: use partial-json fallback in ToolArgumentsRepairer to recover incomplete args

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use display messages for token counting in group chats

The TokenTag component used dbMessageSelectors.activeDbMessages which
generates a key without groupId, causing empty results in group chats.
This made the Context Details token tag invisible for group agents.

Switch to using the messageString prop (from mainAIChatsMessageString)
which correctly includes groupId in its key generation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 00:59:45 +08:00
YuTengjing a1e91ab30d test: add tests for topic updatedTime grouping (#13249) 2026-03-25 19:46:40 +08:00
Rdmclin2 4a7c89ec25 fix: discord not create thread & wechat media and connect optimize (#13228)
* fix: avoid subscribe whole channel

* chore: add start message whatever

* chore: remove typing interval

* feat: support typing keep alive

* fix: wechat redis client

* feat: add common gateway

* chore: use persistent to replace websocket

* chore: add wechat tip

* fix: add queue Handoff Succeeded stop typing

* feat: optimize connect status display and wechat connect infomation

* chore: wechat maximum 2048

* feat: support wechat files type

* feat: support wechat image upload

* feat: support wechat image resolve

* fix: lint error

* fix: lint error

* fix: postProcessUrl test case

* chore: moke file service

* chore: add page test case timeout
2026-03-25 18:43:45 +08:00
Neko 684a186e3b 🐛 fix(agent-runtime): missing agentId in context (#13250)
Authored-by-agent: Codex <267193182+codex@users.noreply.github.com>
2026-03-25 18:41:14 +08:00
Rdmclin2 e8a948cfaf style: replace plugin icon with skill icon (#13252)
chore: replace plugin icon  with skill icon
2026-03-25 18:21:36 +08:00
YuTengjing 11daf645e9 💄 style: unlock downgrade restrictions i18n and copy improvements (#13241)
* 💬 chore: add i18n keys for unlocking downgrade restrictions

Add subscription i18n keys:
- plans.downgradeWillCancel: warning shown when action cancels pending downgrade
- plans.pendingDowngrade: button text for pending downgrade target
- Update plans.downgradeTip to reflect cancellation context

LOBE-6155

* 🐛 fix: close model switch panel on clicking multi-provider item in generation mode

* 🌐 i18n: add cancel downgrade schedule translations

* 💄 style: simplify menu and tab labels for billing, credits, and usage

* 💄 style: rename switch success to downgrade and update copy

* 🌐 i18n: add switchDowngradeTarget translation key

* 🌐 i18n: sync translations for downgrade schedule keys
2026-03-25 16:44:49 +08:00
Rdmclin2 a4a03eadc4 chore: remove like github star footer (#13246) 2026-03-25 16:29:04 +08:00
Innei 04ddb992d1 🐛 fix(desktop): add missing Stats and Creds tabs to Electron componentMap (#13243) 2026-03-25 16:27:37 +08:00
LobeHub Bot 991de25b97 🌐 chore: translate non-English comments to English in packages/openapi (#13184)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 15:42:28 +08:00
Arvin Xu 056f390abc 🐛 fix: use partial-json fallback in ToolArgumentsRepairer to recover incomplete args (#13239)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:50:34 +08:00
Rdmclin2 9b9949befa chore: remove runtime config in agent builder and doc writer (#13238) 2026-03-25 12:54:35 +08:00
LobeHub Bot 366b02bb46 test: add unit tests for topicReference serverRuntime (#13055)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 12:31:45 +08:00
Hardy ad2087cf65 feat: add Coding Plan providers support (#13203)
*  feat: add Aliyun Bailian Coding Plan provider

- Add new AI provider for Bailian Coding Plan (coding.dashscope.aliyuncs.com/v1)
- Support 8 coding-optimized models: Qwen3.5 Plus, Qwen3 Coder Plus/Next, Qwen3 Max, GLM-5/4.7, Kimi K2.5, MiniMax M2.5
- Reuse QwenAIStream for stream processing
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add MiniMax Coding Plan provider

- Add new AI provider for MiniMax Token Plan (api.minimax.io/v1)
- Support 6 models: MiniMax-M2.7, M2.7-highspeed, M2.5, M2.5-highspeed, M2.1, M2
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add GLM Coding Plan provider

- Add new AI provider for GLM Coding Plan (api.z.ai/api/paas/v4)
- Support 6 models: GLM-5, GLM-5-Turbo, GLM-4.7, GLM-4.6, GLM-4.5, GLM-4.5-Air
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add Kimi Code Plan provider

- Add new AI provider for Kimi Code Plan (api.moonshot.ai/v1)
- Support 3 models: Kimi K2.5, Kimi K2, Kimi K2 Thinking
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add Volcengine Coding Plan provider

- Add new AI provider for Volcengine Coding Plan (ark.cn-beijing.volces.com/api/coding/v3)
- Support 5 models: Doubao-Seed-Code, Doubao-Seed-Code-2.0, GLM-4.7, DeepSeek-V3.2, Kimi-K2.5
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: update coding plan providers default enabled models and configurations

*  feat: add reasoningBudgetToken32k and reasoningBudgetToken80k slider variants

- Add ReasoningTokenSlider32k component (max 32*1024)
- Add ReasoningTokenSlider80k component (max 80*1024)
- Add reasoningBudgetToken32k and reasoningBudgetToken80k to ExtendParamsType
- Update ControlsForm to render appropriate slider based on extendParams
- Update ExtendParamsSelect with new options and previews
- Fix ReasoningTokenSlider max value to use 64*Kibi (65536) instead of 64000

* 🔧 fix: support reasoningBudgetToken32k/80k in ControlsForm and modelParamsResolver

- Add reasoningBudgetToken32k and reasoningBudgetToken80k fields to chatConfig type and schema
- Update ControlsForm to use correct name matching for 32k/80k sliders
- Add processing logic for 32k/80k params in modelParamsResolver
- Add i18n translations for extendParams hints

* 🎨 style: use linear marks for reasoning token sliders (32k/80k)

- Switch from log2 scale to linear scale for equal mark spacing
- Add minWidth/maxWidth constraints to limit slider length
- Fix 64k and 80k marks being too close together

* 🎨 fix: use equal-spaced index for reasoning token sliders (32k/80k)

- Slider uses index [0,1,2,3,...] for equal mark spacing
- Map index to token values via MARK_TOKENS array
- Add minWidth/maxWidth to limit slider length when marks increase

*  feat: add reasoningBudgetToken32k for GLM-5 and GLM-4.7 in Bailian Coding Plan

* 🔧 fix: update coding plan API endpoints and model configurations

- minimaxCodingPlan: change API URL to api.minimaxi.com (China site)
- kimiCodingPlan: change API URL to api.kimi.com/coding/v1
- volcengineCodingPlan: update doubao-seed models with correct deploymentName, pricing
- volcengineCodingPlan: add minimax-m2.5 model
- bailianCodingPlan & volcengineCodingPlan: remove unsupported extendParams from minimax-m2.5

*  feat: add Coding Plan tag to provider cards with i18n support

* ♻️ refactor: set showModelFetcher to false for Bailian Coding Plan

- Coding Plan does not support fetching model list via API
- Set both modelList.showModelFetcher and settings.showModelFetcher to false

* 🔧 fix: correct Coding Plan exports case in package.json

*  feat: update coding plan models with releasedAt and remove pricing

* 🔧 fix: remove unsupported reasoning abilities from MiniMax Coding Plan models

* 🐛 fix(modelParamsResolver): fix reasoningBudgetToken32k/80k not being read when enableReasoning is present

- Add nested logic to check which budget field (32k/80k/generic) the model supports when enableReasoning is true
- Move reasoningBudgetToken32k/80k else-if branches before reasoningBudgetToken to ensure correct field is read
- Fix GLM-5/GLM-4.7 models sending wrong budget_tokens value to API
2026-03-25 11:53:16 +08:00
LobeHub Bot 0689dd68a3 🌐 chore: translate non-English comments to English in routes and layout (#13210)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:52:28 +08:00
LobeHub Bot 75ea33153f 🌐 chore: translate non-English comments to English in packages/agent-runtime (#13236)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:51:28 +08:00
YuTengjing dbff1e0668 🐛 fix: default topic display mode to byUpdatedTime and fix nanoBanana2 resolution enum (#13235) 2026-03-25 11:17:41 +08:00
LobeHub Bot afefe217db test: add unit tests for eval-dataset-parser (#13197)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 10:55:58 +08:00
Arvin Xu fed8b39957 feat: desktop support connect to gateway (#13234)
* support desktop gateway

* support device mode

* support desktop

* fix tests

* improve

* fix tests

* fix tests

* fix case
2026-03-25 10:43:15 +08:00
Rdmclin2 f853537695 Add /new and /stop slash commands for bot message management (#13194)
*  feat(bot): implement /new and /stop slash commands

Add Chat SDK slash command handlers for bot integrations:
- /new: resets conversation state so the next message starts a fresh topic
- /stop: cancels any active agent execution on the current thread

https://claude.ai/code/session_01MDofskrz64tRjh2T6xzGBL

* feat: support telegram text type  commands

* fix: stop commands

* feat: register discord slash commands

* feat: add chat adapter patch

* feat: add interuption action

* chore: add agent thread interuption signal

* chore: optimize interruption result

* fix: /stop command message edit

* chore: create a message when interrupted

* chore: add bot test case

* chore: fix test case

* chore: fix test case and remove duplicate completion

* fix: lint error

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-25 00:31:01 +08:00
Baki Burak Öğün 0cdaf117cb 🌐 fix(locale): translate missing Turkish (tr-TR) strings (#13196)
fix(locale): translate missing Turkish (tr-TR) strings in setting.json

- Translate agentCronJobs.clearTopics, clearTopicsFailed, confirmClearTopics
- Translate agentCronJobs.confirmDeleteCronJob, deleteCronJob, deleteFailed

Co-authored-by: bakiburakogun <bakiburakogun@users.noreply.github.com>
2026-03-25 00:11:55 +08:00
Innei ada555789d 🐛 fix(editor): reset editor state when switching to empty page (#13229)
Fixes LOBE-6321
2026-03-24 21:37:08 +08:00
Arvin Xu 007d2dc554 🐛 fix: compress uploaded images to max 1920px before sending to API (#13224)
* 🐛 fix: compress uploaded images to max 1920px before sending to API

Anthropic API rejects images exceeding 2000px in multi-image requests.
Compress images during upload to stay within limits while preserving
original aspect ratio and format (no webp conversion).

Fixes LOBE-6315

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: skip canvas compression for GIF and SVG images

Canvas serialization flattens animated GIFs and rasterizes SVGs.
Restrict compression to safe raster formats: JPEG, PNG, WebP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: always compress images to PNG to avoid MIME mismatch

canvas.toDataURL with original file type can produce content that
doesn't match the declared MIME type, causing Anthropic API errors.
Always output PNG which is universally supported and consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: progressively shrink images to stay under 5MB API limit

If compressed PNG still exceeds 5MB, progressively reduce dimensions
by 20% until it fits. Also triggers compression for small-dimension
images that exceed 5MB file size.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: extract compressImageFile to utils and add comprehensive tests

Move compressImageFile, COMPRESSIBLE_IMAGE_TYPES, and constants to
@lobechat/utils/compressImage for reusability and testability.
Add tests for: dimension compression, file size limit, format filtering,
error handling, and progressive shrinking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:23:58 +08:00
Innei 995d5ea354 🐛 fix(conversation): preserve mention runtime context (#13223)
* 🐛 fix(conversation): preserve mention context on retry

* 🐛 fix(runtime): preserve initial payload for mention context

*  feat(store): expose Zustand stores on window.__LOBE_STORES in dev

Made-with: Cursor
2026-03-24 19:50:26 +08:00
Arvin Xu 72ba8c8923 🐛 fix: add document parsing to knowledge base chunking pipeline (#13221)
* 🐛 fix: add document parsing to knowledge base chunking pipeline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix plugin title

* update

* 🐛 fix: add missing findByFileId mock in document service tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:49:26 +08:00
YuTengjing 6f65b1e65e feat: improve model switch panel with provider settings shortcut and default highlight (#13220) 2026-03-24 16:30:38 +08:00
YuTengjing 383caceb77 ♻️ refactor: rename getBusinessMenuItems to useBusinessMenuItems hook (#13219) 2026-03-24 15:58:29 +08:00
Rdmclin2 b4862f2942 🐛 fix: manual tool disabled (#13218)
fix: manual tool disabled
2026-03-24 15:24:18 +08:00
YuTengjing d1affa8e44 🌐 feat(i18n): add userPanel.upgradePlan i18n key (#13213) 2026-03-24 15:20:34 +08:00
Innei 6e3053fcb3 feat(cli): add generated man pages (#13200) 2026-03-24 14:46:56 +08:00
Innei b845ba4476 🔨 chore(vite): support direct markdown imports (#13216)
 feat(vite): support markdown imports
2026-03-24 14:33:57 +08:00
LiJian 7c00650be5 ♻️ refactor: add the user creds modules & skill should auto inject the need creds (#13124)
* feat: add the user creds modules & skill should auto inject the need creds

* feat: add the builtin creds tools

* fix: add some prompt in creds & codesandbox

* fix: open this settings/creds in community plan

* fix: refacoter the settings/creds the ui

* feat: improve the tools inject system Role

* feat: change the settings/creds mananger ui

* fix: add the creds upload Files api

* feat: should call back the files creds url
2026-03-24 14:28:23 +08:00
Innei 5bc015a746 🐛 fix: move nodrag from TabBar container to individual TabItems (#13211) 2026-03-24 11:33:00 +08:00
Arvin Xu 6757e10ec2 🐛 fix: map unsupported time_range values for Search1API (#13208)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:22:04 +08:00
Arvin Xu 48428594c3 🐛 fix: correct Search1API response parsing to match actual API format (#13207)
* 🐛 fix: correct Search1API response parsing to match actual API format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix tests

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 02:18:28 +08:00
Innei 6a45414b46 🐛 fix(electron): reserve titlebar control space (#13204)
* 🐛 fix(electron): reserve titlebar control space

* 🐛 fix(electron): update titlebar padding for Windows control space
2026-03-23 23:29:55 +08:00
Arvin Xu 0f53490633 🐛 fix: fix anthropic claude model max window tokens (#13206)
* fix anthropic max tokens

* fix anthropic max tokens

* clean

* fix tests
2026-03-23 23:01:31 +08:00
Rdmclin2 66fba60194 fix: add discord redisClient lost problem (#13205) 2026-03-23 21:13:03 +08:00
YuTengjing fadaeef8d3 feat: add GLM-5 model support to LobeHub provider (#13189) 2026-03-23 17:46:32 +08:00
CanisMinor 3c5249eae7 📝 docs: fix agent usage typo (#13198)
docs: fix agent usage
2026-03-23 14:14:58 +08:00
Innei 9eca3d2ec0 ♻️ refactor(store): replace dynamic imports with static imports in actions (#13159)
Made-with: Cursor
2026-03-23 14:11:04 +08:00
Innei 4e89a00d2a feat(cli): add shell completion and migrate to tsdown (#13164)
* 👷 build(cli): migrate bundler from tsup to tsdown

Made-with: Cursor

* 🔧 chore(cli): update package.json and tsdown.config.ts dependencies

- Moved several dependencies from "dependencies" to "devDependencies" in package.json.
- Updated the bundling configuration in tsdown.config.ts to simplify the bundling process.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(cli): reorganize package.json and tsdown.config.ts

- Moved "fast-glob" from "dependencies" to "devDependencies" in package.json for better clarity.
- Removed the "onlyBundle" option from tsdown.config.ts to streamline the configuration.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(cli): add shell completion support

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-23 14:10:39 +08:00
LobeHub Bot 89a0211adf 🌐 chore: translate non-English comments to English in plugindevmodal and image-config (#13169)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 13:29:46 +08:00
Rdmclin2 ecde45b4ce feat: support wechat bot (#13191)
* feat: support weixin channel

* chore: rename to wechat

* chore: refact wechat adapter with ilink spec

* feat: add qrcode generate and refresh

* chore: update wechat docs

* fix: qrcode

* chore: remove developer mode restrict

* fix: wechat link error

* chore: add thread typing

* chore: support skip progressMessageId

* fix: discord eye reaction

* chore: resolve CodeQL regex rule

* test: add chat adapter wechat test case

* chore: wechat refresh like discord

* fix: perist token and add typing action

* chore: bot cli support weixin

* fix: database test case
2026-03-23 12:52:11 +08:00
LiJian 1df02300bc 🐛 fix: add the lost desktop community skill page (#13170)
fix: add the lost desktop community skill page
2026-03-23 10:48:47 +08:00
Rdmclin2 637ef4a84e 🔨 chore: remove default calculator (#13162)
* chore: remove calculator from RECOMMENDED_SKILLS

* chore: add default uninstalled builtin list

* fix: ensure uninstall tool loaded

* fix: lint error
2026-03-22 23:15:59 +08:00
Zhijie He 7af4562a60 💄 style: add Tencent Hunyuan 3.0 ImageGen support (#13166) 2026-03-22 12:54:27 +08:00
Sun13138 f9166133a7 🐛 fix(mobile): render topic menus and rename popovers inside active overlay container (#12477) 2026-03-22 01:15:28 +08:00
René Wang 81bd6dc732 📝 docs: add changelog entries for Jan–Mar 2026 (#13163)
* 📝 docs: add changelog entries for Jan–Mar 2026

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: Changelog content

* feat: Changelog content

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:53:48 +08:00
Arvin Xu b97c33a29a 🔧 chore: grant write permissions to Claude Code Action workflow (#13173)
Allow Claude Code to push branches and create PRs by upgrading
contents/pull-requests/issues permissions from read to write,
and adding git/gh to allowed tools.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:39:28 +08:00
Rylan Cai b0253d05dd 🔧 chore: adjust jina timeout to 15s (#13171)
🔧 adjust jina timeout setting
2026-03-21 14:39:15 +08:00
Neko 48c3f0c23b feat(memory): support to delete all memory entries (#13161) 2026-03-20 23:32:28 +08:00
LobeHub Bot f812d05ca6 🌐 chore: translate non-English comments to English in openapi services (#13092)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:31:02 +08:00
Neko 88935d84bf 🔧 chore(memory): analysis action icon not aligned (#13160) 2026-03-20 21:39:50 +08:00
Rdmclin2 c39ba410f2 📝 docs: spilit feishu with lark and update overview (#13165)
chore: spilit feishu with lark and update overview
2026-03-20 21:31:33 +08:00
sxjeru 12280badbd 🐛 fix: adjust historyCount calculation to include accurate user messages (#13051) 2026-03-20 21:26:25 +08:00
Rdmclin2 e18855aa25 🔨 chore: bot architecture upgrade (#13096)
* chore: bot architecture upgrade

* chore: unify schema definition

* chore: adjust channel schema

* feat: add setting render page

* chore: add i18n files

* chore: tag use field.key

* chore: add i18n files

* chore: add dev mode

* chore: refactor body to header and footer with body

* chore: add dev portal dev

* chore: add showWebhookUrl config

* chore: optimize form render

* feat: add slack channel

* chore: add new bot platform docs

* chore: unify applicationId to replace appId

* chore: add instrumentation file logger

* fix: gateway client error

* feat: support usageStats

* fix: bot settings pass and add  invalidate

* chore: update delete modal title and description

* chore: adjust save and connect button

* chore: support canEdit function

* fix: platform specific config

* fix: enable logic reconnect

* feat: add connection mode

* chore: start  gateway service in local dev env

* chore: default add a thread in channel when on mention at discord

* chore: add necessary permissions for slack

* feat: support charLimt and debounceMS

* chore: add schema maximum and minimum

* chore: adjust debounceMs and charLimit default value

* feat: support reset to default settings

* chore: hide reset when collapse

* fix: create discord bot lost app url

* fix: registry test case

* fix: lint error
2026-03-20 20:34:48 +08:00
Innei a64f4bf7ab 🔨 chore(desktop): bust stable release manifest cache (#13157)
🐛 fix(desktop): bust stable release manifest cache
2026-03-20 20:12:45 +08:00
Rylan Cai e577c95fa8 🐛 fix: should record unique case id in eval dataset (#13129)
* fix: should capture id if dataset has

* fix: should use unique case id
2026-03-20 19:07:36 +08:00
LobeHub Bot 15cda726a0 🌐 chore: translate non-English comments to English in chat-input-features (#13119)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 18:58:12 +08:00
lobehubbot b53abaa3b2 🔖 chore(release): release version v2.1.44 [skip ci] 2026-03-20 10:39:27 +00:00
lobehubbot 12c325494d Merge remote-tracking branch 'origin/main' into canary 2026-03-20 10:37:53 +00:00
YuTengjing 0edc57319e 🚀 release: 20260320 (#13155)
fix (#13110).
Fixed empty editor state structure and wide screen layout (#13131).
Fixed missing `BusinessAuthProvider` slot in auth layout (#13130).
Fixed artifacts code scroll preservation while streaming (#13114).
Fixed SSRF block error distinction from network errors (#13103).
Fixed Responses API tool pairing and context limit errors (#13078).
Fixed missing `userId` in embeddings API calls (#13077) and
Fixed unsupported xAI reasoning penalties pruning (#13066).
Fixed market OIDC lost call tools error (#13025).
Fixed `jsonb ?` operator usage to avoid Neon `rt_fetch` bug (#13040).
Fixed model provider popup problems (#13012).
Fixed agent-level memory config priority over user settings (#13018).
Fixed multi-provider model item selection (#12968).
Fixed agent stream error in local dev (#13054).
Fixed skill crash (#13011).
Fixed desktop agent-browser upgrade to v0.20.1 (#12985).
Fixed topic share modal inside router (#12951).
Fixed Enter key submission during IME composition (#12963).
Fixed error collapse default active key (#12967).
2026-03-20 18:37:09 +08:00
Rylan Cai 4d360714ad 🐛 fix: fix compression UI (#13113)
* 🐛 fix: restore eval pass@1 display after compression

* ♻️ refactor: narrow eval compression pass@1 fix scope

* ♻️ refactor: reduce eval compression fix to parser core

* 🐛 fix compressed group indexing type narrowing

*  add conversation-flow compression tests

*  fix orphan structuring test expectation
2026-03-20 17:23:02 +08:00
LobeHub Bot 9d441c5ab3 🌐 chore: translate non-English comments to English in packages/openapi/src/controllers (#13146)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 17:13:41 +08:00
YuTengjing abd152b805 🐛 fix: misc UI/UX improvements and bug fixes (#13153) 2026-03-20 16:42:16 +08:00
LobeHub Bot c0834fb59d test: add unit tests for rbac utils (#13150)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:33:41 +08:00
CanisMinor 2067cb2300 💄 style: add image/video switch (#13152)
* style: add image/video switch

* style: update i18n
2026-03-20 15:55:53 +08:00
Innei cada9a06fc 🔧 chore(vercel): add SPA asset cache headers and no-store for dev proxy (#13151)
Made-with: Cursor
2026-03-20 14:45:19 +08:00
Innei cd75228933 👷 build(ci): add dedicated docker canary tag (#13148) 2026-03-20 14:38:58 +08:00
CanisMinor 57469f860e 💄 style: redesign image / video (#13126)
* ♻️ refactor: Refactor image and video

* chore: rabase canary

* style: update

* style: update

* style: update

* style: update

* style: update

* style: update

* style: update

* chore: update i18n

* style: update

* fix: fix config

* fix: fix proxy

* fix: fix type

* chore: fix test
2026-03-20 14:10:01 +08:00
Arvin Xu d3ea4a4894 ♻️ refactor: refactor agent-runtime hooks mode (#13145)
*  feat: add Agent Runtime Hooks — external lifecycle hook system

Hooks are registered once and automatically adapt to runtime mode:
- Local: handler functions called directly (in-process)
- Production: webhook configs persisted to Redis, delivered via HTTP/QStash

- HookDispatcher: register, dispatch, serialize hooks per operationId
- AgentHook type: id, type (beforeStep/afterStep/onComplete/onError),
  handler function, optional webhook config
- Integrated into AgentRuntimeService.createOperation + executeStep
- Hooks persisted in AgentState.metadata._hooks for cross-request survival
- Dispatched at both normal completion and error paths
- Non-fatal: hook errors never affect main execution flow

LOBE-6208

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

*  test: add HookDispatcher unit tests (19 tests)

Tests cover:
- register/unregister/hasHooks
- Local mode dispatch: matching types, multiple handlers, error isolation
- Production mode dispatch: webhook delivery, body merging, mode isolation
- Serialization: getSerializedHooks filters webhook-only hooks
- All hook types: beforeStep, afterStep, onComplete, onError

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

*  feat: migrate SubAgent to hooks + add afterStep dispatch + finalState

- AgentHookEvent: added finalState field (local-mode only, stripped from webhooks)
- AgentRuntimeService: dispatch afterStep hooks alongside legacy callbacks
- AiAgentService: createThreadHooks() replaces createThreadMetadataCallbacks()
  for SubAgent Thread execution — same behavior, using hooks API
- HookDispatcher: strip finalState from webhook payloads (too large)

LOBE-6208

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: add Vercel bypass header to QStash hook webhooks

Preserves x-vercel-protection-bypass header when delivering hook
webhooks via QStash, matching existing behavior in
AgentRuntimeService.deliverWebhook and libs/qstash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

*  feat: migrate Eval Run to hooks + add finalState to AgentHookEvent

Eval Run now uses hooks API instead of raw completionWebhook:
- executeTrajectory: hook with local handler + webhook fallback
- executeThreadTrajectory: hook with local handler + webhook fallback
- Local mode now works for eval runs (previously production-only)

Also:
- AgentHookEvent: added finalState field (local-only, stripped from webhooks)
  for consumers that need deep state access

LOBE-6208

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: dispatch beforeStep hooks + fix completion event payload fields

P1: Add hookDispatcher.dispatch('beforeStep') alongside legacy
onBeforeStep callback. All 4 hook types now dispatch correctly:
beforeStep, afterStep, onComplete, onError.

P2: Fix completion event payload to use actual AgentState fields
(state.cost.total, state.usage.llm.*, state.messages) instead of
non-existent state.session.* properties. Matches the field access
pattern in triggerCompletionWebhook.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: update eval test assertions for hooks migration + fix status type

- Test: update executeTrajectory assertion to expect hooks array
  instead of completionWebhook object
- Fix: add fallback for event.status (string | undefined) when passing
  to recordTrajectoryCompletion/recordThreadCompletion (status: string)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: update SubAgent test assertions for hooks migration

Update execGroupSubAgentTask tests to expect hooks array instead of
stepCallbacks object, matching the SubAgent → hooks migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:05:25 +08:00
Rylan Cai 6ce9d9a814 🐛 fix: agent stream error in local dev (#13054)
* 🐛 fix: close local agent streams on terminal errors

* ♻️ refactor: revert redundant cli stream error handling

* 🧪 test: remove redundant cli stream error test

* wip: prune tests

* 🐛 fix: guard terminal agent runtime end step index
2026-03-20 11:39:54 +08:00
Neko f51da14f07 🔧 chore(locales): use "created" for "sent" in "sent x messages" (#13140) 2026-03-20 11:08:13 +08:00
Protocol Zero bc8debe836 🐛 fix(chat): strip forkedFromIdentifier before LLM API request (#13142)
fix(chat): strip forkedFromIdentifier before LLM API request

Fork & Chat stores forkedFromIdentifier in agent.params for DB lookup.
Spreading params into the chat payload forwarded it to Responses API,
causing strict providers (e.g. AiHubMix) to reject the request.

Remove the field in getChatCompletion alongside existing non-API keys.

Fixes lobehub/lobehub#13071

Made-with: Cursor
2026-03-20 11:07:29 +08:00
Neko 1b909a74d7 🔧 chore(locales): missing category locale for productivity (#13141) 2026-03-20 03:46:23 +08:00
Arvin Xu 04f963d1da ♻️ refactor: use incremental diff for snapshot messages to prevent OOM (#13136)
* ♻️ refactor: use incremental diff for snapshot messages to prevent OOM

Replace full messages/messagesAfter duplication per step with baseline + delta approach:
- Step 0 and compression resets store full messagesBaseline
- Other steps store only messagesDelta (new messages added)
- Strip llm_stream events from snapshot (not useful for post-analysis)
- Strip messages from done.finalState (reconstructible from delta chain)
- Strip duplicate toolResults from context.payload
- Reduce context_engine_result event size by removing messages and toolsConfig
- Add reconstructMessages() utility for rebuilding full state from delta chain
- AiAgentService constructor now accepts runtimeOptions for DI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: add incremental toolset delta for snapshot

- Store operationToolSet as toolsetBaseline in step 0 only (immutable)
- Track activatedStepTools changes via per-step activatedStepToolsDelta
- Strip operationToolSet/toolManifestMap/tools/toolSourceMap from done.finalState
- Add reconstructToolsetBaseline() and reconstructActivatedStepTools() utilities

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: correct snapshot delta recording and restore context-engine output

- P1: messagesDelta now always stores only appended messages (afterMessages.slice),
  fixing duplication when isBaseline was true (step 0 / compression reset)
- P2: Restore context_engine_result.output (processedMessages) — needed by
  inspect CLI for --env, --system-role, and -m commands
- Add P1 regression test for message deduplication

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 01:01:35 +08:00
YuTengjing d6f75f3282 feat(model-runtime): add xiaomimimo to RouterRuntime base runtime map (#13137) 2026-03-20 01:01:06 +08:00
YuTengjing 563f4a25f1 💄 style: add XiaomiMiMo LobeHub-hosted model cards and fix pricing (#13133) 2026-03-19 23:51:23 +08:00
Zhijie He e2d25be729 💄 style: add mimo-v2-pro & mimo-v2-omni support (#13123) 2026-03-19 22:14:20 +08:00
Innei 80cb6c9d11 feat(chat-input): add category-based mention menu (#13109)
*  feat(chat-input): add category-based mention menu with keyboard navigation

Replace flat mention list with a structured category menu (Agents, Members, Topics).
Supports home/category/search views, Fuse.js fuzzy search, floating-ui positioning,
and full keyboard navigation.

* 🔧 chore: update @lobehub/editor to version 4.3.0 and refactor type definition in useMentionCategories

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(MentionMenu): enhance icon rendering logic in MenuItem component

Updated the MenuItem component to improve how icons are rendered. Now, it checks if the icon is a valid React element or a function, ensuring better flexibility in icon usage. This change enhances the overall user experience in the mention menu.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/editor to version 4.3.1 in package.json

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-19 21:48:10 +08:00
YuTengjing 57ec43cd00 🐛 fix(database): add drizzle-zod and zod as peer dependencies to fix type-check errors (#13132) 2026-03-19 21:24:41 +08:00
Innei 0f67a5b8d7 💄 style(desktop): improve WelcomeStep layout centering in onboarding (#13125)
* 💄 style(desktop): improve WelcomeStep layout centering in onboarding

Made-with: Cursor

* 🐛 fix(desktop): validate remote server URL in isRemoteServerConfigured

Made-with: Cursor
2026-03-19 21:18:41 +08:00
Innei 8d387a98a0 🐛 fix(editor): correct empty editor state structure and wide screen layout (#13131)
- Fix EMPTY_EDITOR_STATE with proper Lexical node structure (root id, paragraph id)
- Add flex-grow to WideScreenContainer for proper editor canvas expansion

Made-with: Cursor
2026-03-19 21:07:18 +08:00
YuTengjing 3931aa9f76 🐛 fix(auth): add BusinessAuthProvider slot to auth layout (#13130) 2026-03-19 18:56:45 +08:00
YuTengjing 73d46bb4c4 feat(ci): add Claude PR auto-assign reviewer workflow (#13120) 2026-03-19 16:13:01 +08:00
Innei f827b870c3 feat(version): display actual desktop app version with canary suffix (#13110)
*  feat(version): display actual desktop app version with canary suffix

Add support for fetching and displaying the desktop application's actual version number in the About section. When running on desktop, the version now displays the desktop app's version (including canary suffix if applicable), falling back to the web version if unavailable.

- Add getAppVersion IPC method in SystemController
- Create versionDisplay utility module with comprehensive tests
- Integrate desktop version fetching in Version component

* ♻️ refactor(desktop): inject about version at build time
2026-03-19 14:24:03 +08:00
Neko efd99850df feat(agentDocuments): added agent documents impl, and tools (#13093) 2026-03-19 14:05:02 +08:00
Neko 87c770cda7 🔨 chore: use percentage value for Codecov (#13121)
build: use percentage value
2026-03-19 13:28:48 +08:00
YuTengjing 715481c471 🐛 fix(portal): preserve artifacts code scroll while streaming (#13114) 2026-03-19 00:35:20 +08:00
YuTengjing 25e1a64c1b 💄 style: update Grok 4.20 to 0309 and add MiniMax M2.7 models (#13112) 2026-03-19 00:05:07 +08:00
Innei 465c9699e7 feat(context-engine): inject referenced topic context into last user message (#13104)
*  feat: inject referenced topic context into last user message

When users @refer_topic in chat, inject the referenced topic's summary
or recent messages directly into the context, reducing unnecessary tool calls.

* 🐛 fix: include agentId and groupId in message retrieval for context engineering

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: skip topic reference resolution for messages with existing topic_reference_context

Added logic to prevent double injection of topic references when messages already contain the topic_reference_context. Updated tests to verify the behavior for both cases: when topic references should be resolved and when they should be skipped.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-18 21:58:41 +08:00
Innei ac29897d72 ♻️ refactor(perf): user message renderer (#13108)
refactor(perf): user message renderer
2026-03-18 21:58:29 +08:00
YuTengjing 1df5ae32f1 🐛 fix: distinguish SSRF block errors from network errors (#13103) 2026-03-18 18:16:19 +08:00
Innei 8a90f79c11 ♻️ refactor(nav): remove devOnly mode from nav layout and stabilize Footer (#13101)
* ♻️ refactor(nav): remove devOnly mode from nav layout and stabilize Footer during panel transitions

- Remove devOnly filtering from useNavLayout, treat all items as non-dev mode
- Move Pages to top nav position, remove video/image/settings/memory nav items
- Extract Footer from SideBarLayout into NavPanelDraggable outside animation layer
- Show settings ActionIcon in Footer when dev mode is enabled (hidden on settings page)

* 🔧 fix(footer): update settings icon in Footer component

- Replace Settings2 icon with Settings icon in the Footer when dev mode is enabled, ensuring consistency in the user interface.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-18 15:44:51 +08:00
LobeHub Bot 91ec7b412b 🌐 chore: translate non-English comments to English in ProfileEditor and related features (#13048)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 15:40:07 +08:00
YuTengjing e9766be3f3 🐛 fix: pass userId in initModelRuntimeFromDB (#13100) 2026-03-18 15:11:29 +08:00
Rylan Cai 52652866e0 feat: support server context compression (#12976)
* ♻️ refactor: add eval-only server context compression

* ♻️ refactor: align eval compression with runtime step flow

* ♻️ refactor: trim redundant call_llm diff

*  add mid-run context compression step

* 📝 document post compression helper

* 🐛 revert unnecessary agent runtime service diff

* ♻️ refactor: clean up context compression follow-up logic

* ♻️ refactor: move compression gate before call llm

* ♻️ refactor: make call llm compression gate explicit

* ♻️ refactor: restore agent-side compression checks

* ♻️ refactor: rename agent llm continuation helper

* ♻️ refactor: inline agent compression helper

* ♻️ refactor: preserve trailing user message during compression

* 📝 docs: clarify toLLMCall refactor direction

*  test: add coverage for context compression flow

*  reset: unstash
2026-03-18 12:48:34 +08:00
YuTengjing 95ef230354 💄 style: add GPT-5.4 mini and nano models (#13094) 2026-03-18 12:34:31 +08:00
lobehubbot b894622dfe Merge remote-tracking branch 'origin/main' into canary 2026-03-18 04:29:39 +00:00
Arvin Xu ae77fee1b8 👷 build: add settings column to agent_bot_providers (#13081) 2026-03-18 12:28:58 +08:00
YuTengjing 7cd4b1942f 💄 style: use credit terminology in auto top-up tooltips (#13091) 2026-03-18 11:12:39 +08:00
Rylan Cai 69c24c714e 🔧 chore(eval): improve trajectory workflow controls and execution metadata (#13049)
* 🔧 chore(search): reduce Exa default result count

* 🐛 fix(eval): relax run input schema limits

*  feat(agent): persist tool execution time in message metadata

* 🔧 chore(eval): add flow control to trajectory workflows

* 🧪 test: adjust Exa numResults expectation
2026-03-18 10:29:49 +08:00
Sirui He 3a789dc612 🐛 fix: SPA HTML entry returns stale content after server upgrade (#12998)
fix: add no-cache header to SPA HTML entry point

Prevent stale SPA HTML from being served after server upgrades.
JS/CSS assets still cache normally via hashed filenames.
2026-03-18 01:27:52 +08:00
Xial 46455cb6c3 🐛 fix: load PDF.js worker from local assets via Vite ?url import (#13006) 2026-03-18 01:26:10 +08:00
YuTengjing 81becc3583 🐛 fix(model-runtime): handle Responses API tool pairing and context limit errors (#13078) 2026-03-18 00:07:10 +08:00
YuTengjing cb0037ce1e 🐛 fix: pass userId to all embeddings API calls (#13077) 2026-03-17 23:44:34 +08:00
Innei 03f3a2438c 🐛 fix(skills): repair db-migrations frontmatter (#13073) 2026-03-17 23:32:14 +08:00
Innei 4994d19a9c 🐛 fix(desktop): remove electron-liquid-glass to fix click event blocking (#13070)
* 🐛 fix(desktop): remove electron-liquid-glass to fix click event blocking

The electron-liquid-glass native addon was blocking all click events in the
Electron desktop app window. Remove the dependency and restore vibrancy-based
transparency with semi-transparent body background via `.desktop` CSS class.

* 🔨 chore(desktop): remove electron-liquid-glass from native modules config
2026-03-17 22:56:29 +08:00
YuTengjing f8d51bbf4f 🐛 fix(model-runtime): filter internal thinking content in openai-compatible payloads (#13067) 2026-03-17 22:28:08 +08:00
YuTengjing 189e5d5a20 🐛 fix(model-runtime): prune unsupported xAI reasoning penalties (#13066) 2026-03-17 22:27:59 +08:00
Innei b2122a5224 ♻️ refactor: replace per-message useNewScreen with centralized useConversationSpacer (#13042)
* ♻️ refactor: replace per-message useNewScreen with centralized useConversationSpacer

Replace the old per-message min-height approach with a single spacer element appended to the virtual list, simplifying scroll-to-top UX when user sends a new message.

* 🔧 refactor: streamline handleSendButton logic and enhance editor focus behavior

Removed redundant editor null check and added double requestAnimationFrame calls to ensure the editor is focused after sending a message.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-17 21:19:58 +08:00
Innei d2d9e6034e 🐛 fix(chat): clear input immediately on send to preserve drafts during streaming (#13038)
* 🐛 fix: clear input immediately on send to preserve drafts typed during streaming

Move inputMessage reset before the async streaming lifecycle so text
entered while the assistant is responding is not overwritten on completion.

Also normalize null/undefined in operation context matching so that
cancelOperations works correctly in null-topic sessions.

Fixes LOBE-2647

* 🐛 fix: resolve TS2322 null-vs-undefined type error in useOperationState test
2026-03-17 21:14:40 +08:00
YuTengjing 97f4a370ab feat: add request trigger tracking, embeddings billing hooks, and memory extraction userId fix (#13061) 2026-03-17 20:54:28 +08:00
YuTengjing 62a6c3da1d 🌐 i18n: add pending_reward status translation for referral table (#13065) 2026-03-17 20:08:18 +08:00
YuTengjing 10b7906071 🔨 chore: add device fingerprint utility and pending_reward status (#13062) 2026-03-17 18:49:35 +08:00
YuTengjing 3207d14403 🔨 chore: add batch query methods for UserModel and MessageModel (#13060) 2026-03-17 18:20:03 +08:00
Innei 8f7527b7e2 feat(desktop): Linux window specialization (#13059)
*  feat(desktop): Linux window specialization

- Add minimize/maximize/close buttons for Linux (WinControl)
- Linux: no tray, close main window quits app
- Linux: native window shadow and opaque background
- i18n for window control tooltips

Made-with: Cursor

* 🌐 i18n: add window control translations for all locales

Made-with: Cursor

* 🐛 fix(desktop): show WinControl in SimpleTitleBar only on Linux

Made-with: Cursor

* 🐛 fix(desktop): limit custom titlebar controls to Linux

Avoid rendering duplicate window controls on Windows and keep the Linux maximize button in sync with the current window state.

Made-with: Cursor

---------

Co-authored-by: LiJian <onlyyoulove3@gmail.com>
2026-03-17 16:59:33 +08:00
LiJian 26269eacbb 🐛 fix: slove the market oidc lost the call tools error (#13025)
* fix: slove the market oidc lost the call tools error

* fix: add the beta-version & add some log

* fix: fixed the oidc error ts
2026-03-17 11:27:19 +08:00
Zhijie He 78cfb087b4 💄 style: update claude 4.6 series 1M contextWindow (#12994)
* style: update claude 4.6 series 1M contextWindow

* chore: cleanup bedrock search tag

chore: cleanup bedrock retired model

chore: cleanup bedrock retired model

chore: cleanup bedrock retired model

* fix: fix ci test
2026-03-17 10:58:20 +08:00
Zhijie He 2717f8a86c 💄 style: add Seedance 1.5 Pro support for OSS (#13035)
* style: add seedance 1.5 support for OSS

* style: update volcengine videoGen models
2026-03-17 10:43:25 +08:00
Arvin Xu 44e4f6e4b0 ️ perf: optimize tool system prompt — remove duplicate APIs, simplify XML tags (#13041)
* 💄 style: remove platform-specific Spotlight reference from searchLocalFiles

Replace "using Spotlight (macOS) or native search" with "using native search"
since the actual search implementation is platform-dependent and the LLM
doesn't need to know the specific backend.

Fixes LOBE-5778

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ️ perf: remove duplicate API descriptions from tool system prompt

API identifiers and descriptions are already in the tools schema passed
via the API tools parameter. Repeating them in the system prompt wastes
tokens. Now only tools with systemRole (usage instructions) are injected.

Also rename XML tags: plugins→tools, collection→tool,
collection.instructions→tool.instructions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 💄 style: inject tool description when no systemRole instead of skipping

Tools without systemRole now show their description as <tool> children.
Tools with systemRole use <tool.instructions> wrapper as before.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 💄 style: always emit <tool> tag, fallback to "no description"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* update tools

* fix

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:01:05 +08:00
Arvin Xu 9bdc3b0474 feat: improve agent context injection (skills discovery, device optimization, prompt cleanup) (#13021)
*  feat: inject all installed skills into <available_skills> for AI discovery

Previously, only skills explicitly added to the agent's plugins list appeared
in <available_skills>. Now all installed skills are exposed so the AI can
discover and activate them via activateSkill.

Changes:
- Frontend: use getAllSkills() instead of getEnabledSkills(plugins)
- Backend: pass skillMetas through createOperation → RuntimeExecutors → serverMessagesEngine
- Add skillsConfig support to serverMessagesEngine

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use DB + builtin skills for available_skills instead of provider manifests

lobehubSkillManifests are tool provider manifests (per-provider, containing
tool APIs), not skill metadata. Using them for <available_skills> incorrectly
showed provider names (e.g. "Arvin Xu") as skills.

Now fetches actual skills from AgentSkillModel (DB) + builtinSkills for correct
<available_skills> injection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 💄 style: use XML structure for online-devices in system prompt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: extract online-devices prompt to @lobechat/prompts package

Move device XML prompt generation from builtin-tool-remote-device into
the shared prompts package for reusability and consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

*  test: add failing tests for Remote Device suppression when auto-activated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ️ perf: suppress Remote Device tool when device is auto-activated

When a device is auto-activated (single device in IM/Bot or bound device),
the Remote Device management tool (listOnlineDevices, activateDevice) is
unnecessary — saves ~500 tokens of system prompt + 2 tool functions.

- Add autoActivated flag to deviceContext
- Move activeDeviceId computation before tool engine creation
- Disable Remote Device in enableChecker when autoActivated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* update system role

* update system role

* ♻️ refactor: use agentId instead of slug for OpenAPI responses model field

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use JSON round-trip instead of structuredClone in InMemoryAgentStateManager

structuredClone fails with DataCloneError when state contains non-cloneable
objects like DOM ErrorEvent (from Neon DB WebSocket errors).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: only inject available_skills when tools are enabled

Restore plugins guard to prevent skills injection when tool use is
disabled (plugins is undefined), fixing 28 test failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

*  test: update system message assertions for skills injection

Use stringContaining instead of exact match for system message content,
since available_skills may now be appended after the date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:35:18 +08:00
Arvin Xu 41c1b1ee85 🐛 fix: use jsonb ? operator to avoid Neon rt_fetch bug (#13040)
🐛 fix: use jsonb ? operator instead of ->> to avoid Neon rt_fetch bug

The ->> operator in WHERE clauses triggers a Neon-specific
`rt_fetch used out-of-bounds` error. Switch to the ? operator
which is semantically equivalent for checking key existence.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:33:35 +08:00
Innei 23385abaea ♻️ refactor: centralize NavBar dev mode logic into useNavLayout hook (#13037)
* ♻️ refactor: centralize NavBar dev mode logic into useNavLayout hook

Extract scattered isDevMode checks from Nav, BottomMenu, Footer, and
UserPanel into a single useNavLayout hook with declarative devOnly
metadata. Also restore dev-mode-gated home page modules and fix
LangButton visual alignment in UserPanel.

*  test: update PanelContent test to match LangButton Menu removal
2026-03-16 23:16:13 +08:00
YuTengjing fc5b462892 ️ perf: optimize search with BM25 indexes and ICU tokenizer (#12914) 2026-03-16 21:37:57 +08:00
LobeHub Bot 935304dbd2 🌐 chore: translate non-English comments to English in features/MCPPluginDetail (#13008)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 21:21:45 +08:00
YuTengjing d2666b735b feat: add ModelRuntime hooks for billing lifecycle interception (#13013) 2026-03-16 20:59:40 +08:00
Arvin Xu 69accd11df 🐛 fix: return structured error from invokeBuiltinTool instead of undefined (#13020)
When a builtin tool executor is not found, invokeBuiltinTool now returns
a structured error object instead of silently returning undefined. Also
adds a fallback in call_tool executor for undefined results to prevent
agent loop from terminating abnormally.

Fixes LOBE-5318

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:12:48 +08:00
lobehubbot 9fa060f01e 🔖 chore(release): release version v2.1.43 [skip ci] 2026-03-16 11:53:29 +00:00
lobehubbot 7a8f682879 Merge remote-tracking branch 'origin/main' into canary 2026-03-16 11:51:39 +00:00
YuTengjing 70a74f485a 👷 build: add BM25 indexes with ICU tokenizer for search optimization (#13032) 2026-03-16 19:50:57 +08:00
YuTengjing cec079d34b 🗃️ db: add BM25 indexes with ICU tokenizer for 14 tables 2026-03-16 19:41:19 +08:00
Innei ee8eade485 🔨 chore: add trpc mock.vite stub to stop Vite SPA warmup from traversing server router (#13022)
Made-with: Cursor
2026-03-16 18:10:35 +08:00
Rdmclin2 d9388f2c31 🐛 fix: add skill crash (#13011)
* fix: Error Page style lost

* fix: add skill button error

* chore: add add skill e2e tests

* chore: remove unnecessary skill
2026-03-16 16:46:49 +08:00
Innei bffdbf8ad4 🐛 fix: upgrade desktop agent-browser to v0.20.1 and default native mode (#12985)
* 🐛 fix(desktop): update bundled agent-browser to v0.20.1 and align native-mode docs

Upgrade desktop bundled agent-browser to 0.20.1 and remove obsolete AGENT_BROWSER_NATIVE runtime override since native mode is now default. Update builtin agent-browser skill descriptions to reflect the new default behavior.

Made-with: Cursor

*  feat: enable agent-browser skill on Windows desktop

Made-with: Cursor

* 🔧 refactor: remove isWindows from ToolAvailabilityContext interface

Updated the ToolAvailabilityContext interface to remove the isWindows property, simplifying the context checks in the isBuiltinSkillAvailableInCurrentEnv function.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-16 16:41:17 +08:00
Rdmclin2 51d6fa7579 🐛 fix: model provider pop up problems (#13012)
* fix: model provider pop up problems

* chore: optimize list scroll
2026-03-16 16:27:45 +08:00
Arvin Xu 517a67ced7 🐛 fix: respect agent-level memory config priority over user settings (#13018)
* update skills

* 🐛 fix: respect agent-level memory config priority over user settings

Agent chatConfig.memory.enabled now takes priority. Falls back to user-level
memory setting when agent config is absent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: resolve tsgo type error in memory integration test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 15:48:14 +08:00
YuTengjing 1d1e48d1b5 ♻️ refactor: split Stats into separate settings tab and update i18n (#13016)
* 🌐 i18n: add auto top-up payment method hint translations

* ♻️ refactor: split Stats into separate settings tab and rename Subscription group to Plans

* 🌐 i18n: update auto top-up payment method hint copy

* 🌐 i18n: add auto top-up payment method hint translations for all locales

* 🌐 i18n: rename Subscription Plans tab to Plans

* 🌐 i18n: add high usage FAQ, rename Text Generation to Chat Message, rename tab.plans
2026-03-16 14:45:31 +08:00
René Wang 70ef815692 🐛 fix: select first provider on click for multi-provider model items (#12968) 2026-03-16 14:08:10 +08:00
lobehubbot a2c22f705d Merge remote-tracking branch 'origin/main' into canary 2026-03-16 03:49:09 +00:00
Neko 93ee1e30af 👷 build: add agent_documents table (#12944) 2026-03-16 11:48:30 +08:00
LobeHub Bot a1fdd56565 🌐 chore: translate non-English comments to English in packages/database (#12975)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 11:01:39 +08:00
LobeHub Bot 4bfec4191e test: add unit tests for error utility functions (#12996)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 10:58:43 +08:00
LobeHub Bot cb955048f3 🌐 chore: translate non-English comments to English in openapi-services (#12993)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 11:57:00 +08:00
Arvin Xu 6a4d6c6a86 🛠 chore: support injectable snapshot store in AgentRuntimeService (#12984) 2026-03-15 01:00:56 +08:00
Arvin Xu adbf11dc11 📝 docs: update documents (#12982)
update document
2026-03-14 22:06:09 +08:00
Arvin Xu a96cac59d7 🛠 chore: add subscribeStreamEvents to InMemoryStreamEventManager (#12964)
*  feat: add subscribeStreamEvents to InMemoryStreamEventManager and use factory for stream route

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix: remove duplicate agentExecution types and fix stream route test mock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:07:46 +08:00
lobehubbot ae9e51ec12 🔖 chore(release): release version v2.1.42 [skip ci] 2026-03-14 04:03:41 +00:00
lobehubbot 6052b67953 Merge remote-tracking branch 'origin/main' into canary 2026-03-14 04:01:59 +00:00
Innei 9bb9222c3d 🐛 fix(ci): create stable update manifests for S3 publish (#12974) 2026-03-14 12:01:21 +08:00
YuTengjing 46eb28dff4 feat: add i18n keys for auto top-up feature (#12972) 2026-03-14 02:16:53 +08:00
YuTengjing 4aadfd608b 🐛 fix: require valid action for referral backfill and add anti-abuse rule (#12958) 2026-03-14 01:48:07 +08:00
Rdmclin2 942412155e feat: support skill activite switch back (#12970)
* feat: support skill activate mode

* feat: support skill panel search

* chore: update i18n files

* chore: update i18n files
2026-03-13 23:15:31 +08:00
Coooolfan 8373135253 🐛 fix: prevent Enter key submission during IME composition in LoginStep (#12963)
* 🐛 fix: prevent Enter key submission during IME composition in LoginStep

* ♻️ refactor: extract useIMECompositionEvent hook for IME composition tracking

Made-with: Cursor

---------

Co-authored-by: Innei <tukon479@gmail.com>
2026-03-13 22:41:26 +08:00
Innei 4438b559e6 feat: add slash action tags, topic reference tool, and command bus system (#12860)
*  feat: add slash action tags in chat input

Made-with: Cursor

*  feat: enhance editor with new slash actions and localization updates

- Added new slash actions: change tone, condense, expand, polish, rewrite, summarize, and translate.
- Updated localization files for English and Chinese to include new action tags and slash commands.
- Removed deprecated useSlashItems component and integrated its functionality directly into InputEditor.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add slash placement configuration to chat input components

- Introduced `slashPlacement` prop to `ChatInputProvider`, `StoreUpdater`, and `InputEditor` for customizable slash menu positioning.
- Updated initial state to include `slashPlacement` with default value 'top'.
- Adjusted `ChatInput` and `InputArea` components to utilize the new `slashPlacement` prop.

This enhancement allows for better control over the user interface in chat input interactions.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: implement command bus for slash action tags processing

Add command bus system to parse and execute slash commands (compact context,
new topic). Refactor action tag categories from ai/prompt to command/skill.
Add useEnabledSkills hook for dynamic skill registration.

* feat: compress command

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: compress

Signed-off-by: Innei <tukon479@gmail.com>

* fix: skill inject

*  feat: slash action tags with context engine integration

Made-with: Cursor

*  feat: add topic reference builtin tool and server runtime

Made-with: Cursor

*  feat: add topic mention items and update ReferTopic integration

Made-with: Cursor

* 🐛 fix: preserve editorData through assistant-group edit flow and update RichTextMessage reactively

- EditState now forwards editorData from EditorModal to modifyMessageContent
- modifyMessageContent accepts and passes editorData to updateMessageContent
- RichTextMessage uses useEditor + effect to update document on content change instead of key-based remount
- Refactored RichTextMessage plugins to use shared createChatInputRichPlugins()

*  feat(context-engine): add metadata types and update processors/providers

Made-with: Cursor

*  feat(chat-input): add slash action tags and restore failed input state

* 🔧 chore: update package dependencies and enhance Vite configuration

- Changed @lobehub/ui dependency to a specific package URL.
- Added multiple SPA entry points and layout files to the Vite warmup configuration.
- Removed unused monorepo packages from sharedOptimizeDeps and added various dayjs locales for better localization support.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to version 5.4.0 in package.json

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: correct SkillsApiName.runSkill to activateSkill and update trimmed content assertions

* 🐛 fix: resolve type errors in context-engine tests and InputEditor slashPlacement

* 🐛 fix: update runSkill to activateSkill in conversationLifecycle test

* 🐛 fix: avoid regex backtracking in placeholder parser

*  feat(localization): add action tags and tooltips for slash commands across multiple languages

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: preserve file attachments when /newTopic has no text content

* cleanup

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-13 22:17:36 +08:00
Innei d7bfd1b6c8 🐛 fix: fix error collapse default active key (#12967) 2026-03-13 21:35:35 +08:00
Innei 110f27f2ac ♻️ refactor: merge beta settings into advanced tab (#12962)
* ♻️ refactor: merge beta settings into advanced tab

- Remove dedicated beta settings tab (desktop only)
- Integrate update channel selection into advanced settings
- Rename i18n keys from tab.beta.* to tab.advanced.updateChannel.*
- Mark SettingsTabs.Beta as deprecated
- Clean up unused FlaskConical icon import
- Update all 18 locale files with migrated keys

* 🔥 chore: remove deprecated SettingsTabs.Beta enum value

* 🔀 refactor: redirect deprecated /settings/beta to /settings/advanced

* 🔥 chore: remove unnecessary beta redirect from REDIRECT_MAP

* 🐛 fix: resolve lint errors and update outdated User panel tests

---------

Co-authored-by: Arvin Xu <arvinx@foxmail.com>
2026-03-13 20:29:07 +08:00
LobeHub Bot e4d960376c test: add unit tests for search impls (brave, exa, tavily) (#12960)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 19:43:31 +08:00
lobehubbot 7bcde61e5d 🔖 chore(release): release version v2.1.41 [skip ci] 2026-03-13 10:47:25 +00:00
lobehubbot 7d2f88f384 Merge remote-tracking branch 'origin/main' into canary 2026-03-13 10:45:42 +00:00
Rdmclin2 3712d75bf8 🚀 release: 20260313 (#12956)
This release includes **~400 commits**. Key updates are below.

### New Features and Enhancements

- **Bot Platform Integration**: Added abstract bot platform layer with
**QQ Bot**, **Telegram Bot**, **Lark/Feishu Bot**, and **Discord Bot**
integrations, including remote device support for IM integration.
- **LobeHub CLI**: Full CLI implementation across 5 phases — agent
run/status, generate (text/image/video/TTS/ASR), doc, search, device,
bot integration, cron, topic share, agent KB/file/pin, thread, and eval
commands.
- **Agent Skills**: Added built-in skills management, skill store, agent
browser automation skill, and tool detection.
- **Video Generation**: End-to-end video generation feature with free
quota, webhook handling, and skeleton loading.
- **Agent Benchmark**: Added benchmark support with external scoring
mode and dedicated DB schema.
- **Memory Settings**: Support for memory effort/tool permission
configuration, user persona injection, and improved memory analysis.
- **Batch Topic Deletion** from file support.
- **Runtime Config** support for flexible deployment configuration.
- **V1 API** and **Response API** support (including OpenAI Responses
API).
- **Device Code Auth Flow** for CLI authentication.
- **Emoji Reactions** for messages.
- **Starter Suggested Questions** and recommend agents.
- **Page Tabs** for Electron desktop.
- **Sort Topics by Updated Time** option.
- **Change Email Address** in profile settings.
- **Model Detail Dropdown** in model switch panel.
- Added **unread completion indicator** for agents and topics.

### Models and Provider Expansion

- New providers: **Straico**, **LongCat (美团)**.
- Added/updated model support:
  - **GPT-5.4** series
  - **Claude Sonnet 4.6** and **Claude Opus 4.6** (including Bedrock)
  - **Gemini 3.1 Pro Preview** and **Gemini 3.1 Flash Lite Preview**
  - **Qwen3.5** series (including Flash, OSS, and SiliconCloud models)
  - **Grok 4.20** series and **Grok Imagine** image generation
  - **Kimi K2.5** thinking models
  - **MiniMax 2.5** / **MiniMax M2.5**
  - **Nano Banana 2**
  - **Seedream 5 Lite** / **Seedance 2.0**
  - **NVIDIA** new models
  - **GLM-5**, **GLM-4.6V**, **GLM-Image** for Zhipu
  - Additional Qwen image-to-image and text-to-image models
- Added video input support for SiliconCloud provider.
- Use Response API for Grok as default.

### Desktop Improvements

- Integrated `electron-liquid-glass` for macOS Tahoe.
- Unified canary with stable app name/icon, added channel tag in About.
- Support clearing hotkey bindings in ShortcutManager.
- Subscription pages embedding with webview.
- Enhanced desktop menu and navigation system.
- Proactive token refresh on app startup and activation.
- DMG background image configuration.
- S3 publish for canary/nightly with cleanup.
- Unified update channel switching with S3 distribution.

### Architecture and Infrastructure

- **Vite SPA Migration**: Migrated frontend from Next.js App Router to
Vite SPA, restructured SPA routes to `src/routes` and `src/router`.
- **Response API Support** across agent runtime.
- Refactored client agent runtime and centralized tool availability
checks.
- Added Redis pipeline support and Lua script execution.
- Database migrations: `pg_search` extension, video generation schema,
agent skills schema, benchmark schema, topics description column, API
key hash column, ID migration to nanoid.
- Preload bundled i18n resources with lazy-load for target language.
- Simplified build config, removed webpack customization, and resolved
Vercel OOM.
- Class-based Zustand actions with `flattenActions` migration.
- Extracted `@lobechat/local-file-shell` shared package.
- Resolved all ESLint suppressions and enabled `consistent-type-imports`
rule.

### Stability, Security, and UX Fixes

- Fixed model provider popup problems and ModelSelect crash.
- Fixed tool engine, input-loading, and MCP tool install loading issues.
- Hardened Anthropic message building and sampling parameter handling.
- Fixed Vertex AI 400 error from duplicate tool function declarations.
- Fixed context window exceeded error detection from message text.
- Added rate limit custom rules for password reset and email
verification.
- Fixed `sanitizeFileName` path traversal risks.
- Fixed multiple Docker build issues (`@napi-rs/canvas`, `librt.so.1`,
`ffmpeg-static`).
- Fixed desktop advanced mode, onboarding redirect, and auth modal
during onboarding.
- Added unsaved changes guard to prevent data loss on navigation.
- Fixed SiliconCloud thinking mode toggle issue.
- Improved Moonshot interleaved thinking and circular dependency.
- Fixed multimodal `content_part` images rendered as base64 text.
- Security: upgraded `next-mdx-remote` to v6 for CVE-2026-0969.

### Credits

Huge thanks to these contributors (alphabetical):

@AmAzing- @AntoineRoux @BrandonStudio @CanisMinor @Coooolfan @eronez
@Hardy @huangkairan @Innei @Kingsword @LiJian @LuisSambrano @MarcellGu
@MikeLambert @Neko @rdmclin2 @Rdmclin2 @RenéWang @RuxiaoYin @RylanCai
@Shinji-Li @Sun13138 @sxjeru @VarunChawla @WangYK @YuTengjing @Zephyr
@ZhijieHe
2026-03-13 18:45:02 +08:00
Innei 7729adcfd4 🐛 fix: support topic share modal inside router (#12951)
🐛 fix(share-modal): support topic share modal
2026-03-13 17:27:46 +08:00
René Wang a09316a474 feat: Simplify UI (#12961)
* style: Simplify the sidebar

* style: Simplify the sidebar

* style: Simplify the sidebar

* style: Simpliofy the model selct

* style: Simpliofy the model selct

* style: Simpliofy the model selct

* style: Simpliofy the agent profile

* style: Simplify the input bar

* style: Re-organize the settings

* style: Simplify the mode linfo pane

* style: Simplify agent profile

* style: Advanced settings

* style: Advanced settings

* feat: Update translation

* fix: type error

* fix: Add missing translation

* fix: Add missing translation

* fix: Remove Lite mode

* fix: Add model paramters

* style: Remove token tag

* fix: model order

* fix: model order

* fix: Add missing translation

* fix: Add missing translation

* fix: Hide the subtopic button

* fix: User plan badge

* feat: Add settings

* feat: Add cover to the lab

* style: Make the switch vertically centered

* style: Add divider

* feat: Add group by provider

* feat: Move Usage stats

* fix: Subscription badge

* fix: Rebase onto canary

* fix: Rebase onto canary

* fix: Drag to adjust width

* feat: Rebase onto canary

* feat: Regroup settings tab

* feat: Regroup settings tab

* feat: Regroup settings tab

* feat: Regroup settings tab
2026-03-13 16:48:14 +08:00
Arvin Xu a5cc75c1ed 🐛 fix: lh command issue (#12949)
* fix command issue

* add run command UI

* fix API key

* add apikey page

* add apikey

* 🐛 fix: update apiKey model tests to use new sk-lh- prefix format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:16:11 +08:00
Rdmclin2 11ce1b2f9f 🐛 fix: model provider pop up problems (#12950)
fix: model provider pop up problems
2026-03-12 22:29:04 +08:00
Rdmclin2 afb6d8d3ca feat: bot platform abstract & QQ bot intergration (#12941)
* chore: add bot platform abstract

* chore: refactor platform abstract

* feat: support QQ platform

* docs : add qq channel

* fix: crypto algorithm

* fix: discord metion thread

* fix: discord threadId bypass

* fix: edit messsage throw error

* chore: update memory tool icon

* chore: use lobe channel icon

* chore: update platfom icon color

* fix: lint error
2026-03-12 21:25:15 +08:00
Arvin Xu 04a064aaf3 feat: support batch topic deletion from file (#12931)
Add `--file` option to `lh topic delete` command, allowing users to
pass topic IDs via a file (one per line or JSON array) for bulk deletion.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:56:17 +08:00
Innei 46f9135308 ♻️ refactor(tool): centralize availability checks (#12938)
* ♻️ refactor(tool): centralize availability checks

* 🐛 fix(tool): preserve windows skill fallback

* 🐛 fix(tool): restore stdio engine filtering
2026-03-12 20:17:02 +08:00
lobehubbot 425dd81bcf 🔖 chore(release): release version v2.1.40 [skip ci] 2026-03-12 11:42:06 +00:00
lobehubbot fd90f83f0f Merge remote-tracking branch 'origin/main' into canary 2026-03-12 11:40:28 +00:00
YuTengjing 3091489695 👷 build: add description column to topics table (#12939) 2026-03-12 19:39:47 +08:00
LiJian 4065dc0565 🐛 fix: improve skill exec script way (#12926)
* fix: add the activatedSkills to improve the execScripte tools

* feat: change the activePath into call market endpoint

* fix: clean the code

* feat: fixed the execScript in desktop ts error
2026-03-12 17:29:59 +08:00
Rdmclin2 3529b46f2c 💄 style: restore foot gap (#12936)
chore: add back padding
2026-03-12 17:17:06 +08:00
Innei 8b29bb7fc9 feat: preload bundled i18n resources and lazy-load target language (#12929)
 feat: preload bundled i18n resources synchronously and reload actual language in background

For non-default languages, preload bundled en-US resources synchronously to avoid
Suspense on first render, then reload the user's actual language from backend
in the background. This ensures instant rendering with fallback text while the
correct translations load asynchronously.
2026-03-12 16:42:03 +08:00
Rdmclin2 804eb57dd8 💄 style: fix skill banner gap and apporve mode icon style (#12930)
* fix: skill banner style and footer runtime config

* fix:  approval mode icon style fix
2026-03-12 15:33:08 +08:00
Arvin Xu 2399f672e2 feat: add lobehub skill (#12922)
* add builtin lobehub skills

* refactor cloud sandbox

* refactor cloud sandbox

* improve styles
2026-03-12 14:00:35 +08:00
Arvin Xu 9c9e8e8ece 🐛 fix: tool engine and input-loading (#12908)
* 🐛 fix: ensure always-on builtin tools and user-selected plugins are enabled in tool engine

- Add alwaysOnToolIds (lobe-tools, lobe-skills) that are always enabled regardless of user selection
- Include user-selected plugins in enableChecker rules for both frontend and server-side tool engines
- Change enableCheckerFactory default from enabled to disabled (tools must be explicitly enabled via rules)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix: improve input loading state to cover sendMessage through AI generation

- Add isInputLoading state that includes sendMessage operation type, so input stays
  in loading state from the moment user sends until AI finishes generating
- Add INPUT_LOADING_OPERATION_TYPES constant (superset of AI_RUNTIME_OPERATION_TYPES + sendMessage)
- Update ChatInput to use isInputLoading instead of isAIGenerating for disable/loading state
- Update stopGenerating to cancel all input-loading operations and restore editor on cancel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  test: fix stopGenerating tests to match updated action implementation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix agent

* 🐛 fix: add missing selector mocks in toolEngineering tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:35:48 +08:00
Zhijie He 2e45e24df3 💄 style: use Response API for Grok as default (#12843)
* sytle: use Response API for Grok

* chore: add unit test for response api only, cleanup xai unit test
2026-03-12 11:22:20 +08:00
Zhijie He fded8dbb4e 🔨 chore: extend video_url support for OpenAI SDK (#12885)
* style: update moonshot models

* 🔨 chore: extend `video_url` support for OpenAI SDK

* fix: fix ci error

* hotfix: fix sensenova baseUrl error

* fix: fix kimi-k2.5 video tag from LobeHub

* fix: wenxin flag

* chore: cleanup utils

* style: add video tag for `glm-4.1/4.5v`

remove video tag for sensenova due to not support in OpenAI mode
2026-03-12 11:20:48 +08:00
LobeHub Bot 709c9749d0 🌐 chore: translate non-English comments to English in packages/openapi/src (#12873)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Arvin Xu <arvinx@foxmail.com>
2026-03-12 11:19:33 +08:00
sxjeru c07574af12 🔧 chore: refactor build scripts to prevent Vercel OOM (#12912)
* ♻️ refactor: update build scripts for improved performance and consistency

* 🐛 fix: update build:spa script to use pnpm for improved consistency
2026-03-12 10:39:29 +08:00
Arvin Xu b4624e6515 🔨 chore: add Response API support (#12918)
* add response api framework

* finish response api structure

* finish response api structure

*  feat: implement basic text generation for Response API (LOBE-5858)

- Add instructions extraction from system/developer input messages
- Add instructions param to ExecAgentParams, append to agent systemRole
- Implement extractPrompt, extractAssistantContent, extractUsage in ResponsesService
- Wire up execAgent + executeSync flow for non-streaming and streaming
- Add logprobs field to output_text content parts for schema compliance
- Fix truncation field to output string enum instead of object

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat: implement real token-level streaming for Response API (LOBE-5859)

- Replace fake streaming (executeSync → emit events) with real streaming
- Subscribe to InMemoryStreamEventManager for live stream_chunk events
- Run executeSync in background, convert text chunks to output_text.delta SSE events
- Add missing schema fields: item_id on content_part/text events, logprobs on delta/done events
- Fix content_part.added/done to include item_id per OpenResponses spec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat: implement tool calling output extraction for Response API (LOBE-5860)

- Add extractOutputItems to convert AgentState messages to OpenResponses output items
- Extract assistant tool_calls → function_call output items
- Extract tool result messages → function_call_output output items
- Skip message items for assistant messages that have tool_calls (avoid duplicates)
- Add status field to function_call_output items per OpenResponses spec
- Update FunctionCallOutputItemSchema with optional status field
- Output array reflects execution order: function_call → function_call_output → message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat: implement multi-turn conversations via previous_response_id (LOBE-5861)

Encode topicId in response.id to enable stateless multi-turn conversation
chaining. When previous_response_id is provided, extract topicId and pass
to execAgent via appContext, which automatically loads history messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix: add missing type fields for OpenResponses compliance (logprobs, item_id, input_tokens_details)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:39:08 +08:00
Arvin Xu f94f1ae08a feat(cli): CLI Phase 5 - agent KB/file/pin, thread, eval and miscellaneous command enhancements (#12920)
*  feat(cli): CLI Phase 5 - agent KB/file/pin, thread management, eval expansion

- Add agent subcommands: pin/unpin, kb-files, add-file/remove-file/toggle-file, add-kb/remove-kb/toggle-kb
- Create thread command with list/list-all/delete subcommands
- Expand eval with internal benchmark/dataset/testcase/irun management
- Move existing external eval commands under `eval ext` namespace
- Add comprehensive unit tests for all new functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 💄 style(cli): rename eval `irun` to `run` since external moved to `ext` namespace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ♻️ refactor(cli): merge external eval commands into unified tree with --external flag

Remove separate `eval ext` namespace; use `--external` flag on overlapping commands
(dataset get, run get) and integrate external-only commands directly into the tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): CLI Phase 6 - miscellaneous command enhancements

- file: add upload (hash check + create), edit (move to folder), kb-items
- user: new command with info, settings, preferences, update-avatar, update-name
- model: add batch-update, sort order
- plugin: add create (without settings, distinct from install)
- generation: add delete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:47:16 +08:00
Arvin Xu 165697ce47 feat(cli): CLI Phase 4 - cron, message, topic share, agent-group, session-group (#12915)
*  feat(cli): CLI Phase 4 - cron, message enhance, topic share, agent-group, session-group

Add core commands to complete CLI coverage of TRPC routers:

- `lh cron` — Agent cron job management (list/view/create/edit/delete/toggle/reset/stats)
- `lh message` — Enhanced with create/edit/add-files/word-count/rank-models/delete-by-assistant/delete-by-group
- `lh topic` — Enhanced with clone/share/unshare/share-info/import
- `lh agent-group` — Agent group management (list/view/create/edit/delete/duplicate/add-agents/remove-agents)
- `lh session-group` — Session group management (list/create/edit/delete/sort)

Closes LOBE-5920

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update version

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:32:00 +08:00
Rdmclin2 14dd5d09dd feat: support runtime config (#12902)
* feat: support runtime config

* fix: cloud sandbox default tool ids
2026-03-11 23:43:33 +08:00
Innei 21d1f0e472 feat(settings): improve tool detector display layout (#12906)
*  feat(settings): improve tool detector display layout

- Move version to left side with Name, display as Tag
- Right side: two lines (Available status + path), right-aligned
- Unavailable: single line centered
- Add runtime environment detectors (Node, Python, npm)
- Add i18n for system tools settings

Made-with: Cursor

* 🔧 fix(toolDetectors): ensure successful version check for Python runtime

- Update pythonDetector to enforce successful invocation of `--version` for confirming usable runtime.
- Removed redundant version handling logic to streamline the detection process.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-11 19:55:36 +08:00
Rdmclin2 bc50db6a8b 🐛 fix: desktop advanced mode (#12911)
* fix: advanced mode empty

* fix: desktop channel router lost
2026-03-11 19:02:37 +08:00
LobeHub Bot 8db8dff7b0 test: add unit tests for MarketService (#12905)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:51:25 +08:00
LiJian 1a3c561e21 💄 style: add the history count limit back in agents params settings (#12199)
* fix: add the history count limit back in agents params settings

* fix: fixed the test

* fix: change the default settings snap the enableHistoryCount as false

* fix: change the history process to the first into MessageEngine

* fix: fixed some count limited

* fix: fixed the enableHistoryCount check test

* fix: change the getEnableHistoryCountById logic
2026-03-11 15:46:56 +08:00
Arvin Xu 8e60b9f620 feat(cli): CLI Phase 3 - bot integration, search & device (#12904)
* fix cli alias

* 🐛 fix(cli): fix gen text non-streaming mode and streaming SSE parsing

- Add `responseMode: 'json'` for non-streaming requests to get plain JSON instead of SSE
- Fix streaming SSE parser to handle LobeHub's JSON string format (e.g. `"Hello"`)
- Support both OpenAI and Anthropic response formats in non-streaming mode
- Add E2E tests for all generate commands (text, list, tts, asr, alias)
- Update skills knowledge.md docs with new kb commands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): unify skill install command and add e2e tests

Merge import-github/import-url/import-market into a single `skill install <source>` command with auto-detection (GitHub URL/shorthand, ZIP URL, or marketplace identifier). Add alias `skill i`. Add comprehensive e2e and unit tests for skill commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🔨 chore: fix linter formatting in memory e2e test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix: add vitest-environment node declaration to aiProvider test

Fix server-side env variable access error by declaring node environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix cli review

* fix test

*  feat(cli): add web search and crawl support to search command

Add --web flag for web search via tools TRPC client, and search view
subcommand for viewing results (URLs via crawl, local resources by type:id).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): add device management command with TRPC endpoints

Add `lh device` command for managing connected devices via server-side
TRPC API, complementing the existing `lh connect` (device-as-client).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): add bot integration management command

Add `lh bot` top-level command for managing agent bot integrations
(Discord, Slack, Telegram, Lark/Feishu). Includes list, view, add,
update, remove, enable/disable, and connect subcommands.

Also adds `list` procedure to agentBotProvider TRPC router for
querying all bots with optional agent/platform filters.

Closes LOBE-5900

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:29:15 +08:00
Innei 874c2dd706 🐛 fix(i18n): preload default language from JSON to avoid Suspense on first render (#12895)
* 🐛 fix(i18n): preload default language from JSON to avoid Suspense on first render

- Sync load en-US common/error/chat from locales/en-US/*.json
- Use JSON (not locales/default/*.ts) as runtime values - TS source is type-only
- Prevents useTranslation from suspending, avoids CLS from 44px skeleton fallback

Made-with: Cursor

*  feat(i18n): enable partial loading of languages and add tests for dynamic namespace loading

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-11 14:00:39 +08:00
LobeHub Bot 4988413d58 🌐 chore: translate non-English comments to English in src/features/Electron (#12901)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 13:43:39 +08:00
YuTengjing f1dd2fc458 📝 docs: add catch error logging rule to TypeScript skill (#12903) 2026-03-11 12:10:36 +08:00
Arvin Xu aa8082d6b2 feat: lobehub cli for better agency agent (#12897)
* fix cli alias

* 🐛 fix(cli): fix gen text non-streaming mode and streaming SSE parsing

- Add `responseMode: 'json'` for non-streaming requests to get plain JSON instead of SSE
- Fix streaming SSE parser to handle LobeHub's JSON string format (e.g. `"Hello"`)
- Support both OpenAI and Anthropic response formats in non-streaming mode
- Add E2E tests for all generate commands (text, list, tts, asr, alias)
- Update skills knowledge.md docs with new kb commands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): unify skill install command and add e2e tests

Merge import-github/import-url/import-market into a single `skill install <source>` command with auto-detection (GitHub URL/shorthand, ZIP URL, or marketplace identifier). Add alias `skill i`. Add comprehensive e2e and unit tests for skill commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🔨 chore: fix linter formatting in memory e2e test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix: add vitest-environment node declaration to aiProvider test

Fix server-side env variable access error by declaring node environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix cli review

* fix test

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:06:52 +08:00
YuTengjing 37cb4983de 🐛 fix: filter out delisted lobehub provider models from DB residuals (#12896) 2026-03-11 10:22:51 +08:00
Innei 9098d0074a ♻️ refactor(desktop): move onboarding state to main process (#12890)
* refactor: desktop onboarding

* ♻️ refactor(desktop): reinstate onboarding guard before auto OIDC

- Add getDesktopOnboardingCompleted/setDesktopOnboardingCompleted back to localStorage
- These functions persist across sign-out, preventing unexpected OIDC popups
- Fix for Codex review feedback on PR #12890

* ♻️ refactor(desktop): use sessionStorage for onboarding completed flag

*  test(desktop): fix BrowserManager test for async initializeBrowsers
2026-03-11 00:36:05 +08:00
Arvin Xu 860e11ab3a ♻️ refactor(cli): extract shared @lobechat/local-file-shell package (#12865)
* ♻️ refactor(cli): extract shared @lobechat/local-file-shell package

Extract common file and shell operations from Desktop and CLI into a
shared package to eliminate ~1500 lines of duplicated code. CLI now
uses @lobechat/file-loaders for rich format support (PDF, DOCX, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update

* update commands

* update version

* update deps

* refactor version issue

*  feat(local-file-shell): add cwd support, move/rename ops, improve logging

- Add missing `cwd` parameter to `runCommand` (align with Desktop)
- Add `moveLocalFiles` with batch support and detailed error handling
- Add `renameLocalFile` with path validation and traversal prevention
- Add error logging in shell runner's error/completion handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* support update model and provider in cli

* fix desktop build

* fix

* 🐛 fix: pin fast-xml-parser to 5.4.2 in bun overrides

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:04:22 +08:00
YuTengjing c2e9b45d4c feat: add InsufficientBudget error type and Pro badge i18n (#12886) 2026-03-10 23:43:24 +08:00
YuTengjing 8063378a1d 🐛 fix: resolve ModelSelect crash and update default model (#12892) 2026-03-10 21:10:11 +08:00
Innei 93aed84399 🔨 chore(i18n): sync locale files across desktop and web (#12887)
Made-with: Cursor
2026-03-10 19:23:47 +08:00
LiJian eec8e113fc ♻️ refactor: add the skills in community pages (#12761)
* feat: add the skills in community pages

* feat: add some skills & import the import routes

* feat: add detail used pages & prompt

* feat: add the skill sort way

* fix: ts fixed

* fix: ts fixed

* fix: test fixed

* fix: test fixed
2026-03-10 18:00:15 +08:00
Sun13138 826a099f8d 🐛 fix: harden market auth popup handoff and storage fallback (#12863)
* 🐛 fix: make market auth popup handoff COOP-safe

* 🐛 fix: harden market auth popup handoff flow

* 🐛 fix: guard market auth handoff storage access
2026-03-10 17:19:22 +08:00
Innei c087134953 feat(desktop): unify canary with stable app name/icon, add channel tag in About (#12881)
- Use same app name (LobeHub) and icon as stable for canary builds
- Add build channel tag in Settings > About for non-stable channels (Canary, Nightly, Beta)
- Add getBuildChannel IPC to expose build-time channel for display

Made-with: Cursor
2026-03-10 16:41:56 +08:00
Innei 5e468cd850 feat(agent-browser): add browser automation skill and tool detection (#12858)
*  feat(tool-detectors): add browser automation support and refactor tool detector categories

- Introduced browser automation detectors to the tool detector manager.
- Updated tool categories to include 'browser-automation'.
- Refactored imports to use type imports where applicable for better clarity.
- Cleaned up unnecessary comments in tool filters.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: add browser automation tool detection UI

* 🔧 chore: update react-scan version and enhance agent-browser documentation

- Updated `react-scan` dependency from version 0.4.3 to 0.5.3 in package.json.
- Improved documentation in `content.ts` for the agent-browser, clarifying command usage and workflows.
- Added development mode flag `__DEV__` in sharedRendererConfig for better environment handling.
- Integrated `scan` functionality in `initialize.ts` to enable scanning in development mode.
- Updated global type definitions to include `__DEV__` constant for clarity.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(builtin-skills): add dependency and refactor skill filtering logic

- Added `@lobechat/const` as a dependency in package.json.
- Introduced a new function `shouldEnableBuiltinSkill` to determine if a skill should be enabled based on the environment.
- Refactored the `builtinSkills` export to filter skills using the new logic.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(builtin-skills): refactor skill management and add filtering logic

- Removed unnecessary dependency from package.json.
- Simplified skill filtering logic by introducing `filterBuiltinSkills` and `shouldEnableBuiltinSkill` functions.
- Updated various components to utilize the new filtering logic for managing builtin skills based on the environment.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(builtin-skills): introduce new skill APIs and refactor manifest structure

- Added new APIs for skill management: `runSkillApi`, `readReferenceApi`, and `exportFileApi` to enhance functionality.
- Created a base manifest file (`manifest.base.ts`) to centralize API definitions.
- Updated the desktop manifest (`manifest.desktop.ts`) to utilize the new base APIs.
- Refactored existing manifest to streamline API integration and improve maintainability.
- Introduced a detailed system prompt for better user guidance on skill usage.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: desktop skill runtime, skill store inspectors, and tool UI updates

Made-with: Cursor

*  feat: enhance skill import functionality and testing

- Updated `importFromUrl` method in `SkillImporter` to accept additional options for identifier and source.
- Modified `importFromMarket` in `agentSkillsRouter` to utilize the new options for better tracking of skill imports.
- Added integration tests to ensure stable behavior when re-importing skills from the market, verifying that identifiers remain consistent across imports.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update .gitignore and package.json dependencies

- Added 'bin' to .gitignore to exclude binary files from version control.
- Included 'fflate' as a new dependency in package.json to support file compression in the application.
- Updated writeFile method in LocalFileCtr to handle file content as Uint8Array for improved type safety.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update package.json dependencies

- Removed 'fflate' from dependencies and added it to devDependencies for better organization.
- Ensured proper formatting by adding a newline at the end of the file.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add agent-browser download script and integrate binary handling

- Introduced a new script to download the `agent-browser` binary, ensuring it is available for the application.
- Updated `electron-builder.mjs` to include the binary in the build process.
- Modified `dir.ts` to define the binary directory path based on the packaging state.
- Enhanced the `App` class to set environment variables for the agent-browser integration.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add DevTools toggle to Linux and Windows menus

- Introduced a new menu item for toggling DevTools with the F12 accelerator key in both Linux and Windows menu implementations.
- Added a separator for better organization of the view submenu items.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: integrate agent-browser binary download into build process

- Added functionality to download the `agent-browser` binary during the build process in `electron-builder.mjs`.
- Enhanced the download script with detailed logging for better visibility of the download status and errors.
- Updated the `App` class to log the binary directory path for improved debugging.
- Reintroduced the `AuthRequiredModal` in the layout for desktop users.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: mock binary directory path in tests

- Added a mock for the binary directory path in the App tests to facilitate testing of the agent-browser integration.
- This change enhances the test environment by providing a consistent path for the binary during test execution.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: improve authorization notification handling

- Updated the `notifyAuthorizationRequired` method to implement trailing-edge debounce, ensuring that rapid 401 responses are coalesced and the IPC event is sent after the burst settles.
- Refactored the notification logic to enhance clarity and maintainability.

 feat: add desktop onboarding redirect

- Introduced a `useEffect` hook in `StoreInitialization` to redirect users to the `/desktop-onboarding` page if onboarding is not completed, ensuring a smoother user experience on fresh installs.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix(desktop): hide Agent Browser skill on Windows

Made-with: Cursor

* 🔧 chore: update memory limits for build processes

- Increased the `NODE_OPTIONS` memory limit for both `build:next` and `build:spa` scripts from 6144 to 7168, optimizing build performance and resource management.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-10 16:13:33 +08:00
Arvin Xu eb7cf10ff9 test: fix GatewayManager tests to include platform parameter (#12876)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:39:00 +08:00
lobehubbot 7d88b8cda5 Merge remote-tracking branch 'origin/main' into canary 2026-03-10 06:35:39 +00:00
YuTengjing 258e9cb982 👷 build: add migration to enable pg_search extension (#12874)
*  feat: add migration to enable pg_search extension

* 🐛 fix: skip pg_search migration for PGlite test compatibility
2026-03-10 14:34:42 +08:00
sxjeru a7d896843f 💄 style: Add new GPT-5.4 model (#12654)
*  feat(openai): add GPT-5.3 Chat model with enhanced features and pricing details

*  feat: add Codex Max Reasoning Effort parameter and slider component for enhanced model configuration

*  feat: update Qwen model configurations and add new Qwen3.5 models with detailed descriptions and pricing

*  feat: add GPT-5.4 and GPT-5.4 pro models with pricing and capabilities to the model bank

*  feat: add GPT-5.4, GPT-5.4 pro, and GPT-5.3 Chat models with detailed capabilities and pricing to the model bank

*  feat: 更新 zhipu 聊天模型的定价参数,移除不必要的 textOutput 参数

*  feat: 移除 Gemini 3 Pro 模型的详细信息,标记为已弃用
2026-03-10 09:59:14 +08:00
Hardy 7de2a68d20 feat(siliconcloud): add Qwen3.5 series models (#12785) 2026-03-10 09:58:37 +08:00
LobeHub Bot e753856abf test: add unit tests for gateway service (#12784)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 09:58:13 +08:00
René Wang b94503db8b 📝 docs: upgrade usage docs with improved structure and content (#12704)
Adopt Mintlify-quality writing patterns across 11 existing docs and add 3 new docs.
Adds Steps, Tabs, AccordionGroup, and mermaid diagrams for better readability.

Priority 1 (major expansion): agent-market, resource, scheduled-task, mcp-market
Priority 2 (structural): memory, web-search, tts-stt, vision, chain-of-thought
Priority 3 (minor): artifacts, agent
New docs: chat, file-upload, skills-and-tools

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:56:39 +08:00
Marcell Gu 023e3ef11a 📝 docs: Simplify docker compose network architecture & Remove broken links from docker compose docs (#12749)
* ♻️ refactor(docker): simplify network architecture and add admin port
- Remove unnecessary network-service (alpine) container
- Use dedicated lobe-network bridge for all services
- Add RUSTFS_ADMIN_PORT environment variable for admin console
- Update container-to-container communication to use Docker service names
- Use relative path volumes for better data persistence

* 📝 docs: update Docker Compose deployment guide
- Add single-domain deployment documentation
- Update INTERNAL_APP_URL guidance
- Clarify Port Mode vs Domain Mode behavior
- Add S3_ENDPOINT configuration tips
- Remove broken link to non-existent server-database documentation

* fix(docker): keep backward-compatible volume paths for existing deployments

- PostgreSQL: Keep ./data (not ./postgres_data)
- Redis: Keep redis_data named volume (not ./redis_data)
- RustFS: Keep rustfs-data named volume (not ./rustfs_data)

This ensures existing users can upgrade without data migration.

* fix(docker): correct Port Mode vs Domain Mode description

- Fix reversed explanation in comments
- Port Mode: Uses default ports (3210/9000/9001)
- Domain Mode: Custom ports via reverse proxy

This aligns with the actual deployment script behavior.
2026-03-10 09:55:56 +08:00
Rylan Cai ea329113be feat(eval): add external scoring mode (#12729)
* wip: add llm relevant & BrowseComp

* wip: add widesearch desc

* wip: dsqa, hle, widesearch

* wip: add dsqa

* wip: add awaiting eval status for runs

* wip: add awaiting status for run

* wip: adjust hle-verified

* 🐛 fix: browsecomp topics

* 📝 docs: add annotations

* wip: add awaiting status for pass@k

* wip: add complete status

* wip: update theard dots

* wip: update run status page

* wip: remove useless impl

* wip: update prompt

*  feat: add external eval routes

* wip: add eval cli

* 🐛 fix: support authoritize in no browser environment

* wip: pass tests

* ♻️ refactor: remove tests

* ♻️ refactor: mo camel case
2026-03-10 09:53:26 +08:00
Innei 255a1c21a8 🐛 fix: redirect to desktop onboarding when not completed (#12866)
* 🐛 fix: redirect to desktop onboarding when not completed

Desktop app was missing the redirect to `/desktop-onboarding` when
onboarding hadn't been completed. The `useDesktopUserStateRedirect`
callback silently returned instead of navigating, causing:
- Users never see the onboarding flow on fresh install
- `AuthRequiredModal` suppressed because onboarding guard fails

* 🐛 fix: remove desktop onboarding routes from proxy configuration

The `/desktop-onboarding` and its regex route have been removed from the proxy configuration. This change simplifies the routing logic as the onboarding flow is now handled directly in the user state redirect logic.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-10 02:15:27 +08:00
Zephyr 81d25bf124 feat: add v1 api (#12758)
*  feat(openapi): add API key hash support for secure storage

*  feat(openapi): enhance message translation and knowledge base functionality

- Added MessageTranslationController and associated routes for managing message translations, including fetching, creating, updating, and deleting translations.
- Introduced KnowledgeBaseController with routes for CRUD operations on knowledge bases, including file management and access control.
- Updated existing message and translation routes to improve structure and naming consistency.
- Refactored related services and types to support new features and ensure type safety.

This update enhances the API's capabilities for handling message translations and knowledge base management, improving overall functionality and user experience.

* fix: allow OWNER scope to list agents in agents route

- Add OWNER scope to AGENT_READ permission check
- Aligns list behavior with AgentService.queryAgents ownership filter
- Allows owner-scoped users to list their own agents

* 🔧 refactor(rbac): improve import structure in rbac.ts

- Changed import statements to separate type imports from regular imports for better clarity and organization.
- This refactor enhances code readability and maintains consistency in the import structure.

* fix: 修复 chunk 服务与 async router 的循环依赖

- 将 createAsyncCaller 的静态导入改为动态导入 (await import)
- 打破 file.ts -> chunk/index.ts -> async/index.ts 的循环依赖链
- 使用 --skip-dynamic-imports 参数的 dpdm 验证循环依赖已解决

* 🐛 fix: resolve CI failures

* test: 补充 apiKey、KeyVaultsEncrypt、ChunkService 单测至 100% 覆盖率

- test(database): 补充 apiKey.ts query() 解密失败分支测试
- test(server): 补充 KeyVaultsEncrypt 非法密钥/密文格式 getUserKeyVaults 测试
- test(server): 新增 ChunkService 完整测试覆盖异步任务创建/触发/失败回写

所有新增测试通过 (46/46),目标文件覆盖率均达 100%
2026-03-10 01:00:36 +08:00
Rylan Cai 3894facf5f 🐛 fix(cli): require gateway for custom server (#12856)
* 🐛 fix(cli): require --gateway for custom server logins

* 🐛 fix(cli): persist custom server gateway settings

* ♻️ refactor(cli): centralize official endpoint urls
2026-03-10 00:02:51 +08:00
WangYK 473bc4e005 💄 style: support video input for SiliconCloud provider (#9988)
*  feat: support video input for SiliconCloud models

* 🐛 fix: resolve SSRF issue in video fetching; move message transformation to `context-builders`

* 🐛 fix: update MiniMax M2 context size

* 🐛 fix: use ssrf-safe-fetch in `videoUrlToBase64` and `imageUrlToBase64`

* 🐛 fix: fix tests

* 🐛 fix: dynamically import ssrf-safe-fetch to prevent build failures

* Revert "🐛 fix: dynamically import ssrf-safe-fetch to prevent build failures"

This reverts commit 5de0829527ae6dbdc78d694ccc9dca86f46e3168.

* chore: move `videoToBase64` to the `util` package

* fix: fix tests

* chore: update siliconcloud models

* fix: deduplicate siliconcloud models

* fix: videoUrlToBase64 should determine runtime when fetching

* fix: fix tests

* chore: update siliconcloud models

* chore: remove deprecated models

* chore: update model info

* fix: fix tests
2026-03-10 00:02:29 +08:00
lobehubbot 3cf4f28af0 🔖 chore(release): release version v2.1.39 [skip ci] 2026-03-09 15:07:18 +00:00
lobehubbot d54b30750a Merge remote-tracking branch 'origin/main' into canary 2026-03-09 15:05:28 +00:00
Arvin Xu 4e6790e3d7 👷 build: add api key hash column migration (#12862)
*  feat(database): extract openapi database changes

* 📝 docs: update db-migrations and version-release skills

---------

Co-authored-by: MarioJames <mocha.wyh@msn.com>
Co-authored-by: YuTengjing <ytj2713151713@gmail.com>
2026-03-09 23:04:45 +08:00
LobeHub Bot 8a679aa772 🌐 chore: translate non-English comments to English in src/app/(backend) (#12836)
🌐 chore: translate non-English comments to English in src/app/(backend) and src/app/[variants]/(auth)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 20:03:13 +08:00
Arvin Xu 1329490306 feat(cli): add agent run and status commands (#12839)
*  feat(cli): add agent run and status commands

Implement `lh agent run` for executing agents with SSE streaming
and `lh agent status` for checking operation status. Includes
`--replay` option for offline replay from saved JSON fixtures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix(cli): preserve SSE frame state across read boundaries and enable verbose logging

- Move eventType/eventData outside the read loop so partial SSE frames
  split across chunks are not silently dropped
- Call setVerbose(true) when --verbose is passed so logger helpers
  actually print detailed tool arguments and results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:02:41 +08:00
YuTengjing 228044e649 🐛 fix: add ffmpeg-static to default serverExternalPackages (#12846) 2026-03-09 18:13:17 +08:00
YuTengjing 857f469323 🐛 fix: remove ffmpeg-static from outputFileTracingExcludes (#12844) 2026-03-09 17:10:57 +08:00
Zhijie He 8d4d657a5d feat: add LongCat(美团) provider support (#12603)
* feat: add LongCat(美团) provider support

* chore: remove enable_thinking, due to not in doc anymore
2026-03-09 16:59:29 +08:00
Innei 50dbc653fa 🐛 fix: filter v-prefixed Docker tags in manifest creation (#12842) 2026-03-09 16:07:06 +08:00
YuTengjing 5af5b80b83 🐛 fix: include pnpm store path for ffmpeg-static in Vercel tracing (#12838) 2026-03-09 14:37:59 +08:00
Arvin Xu c6de80931e 🐛 fix: fix agent runtime error handle (#12834)
* improve inspect partial ability

* fix error

* fix runtime error
2026-03-09 12:24:13 +08:00
YuTengjing 6e26135978 🐛 fix: harden Anthropic message building and sampling parameter handling (#12827) 2026-03-09 11:05:02 +08:00
LobeHub Bot 10dfc6eec6 test: add unit tests for InMemoryAgentStateManager (#12377)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-09 10:40:34 +08:00
Hardy 8855ac3b8a feat: add new NVIDIA models and tweak the behavior of the enable thinking (#12533)
*  feat: add new NVIDIA models with thinking budget support

- Add 7 new models: MiniMax-M2.1, DeepSeek V3.2, GLM-4.7, GLM-5, Kimi K2.5, MiniMax-M2.5, Qwen3.5-397B-A17B
- Add thinkingBudget support for qwen3.5-397b-a17b model
- Update test case description

* 🐛 fix: remove thinking budget and add video support for Qwen3.5-397B-A17B
2026-03-09 10:34:00 +08:00
Zhijie He e4f8ed78ba 💄 style: add grok-4.20 series early support (#12743)
* style: add grok-4.20 series early support

* chore: disable browser request due to CORS

* style: update ability tag
2026-03-09 10:23:16 +08:00
Arvin Xu 4363994945 feat: support use remote device in IM integration (#12798)
* support timezone in system prompt

refactor to improve user prompts

refactor tool engine

refactor tools map mode

add bot callback service

clean

improve cli

update agentic tracing

refactor cli login

refactor cli

add device auth

improve device gateway implement

implement gateway pipeline

support device Gateway connect

support gateway

* revert electron device

* inject builtins agent prompts

* update tracing

* add testing

* refactor the activeDeviceId

* refactor BotCallbackService

* fix test and lint

* fix test and lint

* add tests

* fix tests

* fix lint
2026-03-09 01:17:56 +08:00
LobeHub Bot c1757e2e19 🌐 chore: translate non-English comments to English in GenerationItem (#12745)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 00:52:07 +08:00
LobeHub Bot 39e36320b2 🌐 chore: translate non-English comments to English in AgentSetting (#12807)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 23:59:44 +08:00
Arvin Xu ccd7f4e22b 🐛 fix(cli): fix type errors in generate image/video commands (#12828)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:36:08 +08:00
Rdmclin2 3f9c23e7b4 feat: support lark and feishu bot (#12712)
* feat: support lark and feishu

* chore: change integration to channel

* chore: rename from integration to channel

* fix: channel router

* feat: add topic list channel provider icon

* chore: update webhook url

* chore:  channel form refact

* chore: update i18n  keys to channel

* chore: update form item description

* style: hide required mark

* feat: add lark chat adapter

* chore: clean speaker tag  & add username api adapter

* chore: adjust topic channel icon

* chore: move developer mode to advanced setting

* chore: add lark icon

* fix: detail style

* fix: token check logic

* fix: encrpted risk

* fix: vercel function appId

* chore: remove webhook mode for discord

* chore: add doc link

* chore: add channel docs

* chore: remove unused import

* fix: create bot with wrong platform

* chore: update intergration to channel

* fix: udpate variable import

* fix: tsgo error

* chore: optimize webhook url trim

* chore: update copy text

* fix: telegram webhook not set

* chore: add persist logic

* docs: update feishu doc

* chore: update feishu and lark tenant

* chore: update docs

* chore: make verfication code required

* chore: update feishu docs

* chore: update verfication comment

* chore: update docs permission  list

* chore: verificationToken optional

* chore: update feishu and lark color

* chore: use test id
2026-03-08 19:18:06 +08:00
YuTengjing 15a95156f3 💄 style: update i18n locales (#12809) 2026-03-08 13:25:46 +08:00
YuTengjing f25edcc027 🔒 fix: add rate limit custom rules for password reset and email verification (#12808) 2026-03-08 12:40:14 +08:00
Arvin Xu e67bcb2571 feat(cli): add generate command for text/image/video/tts/asr (#12799)
*  feat(cli): add generate command for text/image/video/tts/asr

LOBE-5711

- `lh generate text <prompt>` — LLM text completion with SSE streaming
  - Supports --model (provider/model format), --system, --temperature, --pipe
- `lh generate image <prompt>` — Image generation via async task
- `lh generate video <prompt>` — Video generation via async task
- `lh generate tts <text>` — Text-to-speech (openai/microsoft/edge backends)
- `lh generate asr <file>` — Speech-to-text via OpenAI Whisper
- `lh generate status` — Check async generation task status
- `lh generate list` — List generation topics
- Add shared HTTP auth helper (api/http.ts) for webapi endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update info

* ♻️ refactor(cli): split generate command into submodules, text defaults non-streaming

- Split monolithic generate.ts into generate/{index,text,image,video,tts,asr}.ts
- Text subcommand now defaults to non-streaming (use --stream to opt in)
- Text subcommand supports --json for full JSON response output
- Video subcommand uses requiredOption for --model and --provider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix(cli): read generation data from result.data and add required X-lobe-chat-auth header

Image/video mutations return { success, data: { ... } }, read IDs from data.
WebAPI endpoints require X-lobe-chat-auth (XOR-encrypted) alongside Oidc-Auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:19:01 +08:00
Zhijie He 2cce103137 💄 style: add qwen-image-2.0 series support (#12771) 2026-03-08 10:33:48 +08:00
Arvin Xu 6acba612fc feat(cli): add full API integration commands In cli (#12795)
*  feat(cli): add full API integration commands

Add comprehensive CLI commands for managing LobeHub resources:

P0 - Search, Knowledge Base, Memory:
- `lh search` - Global unified search across all resource types
- `lh kb` - Knowledge base CRUD, file management
- `lh memory` - User memory CRUD (identity/activity/context/experience/preference), persona, extraction

P1 - Agent, Session, Topic, Message:
- `lh agent` - Agent CRUD (list/view/create/edit/delete/duplicate)
- `lh session` - Session management with search
- `lh topic` - Topic CRUD with search and recent
- `lh message` - Message listing, search, delete, count, heatmap

P2 - Model, Provider:
- `lh model` - Model listing, toggle, delete per provider
- `lh provider` - Provider listing, toggle, delete

P3 - Plugin, Config:
- `lh plugin` - Plugin install/uninstall/update
- `lh whoami` - User info display
- `lh usage` - Usage statistics (monthly/daily)

Also refactors shared formatting utilities into utils/format.ts.
All commands support `--json` output for scripting.

Closes LOBE-5706, LOBE-5770

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  feat(cli): add file/skill commands, remove session, split kb

- Add standalone `file` command (list, view, delete, recent)
- Add `skill` command (list, view, create, edit, delete, search, import, resources)
- Remove `session` command (no longer needed)
- Remove `files` subcommand from `kb` (now separate `file` command)
- Add tests for file and skill commands
- Register new commands in index.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 🐛 fix(cli): fix ESM require in confirm, login unhandled rejections, memory create

- Replace CommonJS require('node:readline') with ESM import in confirm helper
- Add return after process.exit(1) in login.ts to prevent unhandled rejections
- Simplify memory create to only support identity (other categories lack create procedures)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:18:01 +08:00
Rylan Cai e48fd47d4e 🐛 fix: cli login and run browser in Windows (#12787)
* 🐛 fix: support authoritize in no browser environment

* wip: remove tests

* 📝 docs: remove redundant alerts

* 🐛 fix: could not invoke brower in windows

* wip: add link and unlink cli to global
2026-03-07 23:33:05 +08:00
YuTengjing b91fa68b31 🐛 fix: detect exceeded context window errors from message text (#12788) 2026-03-07 23:26:57 +08:00
LobeHub Bot ac1376ede5 🌐 chore: translate non-English comments to English in ProtocolUrlHandler (#12781) 2026-03-07 17:45:18 +08:00
YuTengjing 32b83b8c0a feat(topic): add sort by updated time option for topic sidebar (#12774) 2026-03-07 17:16:50 +08:00
Arvin Xu 2822b984f4 feat: add doc command in cli (#12752)
* add doc cli

* add doc cli

* add document command
2026-03-07 13:48:02 +08:00
lobehubbot 169d5afa93 🔖 chore(release): release version v2.1.38 [skip ci] 2026-03-06 13:43:22 +00:00
lobehubbot 42ed155944 Merge remote-tracking branch 'origin/main' into canary 2026-03-06 13:41:48 +00:00
Innei 2dc7b15c31 🚀 release: 20260306 (#12757)
This release includes **31 commits**. Key updates are below.

### New Features and Enhancements

- Added **Telegram bot access** support.
- Added **electron page tabs** functionality for desktop.
- Added **device code auth flow** for authentication.
- Added **GPT-5.4** model support.
- Show **last used auth provider** on sign-in page for better UX.
- Support **clearing hotkey bindings** in desktop ShortcutManager.
- Added **Gemini 3.1 Flash Lite Preview** model and thinkingLevel5
extend param.
- Added **auto aspect ratio and image search** support for Nano Banana
2.
- User memories now default to inject user persona instead of
identities.

### Desktop Improvements

- Unified **update channel switching** with S3 distribution.
- Added **S3 publish for canary/nightly** and S3 cleanup (keep latest
15).
- Added electron page tabs functionality.

### Stability and Fixes

- Fixed agents fork not working in community deploy.
- Fixed animation for single-line messages between reasoning and tool
calls.
- Fixed Discord bot conflict with keyPrefix.
- Fixed skew plugin issue.
- Fixed `userMemories` database failure on extra structure mismatch.
- Fixed old LobeHub plugins update issue.
- Fixed context-engine tool type recovery from manifest when models
strip suffixes.
- Added `await` to `handleResponseAPIMode` for proper error handling.
- Fixed M2M token for community agents/MCP/skill list.
- Fixed scripts to support Win32.
- Improved gateway and device gateway CI.

### Credits

Huge thanks to these contributors (alphabetical):

@arvinxx @huangkairan @Innei @LiJian @Luis-Sambrano @nekomeowww
@rdmclin2 @ReneWang @sxjeru @tjx666
2026-03-06 21:41:07 +08:00
Innei 5391ceda7d 🐛 fix(ci): add version prefix to S3 update manifest URLs (#12772)
🐛 fix(ci): target channel yml files instead of latest*.yml for version prefix

The merge-mac-files step already renames latest*.yml to {channel}*.yml
(e.g., canary-mac.yml). The previous fix targeted release/latest*.yml
which matched nothing, so the sed was a no-op.

Now targets release/${CHANNEL}*.yml directly, with latest*.yml as fallback.
2026-03-06 19:34:32 +08:00
Innei a2bf627531 🐛 fix(ci): add version prefix to latest*.yml URLs in S3 upload (#12770)
The latest*.yml files uploaded to S3 channel root lacked the $VERSION/
prefix in their URLs, causing electron-updater to request files at
the wrong path (e.g., /canary/LobeHub-Canary-xxx.zip instead of
/canary/2.1.38-canary.1/LobeHub-Canary-xxx.zip), resulting in 404.

Now sed -i modifies latest*.yml in-place before uploading, and
channel-specific yml files are copied from the already-modified ones.
2026-03-06 18:41:26 +08:00
Innei 0b7c917745 👷 build(ci): fix changelog auto-generation in release workflow (#12765)
After auto-tag-release.yml was introduced, semantic-release in release.yml
stopped working because the tag already exists when it runs. This caused
CHANGELOG.md to never be updated.

Fix: move changelog generation into auto-tag-release.yml with a custom
script that parses git log and generates gitmoji-formatted entries,
matching the existing CHANGELOG.md format. Remove the broken
semantic-release step from release.yml.
2026-03-06 17:25:44 +08:00
YuTengjing 716c27df12 🐛 fix: resolve message reordering in Responses API input conversion (#12764) 2026-03-06 17:14:26 +08:00
Innei 0dd0d11731 👷 build(ci): fix changelog auto-generation in release workflow (#12763)
After auto-tag-release.yml was introduced, semantic-release in release.yml
stopped working because the tag already exists when it runs. This caused
CHANGELOG.md to never be updated.

Fix: move changelog generation into auto-tag-release.yml with a custom
script that parses git log and generates gitmoji-formatted entries,
matching the existing CHANGELOG.md format. Remove the broken
semantic-release step from release.yml.
2026-03-06 17:08:47 +08:00
LiJian 400a0205a3 🐛 fix: when use trustclient not register market m2m token (#12762)
fix: when use trust client not take inject token
2026-03-06 17:03:34 +08:00
lobehubbot 86889b81bd 🔖 chore(release): release version v2.1.37 [skip ci] 2026-03-06 06:25:38 +00:00
Innei d3550afe05 🐛 hotfix(ci): correct stable renderer tar source path (#12755)
🐛 fix(ci): correct stable renderer tar source path

Use the current Electron renderer output directory when creating the stable renderer archive so Linux desktop release builds stop failing after packaging succeeds.

Made-with: Cursor
2026-03-06 14:24:06 +08:00
LiJian 4d240cf7fa 🐛 fix: slove the agnets fork not work in communtiy deploy (#12750)
* fix: slove the agnets fork not work in communtiy deploy

* fix: slove the secure token set & registerM2MToken not batch

* Revert "fix: slove the secure token set & registerM2MToken not batch"

This reverts commit 4485e57165.
2026-03-06 14:12:48 +08:00
YuTengjing db45907ab8 feat: add GPT-5.4 model support (#12744)
*  feat: add GPT-5.4 model support and fix reasoning payload pruning

- Add GPT-5.4 model card to model-bank
- Update planCardModels to use gpt-5.4
- Add gpt-5.4 to responsesAPIModels
- Fix pruneReasoningPayload to strip logprobs/top_logprobs for reasoning models
- Add logprobs, top_logprobs to ChatStreamPayload type
- Extend reasoning_effort to include none and xhigh
- Add success log for non-fallback requests in RouterRuntime
- Fix log parameter mismatch in RouterRuntime

Fixes LOBE-5735

* 🐛 fix: match gpt-5.4 to gpt5_2ReasoningEffort in openrouter and vercelaigateway

* 🐛 fix: update OpenRouterReasoning effort type to include none and xhigh

* 🐛 fix: use tiered pricing for gpt-5.4 based on 272K token threshold

* 🌐 chore: update i18n translations

* 🐛 fix: update claude-sonnet model version to 4-6 in planCardModels

*  feat: add GPT-5.4 Pro model support

* 🐛 fix: remove dated snapshot for gpt-5.4-pro in responsesAPIModels

* 🐛 fix: add tierBy support for cross-unit tiered pricing threshold

OpenAI charges output at 1.5x when INPUT exceeds 272K tokens.
The tiered strategy previously only checked the unit's own quantity
to select a tier. Added optional tierBy field to TieredPricingUnit
so output/cacheRead tiers can reference input quantity for selection.

* 🐛 fix: use totalInputTokens for tiered pricing tier selection

Tiered pricing tiers should be determined by total prompt size
(totalInputTokens), not each unit's own quantity. This fixes output
and cacheRead being charged at the wrong tier rate when the prompt
exceeds the threshold but the individual unit quantity does not.
2026-03-06 13:47:31 +08:00
Arvin Xu 76a07d811b feat: init lobehub-cli (#12735)
* init cli project

* Potential fix for code scanning alert no. 184: Uncontrolled command line

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* update

* Potential fix for code scanning alert no. 185: Uncontrolled command line

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-06 11:42:29 +08:00
LobeHub Bot 616d53e2ec 🌐 chore: translate non-English comments to English in ChatInput/ActionBar/Tools (#12663)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 11:27:27 +08:00
YuTengjing 92cb759c37 feat(auth): show last used auth provider on sign-in page (#12737) 2026-03-06 03:29:31 +08:00
Neko 07f44e2ba2 feat(userMemories,memory-user-memory): now default to inject user persona instead of identities (#12731) 2026-03-05 21:37:27 +08:00
Innei 5920500371 feat(desktop): support clearing hotkey bindings in ShortcutManager (#12727)
* 🔧 chore: update @lobehub/ui dependency to a specific version URL and enhance ShortcutManager functionality

- Updated @lobehub/ui dependency in package.json to a specific version URL.
- Improved ShortcutManager to handle empty accelerator bindings, allowing users to clear shortcuts.
- Updated tests to reflect changes in shortcut handling and added localization for clear binding messages in both Chinese and English.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to version 5.4.0 in package.json

- Changed the @lobehub/ui dependency from a specific version URL to version 5.4.0 for improved stability and consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to use caret versioning in package.json

- Changed the @lobehub/ui dependency from a fixed version to caret versioning (^5.4.0) to allow for minor updates and improvements.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-05 21:23:58 +08:00
Innei 92c70d2485 👷 ci(desktop): add S3 cleanup for canary/nightly (keep latest 15) (#12722)
* 👷 ci(desktop): add S3 cleanup for canary/nightly (keep latest 15)

- Create `.github/actions/desktop-cleanup-s3/` reusable composite action
- Add S3 version cleanup step to canary and nightly cleanup jobs
- Cleanup runs after both publish-release and publish-s3 complete

* 👷 ci(desktop): fix S3 yml upload and add debug output

- Restore latest*.yml → {channel}*.yml logic (electron-builder always generates latest-*.yml)
- Upload both {channel}*.yml and latest*.yml to S3
- Change upload glob from latest* to *.yml for robustness
- Add yml file listing debug output in both upload and publish steps
2026-03-05 21:06:34 +08:00
lobehubbot 6c1c60ee27 🔖 chore(release): release version v2.1.36 [skip ci] 2026-03-05 12:45:01 +00:00
lobehubbot a4a3e024a6 Merge remote-tracking branch 'origin/main' into canary 2026-03-05 12:44:49 +00:00
LiJian e13e0a4db6 🐛 hotfix: add the market m2m request into market api (#12714)
🐛 fix: should add m2m token to use community agents/mcp/skill list (#12708)

fix: should add m2m token to use community agents/mcp/skill list
2026-03-05 20:44:10 +08:00
Innei eb009866cc 🐛 fix(ci): improve release workflows for prereleases (#12634)
- Use GH_TOKEN for desktop canary release upload
- Fix Docker tagging: latest only for stable, tag prerelease versions
- Skip release job when ref contains '-' (prerelease tags)

Made-with: Cursor
2026-03-05 17:32:13 +08:00
Innei 2ebac4679c 👷 ci(desktop): add S3 publish for canary/nightly and extract reusable action (#12721)
👷 ci(desktop): extract S3 publish logic into reusable composite action

- Create `.github/actions/desktop-publish-s3/` composite action for S3 upload
- Add `publish-s3` job to canary and nightly workflows (previously missing)
- Refactor stable workflow to use the shared action
- Fix canary/nightly builds not uploading to S3 despite UPDATE_SERVER_URL being set
2026-03-05 17:23:44 +08:00
Innei 51c857e4a5 feat: add electron page tabs functionality (#12310)
*  feat: add electron page tabs functionality

Implement browser-style page tabs in the Electron titlebar:

- Add TabBar component with explicit tab creation via context menu (desktop only)
- Tab creation triggers: TopicItem/PageItem context menu "Open in New Tab" or double-click
- TabBar only visible when tab count >= 2
- Update active tab's reference when navigating within it (tab follows user navigation)
- Reuse existing plugin system (pluginRegistry, 11 page plugins, PageReference types)
- Persist tabs to localStorage with automatic recovery on restart
- Apply logic to TopicItem (agent & group) and PageItem

Changes:
- src/store/electron/actions/tabPages.ts: New store slice with tab state + actions
- src/features/Electron/titlebar/TabBar/: New UI component + storage + hooks
- src/features/Electron/navigation/: New useTabNavigation hook + extracted cachedData helper
- src/app/.../Topic/List/Item/: Double-click creates tab, context menu "Open in New Tab"
- src/app/.../page/.../Item/: Double-click creates tab, context menu "Open in New Tab"
- i18n: New keys in topic.ts and file.ts namespaces

*  feat: enhance agent topic plugin and tab resolution logic

- Added a new line to ensure the cached title is included when resolving tabs in the useResolvedTabs hook.
- Minor adjustment in the agentTopicPlugin to improve code clarity.

These changes improve the handling of cached titles in the tab resolution process and enhance the overall functionality of the agent topic plugin.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: enhance agent and conversation handling in PageEditor

- Refactored PageAgentProvider to eliminate direct pageAgentId prop, improving context management.
- Updated Conversation and Copilot components to utilize conversation state for agent selection, ensuring better handling of chat-group session IDs.
- Adjusted FileCopilot to synchronize active agent ID with conversation context, enhancing file interaction capabilities.

These changes streamline agent management and improve the overall user experience in the PageEditor feature.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update ESLint suppressions for chat service [skip ci]

- Removed the suppression for `object-shorthand` in `src/services/chat/index.ts` to improve code quality.
- Adjusted the ESLint suppressions in `eslint-suppressions.json` for better linting consistency.

These changes enhance the linting process by ensuring adherence to coding standards in the chat service files.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: optimize NavigationBar panel width handling

*  feat: add tab context menu with close actions

Add right-click context menu on tab items:
- Close current tab
- Close other tabs
- Close tabs to the left (disabled on first tab)
- Close tabs to the right (disabled on last tab)

* 🐛 fix: defer single-click navigation on desktop to prevent double-click addTab race

*  feat: implement onActivate method for RecentlyViewed plugins to manage store state transitions

- Added onActivate method to RecentlyViewedPlugin interface for handling tab activations.
- Updated agentPlugin and agentTopicPlugin to switch topics based on tab activation.
- Enhanced PluginRegistry to notify plugins on tab activation.
- Modified TabBar to trigger onActivate when a tab is activated.
- Improved AgentIdSync to preserve topic state during agent switches.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: update test for BackendProxyProtocolManager to throw on upstream fetch failure

- Changed test description to reflect behavior change from returning a 502 status to throwing an error.
- Updated test implementation to use expect().rejects.toThrow for handling fetch errors.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: use optional chaining for agent configuration properties

- Updated agent configuration properties to use optional chaining for safer access.
- This change prevents potential runtime errors when properties are undefined.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: optimize navigation handling in TabBar with startTransition

- Introduced startTransition for navigation updates to improve performance and user experience.
- Updated handleActivate, handleCloseOthers, handleCloseLeft, and handleCloseRight methods to use startTransition for routing.
- Enhanced code readability by grouping navigation logic within startTransition.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-05 16:50:14 +08:00
Innei 9cb0560ebf feat(desktop): unified update channel switching with S3 distribution (#12644)
*  feat(desktop): add update channel settings for desktop app

* 🔧 chore(desktop): update test scripts for multi-channel update flow

- Support stable/nightly/canary channel structure in generate-manifest.sh
- Add --all-channels flag for generating manifests across all channels
- Dual-mode run-test.sh: packaged (full updater) and --dev (UI only)
- Fix package:mac:local to skip signing for local builds
- Document Squirrel.Mac signature validation limitation

* 🔧 chore(desktop): update local app update configuration

- Change provider from GitHub to Generic for local testing.
- Update local server URL and cache directory settings.
- Revise comments for clarity on usage and configuration.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix(desktop): fix update channel switch race condition and downgrade flag

- P1: Use generation counter to discard stale check results when channel
  is switched mid-flight. Pending recheck is scheduled after current check
  completes instead of forcing concurrent checks.
- P2: Explicitly reset allowDowngrade=false on non-downgrade transitions
  to prevent stale downgrade permission from persisting.
- Fix GitHub fallback repo name (lobe-chat -> lobehub).

* 🔧 chore(settings): remove dynamic import for Beta component from componentMap

- Eliminated the dynamic import for the Beta settings tab, streamlining the component map.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(settings): simplify UpdateChannel component structure

- Refactored the UpdateChannel component to streamline the Select component usage by removing unnecessary nested children.

Signed-off-by: Innei <tukon479@gmail.com>

* update

* 🐛 fix(desktop): strip channel suffix from UPDATE_SERVER_URL before appending channel

The UPDATE_SERVER_URL secret may already contain a channel path (e.g., /stable).
Previously, the code unconditionally appended /{channel}, resulting in double
paths like /stable/stable/stable-mac.yml.

Now both electron-builder.mjs and UpdaterManager strip any trailing channel
suffix before re-appending the correct channel, supporting both legacy URLs
(with channel) and clean base URLs.

* update

* update

* redesign ui

- Added `getUpdaterState` method to `UpdaterManager` for retrieving current update status.
- Introduced `UpdaterState` type to encapsulate update progress, stage, and error messages.
- Updated UI components to reflect update states, including checking, downloading, and latest version notifications.
- Enhanced menu items for macOS and Windows to display appropriate update statuses.
- Localized new update messages in English and Chinese.

This improves user experience by providing real-time feedback during the update process.

Signed-off-by: Innei <tukon479@gmail.com>

* Enhance UpdaterManager tests and mock implementations

- Updated tests for UpdaterManager to reflect changes in broadcasting update states, including 'checking', 'downloading', and 'error' stages.
- Modified mock implementations in macOS and Windows test files to include `getUpdaterState` and `installNow` methods for better state management.
- Improved test coverage for update availability and download processes.

These changes ensure more accurate testing of the update flow and enhance the overall reliability of the UpdaterManager functionality.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-05 15:15:03 +08:00
LiJian 15a50e999a 🐛 fix: should add m2m token to use community agents/mcp/skill list (#12708)
fix: should add m2m token to use community agents/mcp/skill list
2026-03-05 13:44:56 +08:00
Rdmclin2 1be9c000ec feat: support telegram bot access (#12671)
* support keyPrefix

* feat: add telegram platform implementation

* feat: add telegram front end ui

* feat: support webhookProxyUrl

* chore: add more log info

* fix: header align

* chore: add onNewMessage to platform specific

* fix: test connnectitvity and add application id

* feat: support local tunnel

* chore: optimize telegram message format

* fix: webhook secrect

* feat: keep typing interval

---------

Co-authored-by: arvinxx <arvinx@foxmail.com>
2026-03-05 10:52:32 +08:00
Innei 522dcf789c 🐛 fix(conversation): disable animation for single-line messages between reasoning and tool calls (#12675)
When a short message is sandwiched between reasoning and tool call blocks,
component remount during streaming causes the fadeIn animation to replay.
Disable animation for these tool-adjacent single-line messages to prevent
the visual flicker.
2026-03-05 01:10:11 +08:00
Arvin Xu a0c6c9765c 🐛 fix: use keyPrefix to fix discord bot conflict (#12638)
support keyPrefix
2026-03-05 00:01:40 +08:00
Arvin Xu ab376d9185 feat: add device code auth flow (#12697)
* add i18n

* fix types
2026-03-04 23:58:41 +08:00
YuTengjing 08b23a9732 feat(google): add gemini-3.1-flash-lite-preview model and thinkingLevel5 extend param (#12652) 2026-03-04 23:39:49 +08:00
LiJian 1fece1f8d9 🔨 chore: update the market sdk to 0.31.3 (#12693)
chore: update the market sdk to 0.31.3
2026-03-04 21:50:58 +08:00
Innei 07997b44a5 🐛 fix: skew plugin (#12669)
* fix: skew plugin

Signed-off-by: Innei <tukon479@gmail.com>

* refactor(vite): enhance vercelSkewProtection to handle static imports and improve coverage

- Added handling for static import/export declarations to ensure correct deployment links.
- Updated coverage documentation to reflect new handling for static imports and additional cases.
- Adjusted comment numbering for clarity in the processing steps.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: dev proxy

Signed-off-by: Innei <tukon479@gmail.com>

* refactor(AssistantGroup): streamline contentId handling in GroupMessage component

- Simplified the logic for determining contentId by directly using lastAssistantMsg?.id.
- Moved the creation and generation state checks to follow the contentId assignment for better clarity.

Signed-off-by: Innei <tukon479@gmail.com>

* ♻️ refactor: remove chunk error reload retry, keep notification only

Made-with: Cursor

* fix: inject

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-04 21:47:31 +08:00
René Wang 5d19dbf430 fix: Move email contact (#12323)
* fix: Move email contact

* style: profile

* fix: urk

* fix: urk

* feat: loading indicator

* fix: build error

* fix: sort

* fix: sort

* fix: sort

* fix: sort

* fix: sort
2026-03-04 19:37:31 +08:00
Neko 3f1473d65f fix(userMemories,database): should not fail if extra structure mismatch (#12686) 2026-03-04 19:09:13 +08:00
LiJian bf5d6ce2f8 🐛 fix: updown the old lobehub plugins (#12674)
* fix: updown the old lobehub plugins

* fix: update test.ts
2026-03-04 18:05:43 +08:00
Arvin Xu 6ba657e6d0 🔨 chore: fix to improve gateway (#12647)
improve gateway
2026-03-04 00:10:53 +08:00
Arvin Xu c2a49342f0 🔨 chore: update device gateway ci (#12645)
improve gateway
2026-03-03 23:41:51 +08:00
Luis Sambrano d92bb7a8e8 🐛 fix(context-engine): allow tool type recovery from manifest when models strip suffixes (#12636)
🐛 fix(context-engine): allow tool type recovery from manifest when models like GLM strip suffixes
2026-03-03 23:35:07 +08:00
Arvin Xu f223aeb7f4 🔨 chore: improve gateway (#12643)
improve gateway
2026-03-03 23:26:46 +08:00
YuTengjing 90714af0dc 🐛 fix: add await to handleResponseAPIMode to ensure proper error handling (#12640) 2026-03-03 21:56:57 +08:00
lobehubbot 8263359cc2 🔖 chore(release): release version v2.1.35 [skip ci] 2026-03-03 12:07:58 +00:00
lobehubbot 936379bd21 Merge remote-tracking branch 'origin/main' into canary 2026-03-03 12:07:53 +00:00
Arvin Xu a2c2a0ae76 🚀 release: 20260303 (#12631)
This release includes **90 commits**. Key updates are below.

###  New Features and Enhancements

- 🤖 Added **Discord IM bot integration** for receiving and responding to
messages within Discord channels.
([#12517](https://github.com/lobehub/lobehub/pull/12517))
- 🧩 Introduced **Agent Skills** support with progressive disclosure via
`lobe-tools`, allowing agents to expose task-specific capabilities.
([#12424](https://github.com/lobehub/lobehub/pull/12424),
[#12489](https://github.com/lobehub/lobehub/pull/12489))
- 🧠 Added **Memory Settings** for configuring memory effort and tool
permissions. ([#12514](https://github.com/lobehub/lobehub/pull/12514))
- 📧 Support for **changing email address** in profile settings.
([#12549](https://github.com/lobehub/lobehub/pull/12549))
- 🛡️ Added **unsaved changes guard** to prevent data loss on navigation.
([#12332](https://github.com/lobehub/lobehub/pull/12332))
- 🖱️ Support **Cmd+Click to open sidebar nav in new tab**.
([#12574](https://github.com/lobehub/lobehub/pull/12574))
- 🧮 Added **calculator builtin tool** for agents.
([#11715](https://github.com/lobehub/lobehub/pull/11715))
- 🎬 Added **video tab** to provider ModelList settings page with image
dimension/aspect ratio constraints for uploads.
([#12534](https://github.com/lobehub/lobehub/pull/12534),
[#12607](https://github.com/lobehub/lobehub/pull/12607))
- 🎯 Center active model on open in **model switch panel**.
([#12215](https://github.com/lobehub/lobehub/pull/12215))
- 🕹️ Support **agent management**.
([#12061](https://github.com/lobehub/lobehub/pull/12061))

### 🤖 Models and Provider Expansion

- 🌟 Added **Kimi K2 thinking models** (Moonshot).
([#12630](https://github.com/lobehub/lobehub/pull/12630))
- 🍌 Added **Nano Banana 2** support.
([#12493](https://github.com/lobehub/lobehub/pull/12493),
[#12496](https://github.com/lobehub/lobehub/pull/12496))
- 🎨 Added **Seedream 5 Lite** image generation model.
([#12459](https://github.com/lobehub/lobehub/pull/12459))
- 💨 Added **Qwen3.5 Flash** and Qwen3.5 OSS models.
([#12465](https://github.com/lobehub/lobehub/pull/12465))
- 🔮 Added **GLM-5**, **GLM-4.6V**, and **GLM-Image** for Zhipu.
([#12272](https://github.com/lobehub/lobehub/pull/12272))
- 📦 Batch updated model lists for AI360, Hunyuan, InternLM, Spark,
StepFun, Wenxin, and Seedream.
([#12371](https://github.com/lobehub/lobehub/pull/12371))
- 🗑️ Removed deprecated `chatgpt-4o-latest`.
([#12486](https://github.com/lobehub/lobehub/pull/12486))
-  Supplemented models from NewAPI pricing endpoint.
([#10628](https://github.com/lobehub/lobehub/pull/10628))

### 🏗️ Architecture

-  **Migrated frontend from Next.js App Router to Vite SPA** — a major
architectural change improving dev experience and build performance.
([#12404](https://github.com/lobehub/lobehub/pull/12404))
- 📂 Restructured SPA routes to `src/routes` and `src/router`.
([#12542](https://github.com/lobehub/lobehub/pull/12542))
- ♻️ Refactored client agent runtime.
([#12482](https://github.com/lobehub/lobehub/pull/12482))
- 🔥 Removed invite code requirement feature.
([#12474](https://github.com/lobehub/lobehub/pull/12474))

### 🖥️ Desktop Improvements

- 🔧 Fixed better-auth client stub for Electron renderer.
([#12563](https://github.com/lobehub/lobehub/pull/12563))

### Stability, Security, and UX Fixes

- Fixed topic/thread title summarization to respect `responseLanguage`
setting. ([#12627](https://github.com/lobehub/lobehub/pull/12627))
- Fixed MCP tool install loading state.
([#12629](https://github.com/lobehub/lobehub/pull/12629))
- Fixed mermaid rendering in notebook documents.
([#12624](https://github.com/lobehub/lobehub/pull/12624))
- Fixed global memory setting and tool enabled logic.
([#12610](https://github.com/lobehub/lobehub/pull/12610))
- Fixed Vertex AI 400 error caused by duplicate tool function
declarations. ([#12604](https://github.com/lobehub/lobehub/pull/12604))
- Fixed multiple Vertex AI and Moonshot runtime issues.
([#12595](https://github.com/lobehub/lobehub/pull/12595))
- Fixed SiliconCloud model thinking mode toggle.
([#10011](https://github.com/lobehub/lobehub/pull/10011))
- Fixed DeepSeek-Reasoner `reasoning_content` for tool calls.
([#12564](https://github.com/lobehub/lobehub/pull/12564))
- Fixed Google API key header passing (`x-goog-api-key`).
([#12506](https://github.com/lobehub/lobehub/pull/12506))
- Fixed `@napi-rs/canvas` hoisting for PDF parsing in Docker.
([#12475](https://github.com/lobehub/lobehub/pull/12475))
- Fixed model select panel flickering and improved list implementation.
([#12485](https://github.com/lobehub/lobehub/pull/12485))
- Fixed memory tools to run in server correctly with correct cron
schedule. ([#12471](https://github.com/lobehub/lobehub/pull/12471),
[#12568](https://github.com/lobehub/lobehub/pull/12568))
- Fixed group agent rename, skill search, and editor focus issues in
agent settings.
([#12511](https://github.com/lobehub/lobehub/pull/12511),
[#12432](https://github.com/lobehub/lobehub/pull/12432),
[#12512](https://github.com/lobehub/lobehub/pull/12512))
- Fixed NewAPI proxy gzip handling.
([#10628](https://github.com/lobehub/lobehub/pull/10628))
- Fixed provider request filtering for disabling browser requests.
([#12002](https://github.com/lobehub/lobehub/pull/12002))
- Fixed `input_image` incorrectly passed when no `image_url` present.
([#12017](https://github.com/lobehub/lobehub/pull/12017))
- Fixed crawler error handling and timeout cancellation.
([#12487](https://github.com/lobehub/lobehub/pull/12487))
- Added username and fullName length validation.
([#12614](https://github.com/lobehub/lobehub/pull/12614))
- Added database migration to Vercel build command.
([#12551](https://github.com/lobehub/lobehub/pull/12551))
- Improved auth db fallback for secondary-storage sessions.
([#12548](https://github.com/lobehub/lobehub/pull/12548))
- Fixed type not preserved when model batch processing.
([#10015](https://github.com/lobehub/lobehub/pull/10015))
- Fixed search issue.
([#12457](https://github.com/lobehub/lobehub/pull/12457))

### 🙏 Credits

Huge thanks to these contributors (alphabetical):

@Innei @arvinxx @canisminor1990 @cy948 @eaten-cake @eronez @hezhijie0327
@mikelambert @nekomeowww @rdmclin2 @sxjeru @tjx666
2026-03-03 20:07:11 +08:00
sxjeru 1c1af17716 feat: add auto aspect ratio and image search support for Nano Banana 2 (#12537)
* Update sync.yml

*  feat: update aspect ratio defaults to 'auto' for image generation models

*  feat: enhance grounding metadata handling with image search results support

*  feat: filter empty strings from searchQueries in groundingMetadata and update favicon handling in SearchGrounding component

*  feat: add inputToolTokens tracking and update related components for tool usage

*  feat: enhance search grounding with image results and update related components

*  feat: add ImageSearchRef component and related tests for image reference handling

* fix test: rename VertexAIStream to GoogleGenerativeAIStream for consistency in test cases

* Update sync.yml
2026-03-03 19:31:29 +08:00
huangkairan 1cf0257326 fix: scripts support win32 (#12613)
Co-authored-by: Innei <tukon479@gmail.com>
2026-03-03 19:19:56 +08:00
YuTengjing 138788b1d4 feat(moonshot): add kimi-k2 thinking models and update model bank (#12630) 2026-03-03 19:15:10 +08:00
YuTengjing b44f79857b 🐛 fix(topic): use responseLanguage for topic/thread title summarization (#12627) 2026-03-03 18:52:29 +08:00
Innei 58fb45d251 🐛 fix: add unsaved changes guard to prevent data loss on navigation (#12332)
* 🐛 fix: add unsaved changes guard to prevent data loss on navigation

Migrate from BrowserRouter to createBrowserRouter (data router API) to enable
route-level navigation blocking. Add UnsavedChangesGuard component that uses
useBlocker to prevent leaving editor pages with unsaved changes, auto-saving
before navigation. Remove legacy renderRoutes/RouteConfig dead code.

Fixes LOBE-4973

* 🔧 chore: remove unused ESLint suppressions for welcome.ts

Cleaned up eslint-suppressions.json by removing suppressions related to sort-keys-fix and typescript-sort-keys for welcome.ts, as they are no longer needed.

Signed-off-by: Innei <tukon479@gmail.com>

*  perf: skip JSON snapshot on selection-only Lexical updates

Reintroduce dirtyElements/dirtyLeaves guard before editor.getDocument('json')
and deep-equality check, avoiding O(document-size) work on caret/selection
updates that do not mutate content.

* 🔧 test: update UnsavedChangesGuard tests to use message.destroy instead of message.success

Signed-off-by: Innei <tukon479@gmail.com>

* fix: dayjs init

- Moved dayjs plugin extensions (relativeTime, utc, isToday, isYesterday) to src/initialize.ts for centralized initialization.
- Removed redundant extensions from individual components to prevent duplicate calls.
- Updated locale loading logic in Locale.tsx to ensure correct dayjs locale handling.

This change improves performance by ensuring dayjs plugins are only extended once during application initialization.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: update router configuration to use RouteObject type

- Changed the type of desktopRoutes from RouteConfig[] to RouteObject[] for better compatibility with react-router-dom.
- Removed the RouteConfig interface from the router utility file to streamline the codebase.

This refactor enhances the router's integration with the latest routing library standards.

Signed-off-by: Innei <tukon479@gmail.com>

* feat: enhance Vite configuration and chunk management

- Added a function to suppress Vite's default URL print in the server configuration.
- Updated chunk file naming strategy in sharedRollupOutput to organize output files into specific directories based on chunk type (i18n, vendor, assets).
- Removed redundant dayjs chunk handling logic to streamline the manualChunks function.

These changes improve the clarity of the build output and enhance the server's configuration options.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add collapsible error stack with __CI__ default expand

- Add Collapse + Highlighter for error stack in Error component
- Define __CI__ in Vite (sharedRendererDefine) based on process.env.CI
- Add __CI__ to global.d.ts
- Add error.stack i18n to all 18 locales

Made-with: Cursor

* chore: update build:spa:copy script to handle multiple asset directories

- Modified the build:spa:copy script in package.json to iterate over multiple directories (assets, i18n, vendor) for both desktop and mobile builds, improving the asset copying process.

This change enhances the build process by ensuring all relevant directories are copied correctly.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: mark initialize.ts as sideEffects to prevent tree-shaking

sideEffects: false caused Rollup to drop the side-effect-only import
of initialize.ts, removing dayjs.extend(relativeTime) and enableMapSet()
from the production bundle.

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-03 18:50:57 +08:00
Rdmclin2 026af3f6bc 🐛 fix: mcp tool install loading (#12629)
fix: mcp tool install loading
2026-03-03 18:47:43 +08:00
Arvin Xu bcae49ff65 🔨 chore: exclude apps/device-gateway in type check (#12628)
exclude apps/device-gateway route
2026-03-03 18:41:26 +08:00
Innei 89857847bf 🐛 fix(markdown): render mermaid in notebook document (#12624)
* 🐛 fix(markdown): render mermaid blocks in notebook documents

Render `mermaid` code fences with the Mermaid component in MDX code blocks so notebook documents display diagrams consistently with chat flow.

Made-with: Cursor

* fix: search event

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-03 18:03:58 +08:00
Arvin Xu a1a89b3531 💄 style: improve server agent harness (#12611)
* add device gateway

* improve persona memory

* support auto renaming

* support memory

* fix memory captureAt

* add more db testing

* add more db testing

* add agent tracing tool

* add agent tracing tool

* fix lint

* fix lint

* update skills

* Potential fix for code scanning alert no. 178: Workflow does not contain permissions

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-03 17:35:18 +08:00
LobeHub Bot f234397bf8 🌐 chore: translate non-English comments to English in bot/ackPhrases (#12606)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 17:34:20 +08:00
Rdmclin2 ceeb9c6613 🐛 fix: global memory setting & tool enabled logic (#12610)
* fix: global enable user memories

* fix: memory tool enabled logic
2026-03-03 16:50:24 +08:00
YuTengjing 9ab2f219e4 🌐 locale: add usernameTooLong translations with CJK spacing fix (#12615) 2026-03-03 16:13:18 +08:00
CanisMinor 43578a9bcc 📝 docs: Polishing and improving product documentation (#12612)
* 🔖 chore(release): release version v2.1.34 [skip ci]

* 📝 docs: Polish documents

* 📝 docs: Fix typo

* 📝 docs: Update start

* 📝 docs: Fix style

* 📝 docs: Update start

* 📝 docs: Update layout

* 📝 docs: Fix typo

* 📝 docs: Fix typo

---------

Co-authored-by: lobehubbot <i@lobehub.com>
2026-03-03 16:01:41 +08:00
YuTengjing 4926b20271 🐛 fix(user): add length validation for username and fullName (#12614) 2026-03-03 15:48:04 +08:00
YuTengjing 521a0a077e feat(video): add image dimension and aspect ratio constraints for uploads (#12607)
* ♻️ refactor: replace minImageSize with width/height min/max constraints

Refactor image dimension validation from a single `minImageSize` value
to flexible `width`/`height` objects with `min`/`max`, consistent with
the `duration` field's min/max pattern.

* ♻️ refactor: handle single-axis constraints in dimension error messages

Build dimension constraint text dynamically (e.g. "width ≥ 300px" or
"width ≥ 300px, height ≥ 300px") instead of interpolating raw
minWidth/minHeight values, preventing "300xundefinedpx" when only one
axis is constrained.

* ♻️ refactor(video): add max dimension constraint per official docs

Seedance image dimensions: 300-6000px per official documentation.

*  feat(video): add aspect ratio validation for image uploads

Support aspectRatio constraint (width/height) with min/max in schema.
Seedance config: aspectRatio { min: 0.4, max: 2.5 } per official docs.

* ♻️ refactor(locales): add image dimension validation messages for multiple languages
2026-03-03 14:12:34 +08:00
YuTengjing e733397f5d 🐛 fix: deduplicate tool function declarations to fix Vertex AI 400 error (#12604) 2026-03-03 11:44:58 +08:00
YuTengjing c1521d2aeb 💄 style: batch fix eslint violations across packages (#12601) 2026-03-03 02:19:50 +08:00
Arvin Xu 466f713ca6 💄 style: improve discord intergration (#12598)
* add tests

* fix reference messages issue

* support file upload

* support reference file content

* fix eye issue
2026-03-03 01:44:45 +08:00
YuTengjing 8ced872e53 🐛 fix(model-runtime): fix multiple Vertex AI and Moonshot runtime issues (#12595) 2026-03-03 01:34:53 +08:00
YuTengjing 6ecba929b7 🔨 chore: remove dead eslint disable comments for deleted rules (#12597) 2026-03-02 23:18:01 +08:00
Rdmclin2 607dfdec96 feat: support memory setting (#12514)
* feat: add memory actionbar and setting config

* chore: hide memory tool in skill popcontent

* test: add memory effort test case

* chore: update i18n files

* chore: update i18n files
2026-03-02 23:14:02 +08:00
Innei c4d85d100c ⬆️ chore(deps): migrate @lobehub/ui to base-ui exports (#12587)
* ⬆️ chore(deps): migrate @lobehub/ui to base-ui exports

- Migrate LobeSelect → Select from @lobehub/ui/base-ui
- Migrate LobeSwitch → Switch from @lobehub/ui/base-ui
- Fix DropdownItem import (use main package instead of internal path)
- Add initialWidth, popupWidth support to ModelSelect

Made-with: Cursor

* ⬆️ chore(deps): update @lobehub packages to latest versions

- Upgrade @lobehub/charts to ^5.0.0
- Upgrade @lobehub/editor to ^4.0.0
- Upgrade @lobehub/icons to ^5.0.0
- Upgrade @lobehub/market-sdk to ^0.31.1
- Upgrade @lobehub/tts to ^5.0.0
- Upgrade @lobehub/ui to ^5.0.0 across multiple packages
- Update peer dependencies for various packages to align with new @lobehub/ui version

Made-with: Cursor
Signed-off-by: Innei <tukon479@gmail.com>

* ⬆️ chore(deps): update @lobehub/tts to version 5.1.2

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-02 22:40:46 +08:00
YuTengjing a9511344f9 feat(model-runtime): add optionIndex to RouteAttemptResult (#12588) 2026-03-02 20:10:22 +08:00
LobeHub Bot eb1da3c297 🌐 chore: translate non-English comments to English in market-auth module (#12572)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 17:45:04 +08:00
YuTengjing c8d2f28bf5 💄 style: fix cursor pointer on dropdown tags and rename downloadClient to getDesktopApp (#12582) 2026-03-02 17:04:52 +08:00
Arvin Xu 46c9cb3b03 💄 style: improve discord interaction (#12573)
* improve discord interaction

* improve discord interaction

* update

* update Message engine

* add test

* update vercel route
2026-03-02 16:13:21 +08:00
Innei dc6d5cf489 📝 docs(desktop): update Development.md to reflect current project structure [skip ci] (#12581)
📝 docs(desktop): update Development.md to reflect current project structure

Made-with: Cursor
2026-03-02 15:36:04 +08:00
YuTengjing c068363fac 💄 style: support Cmd+Click to open sidebar nav in new tab (#12574) 2026-03-02 12:50:05 +08:00
arvinxx dd0d4d8890 improve discord interaction 2026-03-02 11:38:47 +08:00
Neko 01606208c5 fix(userMemories): incorrect hourly cron schedule for memory analysis (#12568) 2026-03-02 02:06:56 +08:00
Rylan Cai 5fe0ac228e 🐛 fix: should not pass input_image in message content when has no image_url (#12017)
* 🐛 fix: should not pass `input_image` when has no url

* 🐛 fix: model output should use output text

* 📝 docs: re run ci

* 📝 docs: improve codes
2026-03-02 01:35:04 +08:00
Arvin Xu 16946a4d5b 💄 style: get user timezone when open (#12567)
* fix timezone issue

* fix tests
2026-03-02 01:30:10 +08:00
Innei 37e90cebfa 🐛 fix(desktop): stub better-auth client for Electron renderer (#12563)
* 🐛 fix(desktop): stub better-auth client for Electron and improve drag regions

Add auth-client.desktop.ts noop stub so the Electron renderer build
skips the real better-auth dependency that was crashing module evaluation
and preventing React from mounting.

Also fix drag-bar regions in splash.html and error.html, and add
dev:desktop convenience script.

* ♻️ refactor(desktop): lazy-init better-auth client with remote server URL

Replace noop stub with Proxy-based lazy initialization that creates the
real better-auth client on first use, using the configured remote server
URL from the electron store as baseURL.

* 🔧 fix(desktop): update Proxy target in lazyProp for better-auth client initialization

Change the Proxy target in the lazyProp function from a noop stub to a function, ensuring the apply trap works correctly for lazy initialization of the better-auth client.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix(profile): restrict SSO providers display to non-desktop view

Update the condition for rendering the SSO Providers Row in the Profile Settings to only show when the user is logged in and not on a desktop device. This change improves the user interface by preventing unnecessary display on desktop screens.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-01 22:20:10 +08:00
YuTengjing ee85ea728a 🐛 fix(model-runtime): ensure reasoning_content for deepseek-reasoner tool calls (#12564) 2026-03-01 22:16:12 +08:00
YuTengjing 9b5b4d2579 feat(model-runtime): pass userId in RouteAttemptResult callback (#12562) 2026-03-01 21:45:03 +08:00
Innei 5f2f49a26e feat(vite): add env restart keys plugin for selective .env restart (#12561)
Add a Vite plugin that prevents server restart on every .env file change,
only restarting when whitelisted env keys actually change their values.
2026-03-01 20:58:05 +08:00
sxjeru 8ca9c0100e 🐛 fix(vercel): add database migration to build command (#12551)
* 🐛 fix(vercel): add database migration to build command

* 🐛 fix(build): update Vercel build command to use new build script

---------

Co-authored-by: Arvin Xu <arvinx@foxmail.com>
2026-03-01 20:56:32 +08:00
LobeHub Bot 1c11921a32 🌐 chore: translate non-English comments to English in MCP module (#12520)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 19:58:59 +08:00
Arvin Xu d68acec58e feat: support Discord IM bot intergration (#12517)
* clean

fix tools calling results

improve display

support discord bot

finish bot integration

* improve next config

* support queue callback mode

* support queue callback mode

* improve error

* fix build

* support serverless gateway

* support serverless gateway

* support serverless enable

* improve ui

* improve ui

* add credentials config

* improve and refactor data working

* update config

* fix integration

* fix types

* fix types

* fix types

* fix types

* move files

* fix update

* fix update

* fix update
2026-03-01 19:54:38 +08:00
sxjeru 902a265aed 🐛 fix: type not preserved when model batch processing (#10015)
*  feat(aiModel): preserve type information when creating and updating models
🔤 fix(clerk): update translation for password to通行密钥

*  feat(qwen): 添加 Qwen3 Max Preview 模型,支持上下文缓存和复杂任务

*  feat(qwen): 更新 qwenChatModels,添加推理和搜索能力

*  feat(aiModel): 优化批量插入和更新模型

*  feat(cerebras, google): 移除 Qwen 3 Coder 480B 模型并更新 Nano Banana 模型的上下文窗口和最大输出

*  feat(moonshot): 添加 Kimi K2 Thinking 和 Kimi K2 Thinking Turbo 模型,更新模型参数处理

*  feat(minimax, ollamacloud): 添加缓存读取和写入定价,更新 Kimi K2 Thinking 模型信息

* ♻️ refactor: 更新通行密钥相关文本及优化数据库模型代码

*  feat(moonshot): 处理模型列表以包含上下文窗口令牌和模型 ID

*  feat(moonshot): 添加支持图像输入的模型属性

*  feat: 更新模型参数,调整上下文窗口令牌,移除冗余代码
2026-03-01 19:30:07 +08:00
LobeHub Bot 9cd63765b0 test: add unit tests for mimeType utility (#12555)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 19:25:28 +08:00
Innei 794fe5f60b ♻️ refactor: restructure SPA routes to src/routes and src/router (#12542)
* 📝 docs: add SPA routes restructure design and implementation plan

* ♻️ refactor: restructure SPA routes to src/routes and src/router

- Move SPA page components from src/app/[variants] to src/routes/
  - (main) -> Desktop pages
  - (mobile) -> Mobile pages
  - (desktop) -> Desktop-specific pages
  - onboarding -> Onboarding pages
  - share -> Share pages
- Move router configurations from src/app/[variants]/router to src/router/
  - desktopRouter.config.tsx
  - desktopRouter.config.desktop.tsx
  - mobileRouter.config.tsx
- Keep auth pages in src/app/[variants]/(auth) for SSR
- Update all import paths:
  - @/app/[variants]/ -> @/routes/
  - Relative paths adjusted for new directory structure
- Update CLAUDE.md and project-overview skill documentation

* 🔧 chore: restore imports for RouteConfig and ErrorBoundary in desktopRouter.config.desktop.tsx

- Reintroduced the imports for RouteConfig, ErrorBoundary, and redirectElement in the desktop router configuration file.
- Ensured proper organization and functionality of the desktop routing setup.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: update import paths after routes restructure

- Fix imports from old `src/app/[variants]/` to new `src/routes/` paths
- Update Title, Sidebar, MakedownRender, McpList imports
- Fix desktop-onboarding/storage import path
- Run lint --fix to sort imports

* 📝 docs: SPA routes convention and spa-routes skill

- Add roots vs features rules to CLAUDE.md and AGENTS.md
- Add .agents/skills/spa-routes for route/feature file division
- Phase 1: move page route logic to src/features/Pages, thin route files

Made-with: Cursor

* 🌐 chore: translate non-English comments to English in memory module (#12547)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* ♻️ refactor: move router and entries to src/spa, platform-based warmup

- Move src/router and entry.*.tsx to src/spa/
- Update HTML, vite.config, and entry imports
- Warmup only the entry matching current platform (web/mobile)
- Update CLAUDE.md, AGENTS.md, and spa-routes skill

Made-with: Cursor

* 🗂️ chore: restructure SPA routes and configurations

- Deleted outdated SPA routes and implementation plan documents.
- Migrated SPA page components to new `src/routes/` directory.
- Moved route configurations to `src/router/`.
- Updated import paths across the project to reflect new structure.
- Revised AI documentation to align with the updated directory layout.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: LobeHub Bot <i@lobehub.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 18:35:38 +08:00
LobeHub Bot 5e3a8146d1 🌐 chore: translate non-English comments to English in memory module (#12547)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 14:58:23 +08:00
YuTengjing c1d2e761fe 💄 style: unify zh-CN wording from 点数 to 积分 (#12553) 2026-03-01 12:38:19 +08:00
Arvin Xu 8bc3a8a886 🔨 chore: fix oidc-provider issue in turbopack (#12550)
fix oidc-provider issue
2026-03-01 12:19:10 +08:00
Zhijie He 2b2892aa2b 💄 style: add qwen3.5-flash & Qwen3.5 OSS models (#12465)
* style: add `qwen3.5-flash` & Qwen3.5 OSS models

* fix: fix vision tag missing

* update list

* fix: restore imageGen models default enabled status
2026-03-01 12:02:46 +08:00
YuTengjing 984884ba2b feat: support changing email address in profile settings (#12549) 2026-03-01 12:01:53 +08:00
YuTengjing dc26f23ea0 🐛 fix(auth): enable db fallback for secondary-storage sessions (#12548) 2026-03-01 11:25:22 +08:00
Innei 18ec113bba 🔧 chore: simplify build config and remove webpack customization (#12539)
- Remove desktop-related build steps from Dockerfile
- Simplify next.config.ts, only apply Vercel-specific config on Vercel
- Remove webpack customization from define-config.ts
- Fix String() type conversion in video.ts
2026-03-01 00:22:21 +08:00
YuTengjing d9b4ab01ce feat(redis): add pipeline support to Redis abstraction layer (#12538) 2026-03-01 00:07:35 +08:00
sxjeru 4279f0e57c 🐛 fix: unable to toggle SiliconCloud model thinking mode (#10011)
*  fix: 修复 siliconcloud 思考模型开关

*  feat: 更新思考模型参数设置,优化 enable_thinking 和 thinking_budget 逻辑

*  feat: 增强 SiliconCloud API 错误处理,支持提取错误代码和消息

* feat: 使用 TextEncoder 计算响应内容的字节长度,替代 Buffer

* 🐛 fix: handle undefined thinking.type in enable_thinking assignment

* 🐛 fix: 修复 enable_thinking 赋值时处理 undefined thinking.type 的情况;更新测试以确保错误消息有效

*  feat: 更新 aiModels 文件中的描述为英文,确保符合英语描述规范;移除不必要的字段
2026-02-28 23:23:25 +08:00
YuTengjing ac0be5ed5c feat: add video tab to provider ModelList settings page (#12534) 2026-02-28 22:29:51 +08:00
lobehubbot 9f22867f3c 🔖 chore(release): release version v2.1.34 [skip ci] 2026-02-28 13:06:21 +00:00
lobehubbot ed4eb874b2 Merge remote-tracking branch 'origin/main' into canary 2026-02-28 13:06:11 +00:00
Arvin Xu 49a8f6b497 🐛 fix: fix benchmarks table schema not correctly (#12532)
* fix benchmark table issue

* add new db migration

* fix types
2026-02-28 21:05:32 +08:00
Innei 3112036b38 🔧 chore: resolve all ESLint suppressions and remove suppression file (#12518)
* 🔧 chore: upgrade ESLint deps and resolve all suppressions

- Upgrade eslint 10.0.0→10.0.2, @lobehub/lint 2.1.3→2.1.5, eslint-plugin-mdx ^3.6.2→^3.7.0
- Remove eslint-suppressions.json and all suppression-related scripts/configs
- Fix 197 ESLint errors: no-console, no-unused-private-class-members, no-useless-assignment, preserve-caught-error, prefer-const, regex issues, etc.
- Remove dead rule references (sort-keys-fix, typescript-sort-keys, ban-types)
- Disable project-convention-conflicting rules globally in eslint.config.mjs
- Update test spies from console.log to console.info

* 🔧 fix: update regex for unresolved model error handling

- Modified the UNRESOLVED_MODEL_REGEXP to allow for additional valid characters in model names, enhancing error detection for missing models.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-28 20:23:04 +08:00
sxjeru 7d7af6b8ca 💄 style: add support for Nano Banana 2 (#12496)
*  feat: add support for new image resolution and thinking level parameters in model configurations

*  feat: add Gemini 3.1 Flash Image model with enhanced capabilities and update model configurations

* 🐛 fix: adjust temperature setting based on model modalities in LobeGoogleAI

*  feat: add DeepSeek V3.2 model and update existing model configurations

*  feat: add ImageResolution2Slider and ThinkingLevel4Slider components; remove obsolete imports

*  feat: add imageAspectRatio2 parameter for Nano Banana 2 model; update related components and configurations

* 🐛 fix: refactor outputTextTokens calculation for clarity and consistency
2026-02-28 20:03:50 +08:00
LobeHub Bot 27c3a831f2 test: add unit tests for DocumentService (#12525)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:50:06 +08:00
Innei a5c454589d ️ perf(spa): lazy import spaHtmlTemplates to reduce initial bundle (#12526)
* ️ perf(spa): lazy import spaHtmlTemplates to reduce initial bundle

* 🔧 chore: update package dependencies and Vite configuration

- Bump @lobehub/icons version from ^4.1.0 to ^4.9.0 in package.json for improved features and fixes.
- Set Vite server host to '0.0.0.0' for better accessibility during development.
- Refactor asset URL rewriting in route.ts to simplify the return statement in the development mode.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(analytics): enhance Google and Vercel analytics integration

- Refactored GoogleAnalytics component to accept a `gaId` prop for improved flexibility.
- Updated VercelAnalytics component to accept a `debug` prop, allowing for dynamic debugging.
- Modified Analytics index to pass the appropriate props to Google and Vercel components based on environment settings.
- Removed the obsolete LobeAnalyticsProviderWrapper.vite.tsx file to streamline the codebase.

This update improves the configurability of analytics components and cleans up unused files.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-28 17:15:59 +08:00
Arvin Xu 4d3c759d25 🔨 chore: fix dev start scripts (#12528)
fix dev start
2026-02-28 15:00:17 +08:00
sxjeru c8b23c6819 🐛 fix(newapi): supplement models from NewAPI pricing endpoint & fix proxy gzip handling (#10628)
*  feat: enhance model pricing handling and prevent duplication from pricing list

*  feat: add description field to NewAPIPricing and update fetch headers for JSON response

*  feat: 添加混元2.0模型及其定价信息,增强模型能力描述

*  feat: 添加 DeepSeek V3.2 模型及其定价信息,移除过时的实验性模型

*  feat: 启用 DeepSeek V3.2 和 V3.1 Terminus 模型,移除不必要的 enabled 属性

*  feat: 添加 GLM-4.6V 和 GLM-4.6V-Flash 模型,更新模型能力和定价信息

*  feat: 移除 Mistral Saba 24B 模型,更新 Zenmux 模型的能力描述

*  feat: 移除 LearnLM 实验性模型,更新 Mistral 模型的上下文窗口和描述信息

*  feat: 添加 GLM-4.6V 模型,更新 siliconcloud 模型的上下文窗口,移除过时的 Gemini 模型

*  feat: update model descriptions and add new model processing test

* update model descriptions to English for better clarity

* Update siliconcloud.ts

* 🔧 refactor: simplify pricing list check and remove unused input reference in Editing component

* translated

*  feat(models): add Z.ai GLM 4.7 model and update Qwen deployment date

* Delete src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/Editing.tsx

* 🔧 refactor(groq): remove unused 'Llama 4 Maverick' model and its properties

* 🔧 refactor(models): 移除多个重复模型模型及其属性

* 🔧 chore(package): 调整构建脚本中的内存限制
2026-02-28 14:49:05 +08:00
Arvin Xu eef04c499f 💄 style: suppot agent management (#12061)
* feat: improve the inject model context plugins decriptions

fix: change the conversation-flow to change the subAgent message show place

fix: eslint fixed

fix: slove the inject not work problem

feat: add the lost agent management inject open

feat: add the AgentManagementInjector

fix: add the exec task mode & improve the Pre-load agents

fix: improve the executor import way & update the getEffectiveAgentId function

fix: slove the test problem

🐛 fix: support agnet manager ments (#12171)

feat: add the sub agents in context scope to support call subagent

refactor agent management implement

update

add builtin agent management

* fix types

* fix import

* fix test

* fix tests

* fix tests
2026-02-28 13:52:35 +08:00
sxjeru 4f3055e0c5 🐛 fix: update provider request filtering to include settings for disabling browser requests (#12002)
* 🐛 fix: update provider request filtering to include settings for disabling browser requests

* 🐛 test: add unit tests for isProviderDisableBrowserRequest function

* 🐛 fix(models): remove deprecated AI models and add Step 3.5 Flash model

*  feat(model-bank): add Qwen3 Coder Next and GLM-4.7 models; remove Qianfan Lightning 128B A19B

* feat: add new Qwen3.5 and MiniMax-M2.5 models with updated pricing and capabilities

* feat: update cerebras and ollamacloud models with new Qwen3.5 capabilities and adjust pricing in qwen model
2026-02-28 12:48:21 +08:00
YuTengjing d9d1d071b7 💄 style: correct translation for Nano Banana2 in home.json (#12515) 2026-02-28 01:07:16 +08:00
YuTengjing c22cd67b5f 💄 style: replace Nano Banana emoji with icon component (#12513) 2026-02-28 01:05:18 +08:00
Innei 687b36c81c ♻️ refactor: migrate frontend from Next.js App Router to Vite SPA (#12404)
* init plan

* 📝 docs: update SPA plan for dev mode Worker cross-origin handling

- Clarified the handling of Worker cross-origin issues in dev mode, emphasizing the need for `workerPatch` to wrap cross-origin URLs as blob URLs.
- Enhanced the explanation of the dev mode's resource URL rewriting process for better understanding.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: Phase 1 - 环境变量整治

- Fix Pyodide env var mismatch (NEXT_PUBLIC_PYPI_INDEX_URL → pythonEnv.NEXT_PUBLIC_PYODIDE_PIP_INDEX_URL)
- Consolidate python.ts to use pythonEnv instead of direct process.env
- Remove NEXT_PUBLIC_ prefix from server-side MARKET_BASE_URL (5 files)

* 🏗️ chore: Phase 2 - Vite 工程搭建

- Add vite.config.ts with dual build (desktop/mobile via MOBILE env)
- Add index.html SPA template with __SERVER_CONFIG__ placeholder
- Add entry.desktop.tsx and entry.mobile.tsx SPA entry points
- Add dev:spa, dev:spa:mobile, build:spa, build:spa:copy scripts
- Install @vitejs/plugin-react and linkedom

* ♻️ refactor: Phase 3 - 第一方包 Next.js 解耦

- Replace next/link with <a> in builtin-tool-web-browsing (4 files, external links)
- Replace next/image with <img> in builtin-tool-agent-builder/InstallPlugin.tsx
- Add Vite import.meta.env compat for isDesktop in const/version.ts, builtin-tool-gtd, builtin-tool-group-management

* ♻️ refactor: Phase 4a - Auth 页面改用直接 next/navigation 和 next/link

- 9 auth files: @/libs/next/navigation → next/navigation
- 5 auth files: @/libs/next/Link → next/link
- Auth pages remain in Next.js App Router, need direct Next.js imports

* ♻️ refactor: Phase 4b - Next.js 抽象层替换为 react-router-dom/vanilla React

- navigation.ts: useRouter/usePathname/useSearchParams/useParams → react-router-dom
- navigation.ts: redirect/notFound → custom error throws
- navigation.ts: useServerInsertedHTML → no-op for SPA
- Link.tsx: next/link → react-router-dom Link adapter (href→to, external→<a>)
- Image.tsx: next/image → <img> wrapper with fill/style support
- dynamic.tsx: next/dynamic → React.lazy + Suspense wrapper

*  feat: Phase 5 - 新建 SPAGlobalProvider

- Create SPAServerConfig type (analyticsConfig, clientEnv, theme, featureFlags, locale)
- Add window.__SERVER_CONFIG__ and __MOBILE__ to global.d.ts
- Create SPAGlobalProvider (client-only Provider tree mirroring GlobalProvider)
- Includes AuthProvider for user session support
- Update entry.desktop.tsx and entry.mobile.tsx to wrap with SPAGlobalProvider

* ♻️ refactor: add SPA catch-all route handler with Vite dev proxy

- Create (spa)/[[...path]]/route.ts for serving SPA HTML
- Dev mode: proxy Vite dev server, rewrite asset URLs, inject Worker patch
- Prod mode: read pre-built HTML templates
- Build SPAServerConfig with analytics, theme, clientEnv, featureFlags
- Update middleware to pass SPA routes through to catch-all

* ♻️ refactor: skip auth checks for SPA routes in middleware

SPA pages are all public (no sensitive data in HTML).
Auth is handled client-side by SPAGlobalProvider's AuthProvider.
Only Next.js auth routes and API endpoints go through session checks.

* ♻️ refactor: replace Next.js-specific analytics with vanilla JS

- Google.tsx: replace @next/third-parties/google with direct gtag script
- ReactScan.tsx: replace react-scan/monitoring/next with generic script
- Desktop.tsx: replace next/script with native script injection

* ♻️ refactor: migrate @t3-oss/env-nextjs to @t3-oss/env-core

Replace framework-specific env validation with framework-agnostic version.
Add clientPrefix where client schemas exist.

* ♻️ refactor: replace next-mdx-remote/rsc with react-markdown

Use client-side react-markdown for MDX rendering instead of
Next.js RSC-dependent next-mdx-remote.

* 🔧 chore: update build scripts and Dockerfile for SPA integration

- build:docker now includes SPA build + copy steps
- dev defaults to Vite SPA, dev:next for Next.js backend
- Dockerfile copies public/spa/ assets for production
- Add public/spa/ to .gitignore (build artifact)

* 🗑️ chore: remove old Next.js route segment files and serwist PWA

- Delete [variants] page.tsx, error.tsx, not-found.tsx, loading.tsx
- Delete root loading.tsx and empty [[...path]] directory
- Delete unused loaders directory
- Remove @serwist/next PWA wrapper from Next.js config

* plan2

*  feat: add locale detection script to index.html for SPA dev mode

* ♻️ refactor: remove locale and theme from SPAServerConfig

*  feat: add [locale] segment with force-static and SEO meta generation

* ♻️ refactor: remove theme/locale reads from SPAGlobalProvider

*  feat: set vite base to /spa/ for production builds

*  feat: auto-generate spaHtmlTemplates from vite build output

* 🔧 chore: register dev:next task in turbo.json for parallel dev startup

* ♻️ refactor: rename (spa) route group to spa segment, rewrite SPA routes via middleware

*  feat: add Vite-compatible i18n/locale modules with import.meta.glob and resolve aliases

* 🔧 fix: use custom Vite plugin for module redirects instead of resolve.alias

* very important

* build

* 🔧 chore: update build scripts and clean up Vite configuration by removing unused plugin and code

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ refactor: remove all electron modifier scripts

Modifiers are no longer needed with Vite SPA renderer build.

*  feat: add Vite renderer entry to electron-vite config

Add renderer build configuration to electron-vite, replacing the old
Next.js shadow workspace build flow. Delete buildNextApp.mts and
moveNextExports.ts, update package.json scripts accordingly.

*  feat: add .desktop suffix files for eager i18n loading

Create 4 .desktop files that use import.meta.glob({ eager: true })
for synchronous locale access in Electron desktop builds, replacing
the async lazy-loading used in web SPA builds.

* 🔧 refactor: adapt Electron main process for Vite renderer

Replace nextExportDir with rendererDir, update protocol from
app://next to app://renderer, simplify file resolution to SPA
fallback pattern, update _next/ asset paths to /assets/.

* 🔧 chore: update electron-builder files config for Vite renderer

Replace dist/next references with dist/renderer, remove Next.js
specific exclusion rules no longer applicable to Vite output.

* 🗑️ chore: remove @ast-grep/napi dependency

No longer needed after removing electron modifier scripts.

* 🔧 refactor: unify isDesktop to __ELECTRON__ compile-time constant

Remove NEXT_PUBLIC_IS_DESKTOP_APP and VITE_IS_DESKTOP_APP env vars.
Unify isDesktop in @lobechat/const using __ELECTRON__ defined by Vite.
Re-export from builtin-tool packages. Scripts use DESKTOP_BUILD.

* update

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: use electron-vite ELECTRON_RENDERER_URL instead of hardcoded port 3015

Replace hardcoded http://localhost:3015 with process.env.ELECTRON_RENDERER_URL
injected by electron-vite dev server. Clean up stale Next.js references.

* 🐛 fix: use local renderer-entry shim to resolve Vite root path issue

HTML entry ../../src/entry.desktop.tsx resolves to /src/entry.desktop.tsx
in URL space, which Vite cannot find within apps/desktop/ root. Add a
local shim that imports across root via module resolver instead.

* 🔧 refactor: extract shared renderer Vite config into sharedRendererConfig

Deduplicate plugins (nodeModuleStub, platformResolve, tsconfigPaths) and
define (__MOBILE__, __ELECTRON__, process.env) between root vite.config.ts
and electron.vite.config.ts renderer section.

* 🔧 refactor: move all renderer plugins and optimizeDeps into shared config

sharedRendererPlugins now includes react, codeInspectorPlugin alongside
nodeModuleStub, platformResolve, tsconfigPaths. Add sharedOptimizeDeps
for pre-bundling list. Both root and electron configs consume shared only.

* 🐛 fix: set electron renderer root to monorepo root for correct glob resolution

import.meta.glob with absolute paths (e.g. /node_modules/antd/...) resolved
within apps/desktop/ instead of monorepo root. Change renderer root to ROOT_DIR,
add electronDesktopHtmlPlugin middleware to rewrite / to /apps/desktop/index.html,
and remove the now-unnecessary renderer-entry.ts shim.

* desktop vite !!

Signed-off-by: Innei <tukon479@gmail.com>

* sync import !!

Signed-off-by: Innei <tukon479@gmail.com>

* clean ci!!

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: update SPA path structure and clean up dependencies

- Changed the path in .gitignore and related files from [locale] to [variants] for SPA templates.
- Updated index.html to set body height to 100%.
- Cleaned up package.json by removing unused dependencies and reorganizing devDependencies.
- Refactored RendererUrlManager to use a constant for SPA entry HTML path.
- Removed obsolete route.ts file from the SPA structure.
- Adjusted proxy configuration to reflect the new SPA path structure.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update build script to include mobile SPA build

- Modified the build script in package.json to add the mobile SPA build step.
- Ensured the build process accommodates both desktop and mobile SPA versions.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update build scripts and improve file encoding consistency

- Modified the build script in package.json to ensure the SPA copy step runs after the build.
- Updated file encoding in generateSpaTemplates.mts from 'utf-8' to 'utf8' for consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: correct Blob import syntax and update global server config type

- Fixed the Blob import syntax in route.ts to ensure proper module loading.
- Updated the global server configuration type in global.d.ts for improved type safety.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 test: update RendererUrlManager test to reflect new file path

- Modified the mock implementation in RendererUrlManager.test.ts to check for the updated file path '/mock/export/out/apps/desktop/index.html'.
- Adjusted the expected resolved path in the test to match the new structure.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: remove catch-all example file and update imports

- Deleted the catch-all example file `catch-all.eg.ts` to streamline the codebase.
- Updated import paths in `ClientResponsiveLayout.tsx` and `ClientResponsiveContent/index.tsx` to use the new dynamic import location.
- Added type declarations for HTML templates in `spaHtmlTemplates.d.ts`.
- Adjusted `tsconfig.json` to include the updated file structure.
- Enhanced type definitions in `global.d.ts` and fixed locale loading in `locale.vite.ts`.

Signed-off-by: Innei <tukon479@gmail.com>

* e2e

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: remove unused build script for Vercel deployment

- Deleted the `build:vercel` script from package.json to streamline the build process.
- Ensured the remaining build scripts are organized and relevant.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: update Vite build input for mobile support

- Changed the build input path in vite.config.ts to conditionally use 'index.mobile.html' for mobile builds, enhancing support for mobile SPA versions.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: add compatibility checks for import maps and cascade layers

- Implemented functions to check for browser support of import maps and CSS cascade layers.
- Redirected users to a compatibility page if their browser does not support the required features.
- Updated the build script in package.json to use the experimental analyze command for better performance.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: rename

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: refactor authentication layout and introduce global providers

- Created a new `RootLayout` component to streamline the layout structure.
- Removed the old layout file for variants and integrated necessary features into the new layout.
- Added `AuthGlobalProvider` to manage authentication context and server configurations.
- Introduced language and theme selection components for enhanced user experience.
- Updated various components to utilize the new context and improve modularity.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: exclude build artifacts from serverless functions

- Updated the `next.config.ts` to exclude SPA, desktop, and mobile build artifacts from serverless functions.
- Added paths for `public/spa/**`, `dist/**`, `apps/desktop/build/**`, and `packages/database/migrations/**` to the exclusion list.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: refine exclusion of build artifacts from serverless functions

- Updated `next.config.ts` to specify exclusion paths for desktop and mobile build artifacts.
- Changed exclusions from `dist/**` and `apps/desktop/build/**` to `dist/desktop/**`, `dist/mobile/**`, and `apps/desktop/**` for better clarity and organization.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: update BrowserRouter basename for local development

- Modified the `ClientRouter` component to conditionally set the `basename` of `BrowserRouter` based on the `__DEBUG_PROXY__` variable, improving local development experience.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: implement mobile SPA workflow and S3 asset management

- Added a new workflow for building and uploading mobile SPA assets to S3, including environment variable configurations in `.env.example`.
- Updated `package.json` to include a new script for the mobile SPA workflow.
- Enhanced the Vite configuration to support dynamic CDN base paths.
- Refactored the template generation script to handle mobile HTML templates more effectively.
- Introduced new modules for uploading assets to S3 and generating mobile HTML templates.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: extract origin from MOBILE_S3_PUBLIC_DOMAIN to prevent double key prefix

* 🔧 fix: update mobile HTML template to use the latest asset versions

- Modified the mobile HTML template to reference the updated JavaScript asset version for improved functionality.
- Ensured consistency in the template structure while maintaining existing styles and scripts.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update dependencies and refine service worker integration

- Removed outdated dependencies related to Serwist from package.json and tsconfig.json.
- Added vite-plugin-pwa to enhance PWA capabilities in the Vite configuration.
- Updated service worker registration logic in the PWA installation component.
- Introduced a new local development proxy route for debugging purposes.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: refactor development scripts and remove Turbo configuration

- Updated the `dev` script in `package.json` to use a new startup sequence script for improved development workflow.
- Removed the outdated `turbo.json` configuration file as it is no longer needed.
- Introduced `devStartupSequence.mts` to manage the startup of Next.js and Vite processes concurrently.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: update entry points and introduce debug proxy for local development

- Changed the main entry point in `index.html` from `entry.desktop.tsx` to `entry.web.tsx` for improved web compatibility.
- Added an `initialize.ts` file to enable `immer`'s `enableMapSet` functionality.
- Introduced a new `__DEBUG_PROXY__` variable in global types to support local development proxy features.
- Implemented a debug proxy route to facilitate local development with dynamic HTML injection and script handling.
- Removed outdated mobile routing components to streamline the codebase.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: replace BrowserRouter with RouterProvider for improved routing

- Updated entry points for desktop, mobile, and web to utilize RouterProvider and createAppRouter for better routing management.
- Removed the deprecated renderRoutes function in favor of a more streamlined router configuration.
- Enhanced router setup to support error boundaries and dynamic routing.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: remove direct access handling for SPA routes in proxy configuration

- Eliminated the handling of direct access to pre-rendered SPA pages in the proxy configuration.
- Simplified the request processing logic by removing checks for SPA routes, streamlining the middleware response flow.

Signed-off-by: Innei <tukon479@gmail.com>

* update

* 🔧 refactor: enhance Worker instantiation logic in mobile HTML template

* 🐛 fix: remove duplicate waitForPageWorkspaceReady calls in page CRUD e2e steps

* 🔧 refactor: simplify createTracePayload function by using btoa for base64 encoding

* 🔧 refactor: specify locales in import.meta.glob for dayjs and antd

* 🔧 refactor: replace Node.js Buffer with web-compatible btoa for base64 encoding in file upload

* 🐛 fix: disable consistent-type-imports rule for mdx files to prevent eslint crash

* 🔧 refactor: add height style to root div for consistent layout

* 🔧 refactor: replace btoa with Buffer for base64 encoding in trace and file upload handling

* 🔧 refactor: extract nextjsOnlyRoutes to a separate file for better organization

* 🔧 refactor: enable Immer MapSet plugin in tests for better state management

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: integrate sharedRollupOutput configuration and increase cache size for better performance

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove obsolete desktop.routes.test.ts file as it is no longer needed

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: use cross-env for env vars in npm scripts (Windows CI)

Co-authored-by: Cursor <cursoragent@cursor.com>

* 🔧 chore: update Dockerfile for web-only build and adjust npm scripts to use pnpm

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance Dockerfile prebuild process with environment checks and add new dependencies

- Updated Dockerfile to include environment checks before removing desktop-only code.
- Added new dependencies in package.json: @aws-sdk/client-bedrock-runtime, @opentelemetry/auto-instrumentations-node, @opentelemetry/resources, @opentelemetry/sdk-metrics, and ajv.
- Configured Rollup to exclude @aws-sdk/client-bedrock-runtime from the SPA bundle.
- Introduced dockerPrebuild.mts script for environment variable validation and information logging.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance Vite and Electron configurations with environment loading and trace encoding improvements

- Updated Vite and Electron configurations to load environment variables using loadEnv.
- Modified trace encoding in utils to use TextEncoder for better compatibility.
- Adjusted sharedRendererConfig to expose only necessary public environment variables.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove plans directory (migrated to discussion)

* ♻️ refactor: inject NEXT_PUBLIC_* env per key in Vite define

Co-authored-by: Cursor <cursoragent@cursor.com>

*  feat: add loading screen with animation to enhance user experience

- Introduced a loading screen with a brand logo and animations for better visual feedback during loading times.
- Implemented CSS styles for the loading screen and animations in index.html.
- Removed the loading screen from the DOM once the layout is ready using useLayoutEffect in SPAGlobalProvider.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove unnecessary external dependency from Vite configuration

- Eliminated the external dependency '@aws-sdk/client-bedrock-runtime' from the Vite configuration to streamline the build process for the SPA bundle.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add web app manifest link in index.html and enable PWA support in Vite configuration

- Added a link to the web app manifest in index.html to enhance PWA capabilities.
- Enabled manifest support in Vite configuration for improved service worker functionality.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update link rel attributes for improved SEO and consistency

- Modified link rel attributes in multiple components to remove 'noreferrer' and standardize to 'nofollow'.
- Adjusted imports in PageContent components for better organization.

Signed-off-by: Innei <tukon479@gmail.com>

* update provider

*  feat: enhance loading experience and update package dependencies

- Added a loading screen with animations and a brand logo in index.html for improved user feedback during loading times.
- Introduced CSS styles for the loading screen and animations.
- Updated package.json files across multiple packages to include "@lobechat/const" as a dependency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: update proxy

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove GlobalLayout and Locale components

- Deleted GlobalLayout and Locale components from the GlobalProvider directory to streamline the codebase.
- This removal is part of a refactor to simplify the layout structure and improve maintainability.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: clean up console logs and improve component structure

- Removed unnecessary console log statements from AgentForkTag components in both agent and community directories to enhance code cleanliness.
- Refactored UserAgentList component for better readability by restructuring the useUserDetailContext hook and adjusting the layout of Flexbox components.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: remove console log from MemoryAnalysis component

* chore: update mobile HTML template with new asset links

- Replaced the previous asset links in the mobile HTML template with updated versions to ensure the latest resources are utilized.
- Adjusted the link rel attributes for module preloading to enhance performance and loading efficiency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: correct variable assignment in createClientTaskThread integration test

- Updated the assignment of the second parent message in the createClientTaskThread integration test to improve clarity and ensure proper data handling.
- Changed the variable name from 'secondParentMsg' to 'inserted' for better context before extracting the first message from the inserted results.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: simplify authentication check in define-config

- Removed the dependency on the isDesktop variable in the authentication check to streamline the logic.
- Enhanced the clarity of the redirection process for protected routes by focusing solely on the isLoggedIn status.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(dev): enhance local development setup with debug proxy instructions

- Added detailed instructions for starting the development environment in CLAUDE.md, including commands for SPA and full-stack modes.
- Updated README.md and README.zh-CN.md to reflect new commands and the debug proxy URL for local development.
- Introduced a Vite plugin to print the debug proxy URL upon server start, facilitating easier local development against the production backend.
- Corrected the debug proxy route in entry.web.tsx and define-config.ts for consistency.

This improves the developer experience by providing clear guidance and tools for local development.

Signed-off-by: Innei <tukon479@gmail.com>

* optimize perf

* optimize perf

* optimize perf

* remove speedy plugin

* add dayjs vendor

* Revert "remove speedy plugin"

This reverts commit bf986afeb1.

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-28 00:01:01 +08:00
YuTengjing 6c3e75634f 🐛 fix: prevent editor from stealing focus in agent settings modal (#12512) 2026-02-27 23:20:49 +08:00
Rdmclin2 9b8dabc072 🐛 fix: group agent rename problem (#12511)
* chore: align agent rename usage with agent profile editor

* fix: agent content emoji picker popupProps

* chore: agent and agent group use emoji background color in session list

* chore: remove fixed popupProps
2026-02-27 23:02:05 +08:00
eronez d286c1a9ad 🐛 fix: pass Google API key via x-goog-api-key header (#12506)
Fixes #12462
2026-02-27 21:32:28 +08:00
Zhijie He c2483f97a0 💄 style: add calculator builtin tool (#11715)
 feat: add calculator builtin tool
2026-02-27 21:10:39 +08:00
Rdmclin2 3152568c7d 🔨 chore: add back model select config (#12509)
* fix: user select problem

* feat: add back model config button

* chore: refact model detail props

* chore: add model detail loading

* chore: adjust dropdown side offset
2026-02-27 20:56:55 +08:00
sxjeru 02f2498140 💄 style: center active model on open in model switch panel (#12215)
* 🐛 fix: correct eslint command syntax in lint-ts.sh script

*  feat: add scroll functionality for active model in List component

*  feat: improve scroll behavior for active model in List component
2026-02-27 20:12:18 +08:00
Ruxiao Yin c9b243ca31 🐛 fix(docker): hoist @napi-rs/canvas for PDF parsing (#12475)
🐛 fix(docker): hoist @napi-rs/canvas for PDF parsing in Docker

Add `@napi-rs/canvas-*` to public-hoist-pattern in .npmrc to fix
`DOMMatrix is not defined` error when parsing PDFs in Docker.
2026-02-27 14:32:22 +08:00
YuTengjing 0ec6c2f38e feat(cloud): add Nano Banana 2 support (#12493) 2026-02-27 10:26:07 +08:00
Zhijie He c960705177 💄 style: add glm-5 & glm-4.6v & glm-image for zhipu (#12272)
* sytle: add glm-5 & glm-4.6v for zhipu

sytle: add glm-5 & glm-4.6v for zhipu

sytle: add glm-5 & glm-4.6v for zhipu

sytle: add glm-5 & glm-4.6v for zhipu

* fix: truncated response issue; implicitly set the default limit to 65536.
2026-02-27 09:19:31 +08:00
Arvin Xu c5d41fd2be feat: use lobe-tools to support progressive disclosure (#12489)
* activatedTool type

* support active tools

* fix explicitActivation tools issue

* improve search ux

* improve search result

* improve search result

* improve system prompts

* fix types

* fix tests

* refactor a skills store tools

* refactor a skills store tools

* improve issue

* fix some tests

* fix tests

* enable skills by default
2026-02-27 01:59:12 +08:00
Mike Lambert 22072789b6 🔨 chore(model-runtime): add User-Agent header for Anthropic API calls (#12433)
 feat(model-runtime): add User-Agent header for Anthropic API calls

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:49:54 +08:00
YuTengjing 306c50704e 🐛 fix: improve crawler error handling and timeout cancellation (#12487) 2026-02-26 22:59:10 +08:00
YuTengjing 0365a14e16 💄 style(cloud): remove deprecated chatgpt-4o-latest (#12486) 2026-02-26 18:39:22 +08:00
Rdmclin2 5fbf4b3cd4 🐛 fix: model select panel shiny problem and use normal list implementation (#12485)
fix: model select panel shiny problem and use normal list implementation
2026-02-26 16:52:04 +08:00
Arvin Xu b29a533285 ♻️ refactor: refactor client agent runtime (#12482)
* refactor to remove internal_fetchAIChatMessage

* improve

* fix tests
2026-02-26 15:17:39 +08:00
LobeHub Bot 7f7eeb8fa8 🌐 chore: translate non-English comments to English in src/app/[variants]/(main)/settings (#12430)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 15:09:26 +08:00
LobeHub Bot 059d0cc0fc 🌐 chore: translate non-English comments to English in model-runtime (#12480)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 12:30:20 +08:00
Arvin Xu 5a30c9a14f 🐛 fix: support memory tools run in server (#12471)
* support server memory run

* refactor builtin tools list

* refactor builtin tools list

* add lobe-tools

* fix lint
2026-02-25 22:13:02 +08:00
YuTengjing 5371507b22 🔥 refactor: remove invite code requirement feature (#12474) 2026-02-25 20:55:39 +08:00
YuTengjing f84a363b75 feat(cloud): add Seedream 5 Lite model (#12459) 2026-02-24 20:18:13 +08:00
Arvin Xu bbfbc45925 🔨 chore: update drizzle orm (#12458)
update drizzle orm
2026-02-24 19:14:41 +08:00
Arvin Xu 616ac9438c 🐛 fix: fix search issue (#12457)
* fix search issue

* fix tests
2026-02-24 17:21:26 +08:00
Arvin Xu ddce51eaba 🐛 fix: fix skill search not found (#12432)
* fix skill issue

* fix skills

* fix skills search query
2026-02-23 00:28:10 +08:00
YuTengjing bdc901d1dc 💄 style: video loading circular progress indicator (#12418) 2026-02-22 15:03:12 +08:00
LobeHub Bot 5ab874e877 🌐 chore: translate non-English comments to English in src/store (#12393)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 10:49:16 +08:00
Zhijie He 28b1455f2f 💄 style: update batch of model lists (ai360, hunyuan, intern, spark, stepfun, wenxin, seedream) (#12371) 2026-02-22 09:50:48 +08:00
Arvin Xu e95f7419b9 feat: support agent skills (#12424) 2026-02-22 09:48:11 +08:00
Arvin Xu 93bb83db5d 🔨 chore: improve version sync (#12422)
* update workflow

* update skills

* update skills
2026-02-22 01:09:23 +08:00
LobeHub Bot 01e13959d1 🌐 chore: translate non-English comments to English in src/features/Conversation (#12410)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 00:13:27 +08:00
lobehubbot ef0e4a6743 🐛 chore(hotfix): bump version to v2.1.33 [skip ci] 2026-02-21 16:01:41 +00:00
Arvin Xu 4d1508ee9b 👷 build: update auto tag release (#12421)
update
2026-02-22 00:00:53 +08:00
Arvin Xu 84ecc1e9f6 🚀 release 20260221 (#12420)
This release includes **82 commits** and **854 changed files**. Key updates are below.

### 🚀 New Features and Enhancements

- Added **Agent Benchmark** support for more systematic agent
performance evaluation.
- Introduced the **video generation** feature end-to-end, including
entry points, sidebar “new” badge support, and skeleton loading for
topic switching.
- Expanded memory capabilities: support for memory effort/tool
permission configuration and improved timeout calculation for memory
analysis tasks.
- Added desktop editor support for image upload via file picker.

### 🤖 Models and Provider Expansion

- Added a new provider: **Straico**.
- Added/updated support for:
  - Claude Sonnet 4.6
  - Gemini 3.1 Pro Preview
  - Qwen3.5 series
  - Grok Imagine (`grok-imagine-image`)
  - MiniMax 2.5
- Added related i18n copy and model parameter adaptations.

### 🖥️ Desktop Improvements

- Integrated `electron-liquid-glass` (macOS Tahoe).
- Improved DMG background assets and desktop release workflow.

### 🛠️ Stability, Security, and UX Fixes

- Fixed multiple video generation pipeline issues: precharge refund
handling, webhook token verification, pricing parameter usage, asset
cleanup, and type safety.
- Fixed `sanitizeFileName` path traversal risks and added unit tests.
- Fixed MCP media URL generation with duplicated `APP_URL` prefix.
- Fixed Qwen3 embedding failures caused by batch-size limits.
- Fixed multiple UI/interaction issues, including mobile header agent
selector/topic count, ChatInput scrolling behavior, and tooltip stacking
context.
- Fixed missing `@napi-rs/canvas` native bindings in Docker standalone
builds.
- Improved GitHub Copilot authentication retry behavior and response
error handling in edge cases.

### 🙏 Thanks to Committers

Huge thanks to these contributors (alphabetical):

@AmAzing129 @Coooolfan @Innei @ONLY-yours @Zhouguanyang @arvinxx
@eaten-cake @hezhijie0327 @nekomeowww @rdmclin2 @rivertwilight @sxjeru
@tjx666
2026-02-21 23:37:57 +08:00
Arvin Xu 093af9889d chore: merge main into canary (#12419)
## Summary

Merge latest changes from main into canary.

## Changes

- Merge branch main into canary via
codex/merge-main-into-canary-20260221
- Resolve one merge conflict in packages/model-bank/src/types/aiModel.ts
by keeping both ModelParamsSchema and VideoModelParamsSchema imports

## Summary by Sourcery

Update NVIDIA provider to support preserved thinking and
reasoning_content for new reasoning-capable chat models and bump package
version.

New Features:
- Add NVIDIA chat model entries for MiniMax-M2.1, DeepSeek V3.2,
GLM-4.7, GLM-5, and Kimi K2.5 with reasoning support.

Enhancements:
- Extend NVIDIA runtime payload handling to map reasoning to
reasoning_content and to translate thinking into either thinking or
enable_thinking/clear_thinking depending on model capabilities.
- Refine NVIDIA provider tests to cover GLM preserved thinking behavior
and reasoning_content conversion across models.

Build:
- Bump package version from 2.1.31 to 2.1.32.
2026-02-21 23:11:28 +08:00
arvinxx 508c3ae20c Merge branch 'main' into codex/merge-main-into-canary-20260221 2026-02-21 23:08:54 +08:00
Arvin Xu e7598fe90b feat: support agent benchmark (#12355)
* improve total

fix page size issue

fix error message handler

fix eval home page

try to fix batch run agent step issue

fix run list

fix dataset loading

fix abort issue

improve jump and table column

fix error streaming

try to fix error output in vercel

refactor qstash workflow client

improve passK

add evals to proxy

refactor metrics

try to fix build

refactor tests

improve detail page

fix passK issue

improve eval-rubric

fix types

support passK

fix type

update

fix db insert issue

improve dataset ui

improve run config

finish step limit now

add step limited

100% coverage to models

add failed tests todo

support interruptOperation

fix lint

improve report detail

improve pass rate

improve sort order issue

fix timeout issue

Update db schema

完整 case 跑通

update database

improve error handling

refactor to improve database

优化 test case 的处理流程

优化部分细节体验和实现

基本完成 Benchmark 全流程功能

优化 run case 展示

优化 run case 序号问题

优化 eval test case 页面

新增 eval test 模式

新增 dataset 页面

update schema

support

finish create test run

fix

update

improve import exp

refactor data flow

improve import workflow

rubric Benchmark detail 页面

improve import ux

update schema

finish eval home page

add eval workflow endpoint

implement benchmark run model

refactor RAG eval

implement backend

update db schema

update db migration

init benchmark

* support rerun error test case

* fix tests

* fix tests
2026-02-21 20:36:40 +08:00
Zhijie He c2280561f5 💄 style: add grok-imagine-image series support via Grok Imagine API (#12365) 2026-02-21 20:21:24 +08:00
Innei 9b692c239a ♻️ chore(ci): remove unnecessary fetch-depth: 0 from workflows (#12403)
Only 4 checkouts truly need full git history (tag operations, branch sync).
The remaining 18 occurrences were used in build/lint/test jobs that only
need the current commit. Also removed redundant fetch-tags: true where
fetch-depth: 0 already implies full tag fetch.
2026-02-21 19:20:28 +08:00
LobeHub Bot e32a2fbad4 🌐 chore: translate non-English comments to English in src/libs/oidc-provider (#12383)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 10:27:45 +08:00
lobehubbot cb688b6cfa 🐛 chore(hotfix): bump version to v2.1.32 [skip ci] 2026-02-21 02:23:26 +00:00
Hardy ef474afe84 feat(nvidia): add new models and simplify payload handling for NVIDIA NIM (#12333)
*  feat(nvidia): add interleaved thinking support with new reasoning models

- Add MiniMax-M2.1, DeepSeek V3.2, GLM-4.7, GLM-5, Kimi K2.5 to NVIDIA model bank
- Add reasoning conversion for interleaved thinking mode
- Add tests for GLM-5 and DeepSeek V3.2 thinking

* ♻️ refactor(nvidia): simplify payload handling logic

- Remove redundant THINKING_MODELS and INTERLEAVED_THINKING_MODELS sets
- Apply reasoning -> reasoning_content conversion for all NVIDIA models
- Apply thinking -> chat_template_kwargs conversion based on user input only
- Let API decide if model supports the parameters instead of client-side filtering

* ♻️ refactor(nvidia): add preserved thinking support with model-specific params
2026-02-21 10:20:04 +08:00
YuTengjing 7a1e2b6a48 👷 chore: enable consistent-type-imports ESLint rule (#12399)
👷 chore: enable consistent-type-imports ESLint rule and fix violations
2026-02-21 10:11:38 +08:00
lobehubbot cc926f252a Merge remote-tracking branch 'origin/main' into canary 2026-02-21 02:01:38 +00:00
Arvin Xu 4260474f4e 👷 build: add build prefix to auto-tag release trigger (#12406) 2026-02-21 09:54:48 +08:00
LobeHub Bot ed4c5d125e test: add unit tests for QueueService.calculateDelay (#12356)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-21 09:49:54 +08:00
sxjeru 086dd15add 💄 style: add Claude Sonnet 4.6 model and enhance adaptive thinking logic (#12375)
 feat: add Claude Sonnet 4.6 model and enhance adaptive thinking logic
2026-02-21 09:49:24 +08:00
Zhijie He 1e506c5ebb 💄 style: add qwen3.5 series support (#12364)
style: add `qwen3.5` series support
2026-02-21 09:48:58 +08:00
Coooolfan b799c98487 🐛 fix(mcp): fix double APP_URL prefix in image/audio content URLs (#12400)
contentBlocksToString() was prepending APP_URL via urlJoin() to item.data,
but item.data already contained the full URL after processContentBlocks()
uploaded to S3. This caused URLs like:
https://example.com/https://example.com/f/uuid

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 09:37:04 +08:00
sxjeru 5475188fa0 💄 style: add Gemini 3.1 Pro Preview model (#12392)
*  feat: 添加 Gemini 3.1 Pro Preview 模型及其相关参数

*  feat: 更新 Anthropic 模型

*  feat: 移除过时的 Gemini 2.5 Flash 和 Imagen 4 预览模型

*  feat: 添加 Qwen3 Coder Next 模型并更新 Anthropic 测试用例中的模型版本
2026-02-21 09:35:10 +08:00
Zhijie He 0674eee0d4 🐛 fix: fix qwen3 embedding error due to batch size limitation (#12382)
fix: fix embdding chunk_size limit for qwen

apply suggestion

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

fix: fix embdding chunk_size limit for qwen

fix: fix embdding chunk_size limit for qwen
2026-02-21 01:15:14 +08:00
lobehubbot 870638ea8a Merge remote-tracking branch 'origin/main' into canary 2026-02-20 16:44:44 +00:00
Arvin Xu b155656a7c 👷 build: add benchmark db schema (#12402)
* add eval benchmark database

* fix types

* remove regions
2026-02-21 00:44:06 +08:00
lobehubbot d8b947828c 🐛 chore(hotfix): bump version to v2.1.31 [skip ci] 2026-02-20 13:04:35 +00:00
lobehubbot 8310c5755c Merge remote-tracking branch 'origin/main' into canary 2026-02-20 13:04:23 +00:00
YuTengjing bb2d760b4b 💄 style: support more Qwen i2i & t2i models (#11708)
#### 💻 Change Type

<!-- For change type, change [ ] to [x]. -->

- [ ]  feat
- [ ] 🐛 fix
- [ ] ♻️ refactor
- [X] 💄 style
- [ ] 👷 build
- [ ] ️ perf
- [ ]  test
- [ ] 📝 docs
- [ ] 🔨 chore

#### 🔗 Related Issue

Closes #10346

<!-- Link to the issue that is fixed by this PR -->

<!-- Example: Fixes #xxx, Closes #xxx, Related to #xxx -->

#### 🔀 Description of Change

1. 更新的文生图,图生图模型列表,`z-image` `wan2.5` `wan2.6` `qwen-image-plus/max`
`qwen-image-edit-plus/max`
2. 新增 `image2image` endpoint,为老版本图生图模型进行兼容
3. 默认使用 `multimodal-generation` endpoint(新模型目前调研下来都是用这个了,同时支持图生图和文生图)
4. 支持多区域 Dashscope URL,跟随 baseUrl 参数,自动切分 `/compatible-mode/v1` 默认北京区域
    北京 https://dashscope.aliyuncs.com
    新加坡 https://dashscope-intl.aliyuncs.com
    弗吉尼亚 https://dashscope-us.aliyuncs.com

|Endpoint||
|-|-|
|`multimodal-generation`|<img width="826" height="547" alt="image"
src="https://github.com/user-attachments/assets/38206851-94bc-48cc-8a57-24ed7155782f"
/><img width="521" height="383" alt="image"
src="https://github.com/user-attachments/assets/40fe0ed0-35fd-443d-868f-3ae2c27352f9"
/><img width="681" height="557" alt="image"
src="https://github.com/user-attachments/assets/8101b0f1-81c8-4892-a6e2-b51b5b0e0235"
/>|
|`text2image`|<img width="600" height="564" alt="image"
src="https://github.com/user-attachments/assets/39e82a4f-5305-4f30-ae4d-e5339f401e6d"
/>|

<!-- Thank you for your Pull Request. Please provide a description
above. -->

#### 🧪 How to Test

<!-- Please describe how you tested your changes -->

<!-- For AI features, please include test prompts or scenarios -->

- [ ] Tested locally
- [ ] Added/updated tests
- [ ] No tests needed

#### 📸 Screenshots / Videos

<!-- If this PR includes UI changes, please provide screenshots or
videos -->

| Before | After |
| ------ | ----- |
| ...    | ...   |

#### 📝 Additional Information

ref: https://help.aliyun.com/zh/model-studio/newly-released-models
ref:
https://bailian.console.aliyun.com/cn-beijing/?tab=doc#/doc/?type=model&url=2987148

<!-- Add any other context about the Pull Request here. -->

<!-- Breaking changes? Migration guide? Performance impact? -->

## Summary by Sourcery

Extend Qwen image generation support to cover new text-to-image and
image-to-image models while routing legacy models via dedicated
text2image/image2image endpoints and defaulting other models to the
multimodal-generation API.

New Features:
- Add model metadata and configuration for new Qwen image models
including Z-Image Turbo, Qwen Image Edit Max/Plus, Qwen Image Max/Plus,
and Wanxiang 2.5/2.6 variants.
- Introduce explicit handling of legacy text-to-image and image-to-image
Qwen models via separate async text2image and image2image endpoints.

Enhancements:
- Update the Qwen image creation flow to prefer the
multimodal-generation endpoint for newer models and improve error
messaging and logging across image workflows.
- Reformat select Qwen chat model descriptions for consistency without
changing behavior.

Tests:
- Adjust Qwen image creation tests to align with the new
multimodal-generation behavior and removed strict input validation on
qwen-image-edit-specific image URL requirements.
2026-02-20 21:03:45 +08:00
Sun13138 a9d9e7adf0 🐛 fix: correct mobile header agent selector and topic count (#12204) 2026-02-20 21:02:53 +08:00
YuTengjing e28593cc38 feat: add Gemini 3.1 Pro Preview model support (#12391)
- Add gemini-3.1-pro-preview to Google, Vertex AI, and LobeHub providers
- Add thinkingLevel3 extend param type (low/medium/high)
- Create ThinkingLevel3Slider component for 3-level thinking control
- Fix thinkingLevel2/3 not passing values to API due to form field name mismatch
- Add medium to GoogleThinkingLevel and ChatStreamPayload thinkingLevel types
- Update planCardModels to use gemini-3.1-pro-preview
2026-02-20 09:57:20 +08:00
sxjeru e51234443a feat: Add new provider Straico (#12219)
 feat: add Straico model provider integration and environment variable support
2026-02-19 20:02:07 +08:00
LobeHub Bot a0c4baf1aa 🌐 chore: translate non-English comments to English in src/libs (#12353)
* 🌐 chore: translate non-English comments to English in src/libs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* 🐛 fix: update test to match translated error message

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: arvinxx <arvinx@foxmail.com>
2026-02-18 23:47:49 +08:00
LobeHub Bot 1e20edef3d 🌐 chore: translate non-English comments to English in plugin slice (#12367)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-18 22:28:30 +08:00
Ruxiao Yin 949873adbc 🐛 fix(docker): Fix the issue of missing @napi-rs/canvas platform native binding package in standalone build (#12370)
🐛 fix(docker): include platform-specific @napi-rs/canvas bindings in standalone output
2026-02-18 22:27:58 +08:00
LobeHub Bot 5030177f3d 🌐 chore: translate non-English comments to English in apps/desktop/src/main (#12376)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-18 22:15:03 +08:00
Zhijie He a96a5576a7 fix: force fix style 2026-02-18 20:54:53 +08:00
Zhijie He 9766d20979 fix: fix some bugs 2026-02-18 20:51:34 +08:00
Zhijie He 6a4118c628 feat: support switch dashscope URL based on baseURL
feat: support switch dashscope URL based on baseURL

feat: support switch dashscope URL based on baseURL

feat: support switch dashscope URL based on baseURL
2026-02-18 20:36:23 +08:00
Zhijie He 4fba491793 fix: fix multimodal-generation I2I calling
fix: fix wan2.6-image imageUrls num limit

fix: fix wan2.6-image imageUrls format
2026-02-18 20:36:23 +08:00
Zhijie He ea951b72d3 style: fix height & weight range (apply suggestion 5) 2026-02-18 20:36:23 +08:00
Zhijie He 4a29904516 chore: add imageUrl & imageUrls input validation (apply suggestion 3) 2026-02-18 20:36:23 +08:00
Zhijie He 5d7ee01bce fix: fix edit & i2i models input muti-images 2026-02-18 20:36:23 +08:00
Zhijie He 763352c56a chore: apply some suggestion (1,4,6)
chore: apply some suggestion (1,4,6)
2026-02-18 20:36:23 +08:00
Zhijie He 86624e8808 feat: improve error messages with model names for better debugging 2026-02-18 20:36:23 +08:00
Zhijie He f018a7b790 sytle: update default models 2026-02-18 20:36:23 +08:00
Zhijie He 5f10ede77a sytle: add i2i models 2026-02-18 20:36:23 +08:00
Zhijie He 9312298564 feat: support t2i mode in multimodal-generation endpoint 2026-02-18 20:36:23 +08:00
Zhijie He 6f08c302ac chore: minor code 2026-02-18 20:36:23 +08:00
Zhijie He 0aea1b0a3d feat: update Qwen image models info and code formatting 2026-02-18 20:36:23 +08:00
Zhijie He bf9df0424d feat: add model routing logic with multimodal-generation as default 2026-02-18 20:36:23 +08:00
Zhijie He 989223b355 feat: add Qwen image2image endpoint support and refactor image generation functions 2026-02-18 20:36:23 +08:00
Zhijie He d9f91fc23a Update qwen.ts 2026-02-18 20:36:23 +08:00
YuTengjing 38e1adba2f 🌐 chore: add i18n translations for Claude Sonnet 4.6 (#12374) 2026-02-18 10:13:44 +08:00
YuTengjing f91acfca95 feat(model-bank): lobehub provider add Claude Sonnet 4.6 support (#12373)
Add Claude Sonnet 4.6 model card to lobehub provider and extend
assistant turn prefill restriction to all 4.6 models.
2026-02-18 10:07:43 +08:00
Innei 1f1c49fc52 🐛 fix(tool-ui): fix icon margin and text overflow in FilePathDisplay (#12331)
* 🐛 fix(tool-ui): fix icon margin and text overflow in FilePathDisplay

Fixes LOBE-2541

* 🐛 fix(DragUploadZone): remove border-radius from upload overlay
2026-02-16 21:02:20 +08:00
AmAzing- 8db783b5b8 🔨 chore: add MiniMax 2.5 (#12345)
chore: add mini max 2.5
2026-02-16 19:40:39 +08:00
Innei b3e87f6cd4 ♻️ refactor: replace per-item Editing components with singleton EditingPopover (#12327)
* ♻️ refactor: replace per-item Editing components with singleton EditingPopover

Eliminate 3 duplicate Editing components (AgentItem, AgentGroupItem, Group)
in favor of a single imperative EditingPopover using @lobehub/ui Popover atoms.
Anchor elements are passed via React state (useState + callback ref) instead
of DOM queries. Removes agentRenamingId/groupRenamingId from homeStore.

* fix: edit group agent avaar

Signed-off-by: Innei <tukon479@gmail.com>

*  test(e2e): update rename popover selectors and allow console in tests

Support both antd Popover and @lobehub/ui Popover atoms selectors.
Use save button click instead of click-outside for non-Enter rename flow.
Disable no-console rule for e2e and test files.

*  test(e2e): fix rename popover input detection with data-testid

Add data-testid="editing-popover" to PopoverPopup. Simplify inputNewName
to use single combined selector instead of sequential try-catch loop that
caused 8s+ timeout. Support both @lobehub/ui and antd Popover.

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-16 18:17:59 +08:00
lobehubbot abbf53feda Merge remote-tracking branch 'origin/main' into canary 2026-02-16 06:44:35 +00:00
Arvin Xu 3f432a43d8 🐛 fix(ci): use pull_request_target to support fork PR secrets (#12350)
🐛 fix(ci): use pull_request_target to support fork PR secrets
2026-02-16 14:43:58 +08:00
Innei 8b0d1ec9e3 👷 ci: improve canary versioning to patch+1 sequential numbering (#12347)
Change canary version format from X.(Y+1).0-canary.TIMESTAMP to
X.Y.(Z+1)-canary.N with auto-incrementing sequence. Also add
release prefix as build trigger and update sync PR titles.
2026-02-16 00:49:33 +08:00
Innei b43cbae2e1 🐛 fix: remove isDesktop guard from client fetch switch visibility (#12336)
Allow desktop app users to see and toggle the "Fetch on Client" option
in provider settings. The server-side default values for desktop remain
unchanged, so this only affects UI visibility.
2026-02-16 00:48:02 +08:00
Arvin Xu d2a042cd95 🐛 fix: scroll ChatInput into view when starter mode activates (#12334)
* 🐛 fix: scroll ChatInput into view when starter mode activates

When clicking Create Agent/Group/Write, the SuggestQuestions panel
renders below the ChatInput and pushes total content beyond the
viewport, causing the ChatInput to scroll out of view. This adds
scrollIntoView + focus on mode change so the editor stays visible
and ready for input. Also improves E2E test to target contenteditable
inside ChatInput directly and wait for animation to settle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:06:14 +08:00
lobehubbot c1916a1996 Merge remote-tracking branch 'origin/main' into canary 2026-02-15 13:28:56 +00:00
sxjeru 502d94bd4c 💄 style: add new MiniMax-M2.5 model (#12289)
* feat: 添加多个新模型及其定价信息,更新模型解析配置

* fix: 更新多个模型的导入语法,添加新模型GLM-5及其属性

* feat: 添加多个Doubao模型及其定价信息,优化payload处理逻辑
2026-02-15 21:28:16 +08:00
YuTengjing f4bd332d11 🐛 fix: use batch config for computePriceParams and pass latency (#12348)
## Summary
- Pass latency (task submission → webhook callback) to
`chargeAfterGenerate` for video generation metrics
- Use `batch.config` instead of webhook `result` for
`computePriceParams` (generateAudio), ensuring pricing uses
user-submitted config
- Rename `generateAudio` top-level param to `computePriceParams: {
generateAudio }` for better structure

## Test plan
- [ ] Submit a video generation task with generateAudio enabled, verify
charge uses correct pricing
- [ ] Submit a video generation task with generateAudio disabled, verify
charge reflects the difference
- [ ] Verify latency is recorded in the charge metrics

## Summary by Sourcery

Adjust video generation charging and metadata to rely on batch config
and record end-to-end latency.

Bug Fixes:
- Ensure generateAudio pricing uses the original batch configuration
instead of the webhook result payload.

Enhancements:
- Pass task submission-to-webhook latency into video charging for
improved metrics.
- Rename chargeAfterGenerate pricing input to computePriceParams for
clearer structure and future extensibility.
- Name generated video files using the batch prompt prefix when
available to improve asset identification.

Tests:
- Add unit tests for the Volcengine video provider request/response
handling, including payload mapping, client config, and error cases.
- Add initial test scaffolding for video standard parameters, cost
computation, single-price resolution, and Volcengine video webhook
handling.
2026-02-15 20:46:29 +08:00
YuTengjing 7df81ffaa1 🐛 fix: add sanitizeFileName alias to vitest config for test resolution 2026-02-15 20:32:24 +08:00
YuTengjing ed076b3cf5 test: add unit tests for sanitizeFileName utility 2026-02-15 20:13:22 +08:00
YuTengjing 0abde1623d 🐛 fix: extract sanitizeFileName util to prevent path traversal in generated file names 2026-02-15 20:03:04 +08:00
YuTengjing 481e5c0066 🐛 fix: sanitize prompt for video file name to prevent path traversal 2026-02-15 20:00:41 +08:00
YuTengjing 8719354282 🐛 fix: use batch config for computePriceParams instead of webhook result 2026-02-15 19:47:10 +08:00
YuTengjing 5957bd4578 🐛 fix: use prompt as video file name instead of generation id 2026-02-15 19:34:14 +08:00
YuTengjing 335e246ac5 test: add unit tests for video generation feature
Cover resolveVideoSinglePrice, computeVideoCost, handleCreateVideoWebhook,
createVolcengineVideo, and video standard-parameters (63 cases total).
2026-02-15 19:34:14 +08:00
YuTengjing 918d048b3d feat: pass latency to chargeAfterGenerate for video generation metrics 2026-02-15 19:32:19 +08:00
Arvin Xu 398d8b7f3c Sync main branch to canary branch (#12339)
Automatic sync from main to canary. Merge conflicts detected.

**Resolution steps:**
```bash
git fetch origin
git checkout sync/main-to-canary-20260214-22020422229
git merge origin/main
# Resolve conflicts
git add -A && git commit
git push
```

> Do NOT merge canary into a main-based branch — always merge main INTO
the canary-based branch to keep a clean commit graph.
2026-02-15 18:52:05 +08:00
Innei 1529f31dff ci: sync workflow for main to canary branch
- Added concurrency control to prevent overlapping sync jobs.
- Improved logic for detecting changes between main and canary branches.
- Streamlined handling of fast-forward merges and conflict resolution.
- Updated PR creation process for manual conflict resolution with detailed instructions.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-15 16:36:16 +08:00
Innei b4bd5b288c Merge remote-tracking branch 'origin/main' into sync/main-to-canary-20260214-22020422229 2026-02-15 16:03:47 +08:00
YuTengjing 448cfb2cfd 🐛 fix: prevent stale topic ID from persisting in URL on remount (#12341)
## Summary
- Fix bidirectional sync race condition in `TopicUrlSync` where stale
`activeGenerationTopicId` from zustand store overwrites the URL when
navigating back to image/video pages without a `?topic=` param
- Replace `createStoreUpdater` (useEffect-based) with `useLayoutEffect`
for URL → store sync, ensuring it runs before the store → URL
subscription
- Generate latest i18n locales

## Test plan
- [ ] Visit `/video?topic=<id>`, navigate to home, click `/video` —
topic should not persist
- [ ] Visit `/image?topic=<id>`, navigate to home, click `/image` —
topic should not persist
- [ ] Click a topic in the sidebar — URL should update with
`?topic=<id>`
- [ ] Refresh page with `?topic=<id>` — correct topic should be selected

## Summary by Sourcery

Fix URL and store synchronization for generation topics and refresh
localized video page translations.

Bug Fixes:
- Prevent stale activeGenerationTopicId values in the store from
overwriting the URL when remounting image or video pages without a topic
query parameter.

Documentation:
- Regenerate and update i18n locale JSON files across all supported
languages, including new video translation files.
2026-02-15 11:11:47 +08:00
YuTengjing d8c3ef3232 🌐 chore: generate latest i18n locales 2026-02-15 11:10:47 +08:00
YuTengjing 2a23fb9a10 🐛 fix: prevent stale topic ID from persisting in URL on remount 2026-02-15 11:03:06 +08:00
YuTengjing 82f9cb4486 🔨 chore: add video generation feature (#12312)
## Summary
- Add complete video generation feature including UI pages, store
management, server routes, and webhook handling
- Support Volcengine video generation provider with text-to-video and
image-to-video capabilities
- Add video generation topic management, config panel, generation feed,
and prompt input components
- Include database migration for video generation schema
- Refactor GenerationTopicList/TopicPanel as shared components for both
image and video generation

## Test plan
- [ ] Verify video generation page renders correctly
- [ ] Test text-to-video generation flow end-to-end
- [ ] Test image-to-video generation with reference frames
- [ ] Verify video generation topic CRUD operations
- [ ] Confirm webhook handling for async video generation results
- [ ] Check video generation config panel model selection and parameter
controls
2026-02-15 10:13:43 +08:00
YuTengjing 6419fd32b1 🔧 chore: revert some lint config 2026-02-15 09:46:02 +08:00
Arvin Xu 927fe3fd22 ci: fix sync workflow by using PAT for checkout (#12338)
The GITHUB_TOKEN cannot push changes to .github/workflows/ files due to
GitHub's security restrictions. The 'workflows' permission key added in
the previous commit is not a valid workflow permission scope.

Fix: Use secrets.GH_TOKEN (PAT with workflow scope) in the checkout step
so that git push has the necessary credentials to push branches that
contain workflow file changes (e.g. from merge conflicts).

Also reverts the invalid 'workflows: write' permission.
2026-02-15 00:13:13 +08:00
Arvin Xu 03bda41c07 chore(ci): add workflows permission to sync-main-to-canary (#12337)
When merge conflicts involve .github/workflows/ files, GitHub requires
the `workflows: write` permission to push branches containing workflow
file changes. Without this permission, the sync branch push is rejected
with 'refusing to allow a GitHub App to create or update workflow without
workflows permission'.
2026-02-14 23:56:07 +08:00
LobeHub Bot e804773a7e 🌐 chore: translate non-English comments to English in lobehub-skill-store (#12316)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-14 22:22:40 +08:00
YuTengjing 67875bd60a feat: add skeleton loading screen for video topic switching 2026-02-14 21:07:01 +08:00
YuTengjing 916d4841f4 🔒 chore: hide video nav entry behind enableBusinessFeatures flag 2026-02-14 20:52:03 +08:00
YuTengjing d5b1ff20e0 🔧 chore: revert locales/ changes and remove unused locale key
- Revert locales/ directory to canary state (CI auto-generates translations)
- Remove unused `video.topic.empty` key from default locale
2026-02-14 20:16:26 +08:00
YuTengjing 212348eafe 🐛 fix: refund precharge when video task submission fails 2026-02-14 20:16:26 +08:00
YuTengjing 43820eeb2e 🐛 fix: improve video generation security and type safety
- Reject webhook requests when token is missing instead of skipping verification
- Use proper union type for generation assets instead of blanket VideoGenerationAsset cast
- Replace sync js-sha256 with Node.js crypto.createHash for video hashing
- Add 500MB size limit and 5-minute timeout for video downloads
- Add displayName to VideoLoading component
2026-02-14 20:16:26 +08:00
YuTengjing 7397d6f8c1 🐛 fix: add type assertion for prechargeResult in video webhook route 2026-02-14 20:16:26 +08:00
YuTengjing 85d5bc9e08 ♻️ refactor: add model parameter to video free quota query 2026-02-14 20:16:26 +08:00
YuTengjing 3fbc46b23a 🔒 feat: add webhook token verification for video generation callbacks
Generate a one-time crypto-random token per video task, store it in
asyncTask metadata, and append it to the callback URL. The webhook
endpoint verifies the token using timing-safe comparison before
processing, returning 401 on mismatch. Old tasks without a token
are allowed through for backward compatibility.
2026-02-14 20:16:26 +08:00
YuTengjing 6e2ef05270 feat: support new badge on sidebar nav items and enable for video 2026-02-14 20:16:26 +08:00
YuTengjing 06d65e9ce5 🙈 chore: hide Seedance 2.0 entry from home starter list
Temporarily comment out the Seedance 2.0 video button until it's ready for launch. Seedance 1.5 will be released first.
2026-02-14 20:16:26 +08:00
YuTengjing 6002863c17 feat: add video free quota query endpoint and UI stub
Add getVideoFreeQuota TRPC query and business stub for displaying
daily free video generation quota in PromptInput.
2026-02-14 20:16:26 +08:00
YuTengjing 8f2e72d1b8 🐛 fix: update generationBatch tests to match filesToDelete refactor 2026-02-14 20:16:26 +08:00
YuTengjing fcf2444fa8 feat: add eval method to RedisClient for Lua script execution 2026-02-14 20:16:25 +08:00
YuTengjing 661f1a80b4 ♻️ refactor: improve video generation webhook and type safety
- Make AsyncTaskModel.findByInferenceId static to avoid empty userId
- Extract GenerationTopicType for type-safe topic type narrowing
- Hoist batch query to eliminate duplicate DB call in webhook handler
- Add missing i18n keys for video error actions and status
- Fix comment accuracy in generationBatch deletion
2026-02-14 20:16:25 +08:00
YuTengjing 57772d1f3b 🐛 fix: add videoGeneration pricing unit and clean up all asset files on deletion
- Add videoGeneration to PricingGroup maps to fix TS2741 type errors
- Collect url and coverUrl in addition to thumbnailUrl when deleting topics/batches
- Fix createTopic test assertion to match new optional type parameter
2026-02-14 20:16:25 +08:00
YuTengjing abe4c969a5 feat: add video generation feature 2026-02-14 20:16:25 +08:00
lobehubbot b767a66d38 🐛 chore(hotfix): bump version to v2.1.30 [skip ci] 2026-02-14 11:03:50 +00:00
Innei 53e4228ea7 🐛 fix: hotfix v2.1.30 (#12321)
*  chore: enhance release workflow to include conditional release body handling

- Added environment variable `RELEASE_BODY` to capture release notes from the GitHub event.
- Updated the workflow to use this variable, ensuring proper handling of release body content during manual dispatch events.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: simplify GitHub release workflow by removing hotfix-specific logic

- Consolidated the GitHub release creation step to handle both regular and hotfix releases under a single condition.
- Removed the separate hotfix release creation step to streamline the workflow.

Signed-off-by: Innei <tukon479@gmail.com>

*  fix: replace UserPanel popover

- Introduced `PanelContentSkeleton` for better user experience during loading states in the UserPanel.
- Updated `UserPanel` to use the new skeleton and adjusted popover content handling.
- Refactored `PanelContent` to use `FC` type for better type safety.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: bump @lobehub/ui dependency to version 4.38.1

- Updated the @lobehub/ui package to the latest version for improved features and bug fixes.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: remove inset prop from Popover in UserPanel

- Cleaned up the Popover component in UserPanel by removing the unnecessary inset prop for improved clarity and maintainability.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-14 19:03:00 +08:00
Innei 7efcdd2f7c 🐛 fix: resolve tooltip z-index stacking context in ModelSwitchPanel (#12324)
🐛 fix: move TooltipGroup to panel root to fix z-index stacking context
2026-02-14 18:49:23 +08:00
Neko bde1503309 🔨 chore(memory-user-memory): support effort & tool permission for configuring memory (#12311) 2026-02-14 18:17:15 +08:00
Neko 487713361a 🔨 chore(userMemories): support to auto calculate the timeout of the memory analysis task (#12325) 2026-02-14 17:36:58 +08:00
LiJian 7bad876259 🐛 fix: slove the execAgent task run error & parse crash problem (#12318)
fix: slove the execAgent task run error & parse crash problem
2026-02-14 14:22:33 +08:00
lobehubbot 229200853a 🐛 chore(hotfix): bump version to v2.1.29 [skip ci] 2026-02-14 02:09:17 +00:00
Innei 5ec89941f3 🐛 fix: bump lobehub/ui and fix workflow (#12313)
## 🩹 Hotfix v2.1.29

This PR starts a hotfix release from `main`.

### Release Process
1.  Hotfix branch created from main
2.  Pushed to remote
3. 🔄 Waiting for PR review and merge
4.  Auto tag + GitHub Release will be created after merge

---
Created by hotfix script

## Summary by Sourcery

Improve main-to-canary sync workflow robustness and tighten hotfix
auto-tagging criteria for release automation.

Enhancements:
- Make the main-to-canary sync workflow attempt direct merges to canary,
falling back to PR creation only when necessary or when conflicts occur,
and handle existing sync PRs more gracefully.
- Refine hotfix detection in the auto-tag workflow by requiring both a
hotfix branch prefix and a valid conventional commit-style PR title
prefix before tagging.
- Update the @lobehub/ui dependency to the latest patch version.

Build:
- Adjust release auto-tag workflow logic to gate hotfix tagging by both
branch naming and PR title format.

CI:
- Enhance GitHub Actions workflow for syncing main to canary with
conflict handling, direct-push optimization, and automated PR
management.
2026-02-14 10:08:31 +08:00
Innei f46916a74d feat(desktop): integrate electron-liquid-glass for macOS Tahoe (#12277)
*  feat(desktop): integrate electron-liquid-glass for macOS Tahoe

Add native liquid glass visual effect on macOS 26+ (Tahoe), replacing
vibrancy with Apple's NSGlassEffectView API via electron-liquid-glass.

- Centralize all platform visual effects in WindowThemeManager
- Strip platform props from BrowserWindow options to prevent config leaking
- Remove vibrancy from appBrowsers/WindowTemplate (managed by ThemeManager)
- Add isMacTahoe detection in env.ts and preload
- Fix applyVisualEffects to handle macOS platform symmetrically

* fix(tests): add isMacTahoe detection in Browser test environment

Introduce isMacTahoe flag in the test environment to support macOS Tahoe-specific features. This change enhances the test suite's ability to simulate and validate platform-specific behavior.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(theme): update liquid glass variant and adjust background color mix for desktop themes

- Changed liquid glass variant from 2 to 15 for improved visual effects.
- Adjusted background color mix percentages for dark and light themes on desktop to enhance visual consistency.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(theme): adjust background color mix for dark theme on desktop

- Updated the background color mix percentage for the dark theme on desktop from 70% to 90% for improved visual effect consistency.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-14 00:31:16 +08:00
Arvin Xu 2ee46b8693 Sync main branch to canary branch (#12308)
Automatic sync

## Summary by Sourcery

Extend database schemas and migrations to support async task inference
tracking and typed generation topics.

New Features:
- Add an inferenceId field to async tasks with a dedicated index for
lookup by inference ID.
- Add a typed generation topic field to distinguish between image and
video topics with a default of image.

Enhancements:
- Update database schema metadata and documentation snapshots to reflect
the new async task and generation topic fields.

Tests:
- Adjust async task and generation topic tests to cover the new
inferenceId and topic type fields.
2026-02-13 23:44:28 +08:00
Innei baf0b56f64 🔧 ci: optimize sync-main-to-canary to merge directly when no conflicts (#12306)
## Summary
- Optimize the main-to-canary sync workflow to directly merge and push
when there are no conflicts, avoiding unnecessary PR creation
- When merge conflicts exist, fall back to creating a PR for manual
resolution
- Add duplicate PR detection to prevent multiple PRs on the same day

## Test plan
- [ ] Push to main with no conflicts on canary → should auto-merge
without PR
- [ ] Push to main with conflicts on canary → should create PR
- [ ] Trigger workflow twice on same day with conflicts → should not
create duplicate PRs

## Summary by Sourcery

CI:
- Update the sync-main-to-canary workflow to merge main into canary
directly on no-conflict updates, only creating a PR when merge conflicts
occur and avoiding duplicate PRs for the same sync date.
2026-02-13 17:39:19 +08:00
YuTengjing 12dc7f90be 👷 build: add video generation schema changes (#12293) 2026-02-13 17:13:16 +08:00
Innei 1b905ede31 Sync main branch to canary branch (#12297)
Automatic sync
2026-02-13 15:50:44 +08:00
Innei cfaa911153 🔧 ci: add commit prefix gate for hotfix auto-tag (#12304)
* 🔧 ci: add commit prefix gate for hotfix auto-tag

* 🔧 chore: update ESLint suppressions and dependencies

- Added new ESLint suppressions for various files to address linting issues, including `no-console` and `object-shorthand`.
- Updated ESLint version to 10.0.0 in both root and desktop package.json files.
- Adjusted linting scripts for improved performance and consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: add ESLint support for YAML files in package.json

- Included ESLint fix command for YAML files (*.yml, *.yaml) in the linting scripts section.
- Ensured consistent formatting by adding a newline at the end of the file.

This update enhances linting capabilities for YAML configuration files.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: remove ESLint configuration file

- Deleted the .eslintrc.js file, which contained custom ESLint rules and overrides.
- This change simplifies the project by relying on default ESLint configurations.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-13 15:49:33 +08:00
Innei e17bf4b0cc Merge remote-tracking branch 'origin/main' into canary
# Conflicts:
#	locales/ja-JP/suggestQuestions.json
#	locales/vi-VN/models.json
2026-02-13 15:43:49 +08:00
LiJian 58cf27dcf8 🐛 fix: add the Agent Meta info back into agent advance model (#12302)
fix: add the Agent Meta info back into agent advance model
2026-02-13 15:01:50 +08:00
YuTengjing f12d9fbd22 🔒 fix: upgrade next-mdx-remote to v6 for CVE-2026-0969 (#12296)
Upgrade next-mdx-remote from v5.0.0 to v6.0.0 to fix CVE-2026-0969,
an arbitrary code execution vulnerability in MDX content processing.
2026-02-13 13:36:41 +08:00
YuTengjing d4f72eb752 🐛 fix: add missing inferenceId and type fields in test mocks 2026-02-13 12:34:19 +08:00
YuTengjing e112cd6f7f 🗃️ db: add video generation schema changes
- async_tasks: add inference_id column with index
- generation_topics: add type column (default 'image')
2026-02-13 12:09:18 +08:00
Innei 9a9147ca7e feat: support image upload in editor with desktop file picker (#12285)
- Add handleShowOpenDialog and handlePickFile IPC methods for Electron
- Create useImageUpload hook for editor image upload with progress
- Refactor ReactImagePlugin config to support handleUpload and onPickFile
- Simplify slash command image insertion by delegating upload to plugin
- Upgrade @lobehub/editor to ^3.16.1
2026-02-13 01:27:22 +08:00
Innei 2d1eec4482 feat(desktop): configure DMG background image (#12284)
*  feat: configure DMG background image for macOS installer

*  feat(desktop): set DMG window size, icon positions, and retina DPI

* 🔧 chore(desktop): resize DMG background to 600x400 and adjust window/icon positions

* chore: update remote
2026-02-13 01:06:43 +08:00
Innei c11d6de7db 🔧 build: add canary desktop release workflow (#12286)
🔧 build: add canary desktop release workflow and channel support

Add automated canary build pipeline triggered by build/fix/style commits
on canary branch, with concurrency control to cancel stale builds.
2026-02-13 00:37:03 +08:00
René Wang bbbe3a8d09 feat: add banner (#12258)
* feat: add banner

* fix: type error
2026-02-12 21:22:21 +08:00
Innei e51fbba881 feat: redesign Copilot ChatInput with compact action bar layout (#12279)
* add

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: enhance ChatInput with customizable action bar properties

- Added `actionSize` to `ActionBarContextValue` for flexible action sizing.
- Updated `Action` component to utilize `actionSize` for dynamic sizing.
- Introduced `actionBarStyle` and `leftContent` props in `DesktopChatInput` for custom styling and content.
- Enhanced `SendButton` to accept size from `sendButtonProps`.
- Updated `ChatInput` to support new props for improved layout customization.
- Refactored `Conversation` component to implement compact action bar style and size.

This update improves the flexibility and customization of the ChatInput feature, allowing for better user experience.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: enhance NavHeader and Copilot Toolbar with layout improvements

- Added `allowShrink` property to Flexbox components in NavHeader for better responsiveness.
- Updated Text component in Copilot Toolbar to include tooltip support for ellipsis overflow, improving user experience.

These changes enhance the layout flexibility and visual consistency across the application.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: update Conversation and AgentSelectorAction components for improved styling

- Adjusted padding in the compact action bar style for better alignment.
- Enhanced AgentSelectorAction styles with additional border radius for a refined look.
- Simplified title translation in AgentSelectorAction for consistency.

These changes enhance the visual appeal and maintainability of the components within the Copilot feature.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: update ModelSwitchPanel to improve DropdownMenuPositioner prop usage

- Changed the `hoverTrigger` prop in `DropdownMenuPositioner` from a boolean to a destructured assignment for better clarity and consistency in the component's API.

This update enhances the readability and maintainability of the ModelSwitchPanel component.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-12 20:09:39 +08:00
Arvin Xu 1bfeeea6f4 🔧 chore: always run E2E tests on main and canary branches (#12268)
Skip duplicate check only applies to development branches now.
Main and canary branches will always execute E2E tests on every commit.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:42:56 +08:00
Rdmclin2 12d0ec21d0 fix: setting response error and other bugs (#12265)
* fix: setting response error and other bugs

* chore: remove  popover arrow
2026-02-12 18:20:28 +08:00
Rdmclin2 2bf0a08919 feat: support model detail dropdown (#12275)
* feat: support model detail dropdown

# Conflicts:
#	src/features/ChatInput/ActionBar/Model/index.tsx

* chore: fix test cases

* fix: type error

* fix: e2e tests
2026-02-12 17:51:52 +08:00
Innei 79e146f1a3 🐛 fix: improve RunCommand copy button visibility and ActionBar border radius (#12280)
Closes LOBE-4402
2026-02-12 16:01:44 +08:00
Innei 0e42ca5ca2 🐛 fix: improve GitHub Copilot auth retry logic (#12250)
* 🐛 fix: improve GitHub Copilot auth retry logic

Simplify auth refresh tracking from counter to boolean flag and clear
cached bearer token on 401 to ensure fresh token exchange.

* 🔧 fix: update package.json formatting and import statements in GitHub Copilot provider

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: refine GitHub Copilot auth refresh logic to check for exchange credential

Update the 401 error handling to refresh the token only if an exchange credential is available, improving the authentication flow.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-12 13:09:38 +08:00
LobeHub Bot 823aa29c67 Sync main branch to canary branch (#12267)
* 🔧 chore(release): bump version to v2.1.27 [skip ci]

* chore: update sync main to canary workflow

* 🐛 fix: update @lobehub/ui version and refactor dynamic import handling (#12260)

*  feat: add hotfix workflow and script for automated hotfix management

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: refactor PR creation command to use execFileSync for improved reliability

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui version and refactor dynamic import handling

- Bump @lobehub/ui dependency from ^4.35.0 to ^4.36.2 in package.json.
- Refactor settingsContentToStatic.mts to simplify dynamic import processing by removing business feature checks.
- Add initialize.ts to enable immer's map set functionality.
- Correct import path in layout.tsx from 'initiallize' to 'initialize'.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @types/react version in package.json

- Bump @types/react dependency from ^19.2.9 to 19.2.14.
- Add @types/react version to overrides section for consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance auto-tag-release workflow for strict semver validation

- Updated regex to match strict semantic versioning format, allowing for optional prerelease and build metadata.
- Added validation step to ensure the version is a valid semver before proceeding with the release process.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove defaultSecurityBlacklist test file

- Deleted the test file for DEFAULT_SECURITY_BLACKLIST as it is no longer needed.
- This cleanup helps maintain a more streamlined test suite.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update localization files for multiple languages

- Improved translations in Arabic, Bulgarian, German, English, and Spanish for chat and tool-related strings.
- Enhanced descriptions for various parameters and added new keys for file handling and security warnings.
- Adjusted phrasing for clarity and consistency across languages.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update PR comment script to include Actions Artifacts link

- Modified the PR comment generation script to accept an additional artifactsUrl parameter.
- Updated the comment format to include both Release download and Actions Artifacts links for better accessibility.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 chore(hotfix): bump version to v2.1.28 [skip ci]

* chore: update secrets token

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: rdmclin2 <rdmclin2@gmail.com>
Co-authored-by: Arvin Xu <arvinx@foxmail.com>
Co-authored-by: Innei <i@innei.in>
2026-02-11 23:51:35 +08:00
rdmclin2 d225da96df chore: update secrets token 2026-02-11 23:45:07 +08:00
lobehubbot 0acaf01f9a 🐛 chore(hotfix): bump version to v2.1.28 [skip ci] 2026-02-11 15:34:52 +00:00
Innei 5a8911b72d 🐛 fix: update @lobehub/ui version and refactor dynamic import handling (#12260)
*  feat: add hotfix workflow and script for automated hotfix management

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: refactor PR creation command to use execFileSync for improved reliability

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui version and refactor dynamic import handling

- Bump @lobehub/ui dependency from ^4.35.0 to ^4.36.2 in package.json.
- Refactor settingsContentToStatic.mts to simplify dynamic import processing by removing business feature checks.
- Add initialize.ts to enable immer's map set functionality.
- Correct import path in layout.tsx from 'initiallize' to 'initialize'.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @types/react version in package.json

- Bump @types/react dependency from ^19.2.9 to 19.2.14.
- Add @types/react version to overrides section for consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance auto-tag-release workflow for strict semver validation

- Updated regex to match strict semantic versioning format, allowing for optional prerelease and build metadata.
- Added validation step to ensure the version is a valid semver before proceeding with the release process.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove defaultSecurityBlacklist test file

- Deleted the test file for DEFAULT_SECURITY_BLACKLIST as it is no longer needed.
- This cleanup helps maintain a more streamlined test suite.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update localization files for multiple languages

- Improved translations in Arabic, Bulgarian, German, English, and Spanish for chat and tool-related strings.
- Enhanced descriptions for various parameters and added new keys for file handling and security warnings.
- Adjusted phrasing for clarity and consistency across languages.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update PR comment script to include Actions Artifacts link

- Modified the PR comment generation script to accept an additional artifactsUrl parameter.
- Updated the comment format to include both Release download and Actions Artifacts links for better accessibility.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 23:33:44 +08:00
Arvin Xu e6596e94a5 🔨 chore: update sync main to canary script (#12264)
#### 💻 Change Type

<!-- For change type, change [ ] to [x]. -->

- [ ]  feat
- [ ] 🐛 fix
- [ ] ♻️ refactor
- [ ] 💄 style
- [ ] 👷 build
- [ ] ️ perf
- [ ]  test
- [ ] 📝 docs
- [x] 🔨 chore

#### 🔗 Related Issue

<!-- Link to the issue that is fixed by this PR -->

<!-- Example: Fixes #xxx, Closes #xxx, Related to #xxx -->

#### 🔀 Description of Change

<!-- Thank you for your Pull Request. Please provide a description
above. -->

#### 🧪 How to Test

<!-- Please describe how you tested your changes -->

<!-- For AI features, please include test prompts or scenarios -->

- [ ] Tested locally
- [ ] Added/updated tests
- [ ] No tests needed

#### 📸 Screenshots / Videos

<!-- If this PR includes UI changes, please provide screenshots or
videos -->

| Before | After |
| ------ | ----- |
| ...    | ...   |

#### 📝 Additional Information

<!-- Add any other context about the Pull Request here. -->

<!-- Breaking changes? Migration guide? Performance impact? -->

## Summary by Sourcery

CI:
- Introduce a new sync-main-to-canary GitHub Actions workflow that
creates an automatic PR from main to canary on pushes to main and remove
the previous sync-main-to-dev workflow.
2026-02-11 23:18:27 +08:00
rdmclin2 9c09160154 chore: update sync main to canary workflow 2026-02-11 23:09:00 +08:00
LiJian 6eee83ab4c ♻️ refactor: imporve agent builder prompt (#12259) 2026-02-11 21:16:37 +08:00
lobehubbot d7d186df1a 🔧 chore(release): bump version to v2.1.27 [skip ci] 2026-02-11 09:33:15 +00:00
Arvin Xu b225820679 🚀 release: v2.1.27 (#12248)
## 📦 Release v2.1.27

This branch contains changes for the upcoming v2.1.27 release.

### Change Type
- Checked out from dev branch and merged to main branch

### Release Process
1.  Release branch created
2.  Pushed to remote
3. 🔄 Waiting for PR review and merge
4.  Release workflow triggered after merge

---
Created by release script
2026-02-11 17:15:36 +08:00
Innei 089ffbee52 🐛 fix: correct import path for defaultSecurityBlacklist test (#12255)
🐛 fix: correct import path for defaultSecurityBlacklist in test

The import path was pointing to `../defaultSecurityBlacklist` (core/) but
the file was moved to `../../audit/defaultSecurityBlacklist` during a
prior refactor. The broken import was lost during a rebase conflict
resolution, causing 8 cascading TS errors.
2026-02-11 15:56:33 +08:00
Innei 7d19102d6b 🔧 chore: remove unused ESLint suppression for anonymous default export in global styles (#12252)
* 🔧 chore: remove unused ESLint suppression for anonymous default export in global styles

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: refactor TypeScript linting to use a dedicated script for improved maintainability

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 14:20:30 +08:00
Innei 59fb5a7d63 🔧 fix: update PR build workflows to trigger on release branches (#12249)
🔧 fix: update PR build workflows to trigger on release branches in addition to specific labels
2026-02-11 13:53:37 +08:00
Innei 6ad1eddf29 🔧 chore(release): prepare release v2.1.27 2026-02-11 13:21:50 +08:00
Innei 047c1ee5a2 fix: accordion action opacity 2026-02-11 13:19:55 +08:00
Innei 01f927bf5f 🔧 fix: update pre-commit hook to conditionally run type-check on dev and main branches 2026-02-11 13:19:49 +08:00
Innei 1fc833b80b 🐛 fix: filter stdio MCP tools on web environment (#12235)
* 🐛 fix: filter stdio MCP tools on web environment

Prevent stdio-based MCP tools (desktop-only) from being injected into agent
conversations on web platforms. Stdio transport requires Electron IPC which
is unavailable on web, causing runtime errors. Added environment-aware
filtering in createAgentToolsEngine enableChecker with comprehensive tests.

* 🐛 fix: filter stdio MCP tools on web environment

- Simplify serverExternalPackages config with nullish coalescing
- Filter out stdio MCP plugins in non-desktop environments since stdio transport requires Electron IPC
2026-02-11 13:19:38 +08:00
Innei a33cf6c8c6 update 2026-02-11 13:12:34 +08:00
Innei 6016299ad1 🔧 fix: update onSave handler in PageEditor to use passed function instead of console log 2026-02-11 13:10:32 +08:00
Innei 9db344fa4b feat: enhance ToolItem and ToolsList components with improved text handling and styling 2026-02-11 13:10:31 +08:00
Innei 8e2009d3e5 ♻️ refactor: replace inline stopPropagation/preventDefault with @lobehub/ui stable exports 2026-02-11 13:10:30 +08:00
Innei b40fd3464e ♻️ refactor: replace window.open interception with setWindowOpenHandler in main process
- Use Electron's setWindowOpenHandler in Browser.ts to intercept external links
- Remove window.open override from preload script
- Remove pushState/replaceState interception as no longer needed
- Update tests to reflect changes

This moves external link handling to the main process for better security
and simplifies the preload script.
2026-02-11 13:10:30 +08:00
Innei 06440f2675 style(nav-panel): simplify motion variants and update type import
- Changed type import for ReactNode to a more concise syntax.
- Removed unnecessary blur effects from motion variants to streamline animations.
- Updated AnimatePresence mode from 'popLayout' to 'sync' for improved transition handling.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:10:29 +08:00
Innei dd473560fa 🔨 chore: add auto-tag release workflow and interactive release script (#12236)
* init

* add missing deps
2026-02-11 13:05:59 +08:00
Innei 0fbb152f09 chore: update ESLint suppressions with new rules and counts for various components 2026-02-11 13:05:59 +08:00
Innei 0685069444 test: increase timeout for API_AUDIENCE and createOIDCProvider tests to 10 seconds
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:05:59 +08:00
arvinxx 4dc6de6822 fix lint 2026-02-11 13:05:59 +08:00
Innei 92670136de fix: correct type assertion in ConfigGroupModal and update import path for Transport
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:05:59 +08:00
Innei 96627b9bb8 chore: fix lint 2026-02-11 13:05:56 +08:00
Innei 2b178010cc 🐛 fix: add markdownToTxt alias override in vitest config
The @/utils alias maps to packages/utils/src, but markdownToTxt lives
in src/utils. Add explicit alias to fix test resolution failures.
2026-02-11 13:05:16 +08:00
Innei 8493e20e5b test(desktop): fix menu accelerator tests to assert role instead of explicit accelerator
Role-based menu items have their accelerators handled by Electron runtime, so tests should verify the role property rather than an explicit accelerator value.
2026-02-11 13:05:16 +08:00
Innei eefb67e74a 🔧 chore: update ESLint configuration and dependencies 2026-02-11 13:05:16 +08:00
Innei 374b8ed8cd 👷 ci: add desktop nightly release workflow
- Schedule daily at 14:00 UTC+8, with manual dispatch support
- Version: latest stable tag minor+1 (e.g., 2.0.12 → 2.1.0-nightly.YYYYMMDDHHMM)
- Skip build when no code changes in package.json, src/, packages/, apps/desktop/
- Support force build option to bypass diff check
- Auto cleanup old nightly releases (keep 7)
- Exclude nightly from beta workflow to prevent duplicate builds
- Remove next channel from beta workflow
2026-02-11 13:05:16 +08:00
Innei 1f57d5cc4f 🔧 chore: remove desktop download route move to cloud 2026-02-11 13:05:16 +08:00
Innei 6029fd3078 💄 style: enhance sidebar transition with Vercel-style motion
- Add blur effect (4px) during transitions

- Implement direction-aware slide animation (8px offset)

- Support animation mode preference

- Optimize with will-change and Freeze component

- Update @lobehub/ui to v4.35.0
2026-02-11 13:05:16 +08:00
Innei d1d46cfb41 feat: add unread completion indicator for agents and topics
Add visual indicator (animated neon dot) to show when an agent or topic has
completed generation while user is viewing a different conversation.
2026-02-11 13:05:16 +08:00
Innei 67c403da4d 🐛 fix(desktop): remove redundant accelerators from menu role items
Electron's role-based menu items already provide default accelerators.
Explicitly setting them can override defaults and cause issues like
Ctrl+Plus (requiring Shift) not working for zoom in on Windows.
Only kept intentional overrides: F12 for devTools, F11 for fullscreen
on macOS, Alt+F4 for close and Ctrl+Y for redo on Windows.
2026-02-11 13:05:15 +08:00
Innei 397426de91 💄 style: update ServerVersionOutdatedAlert styling and logic
- Changed border style in ServerVersionOutdatedAlert component for improved visual consistency.
- Commented out the check for server version status and storage mode, setting a default value for isServerVersionOutdated to true for testing purposes.

This update enhances the alert's appearance and temporarily modifies its logic for development.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:05:15 +08:00
Rdmclin2 e4495946d9 feat: add built in skills management (#12106)
* feat: add builtin skills to skillstore

* feat: add builtin skills management and detail display

* chore: update i18n files

* fix: lobehub skill store uninstall icon

* chore: add want more application for lobehub skills

* fix: tool related test case

* fix: lint error

* chore: update i18n files

* fix: new users no built-in tool list avaliable

* chore: uninstalled builtin tools hidden from agent profile editor

* fix: skill store lost

* chore: use univeral error message

* chore: update built in description and readme

* chore: update i18n files

* chore: update i18n files
2026-02-11 13:05:15 +08:00
Innei aaa7b6d153 feat(desktop): implement subscription pages embedding with webview (#12114)
*  feat(desktop): implement subscription pages embedding with webview

- Add SubscriptionIframeWrapper component for embedding subscription pages in Electron webview
- Replace compile-time ENABLE_BUSINESS_FEATURES with runtime serverConfigSelectors
- Add useIsCloudActive hook to detect cloud sync status
- Add setupSubscriptionWebviewSession service for webview session management

Resolves LOBE-4589

*  feat: enhance SubscriptionIframeWrapper for improved configuration

- Updated iframe URL to use OFFICIAL_URL for better maintainability.
- Integrated server configuration to conditionally enable business features.
- Cleaned up code by removing commented-out lines and unnecessary eslint suppressions.

This update improves the flexibility and readability of the SubscriptionIframeWrapper component.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: enhance link interception in SubscriptionIframeWrapper

- Updated the script to intercept both link clicks and window.open calls for better URL handling.
- Added functionality to resolve relative URLs to absolute before logging.

This improvement enhances the tracking of external link interactions within the iframe.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: clean up useIsCloudActive hook

- Removed unnecessary eslint suppressions related to react-hooks rules.
- Improved code readability by eliminating commented-out lines.

This update enhances the clarity and maintainability of the useIsCloudActive hook.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:05:10 +08:00
Innei fcdaf9d814 🔧 chore: update eslint v2 configuration and suppressions (#12133)
* v2 init

* chore: update eslint suppressions and package dependencies

- Removed several eslint suppressions related to array sorting and reversing from eslint-suppressions.json to clean up the configuration.
- Updated @lobehub/lint package version from 2.0.0-beta.6 to 2.0.0-beta.7 in package.json for improvements and bug fixes.
- Made minor formatting adjustments in vitest.config.mts and various SKILL.md files for better readability and consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: clean up import statements and formatting

- Removed unnecessary whitespace in replaceComponentImports.ts for improved readability.
- Standardized import statements in contextEngineering.ts and createAgentExecutors.ts by adding missing spaces for consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: update eslint suppressions and clean up code formatting

* 🐛 fix: use vi.hoisted for mock variable initialization

Fix TDZ error in persona service test by using vi.hoisted() to ensure
mock variables are available when vi.mock factory runs.

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 13:04:48 +08:00
Rdmclin2 2892e8fcff feat: add starter suggested questions and recommend agents (#12033)
* feat: add  suggested questions

* chore: optimize suggest questions and list

* feat: support recommend agents

* chore: update write  related suggestions

* chore: empty and default count

* chore: update suggest questions

* chore: update suggest questions

* chore: fix suggest questions suspense loading

* chore: update i18n files

* fix: suggest questions skeleton

* chore: update i18n files

* fix: showSkillBanner style compatible

* chore: custom  agent group list query

* chore: move ModeHeader to ModeTag

* style: adjust  suggest questions  list item style

* chore: change back to corner right up

* chore: update agent suggest questions

* chore: update agents i18n files

* feat: support agent builder ,group builder and doc copilot suggestions

* feat: support home starter swtich
2026-02-11 12:58:48 +08:00
René Wang 77ec294ab4 feat: Update user guide (#12123)
fix: user guide
2026-02-11 12:58:47 +08:00
René Wang 8dd8ff929f fix: Resource manager (#12040)
* fix: update

* fix: Cannot click page on sidebar

* fix: Cannot remove page from lib

* fix: 404 resource

* fix: No page title

* fix: Chunk

* fix: Search skills in CMDK

* fix: Masonry item style

* fix: Masonry item style

* fix: Search memory

* fix: doc

* fix: doc

* fix: Move to another lib

* fix: Move to another lib

* fix: translation file

* fix: translation

* fix: TS error
2026-02-11 12:58:47 +08:00
Innei 4674a76e2e 🔧 chore: update @lobehub/ui version and enhance UpdateAgentPromptInspector styling
resolves LOBE-4515

- Bump @lobehub/ui dependency from ^4.33.0 to ^4.33.4 for improvements and bug fixes.
- Add min-width style to the container in UpdateAgentPromptInspector for better layout.
- Implement ellipsis with tooltip for agent title to handle overflow gracefully.
- Adjust length diff display to prevent text wrapping.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:47 +08:00
Innei 3ab33e8371 chore: remove log
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:47 +08:00
Innei 30a69eacf3 🐛 fix: prevent scroll anchoring during streaming (#12115)
🐛 fix: stop scroll anchoring in chat list
2026-02-11 12:58:47 +08:00
Innei edec250cf3 feat(settings): add auto-scroll option during AI response streaming
- Introduced new settings for enabling auto-scroll during AI responses in both English and Chinese locales.
- Updated chat configuration and user settings to include `enableAutoScrollOnStreaming`.
- Enhanced the UI to allow users to toggle this feature in the agent settings.
- Refactored auto-scroll logic to respect user preferences and agent-specific settings.

This feature improves user experience by ensuring that the latest AI responses are always visible during streaming.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:47 +08:00
Innei 83e5f31576 ♻️ refactor: cleanup duplicate AddTopicButon components and optimize migration script (#12095)
- Remove duplicate AddTopicButon.tsx files from agent and group layouts
- Refactor migrate-spa-navigation.ts to use switch statement for better readability
- Clean up unused imports in migration script
2026-02-11 12:58:47 +08:00
Rdmclin2 96fa203c81 💄 style: change skills using this skill list style (#12089)
chore: change agents using skill list style
2026-02-11 12:58:47 +08:00
Innei 046eb72961 ♻️ refactor(store): migrate to class-based actions with flattenActions (#12081)
*  feat(store): introduce StoreSetter interface and refactor agent group actions

- Added StoreSetter interface to manage state updates in a more flexible manner.
- Refactored ChatGroupInternalAction, ChatGroupCurdAction, and ChatGroupMemberAction to utilize the new StoreSetter for state management.
- Enhanced action methods to improve clarity and maintainability.
- Introduced createActionProxy utility to streamline action handling across slices.
- Updated lifecycle and member slices to align with the new structure, ensuring consistent state management practices.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor squash

refactor: replace createActionProxy with flattenActions for action handling

- Updated multiple store files to utilize flattenActions instead of createActionProxy, improving the handling of action methods and ensuring proper prototype method binding.
- Removed createActionProxy utility as it is no longer needed, streamlining the action management process across the application.

This change enhances maintainability and consistency in state management practices.

Signed-off-by: Innei <tukon479@gmail.com>

chore: format code

Signed-off-by: Innei <tukon479@gmail.com>

fix: correct assignment syntax in GroupChatSupervisor and ResourceSyncEngine

- Updated assignment syntax from object-like notation to standard assignment for error handling and state updates in GroupChatSupervisor and ResourceSyncEngine classes.
- Ensured proper variable assignments for error handling and state management, enhancing code clarity and functionality.

Signed-off-by: Innei <tukon479@gmail.com>

fix: update transformApiArgumentsToAiState return type and logic

- Changed the return type of transformApiArgumentsToAiState from Promise<string> to Promise<string | undefined> to better reflect possible outcomes.
- Modified the return statement to return undefined instead of an empty string when the builtinToolLoading for the given key is true, improving clarity in the function's behavior.

Signed-off-by: Innei <tukon479@gmail.com>

* feat(upload): enhance uploadBase64FileWithProgress return type and add dimensions

- Introduced a new interface, UploadWithProgressResult, to define the structure of the result returned by uploadBase64FileWithProgress.
- Updated the return type of uploadBase64FileWithProgress and uploadFileWithProgress methods to reflect the new interface, improving type safety and clarity.
- This change allows for better handling of image dimensions and file metadata during the upload process.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor(zustand): migrate to class-based actions and enhance action composition

- Updated the implementation of actions from plain StateCreator objects to class-based actions, improving encapsulation and maintainability.
- Introduced a new pattern for defining actions using private fields to prevent internal state leakage.
- Replaced createActionProxy with flattenActions for better method binding and prototype support in action handling.
- Enhanced the structure for multi-class slices, allowing for cleaner composition of actions within store files.

This refactor streamlines state management practices and improves code clarity across the application.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:46 +08:00
Innei de1d17188c refactor: clean up UpdateIdentityMemoryInspector and enhance ErrorResponse styling
- Remove unused success state and related conditional rendering in UpdateIdentityMemoryInspector
- Simplify rendering logic for better readability
- Add custom styles for ErrorResponse component to improve layout and presentation

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:46 +08:00
Innei 9ecca13388 refactor: replace react-diff-view with @lobehub/ui CodeDiff (#12077)
* refactor: replace react-diff-view with @lobehub/ui CodeDiff

- Replace react-diff-view with @lobehub/ui's CodeDiff and PatchDiff components
- Use CodeDiff in Intervention for old/new content comparison
- Use PatchDiff in Render for unified diff patch display
- Remove react-diff-view dark theme CSS file
- Remove diff generation complexity, rely on built-in component styling
- Reduce code by ~93 lines

* 🔧 chore: add font-family style to previewText
2026-02-11 12:58:46 +08:00
Rdmclin2 90c88da19d feat: add feedback request for community list (#12078)
*  feat(skillStore): add "Want more skills?" prompt with feedback integration

- Add WantMoreSkills component below CommunityList
- Extend useFeedbackModal to support preset initial values
- Update FeedbackModal to accept and display initial form values
- Add i18n translations for zh-CN and en-US

Closes LOBE-4163

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* 🔧 fix(skillStore): show skill request prompt at list end instead of fixed footer

- Move WantMoreSkills to VirtuosoGrid Footer, shown only when list ends
- Update text to "已经到底了,未找到所需技能?提交申请 →"
- Use Typography.Link for hyperlink style on action text
- Update feedback form template with structured format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: initial values not set

* chore: remove skill install banner shadow

* chore: use same list height

* chore: update i18n files

* fix: klavis disconnected style

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 12:58:46 +08:00
Innei b010ab9da8 ♻️ refactor(fileSearch): File/Content Search by Platform (#12074)
* ♻️ refactor(fileSearch): consolidate determineContentType to base class and use os.homedir()

- Move determineContentType method to FileSearchImpl base class with merged type mappings
- Replace process.env.HOME with os.homedir() in macOS and Linux implementations
- Replace process.env.USERPROFILE with os.homedir() in Windows implementation
- Remove duplicate implementation from three platform-specific classes

* refactor: content search service

* chore: add engine text

* fix: show engine

* test: add unit tests for contentSearch and fileSearch modules

- Add base.test.ts and index.test.ts for contentSearch module
- Add base.test.ts and index.test.ts for fileSearch module
- Test buildGrepArgs, determineContentType, escapeGlobPattern, etc.
- Test factory functions for platform-specific implementations

* 🐛 fix(contentSearch): use correct ripgrep glob patterns for nested path exclusion

Change `!node_modules` and `!.git` to `!**/node_modules/**` and `!**/.git/**`
to properly exclude nested directories as per ripgrep documentation.

* fix: types
2026-02-11 12:58:46 +08:00
rdmclin2 f829bf7fdf fix: setting highlight and memerid not responding error 2026-02-11 12:58:45 +08:00
Innei 6f24e6b900 feat(desktop): add proactive token refresh on app startup and activation
- Refresh token on every app launch (with 5-minute debounce to prevent rapid restarts)
- Trigger refresh on Mac app activation (Dock click) with same debounce
- Track lastRefreshAt timestamp in encrypted token storage
- Add isRemoteServerConfigured() helper method to avoid code duplication
- Fix cloud mode check that incorrectly required remoteServerUrl
- Add comprehensive tests for all refresh scenarios
2026-02-11 12:58:45 +08:00
Rdmclin2 dad6108a37 chore: revert to back to header mode (#12051) 2026-02-11 12:58:45 +08:00
Innei 8676c22348 feat: GitHub Copilot Provider (#11997)
* feat: implement GitHub Copilot integration with OAuth Device Flow authentication

- Updated package.json to include new GitHub Copilot model.
- Added GitHub Copilot model provider and associated runtime logic.
- Implemented OAuth Device Flow for authentication, including UI components for user interaction.
- Enhanced AI provider settings to support OAuth configuration.
- Updated types and key vaults to accommodate GitHub Copilot tokens.

This integration allows users to authenticate via GitHub Copilot, enabling access to its models through a seamless OAuth experience.

Signed-off-by: Innei <tukon479@gmail.com>

* feat: expand GitHub Copilot model definitions and add new models

- Updated existing models with new descriptions, display names, and IDs.
- Introduced several new models including GPT-5 mini, GPT-4o variants, Grok Code Fast 1, and Claude Haiku 4.5.
- Adjusted context window tokens and max output values for various models.
- Enhanced model capabilities with function call and vision abilities.

This update enriches the AI model offerings and improves the overall functionality of the GitHub Copilot integration.

Signed-off-by: Innei <tukon479@gmail.com>

*  test: add unit tests for OAuth Device Flow and GitHub Copilot

- Add OAuthDeviceFlowService tests (12 tests)
- Add GithubCopilotOAuthService tests (13 tests)
- Add LobeGithubCopilotAI runtime tests (12 tests)
- Add updateConfig keyVaults merge tests (5 tests)
- Fix sleep import in githubCopilot runtime (use inline Promise)

* feat: enhance OAuth Device Flow integration and user experience

- Added new OAuth-related strings to localization files for English, Chinese, and default locales.
- Refactored ProviderConfig component to streamline OAuth authentication handling and improve UI presentation.
- Updated OAuthDeviceFlowAuth component to include user information display (username and avatar).
- Enhanced backend logic to fetch and store GitHub user information during OAuth authentication.
- Improved error handling and user feedback during the OAuth process.

This update significantly enhances the user experience for OAuth authentication, providing clearer communication and a more integrated interface.

Signed-off-by: Innei <tukon479@gmail.com>

* feat: improve OAuth provider handling in ProviderConfig and OAuthDeviceFlowAuth components

- Integrated OAuth authentication status querying in ProviderConfig to conditionally render the form based on authentication state.
- Refactored OAuthDeviceFlowAuth to enhance user experience during the authentication process, including better state management and UI updates.
- Ensured that the form is only displayed when the user is authenticated for OAuth providers.

This update streamlines the OAuth integration, providing a more responsive and user-friendly interface.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: update OpenAI model snapshots with new configurations

- Modified model definitions for GPT 3.5 Turbo and Embedding V2 Ada, including updated context window tokens, descriptions, and display names.
- Enabled function call capability for GPT 3.5 Turbo and changed the type for Embedding V2 Ada from "embedding" to "chat".

This update ensures the model snapshots reflect the latest configurations and capabilities.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: correct casing in model-bank package.json and enhance aiProvider test

- Updated the casing of the GitHub Copilot model path in package.json for consistency.
- Added a call to KeyVaultsGateKeeper.getUserKeyVaults in the aiProvider test to improve test coverage and functionality.

This update ensures better adherence to naming conventions and enhances the robustness of the aiProvider tests.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:45 +08:00
Innei 4db39075a9 feat(electron): refactor RecentlyViewed with Pinned + Recent architecture (#11774)
*  feat(electron): refactor RecentlyViewed with Pinned + Recent architecture

- Add Pinned section for user-pinned pages (persisted to localStorage)
- Add Recent section with auto-deduplication and 20 items limit
- Support dynamic title updates (e.g., conversation names instead of generic "Chat")
- Add Pin/Unpin toggle on hover
- Keep navigation history (back/forward) independent from recent pages

Closes LOBE-4212
Closes LOBE-4230

* 📝 docs(linear): update issue management guidelines

- Revise description for clarity on triggering conditions for Linear issues.
- Add critical section on PR creation with Linear issues, emphasizing immediate comment requirements.
- Update completion comment format to include structured summary and key changes.
- Clarify workflow steps and correct examples for task completion and status updates.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat(electron): history stack

- Introduce a new plugin system for RecentlyViewed, allowing dynamic resolution of page references.
- Implement caching for display data, improving performance and user experience.
- Refactor existing page handling to support various page types (agents, groups, etc.) with dedicated plugins.
- Update Recent and Pinned pages management to utilize the new plugin system for better data integrity and retrieval.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:45 +08:00
René Wang bebfb461e9 feat: Polish CMDK (#12011)
* fix: Hide proxy command for web

* style: add close transition

* fix: cmdk close animation

* style: show current theme
2026-02-11 12:58:45 +08:00
Rdmclin2 501352e035 feat: add tool agents in tool detail page (#11993)
* chore: upgrade market sdk to 0.29.2

* feat: add skill recommendations to agent detail

* fix: agent link error

* feat: support agents using this skill

* feat: support agents using tool list virtual and load more

* chore: remove lobehub skill detail loading

* feat: mcp detail support load more

* fix: mcp detail in comunity scroll problem

* chore: update i18n files
2026-02-11 12:58:45 +08:00
Innei 390335f567 fix: add rs canvas in outputFileTracingIncludes for Docker builds
* Added support for including native bindings in standalone output when building with Docker.
* Updated outputFileTracingIncludes to conditionally include necessary files for `@napi-rs/canvas` and pnpm package locations.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:44 +08:00
Innei 899cf85e94 feat: rebrand stable app icon
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:44 +08:00
Innei 332c66a10d feat: enhance ProviderConfig Checker with static styles
* Added createStaticStyles for styling the popup component
* Updated popupClassName to utilize the new styles

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:44 +08:00
Rdmclin2 6c342525e9 feat: add write starter and fix e2e tests (#11992)
* feat: add write document and image create starter

* chore: update doc starter e2e tests

* chore: remove image stater form home input

* chore: move model header to actionbar extra place

* test: fix e2e test
2026-02-11 12:58:43 +08:00
Innei cd13057a73 chore: update macOS build configuration to fix hdiutil issues and clean previous artifacts
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:43 +08:00
Innei 13e0923c30 chore: update Linear skill description for clarity and usage guidelines
Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:43 +08:00
Rdmclin2 07d223117c 🐛 fix: skill detail error (#11949)
* chore: use only fetch once swr

* chore: use mcp detail tool list

* chore: update tools detail

* chore: update i18n files

* fix: skill style

* chore: add skill loading
2026-02-11 12:58:43 +08:00
rdmclin2 a8582b0b37 refactor: skill list 2026-02-11 12:58:43 +08:00
rdmclin2 6c1eadc638 chore: refactor skill detail page 2026-02-11 12:58:43 +08:00
rdmclin2 2d294048cc chore: migrate integeration detail to skillstore 2026-02-11 12:58:43 +08:00
rdmclin2 3626770ccd chore: use independent swr hook call 2026-02-11 12:58:43 +08:00
Innei 6e65d725c5 🐛 fix(desktop): allow scrolling in read file view and improve new topic creation
- Add `overflow: auto` to ReadFileView component to fix content scrolling issue
- Update new topic creation to use current active agent instead of always navigating to inbox

Closes LOBE-4372
2026-02-11 12:58:42 +08:00
Innei e063d093ae 🐛 fix(desktop): prevent auth modal from showing during onboarding
Use localStorage state check instead of pathname to determine if
onboarding is complete, avoiding timing issues with route transitions.
2026-02-11 12:58:42 +08:00
Innei b8fdcc3070 feat(desktop): enhance desktop menu and navigation system
- Add DesktopFileMenuBridge component for native menu integration
- Update navigation events in electron-client-ipc
- Modify menu implementations across all platforms (Linux, macOS, Windows)
- Add hotkey settings for desktop features
- Update layout and menu creation hooks for desktop navigation
2026-02-11 12:58:42 +08:00
Innei 943b3e86e2 📝 update: change copyright year from 2025 to 2026 in onboarding and email templates
- Updated the copyright year in the footer of onboarding layouts and email templates to reflect 2026.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:42 +08:00
rdmclin2 641de4c3ef feat: add intergration Detail Content and skill list 2026-02-11 12:58:42 +08:00
Innei 48dd92c315 🔧 chore: simplify electron workflow by removing i18n codemod steps
- Removed temporary workspace setup and dynamic import assertions for i18n codemod.
- Updated workflow to directly run the electron workflow modifiers script.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:42 +08:00
Innei 8188e2d9f0 ♻️ refactor: restructure electron build workflow with i18n codemod
- Remove desktop-build-electron.yml workflow
- Add verify-electron-codemod.yml workflow for i18n transformation
- Add i18nDynamicToStatic modifier for dynamic to static i18n conversion
- Update build workflows to use new i18n modifier approach
- Update README and package.json configurations
2026-02-11 12:58:42 +08:00
Rdmclin2 91155fd379 🐛 fix: skill detail page icon problem (#11912)
* fix: integration detail avatar

* fix: Skill List icon style

* chore: support icon and title as a whole to trigger detail page

* fix: avatar size compress

* fix: popover content icon stretch

* fix: avatar align problem

* chore: add kalvis skill icon and lobehub skill icon

* chore: use same style file
2026-02-11 12:58:42 +08:00
Innei 95c999e3c9 feat: add full-width view option to menu in agent and page editor headers
resolves LOBE-4449

- Introduced a new icon for the full-width view option using Maximize2 from lucide-react.
- Updated the useMenu hook in both agent and page editor headers to include the new full-width menu item.

Signed-off-by: Innei <tukon479@gmail.com>
2026-02-11 12:58:41 +08:00
Innei 07f9c2a6a0 🔨 chore: add auto-tag release workflow and interactive release script (#12236)
* init

* add missing deps
2026-02-11 12:43:43 +08:00
Arvin Xu a83dc4d4ed 💄 style: add emoji reaction feature for messages (#12004)
*  feat: add emoji reaction feature for messages

- Add EmojiReaction type definition in metadata
- Add addReaction/removeReaction store actions in Conversation Store
- Create ReactionDisplay component for showing reactions
- Create ReactionPicker component with quick emoji selection
- Add ReactionFeedbackProcessor for context-engine
- Integrate reaction UI into Assistant message component
- Add i18n keys for reaction feature

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

Co-Authored-By: Claude <noreply@anthropic.com>

* update ui

* refactor reaction implement

* add reaction processor

* add reaction processor

* push

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 12:32:48 +08:00
LobeHub Bot e0e158c586 test: add unit tests for markdownToTxt utility (#12058)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 12:14:22 +08:00
LobeHub Bot 9cdfff1aa8 🌐 chore: translate non-English comments to English in model-runtime/core (#12244)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 12:06:12 +08:00
Neko 3346c07ed1 🔨 chore(userMemories): can render persona even without roles (#12237) 2026-02-10 21:46:46 +08:00
YuTengjing 7721261dc0 🔨 chore(model-runtime): add onRouteAttempt callback to RouterRuntime (#12234) 2026-02-10 15:48:12 +08:00
LobeHub Bot db1f813139 🌐 chore: translate non-English comments to English in image store (#12229)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-10 14:29:29 +08:00
lobehubbot 29f886d54b 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-10 02:28:21 +00:00
semantic-release-bot 7a5fc81dc7 🔖 chore(release): v2.1.26 [skip ci]
### [Version&nbsp;2.1.26](https://github.com/lobehub/lobe-chat/compare/v2.1.25...v2.1.26)
<sup>Released on **2026-02-10**</sup>

#### 💄 Styles

- **misc**: Update i18n.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Styles

* **misc**: Update i18n, closes [#12227](https://github.com/lobehub/lobe-chat/issues/12227) ([37b06c4](https://github.com/lobehub/lobe-chat/commit/37b06c4))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-10 02:26:46 +00:00
LobeHub Bot 37b06c4f0b 🤖 style: update i18n (#12227)
💄 style: update i18n

Co-authored-by: canisminor1990 <17870709+canisminor1990@users.noreply.github.com>
2026-02-10 10:08:37 +08:00
lobehubbot 404ea0d7b2 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-09 14:47:04 +00:00
semantic-release-bot 29fd296945 🔖 chore(release): v2.1.25 [skip ci]
### [Version&nbsp;2.1.25](https://github.com/lobehub/lobe-chat/compare/v2.1.24...v2.1.25)
<sup>Released on **2026-02-09**</sup>

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-09 14:45:39 +00:00
Neko b0def6d711 👷 build(database): migrate id using seq and identity to text with nanoid (#12223)
* 🔨 chore(database): added id_nanoid to replace id using seq and identity

* 🔨 chore(database): assgin database id column value to id_nanoid

* 🔨 chore(database): update dbml

* 🔨 chore(database): add not null & unique index

* 🔨 chore(database): drop foreign key dependency, switch to depend on id_nanoid

* 🔨 chore(database): switch to use id_nanoid as primary key

* 🔨 chore(database): drop old id column

* 🔨 chore(database): rename id_nanoid to id

* 🔨 chore(database): remove unique constraint

* 🔨 chore(database): updated dbml

* 🔨 chore(database): incorrect --> statement-breakpoint
2026-02-09 22:27:46 +08:00
lobehubbot 146cf2c978 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-09 10:52:22 +00:00
semantic-release-bot fe48875d47 🔖 chore(release): v2.1.24 [skip ci]
### [Version&nbsp;2.1.24](https://github.com/lobehub/lobe-chat/compare/v2.1.23...v2.1.24)
<sup>Released on **2026-02-09**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix multimodal content_part images rendered as base64 text.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix multimodal content_part images rendered as base64 text, closes [#12210](https://github.com/lobehub/lobe-chat/issues/12210) ([00ff5b9](https://github.com/lobehub/lobe-chat/commit/00ff5b9))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-09 10:50:43 +00:00
LobeHub Bot 748e7fd231 test: add unit tests for scheduleToolCallReport (#12214)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 18:32:07 +08:00
Arvin Xu 00ff5b9c1b 🐛 fix: fix multimodal content_part images rendered as base64 text (#12210) 2026-02-09 18:18:59 +08:00
Neko 4ae90976a0 🔨 chore(memory-user-memory): will try to capture and create more entries for identity when no entries present (#12217) 2026-02-09 15:09:34 +08:00
Neko c41f0af5c6 🔨 chore(memory-user-memory): should not append date & time (#12216) 2026-02-09 14:55:14 +08:00
Arvin Xu 0b91217f14 🔨 chore: improve auto agent workflow (#12209)
* improve auto workflow

* add auto workflow
2026-02-09 12:34:18 +08:00
lobehubbot 788037bfa0 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-09 02:25:01 +00:00
semantic-release-bot b06b0e5662 🔖 chore(release): v2.1.23 [skip ci]
### [Version&nbsp;2.1.23](https://github.com/lobehub/lobe-chat/compare/v2.1.22...v2.1.23)
<sup>Released on **2026-02-09**</sup>

#### 🐛 Bug Fixes

- **swr**: Prevent useActionSWR isValidating from getting stuck.
- **misc**: Fix editor content missing when send error, use custom avatar for group chat in sidebar.

#### 💄 Styles

- **misc**: Update i18n.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **swr**: Prevent useActionSWR isValidating from getting stuck, closes [#12059](https://github.com/lobehub/lobe-chat/issues/12059) ([8877bc1](https://github.com/lobehub/lobe-chat/commit/8877bc1))
* **misc**: Fix editor content missing when send error, closes [#12205](https://github.com/lobehub/lobe-chat/issues/12205) ([ee7ae5b](https://github.com/lobehub/lobe-chat/commit/ee7ae5b))
* **misc**: Use custom avatar for group chat in sidebar, closes [#12208](https://github.com/lobehub/lobe-chat/issues/12208) ([31145c9](https://github.com/lobehub/lobe-chat/commit/31145c9))

#### Styles

* **misc**: Update i18n, closes [#12025](https://github.com/lobehub/lobe-chat/issues/12025) ([c12d022](https://github.com/lobehub/lobe-chat/commit/c12d022))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-09 02:23:15 +00:00
Arvin Xu 31145c9a1f 🐛 fix: use custom avatar for group chat in sidebar (#12208)
* 🐛 fix: use custom avatar for group chat in sidebar

When a group chat has a custom avatar set, the sidebar was always showing
the member composition avatar instead. This fix:

- Queries chatGroups.avatar and chatGroups.backgroundColor in HomeRepository
- Prioritizes custom avatar (string) over member avatars (array) in data layer
- Replaces GroupAvatar with AgentGroupAvatar in AgentGroupItem for proper
  avatar type detection (custom vs member composition)

Closes LOBE-4883

*  test: add DB tests for group chat custom avatar in sidebar

Add 6 test cases covering the custom avatar fix for chat groups:

getSidebarAgentList:
- should return custom avatar when chat group has one set
- should return member avatars when chat group has no custom avatar
- should prioritize custom avatar over member avatars

searchAgents:
- should return custom avatar for chat groups with custom avatar in search
- should return member avatars for chat groups without custom avatar in search
- should prioritize custom avatar over member avatars in search
2026-02-09 10:04:40 +08:00
LobeHub Bot ce8c0c3eaf 🌐 chore: translate non-English comments to English in packages/electron-client-ipc and packages/edge-config (#11926)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 10:02:24 +08:00
LobeHub Bot c12d0221ac 🤖 style: update i18n (#12025)
💄 style: update i18n

Co-authored-by: canisminor1990 <17870709+canisminor1990@users.noreply.github.com>
2026-02-09 09:58:41 +08:00
Kingsword 8877bc12d7 🐛 fix(swr): prevent useActionSWR isValidating from getting stuck (#12059) 2026-02-09 09:57:37 +08:00
semantic-release-bot dd7d590bdd 🔖 chore(release): v2.1.23 [skip ci]
### [Version&nbsp;2.1.23](https://github.com/lobehub/lobe-chat/compare/v2.1.22...v2.1.23)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix editor content missing when send error.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix editor content missing when send error, closes [#12205](https://github.com/lobehub/lobe-chat/issues/12205) ([ee7ae5b](https://github.com/lobehub/lobe-chat/commit/ee7ae5b))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 19:27:56 +00:00
Neko bbc1dfcc23 🔨 chore(userMemories): fetch user persona (#12206) 2026-02-09 03:10:12 +08:00
Neko 0dbd8d6abf 🔨 chore(observability-otel): update name to lobehub (#12207) 2026-02-09 03:09:59 +08:00
semantic-release-bot 40edeb4025 🔖 chore(release): v2.1.23 [skip ci]
### [Version&nbsp;2.1.23](https://github.com/lobehub/lobe-chat/compare/v2.1.22...v2.1.23)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix editor content missing when send error.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix editor content missing when send error, closes [#12205](https://github.com/lobehub/lobe-chat/issues/12205) ([ee7ae5b](https://github.com/lobehub/lobe-chat/commit/ee7ae5b))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 17:43:27 +00:00
Arvin Xu ee7ae5b1d2 🐛 fix: fix editor content missing when send error (#12205)
* fix editor issue

* add virtual block plugin

* snapshot case

* fix task Render issue
2026-02-09 01:25:25 +08:00
lobehubbot 044e290ab0 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-08 17:19:44 +00:00
semantic-release-bot 6ed5e7bba1 🔖 chore(release): v2.1.22 [skip ci]
### [Version&nbsp;2.1.22](https://github.com/lobehub/lobe-chat/compare/v2.1.21...v2.1.22)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Register Notebook tool in server runtime.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Register Notebook tool in server runtime, closes [#12203](https://github.com/lobehub/lobe-chat/issues/12203) ([be6da39](https://github.com/lobehub/lobe-chat/commit/be6da39))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 17:18:18 +00:00
Arvin Xu be6da39437 🐛 fix: register Notebook tool in server runtime (#12203)
* refactor Notebook Executor

* 🐛 fix: register Notebook tool in server runtime

Notebook tool (lobe-notebook) was only registered on the client side,
causing server-side tool calls to fail with "not implemented" error.

- Add NotebookRuntimeService wrapping DocumentModel/TopicDocumentModel
- Add notebook server runtime registration
- Pass context to runtime methods for topicId passthrough
- Add tests for NotebookRuntimeService and runtime registration

Resolves LOBE-4880

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 01:00:13 +08:00
LobeHub Bot 0e688d08b8 🌐 chore: translate non-English comments to English in siliconcloud provider (#12190)
* 🌐 chore: translate non-English comments to English in siliconcloud provider

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

*  test: update siliconcloud test to match translated error message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: arvinxx <arvinx@foxmail.com>
2026-02-08 23:40:43 +08:00
lobehubbot f55b8344c6 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-08 15:37:50 +00:00
semantic-release-bot e1599d2e5e 🔖 chore(release): v2.1.21 [skip ci]
### [Version&nbsp;2.1.21](https://github.com/lobehub/lobe-chat/compare/v2.1.20...v2.1.21)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Add end-user info on OpenAI Responses API call, enable vertical scrolling for topic list on mobile.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add end-user info on OpenAI Responses API call, closes [#12134](https://github.com/lobehub/lobe-chat/issues/12134) ([72a85ac](https://github.com/lobehub/lobe-chat/commit/72a85ac))
* **misc**: Enable vertical scrolling for topic list on mobile, closes [#12157](https://github.com/lobehub/lobe-chat/issues/12157) [lobehub/lobe-chat#12029](https://github.com/lobehub/lobe-chat/issues/12029) ([bd4e253](https://github.com/lobehub/lobe-chat/commit/bd4e253))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 15:35:58 +00:00
Antoine Roux 72a85ac151 🐛 fix: add end-user info on OpenAI Responses API call (#12134)
Add end-user info on OpenAI Responses API call
2026-02-08 23:17:22 +08:00
Varun Chawla bd4e253d1b 🐛 fix: enable vertical scrolling for topic list on mobile (#12157)
Replace `overflow: 'hidden'` with `overflowX: 'hidden', overflowY: 'auto'`
on the topic list container so users can scroll through topics that exceed
the viewport height on mobile devices.

Closes lobehub/lobe-chat#12029
2026-02-08 23:16:51 +08:00
LobeHub Bot 9fa6253406 test: add unit tests for defaultSecurityBlacklist (#12094)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 23:04:12 +08:00
Rdmclin2 35b6d8f9ca chore: add sync main to dev script (#12202) 2026-02-08 23:02:49 +08:00
Arvin Xu e14cfae266 🔨 chore: use tsc in vercel build (#12201)
* try new build

* improve
2026-02-08 22:49:38 +08:00
semantic-release-bot 9740abd1d3 🔖 chore(release): v2.1.21 [skip ci]
### [Version&nbsp;2.1.21](https://github.com/lobehub/lobe-chat/compare/v2.1.20...v2.1.21)
<sup>Released on **2026-02-08**</sup>

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 14:19:55 +00:00
Varun Chawla 3d99e7ed77 fix: add Array.isArray() validation in favoriteTopic to prevent TypeError (#12188)
* fix: add Array.isArray() validation in favoriteTopic to prevent TypeError

Fixes #12072

The favoriteTopic function was using `if (!groups)` which only catches
null/undefined values. When SWR cache contains malformed data (objects,
strings, or other non-array types), the subsequent .map() call would
fail with "TypeError: h.map is not a function".

Changes:
- Replace `if (!groups)` with `if (!Array.isArray(groups))`
- Add defensive Array.isArray() check for group.topics before mapping
- Provide empty array fallback when group.topics is not an array

This ensures proper type validation and prevents runtime errors when
favoriting topics in group chat scenarios.

* test: add regression tests for favoriteTopic malformed cache handling

Add comprehensive regression tests for issue #12072 to verify that
favoriteTopic handles malformed SWR cache data without throwing TypeError:

- Test handling of non-array groups in cache (null, string, object, number)
- Test handling of groups with non-array topics field
- Test correct favorite state updates in well-formed cache
- Test no-op scenario when topic already has target state

These tests ensure the defensive Array.isArray() checks prevent
crashes when the SWR cache contains unexpected data structures.

* fix: correct regression test assertion for malformed groups

The test was incorrectly asserting that group.topics should be [] for
malformed entries. The actual behavior is correct: when no topic ID
matches, the function returns the original groups unchanged via
reference equality. The key regression being tested is that the function
doesn't throw a TypeError when encountering non-array topics.
2026-02-08 22:02:16 +08:00
semantic-release-bot 83173d9380 🔖 chore(release): v2.1.21 [skip ci]
### [Version&nbsp;2.1.21](https://github.com/lobehub/lobe-chat/compare/v2.1.20...v2.1.21)
<sup>Released on **2026-02-08**</sup>

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 12:11:02 +00:00
Arvin Xu 16b1904088 👷 build: add agent skills database schema (#12197)
* add skills db

* improve shell

* fix tests

* fix build

* fix tests
2026-02-08 19:53:27 +08:00
lobehubbot 37814db6df 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-08 11:22:26 +00:00
semantic-release-bot b6ada85d7f 🔖 chore(release): v2.1.20 [skip ci]
### [Version&nbsp;2.1.20](https://github.com/lobehub/lobe-chat/compare/v2.1.19...v2.1.20)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Add api/version and api/desktop to public routes, show notification when file upload fails due to storage plan limit.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add api/version and api/desktop to public routes, closes [#12194](https://github.com/lobehub/lobe-chat/issues/12194) ([ea81cd4](https://github.com/lobehub/lobe-chat/commit/ea81cd4))
* **misc**: Show notification when file upload fails due to storage plan limit, closes [#12176](https://github.com/lobehub/lobe-chat/issues/12176) ([f26d0df](https://github.com/lobehub/lobe-chat/commit/f26d0df))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 11:20:37 +00:00
LobeHub Bot ffeec13c28 🌐 chore: translate non-English comments to English in server/app/components (#12165)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 19:02:30 +08:00
LobeHub Bot 7e919b124c test: add comprehensive unit tests for unzipFile utility (#12191)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 18:46:29 +08:00
semantic-release-bot 42bccd2307 🔖 chore(release): v2.1.20 [skip ci]
### [Version&nbsp;2.1.20](https://github.com/lobehub/lobe-chat/compare/v2.1.19...v2.1.20)
<sup>Released on **2026-02-08**</sup>

#### 🐛 Bug Fixes

- **misc**: Add api/version and api/desktop to public routes, show notification when file upload fails due to storage plan limit.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add api/version and api/desktop to public routes, closes [#12194](https://github.com/lobehub/lobe-chat/issues/12194) ([ea81cd4](https://github.com/lobehub/lobe-chat/commit/ea81cd4))
* **misc**: Show notification when file upload fails due to storage plan limit, closes [#12176](https://github.com/lobehub/lobe-chat/issues/12176) ([f26d0df](https://github.com/lobehub/lobe-chat/commit/f26d0df))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-08 08:45:11 +00:00
Innei ea81cd42aa 🐛 fix: add api/version and api/desktop to public routes (#12194)
* 🐛 fix: add api/version and api/desktop to public routes

These API endpoints should be accessible without authentication.

* 🔧 chore: move location
2026-02-08 16:27:35 +08:00
semantic-release-bot 882de51b8a 🔖 chore(release): v2.1.20 [skip ci]
### [Version&nbsp;2.1.20](https://github.com/lobehub/lobe-chat/compare/v2.1.19...v2.1.20)
<sup>Released on **2026-02-07**</sup>

#### 🐛 Bug Fixes

- **misc**: Show notification when file upload fails due to storage plan limit.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Show notification when file upload fails due to storage plan limit, closes [#12176](https://github.com/lobehub/lobe-chat/issues/12176) ([f26d0df](https://github.com/lobehub/lobe-chat/commit/f26d0df))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-07 20:02:23 +00:00
Neko 3e3ef507ca 🔨 chore(home): fix the session group type with shared base type (#12181) 2026-02-08 03:44:36 +08:00
Neko e1cf2dee9d 🔨 chore(home): type mismatch for SessionGroup (#12180) 2026-02-08 02:26:32 +08:00
semantic-release-bot 2c7ecdafdf 🔖 chore(release): v2.1.20 [skip ci]
### [Version&nbsp;2.1.20](https://github.com/lobehub/lobe-chat/compare/v2.1.19...v2.1.20)
<sup>Released on **2026-02-07**</sup>

#### 🐛 Bug Fixes

- **misc**: Show notification when file upload fails due to storage plan limit.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Show notification when file upload fails due to storage plan limit, closes [#12176](https://github.com/lobehub/lobe-chat/issues/12176) ([f26d0df](https://github.com/lobehub/lobe-chat/commit/f26d0df))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-07 14:56:45 +00:00
YuTengjing f26d0df93d 🐛 fix: show notification when file upload fails due to storage plan limit (#12176)
* 🐛 fix: show notification when file upload fails due to storage plan limit

Previously, when file storage exceeded the plan limit, the TRPC
middleware threw a FORBIDDEN error that was silently swallowed by
the upload components with no user feedback. Now `uploadWithProgress`
catches this specific error and displays a notification guiding
users to upgrade or free up space.

* 🌐 chore: run i18n for upload storage limit error message

* 🌍 i18n: update model descriptions across multiple languages

Added new model descriptions and improved existing ones in Arabic, Bulgarian, German, French, Italian, Japanese, and Korean locales. This update enhances the clarity and detail of model capabilities, ensuring better user understanding and accessibility.
2026-02-07 22:38:49 +08:00
YuTengjing 463d6c8762 📝 docs: improve development guides to reflect current architecture (#12174)
* 🔧 chore(vscode): add typescript.tsdk and disable mdx server

Fix MDX extension crash caused by Cursor's bundled TypeScript version

* 🔧 chore(claude): add skills symlink to .claude directory

* 📝 docs: update development guides with current tech stack and architecture

- Update tech stack: Next.js 16 + React 19, hybrid routing (App Router + React Router DOM), tRPC, Drizzle ORM + PostgreSQL, react-i18next
- Update directory structure to reflect monorepo layout (apps/, packages/, e2e/, locales/)
- Expand src/server/ with detailed subdirectory descriptions
- Add complete SPA routing architecture with desktop and mobile route tables
- Add tRPC router grouping details (lambda, async, tools, mobile)
- Add data flow diagram
- Simplify dev setup section to link to setup-development guide
- Fix i18n default language description (English, not Chinese)
- Sync all changes between zh-CN and English versions

* 📝 docs: expand data flow diagram in folder structure guide

Replace the single-line data flow with a detailed layer-by-layer
flow diagram showing each layer's location and responsibility.

* 📝 docs: modernize feature development guide

- Remove outdated clientDB/pglite/indexDB references
- Update schema path to packages/database/src/schemas/
- Update types path to packages/types/src/
- Replace inline migration steps with link to db-migrations guide
- Add complete layered architecture table (Client Service, WebAPI,
  tRPC Router, Server Service, Server Module, Repository, DB Model)
- Clarify Client Service as frontend code
- Add i18n handling section with workflow and key naming convention
- Remove verbose CSS style code, keep core business logic only
- Expand testing section with commands, skill refs, and CI tip

* 🔥 docs: remove outdated frontend feature development guide

Content is superseded by the comprehensive feature-development guide
which covers the full chain from schema to testing.

* 📝 docs: add LobeHub ecosystem and community resources

Add official ecosystem packages (LobeUI, LobeIcons, LobeCharts,
LobeEditor, LobeTTS, LobeLint, Lobe i18n, MCP Mark) and community
platforms (Agent Market, MCP Market, YouTube, X, Discord).

* 📝 docs: improve contributing guidelines and resources

- Clarify semantic release triggers (feat/fix vs style/chore)
- Add testing section with Vitest/E2E/CI requirements
- Update contribution steps to include CI check
- Add LobeHub ecosystem packages and community platforms to resources

* 📝 docs: rewrite architecture guide to reflect current platform design

* 📝 docs: add code quality tools to architecture guide

* 📝 docs: rewrite chat-api guide to reflect current architecture

- Update sequence diagram with Agent Runtime loop as core execution engine
- Replace PluginGateway with ToolExecution layer (Builtin/MCP/Plugin)
- Update all path references (model-runtime, agent-runtime, fetch-sse packages)
- Split old AgentRuntime section into Model Runtime + Agent Runtime
- Add tool calling taxonomy: Builtin, MCP, and Plugin (deprecated)
- Add client-side vs server-side execution section
- Remove outdated adapter pseudo-code examples

* 📝 docs: update file paths in add-new-image-model guide

- src/libs/standard-parameters/ → packages/model-bank/src/standard-parameters/
- src/config/aiModels/ → packages/model-bank/src/aiModels/
- src/libs/model-runtime/ → packages/model-runtime/src/providers/

* 📝 docs: restore S3_PUBLIC_DOMAIN in deployment guides

The S3_PUBLIC_DOMAIN env var was incorrectly removed from all
documentation in commit 4a87b31. This variable is still required
by the code (src/server/services/file/impls/s3.ts) to generate
public URLs for uploaded files. Without it, image URLs sent to
vision models are just S3 keys instead of full URLs.

Closes #12161

* 📦 chore: pin @lobehub/ui to 4.33.4 to fix SortableList type errors

@lobehub/ui 4.34.0 introduced breaking type changes in SortableList
where SortableListItem became strict, causing type incompatibility
in onChange and renderItem callbacks across 6 files. Pin to 4.33.4
via pnpm overrides to enforce consistent version across monorepo.

* 🐛 fix: correct ReadableStream type annotations and add dom.asynciterable

- Add dom.asynciterable to tsconfig lib for ReadableStream async iteration
- Fix createCallbacksTransformer return type: TransformStream<string, Uint8Array>
- Update stream function return types from ReadableStream<string> to
  ReadableStream<Uint8Array> (llama.ts, ollama.ts, claude.ts)
- Remove @ts-ignore from for-await loops in test files
- Add explicit string[] type for chunks arrays

* Revert "📝 docs: restore S3_PUBLIC_DOMAIN in deployment guides"

This reverts commit 24073f83d3.
2026-02-07 22:29:14 +08:00
lobehubbot 5cae71eda7 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-06 17:53:21 +00:00
semantic-release-bot 521ecdd047 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

#### 🐛 Bug Fixes

- **misc**: Fixed in community pluings tab the lobehub skills not display.

#### 💄 Styles

- **model-runtime**: Add Claude Opus 4.6 support for Bedrock runtime.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

#### What's fixed

* **misc**: Fixed in community pluings tab the lobehub skills not display, closes [#12141](https://github.com/lobehub/lobe-chat/issues/12141) ([193c96f](https://github.com/lobehub/lobe-chat/commit/193c96f))

#### Styles

* **model-runtime**: Add Claude Opus 4.6 support for Bedrock runtime, closes [#12155](https://github.com/lobehub/lobe-chat/issues/12155) ([90a75af](https://github.com/lobehub/lobe-chat/commit/90a75af))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 17:51:13 +00:00
Neko 265491cfde 🔨 chore(userMemories): @upstash/workflow workflow id will drift, fallback to chat-topic group serveMany (#12154) 2026-02-07 01:33:05 +08:00
semantic-release-bot deb28e5c12 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

#### 🐛 Bug Fixes

- **misc**: Fixed in community pluings tab the lobehub skills not display.

#### 💄 Styles

- **model-runtime**: Add Claude Opus 4.6 support for Bedrock runtime.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

#### What's fixed

* **misc**: Fixed in community pluings tab the lobehub skills not display, closes [#12141](https://github.com/lobehub/lobe-chat/issues/12141) ([193c96f](https://github.com/lobehub/lobe-chat/commit/193c96f))

#### Styles

* **model-runtime**: Add Claude Opus 4.6 support for Bedrock runtime, closes [#12155](https://github.com/lobehub/lobe-chat/issues/12155) ([90a75af](https://github.com/lobehub/lobe-chat/commit/90a75af))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 10:52:55 +00:00
YuTengjing 90a75af669 💄 style(model-runtime): add Claude Opus 4.6 support for Bedrock runtime (#12155)
*  feat(model-runtime): add Claude Opus 4.6 support for Bedrock runtime

- Add Opus 4.6 to Bedrock and LobeHub hosted model banks with adaptive thinking and effort config
- Sync Bedrock runtime to support adaptive thinking (type: 'adaptive') and output_config.effort
- Strip assistant turn prefill for Opus 4.6 (not supported)
- Add missing search ability to Opus 4.5, Sonnet 4.5, Haiku 4.5 and 3.7 Sonnet in Bedrock
- Fix single-quote string escaping issues in Bedrock model descriptions

* 🐛 fix(model-runtime): clamp default thinking budget_tokens against max_tokens

* 🐛 fix(model-runtime): remove unnecessary 'as any' for adaptive thinking type

* 💄 style: update planCardModels to latest model lineup
2026-02-06 18:35:04 +08:00
semantic-release-bot f628564acf 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

#### 🐛 Bug Fixes

- **misc**: Fixed in community pluings tab the lobehub skills not display.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

#### What's fixed

* **misc**: Fixed in community pluings tab the lobehub skills not display, closes [#12141](https://github.com/lobehub/lobe-chat/issues/12141) ([193c96f](https://github.com/lobehub/lobe-chat/commit/193c96f))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 08:12:37 +00:00
sxjeru b0a8e0f51c style: add adaptive thinking and effort configuration for Claude Opus 4.6 (#12139)
* feat: add adaptive thinking and effort configuration for Claude Opus 4.6

* fix: update @anthropic-ai/sdk dependency and refine thinking type handling in payload

* fix: enhance payload handling for Claude Opus 4.6

* i18n
2026-02-06 15:54:31 +08:00
semantic-release-bot b3e5b5cc36 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

#### 🐛 Bug Fixes

- **misc**: Fixed in community pluings tab the lobehub skills not display.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

#### What's fixed

* **misc**: Fixed in community pluings tab the lobehub skills not display, closes [#12141](https://github.com/lobehub/lobe-chat/issues/12141) ([193c96f](https://github.com/lobehub/lobe-chat/commit/193c96f))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 07:51:40 +00:00
Shinji-Li 41dcaad567 🐛 fix:add profiles some in review states tags (#12145)
* fix: add the pending review tag in profile pages

* fix: add lost i18n files

* fix: add the pending review tag in group-agents profiles

* chore: update lost i18n files
2026-02-06 15:33:26 +08:00
semantic-release-bot f290164091 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

#### 🐛 Bug Fixes

- **misc**: Fixed in community pluings tab the lobehub skills not display.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

#### What's fixed

* **misc**: Fixed in community pluings tab the lobehub skills not display, closes [#12141](https://github.com/lobehub/lobe-chat/issues/12141) ([193c96f](https://github.com/lobehub/lobe-chat/commit/193c96f))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 06:29:39 +00:00
Shinji-Li 193c96f9d9 🐛 fix: fixed in community pluings tab the lobehub skills not display (#12141)
* fix: fixed in community pluings tab the lobehub skills not display

* fix: add the builtin tools show & jump to mcp indentier
2026-02-06 14:11:58 +08:00
semantic-release-bot 87a6ed06f8 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-06**</sup>

#### ♻ Code Refactoring

- **docker-compose**: Restructure dev environment.
- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **docker-compose**: Restructure dev environment, closes [#12132](https://github.com/lobehub/lobe-chat/issues/12132) ([7ba15cc](https://github.com/lobehub/lobe-chat/commit/7ba15cc))
* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-06 04:39:42 +00:00
YuTengjing 7ba15cceba ♻️ refactor(docker-compose): restructure dev environment (#12132)
* 🔥 chore(docker-compose): remove Casdoor SSO dependency

Casdoor is no longer needed since BetterAuth now supports email/password registration natively.

LOBE-3907

* ♻️ refactor(docker-compose): restructure directories

- Rename local/ to dev/ for development dependencies
- Remove logto/ and zitadel/ from production/
- Restore Casdoor config in production/grafana/
- Simplify dev/ to core services only (postgresql, redis, rustfs, searxng)
- Update docker-compose.development.yml to use dev/
- Remove minio-bucket.config.json (switched to rustfs)

* ♻️ refactor(docker-compose): simplify dev environment setup

- Remove docker-compose.development.yml, use dev/docker-compose.yml directly
- Add npm scripts: dev:docker, dev:docker:down, dev:docker:reset
- Simplify .env.example.development (remove variable refs, redundant vars)
- Update docker-compose/dev/.env.example (consistent passwords)
- Add docker-compose/dev/data/ to .gitignore
- Update setup docs: use npm scripts, remove image generation section

* 🔧 chore: add SSRF_ALLOW_PRIVATE_IP_ADDRESS to dev env example

* 🔒 security: auto-generate KEY_VAULTS_SECRET and AUTH_SECRET in setup.sh

- Remove hardcoded secrets from docker-compose.yml
- Add placeholders to .env.example files
- Generate secrets dynamically in setup.sh using openssl rand -base64 32

* 🔧 chore(docker-compose): expose SearXNG port and improve dev scripts

- Add SearXNG port mapping (8180:8080) for host access
- Use --wait flag in dev:docker to ensure services are healthy
- Include db:migrate in dev:docker:reset for one-command reset
- Update MinIO reference to RustFS in zh-CN docs
- Add SearXNG to service URLs and port conflict docs
2026-02-06 12:21:30 +08:00
semantic-release-bot 9e7825bef1 🔖 chore(release): v2.1.19 [skip ci]
### [Version&nbsp;2.1.19](https://github.com/lobehub/lobe-chat/compare/v2.1.18...v2.1.19)
<sup>Released on **2026-02-05**</sup>

#### ♻ Code Refactoring

- **misc**: Upgrade agents/group detail pages tabs、hidden like button.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **misc**: Upgrade agents/group detail pages tabs、hidden like button, closes [#12127](https://github.com/lobehub/lobe-chat/issues/12127) ([e402c51](https://github.com/lobehub/lobe-chat/commit/e402c51))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-05 16:54:26 +00:00
Neko 20029a7820 🔨 chore(userMemories): should have slug for process-topic endpoint (#12135) 2026-02-06 00:36:20 +08:00
LobeHub Bot a1decbb46f test: add comprehensive unit tests for textLength utilities (#12124)
Extended test coverage for src/utils/textLength.ts with 26 additional test cases covering:
- CJK character detection (Chinese, Japanese, Korean)
- Special Unicode ranges (CJK Compatibility Ideographs, CJK Extension A, Hangul Jamo)
- Edge cases (numbers, special characters, emojis, newlines, tabs)
- Boundary conditions for truncation
- Custom weight configurations
- Very long text and performance scenarios

All 34 tests pass successfully.

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 16:24:31 +08:00
LobeHub Bot bb31a10f45 🌐 chore: translate non-English comments to English in mcp-client (#12121)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 16:21:08 +08:00
Shinji-Li e402c51bec ♻️ refactor: upgrade agents/group detail pages tabs、hidden like button (#12127)
* refactor: upgrade agents/group detail pages tabs、hidden like button

* fix: delete useless code
2026-02-05 16:20:48 +08:00
René Wang 709b24ec6d fix: Chang log compatibility for V1 (#12088)
* fix: changlog

* fix: changelog
2026-02-05 12:51:03 +08:00
lobehubbot ce35fac930 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-04 16:11:15 +00:00
semantic-release-bot e036ccee86 🔖 chore(release): v2.1.18 [skip ci]
### [Version&nbsp;2.1.18](https://github.com/lobehub/lobe-chat/compare/v2.1.17...v2.1.18)
<sup>Released on **2026-02-04**</sup>

#### 🐛 Bug Fixes

- **model-runtime**: Fix moonshot interleaved thinking and circular dependency.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **model-runtime**: Fix moonshot interleaved thinking and circular dependency, closes [#12112](https://github.com/lobehub/lobe-chat/issues/12112) ([3f1a198](https://github.com/lobehub/lobe-chat/commit/3f1a198))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-04 16:09:45 +00:00
YuTengjing 3f1a1983e3 🐛 fix(model-runtime): fix moonshot interleaved thinking and circular dependency (#12112)
* 🐛 fix(model-runtime): fix moonshot interleaved thinking and circular dependency

- Add apiTypes.ts to break circular dependency between createRuntime and baseRuntimeMap
- Use dynamic import for baseRuntimeMap in createRuntime.ts
- Add moonshot to baseRuntimeMap for RouterRuntime support
- Convert reasoning to thinking block in normalizeMoonshotMessages for Anthropic format
- Add tests for interleaved thinking scenarios

* ♻️ refactor(moonshot): extract shared helpers to reduce code duplication

* 🐛 fix(AgentSetting): center Empty component in opening questions
2026-02-04 23:51:12 +08:00
lobehubbot 151261d0c5 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-04 14:10:46 +00:00
semantic-release-bot 0f63781876 🔖 chore(release): v2.1.17 [skip ci]
### [Version&nbsp;2.1.17](https://github.com/lobehub/lobe-chat/compare/v2.1.16...v2.1.17)
<sup>Released on **2026-02-04**</sup>

#### ♻ Code Refactoring

- **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime, closes [#12109](https://github.com/lobehub/lobe-chat/issues/12109) ([71064fd](https://github.com/lobehub/lobe-chat/commit/71064fd))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-04 14:09:20 +00:00
YuTengjing 71064fdede ♻️ refactor(model-runtime): extract Anthropic factory and convert Moonshot to RouterRuntime (#12109)
* ♻️ refactor(model-runtime): extract Anthropic provider into reusable factory

- Create `anthropicCompatibleFactory` for shared Anthropic-compatible logic
- Migrate Anthropic provider to use the new factory
- Migrate Moonshot provider from OpenAI-compatible to Anthropic-compatible API
- Move shared utilities (resolveCacheTTL, resolveMaxTokens, etc.) to factory

* ♻️ refactor(model-runtime): convert Moonshot to RouterRuntime with auto API format detection

- Add baseURLPattern support to RouterRuntime for URL-based routing
- Moonshot now auto-selects OpenAI or Anthropic format based on baseURL
  - /anthropic suffix -> Anthropic format (with kimi-k2.5 thinking)
  - /v1 or default -> OpenAI format
- Remove moonshot from baseRuntimeMap to avoid circular dependency
- Update model-bank config: default to OpenAI format with api.moonshot.ai/v1
- Export CreateRouterRuntimeOptions type from RouterRuntime
- Fix type annotation in Anthropic test

*  feat(model-bank): add Kimi K2.5 to LobeHub provider

- Add Kimi K2.5 model with multimodal capabilities
- Supports vision, reasoning, function calling, structured output, and search
- Context window: 262K tokens, max output: 32K tokens

* 🐛 fix(model-runtime): address PR review feedback

- Restore forceImageBase64 for Moonshot OpenAI runtime to fix vision requests
- Simplify baseURLPattern to only support RegExp (remove string support)
- Add baseURLPattern matching tests for RouterRuntime
2026-02-04 21:51:15 +08:00
lobehubbot 20928ac466 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-04 10:26:13 +00:00
semantic-release-bot 347d0ce70f 🔖 chore(release): v2.1.16 [skip ci]
### [Version&nbsp;2.1.16](https://github.com/lobehub/lobe-chat/compare/v2.1.15...v2.1.16)
<sup>Released on **2026-02-04**</sup>

#### 🐛 Bug Fixes

- **misc**: Add the preview publish to market button preview check.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add the preview publish to market button preview check, closes [#12105](https://github.com/lobehub/lobe-chat/issues/12105) ([28887c7](https://github.com/lobehub/lobe-chat/commit/28887c7))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-04 10:24:51 +00:00
Shinji-Li 28887c77e8 🐛 fix: add the preview publish to market button preview check (#12105)
feat: add the preview publish to market button preview check
2026-02-04 18:07:21 +08:00
lobehubbot 1cc9034c7c 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-04 09:25:23 +00:00
semantic-release-bot 37609e42d6 🔖 chore(release): v2.1.15 [skip ci]
### [Version&nbsp;2.1.15](https://github.com/lobehub/lobe-chat/compare/v2.1.14...v2.1.15)
<sup>Released on **2026-02-04**</sup>

#### 🐛 Bug Fixes

- **misc**: Fixed the agents list the show updateAt time error.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fixed the agents list the show updateAt time error, closes [#12103](https://github.com/lobehub/lobe-chat/issues/12103) ([3063cee](https://github.com/lobehub/lobe-chat/commit/3063cee))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-04 09:23:52 +00:00
Shinji-Li 3063ceef8c 🐛 fix: fixed the agents list the show updateAt time error (#12103)
* feat: refactor community user pages

* feat: add the agents-group like in social types

* feat: add the user favoitor filter

* fix: slove the agents list show the updateAt time
2026-02-04 17:05:56 +08:00
Shinji-Li f61ab26081 🔨 chore: refacctor the community user pages agents/group fitler (#12102)
* feat: refactor community user pages

* feat: add the agents-group like in social types

* feat: add the user favoitor filter
2026-02-04 16:14:03 +08:00
LobeHub Bot 79712bd38c 🌐 chore: translate non-English symbols to English in packages/utils and src/services (#12087)
* 🌐 chore: translate non-English symbols to English in packages/utils and src/services

- Replace Unicode arrow symbols (→, ⇒) with ASCII equivalents (-, =>) in comments
- Replace Chinese colon (:) with English colon (:) in console.log
- Files affected: packages/utils/src/pricing.ts, packages/utils/src/chunkers/trimBatchProbe/trimBatchProbe.ts, src/services/models.ts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Remove debug log for enableFetchOnClient

Removed console log for enableFetchOnClient.

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Arvin Xu <arvinx@foxmail.com>
2026-02-04 14:02:10 +08:00
lobehubbot 66caf30e7e 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-04 05:39:03 +00:00
semantic-release-bot 0c855e44fc 🔖 chore(release): v2.1.14 [skip ci]
### [Version&nbsp;2.1.14](https://github.com/lobehub/lobe-chat/compare/v2.1.13...v2.1.14)
<sup>Released on **2026-02-04**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix cannot uncompressed messages.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix cannot uncompressed messages, closes [#12086](https://github.com/lobehub/lobe-chat/issues/12086) ([ccfaec2](https://github.com/lobehub/lobe-chat/commit/ccfaec2))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-04 05:37:35 +00:00
LobeHub Bot e18b7a92c7 🌐 chore: translate non-English comments to English in desktop menus (#12056)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-04 13:21:24 +08:00
Arvin Xu 3f1fd102c5 👷 build: fix db index (#12090)
* build index

* update
2026-02-04 13:16:56 +08:00
Arvin Xu ccfaec2fdb 🐛 fix: fix cannot uncompressed messages (#12086)
* support uncompressed
* fix open new
2026-02-04 12:25:28 +08:00
lobehubbot 8aba59bffd 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-03 06:54:24 +00:00
semantic-release-bot 13e0652c59 🔖 chore(release): v2.1.13 [skip ci]
### [Version&nbsp;2.1.13](https://github.com/lobehub/lobe-chat/compare/v2.1.12...v2.1.13)
<sup>Released on **2026-02-03**</sup>

#### 🐛 Bug Fixes

- **docker**: Add librt.so.1 to fix PDF parsing.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **docker**: Add librt.so.1 to fix PDF parsing, closes [#12039](https://github.com/lobehub/lobe-chat/issues/12039) ([4a6be92](https://github.com/lobehub/lobe-chat/commit/4a6be92))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-03 06:52:58 +00:00
Ruxiao Yin 4a6be92604 🐛 fix(docker): add librt.so.1 to fix PDF parsing (#12039) 2026-02-03 14:34:36 +08:00
lobehubbot c576a13a43 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-03 03:04:51 +00:00
semantic-release-bot 63a0464a83 🔖 chore(release): v2.1.12 [skip ci]
### [Version&nbsp;2.1.12](https://github.com/lobehub/lobe-chat/compare/v2.1.11...v2.1.12)
<sup>Released on **2026-02-03**</sup>

#### 🐛 Bug Fixes

- **changelog**: Normalize versionRange to valid semver.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **changelog**: Normalize versionRange to valid semver, closes [#12049](https://github.com/lobehub/lobe-chat/issues/12049) ([74b9bd0](https://github.com/lobehub/lobe-chat/commit/74b9bd0))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-03 03:03:19 +00:00
LobeHub Bot b1c6bdb192 🌐 chore: translate non-English comments to English in server/utils (#12042)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 10:45:26 +08:00
Kingsword 74b9bd0bed 🐛 fix(changelog): normalize versionRange to valid semver (#12049) 2026-02-03 10:45:03 +08:00
Arvin Xu 6977c570e6 🔨 chore: improve electron build workflow (#12054)
* improve workflow

* update
2026-02-03 10:44:26 +08:00
BrandonStudio 4efe60e9f7 🔨 chore: Remove unexpected file (#12045) 2026-02-02 15:29:39 +08:00
lobehubbot 336d10663c 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-02 06:36:27 +00:00
semantic-release-bot 5f21aaf048 🔖 chore(release): v2.1.11 [skip ci]
### [Version&nbsp;2.1.11](https://github.com/lobehub/lobe-chat/compare/v2.1.10...v2.1.11)
<sup>Released on **2026-02-02**</sup>

#### 🐛 Bug Fixes

- **misc**: Hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set, closes [#12023](https://github.com/lobehub/lobe-chat/issues/12023) ([e2fd28e](https://github.com/lobehub/lobe-chat/commit/e2fd28e))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-02 06:35:01 +00:00
YuTengjing e2fd28eece 🐛 fix: hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set (#12023) 2026-02-02 14:17:10 +08:00
lobehubbot a6a1fecae0 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-02 05:54:53 +00:00
semantic-release-bot fdee6b9aac 🔖 chore(release): v2.1.10 [skip ci]
### [Version&nbsp;2.1.10](https://github.com/lobehub/lobe-chat/compare/v2.1.9...v2.1.10)
<sup>Released on **2026-02-02**</sup>

#### 🐛 Bug Fixes

- **auth**: Revert authority URL and tenant ID for Microsoft authentication..

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **auth**: Revert authority URL and tenant ID for Microsoft authentication., closes [#11930](https://github.com/lobehub/lobe-chat/issues/11930) ([98f93ef](https://github.com/lobehub/lobe-chat/commit/98f93ef))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-02 05:53:33 +00:00
BrandonStudio 98f93ef2f0 🐛 fix(auth): revert authority URL and tenant ID for Microsoft authentication. (#11930)
🔧 feat(auth): revert authority URL and tenant ID for Microsoft authentication
2026-02-02 13:35:54 +08:00
lobehubbot df7e2800a7 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-02 03:48:44 +00:00
semantic-release-bot 4aac694364 🔖 chore(release): v2.1.9 [skip ci]
### [Version&nbsp;2.1.9](https://github.com/lobehub/lobe-chat/compare/v2.1.8...v2.1.9)
<sup>Released on **2026-02-02**</sup>

#### 🐛 Bug Fixes

- **misc**: Use oauth2.link for generic OIDC provider account linking.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Use oauth2.link for generic OIDC provider account linking, closes [#12024](https://github.com/lobehub/lobe-chat/issues/12024) ([c7a06a4](https://github.com/lobehub/lobe-chat/commit/c7a06a4))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-02 03:47:20 +00:00
YuTengjing c7a06a4b62 🐛 fix: use oauth2.link for generic OIDC provider account linking (#12024) 2026-02-02 11:29:35 +08:00
lobehubbot 2f21c15172 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-01 10:12:44 +00:00
semantic-release-bot de0ce799c7 🔖 chore(release): v2.1.8 [skip ci]
### [Version&nbsp;2.1.8](https://github.com/lobehub/lobe-chat/compare/v2.1.7...v2.1.8)
<sup>Released on **2026-02-01**</sup>

#### 💄 Styles

- **misc**: Improve tasks display.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Styles

* **misc**: Improve tasks display, closes [#12032](https://github.com/lobehub/lobe-chat/issues/12032) ([3423ad1](https://github.com/lobehub/lobe-chat/commit/3423ad1))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-01 10:11:21 +00:00
Arvin Xu 3423ad1b15 💄 style: improve tasks display (#12032)
improve tasks
2026-02-01 17:53:21 +08:00
LobeHub Bot 5db07efe6b 🌐 chore: translate non-English comments to English in src/hooks (#12028)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 17:40:45 +08:00
lobehubbot f5d67a7385 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-01 06:30:03 +00:00
semantic-release-bot 99d4c02b9d 🔖 chore(release): v2.1.7 [skip ci]
### [Version&nbsp;2.1.7](https://github.com/lobehub/lobe-chat/compare/v2.1.6...v2.1.7)
<sup>Released on **2026-02-01**</sup>

#### 🐛 Bug Fixes

- **misc**: Add missing description parameter docs in Notebook system prompt.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add missing description parameter docs in Notebook system prompt, closes [#12015](https://github.com/lobehub/lobe-chat/issues/12015) [#11391](https://github.com/lobehub/lobe-chat/issues/11391) ([182030f](https://github.com/lobehub/lobe-chat/commit/182030f))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-01 06:28:33 +00:00
Arvin Xu 182030f404 🐛 fix: add missing description parameter docs in Notebook system prompt (#12015)
The createDocument API requires a 'description' parameter, but the system prompt
didn't mention it. This caused models (especially Gemini) to omit the description
field when calling createDocument, resulting in validation errors.

Added <api_parameters> section to clearly document all required and optional
parameters for each Notebook API.

closes #11391
2026-02-01 14:09:52 +08:00
lobehubbot da87df9533 📝 docs(bot): Auto sync agents & plugin to readme 2026-02-01 04:32:26 +00:00
semantic-release-bot 710d92d9f6 🔖 chore(release): v2.1.6 [skip ci]
### [Version&nbsp;2.1.6](https://github.com/lobehub/lobe-chat/compare/v2.1.5...v2.1.6)
<sup>Released on **2026-02-01**</sup>

#### 💄 Styles

- **misc**: Improve local-system tool implement.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Styles

* **misc**: Improve local-system tool implement, closes [#12022](https://github.com/lobehub/lobe-chat/issues/12022) ([5e203b8](https://github.com/lobehub/lobe-chat/commit/5e203b8))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-02-01 04:31:04 +00:00
Arvin Xu 5e203b868c 💄 style: improve local-system tool implement (#12022)
* improve local system ability

* fix build

* improve tools title render

* fix tools

* update

* try to fix lint

* update

* refactor the LocalFileCtr.ts result

* refactor the exector result
2026-02-01 12:13:27 +08:00
lobehubbot 6e4ad89c82 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-31 17:01:11 +00:00
semantic-release-bot 73daa2513f 🔖 chore(release): v2.1.5 [skip ci]
### [Version&nbsp;2.1.5](https://github.com/lobehub/lobe-chat/compare/v2.1.4...v2.1.5)
<sup>Released on **2026-01-31**</sup>

#### 🐛 Bug Fixes

- **misc**: Slove the group member agents cant set skills problem.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Slove the group member agents cant set skills problem, closes [#12021](https://github.com/lobehub/lobe-chat/issues/12021) ([2302940](https://github.com/lobehub/lobe-chat/commit/2302940))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-01-31 16:59:50 +00:00
Shinji-Li 2302940079 🐛 fix: slove the group member agents cant set skills problem (#12021)
fix: slove the group member agents cant set skills problem
2026-02-01 00:42:21 +08:00
lobehubbot 9c653e0053 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-31 15:02:40 +00:00
semantic-release-bot 53c9cda9e8 🔖 chore(release): v2.1.4 [skip ci]
### [Version&nbsp;2.1.4](https://github.com/lobehub/lobe-chat/compare/v2.1.3...v2.1.4)
<sup>Released on **2026-01-31**</sup>

#### 🐛 Bug Fixes

- **stream**: Update event handling to use 'text' instead of 'content_part' in gemini 2.5 models.

#### 💄 Styles

- **misc**: Update i18n, Update Kimi K2.5 & Qwen3 Max Thinking models.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **stream**: Update event handling to use 'text' instead of 'content_part' in gemini 2.5 models, closes [#11235](https://github.com/lobehub/lobe-chat/issues/11235) ([a76a630](https://github.com/lobehub/lobe-chat/commit/a76a630))

#### Styles

* **misc**: Update i18n, closes [#11920](https://github.com/lobehub/lobe-chat/issues/11920) ([1a590a0](https://github.com/lobehub/lobe-chat/commit/1a590a0))
* **misc**: Update Kimi K2.5 & Qwen3 Max Thinking models, closes [#11925](https://github.com/lobehub/lobe-chat/issues/11925) ([6f9e010](https://github.com/lobehub/lobe-chat/commit/6f9e010))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-01-31 15:00:54 +00:00
sxjeru 6f9e01047b 💄 style: Update Kimi K2.5 & Qwen3 Max Thinking models (#11925)
* 🔨 feat(models): add new AI models and update pricing strategies

* 🐛 fix(models): remove deprecated Gemini 2.0 Flash Exp model from googleChatModels

* 🔨 fix(moonshot): update Kimi K2.5 model parameters and enhance payload handling

*  feat: 添加新的聊天模型 Kimi-K2.5 和 PaddleOCR-VL 1.5 到 siliconcloud

* Update packages/model-bank/src/aiModels/qwen.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

*  feat: 添加 Kimi K2.5 模型,更新 Qwen 模型的思维预算处理

*  feat: 添加 forceImageBase64 选项以支持强制将图像 URL 转换为 Base64

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-31 22:43:28 +08:00
sxjeru a76a630f28 🐛 fix(stream): update event handling to use 'text' instead of 'content_part' in gemini 2.5 models (#11235)
🐛 fix(stream): update event handling to use 'text' instead of 'content_part' in Google AI stream
2026-01-31 22:43:18 +08:00
Arvin Xu 338df4baf9 📝 docs: Update src directory structure to be more comprehensive (#12016)
* update e2e test

* 📝 docs: Update src directory structure to be more comprehensive

- Add missing directories: business, const, envs, helpers, tools
- Add missing root files: auth.ts, instrumentation.ts, instrumentation.node.ts, proxy.ts
- Update descriptions to be more accurate
- Sync changes across English and Chinese documentation

Fixes #9521
2026-01-31 22:42:30 +08:00
LobeHub Bot 1a590a065c 🤖 style: update i18n (#11920)
💄 style: update i18n

Co-authored-by: canisminor1990 <17870709+canisminor1990@users.noreply.github.com>
2026-01-31 20:34:06 +08:00
Arvin Xu 4a87b31246 📝 docs: improve docs (#12013)
Update docs
2026-01-31 19:46:44 +08:00
lobehubbot 83842b45b3 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-31 10:44:46 +00:00
semantic-release-bot 87e3dad58a 🔖 chore(release): v2.1.3 [skip ci]
### [Version&nbsp;2.1.3](https://github.com/lobehub/lobe-chat/compare/v2.1.2...v2.1.3)
<sup>Released on **2026-01-31**</sup>

#### 🐛 Bug Fixes

- **auth**: Add AUTH_DISABLE_EMAIL_PASSWORD env to enable SSO-only mode.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **auth**: Add AUTH_DISABLE_EMAIL_PASSWORD env to enable SSO-only mode, closes [#12009](https://github.com/lobehub/lobe-chat/issues/12009) ([f3210a3](https://github.com/lobehub/lobe-chat/commit/f3210a3))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-01-31 10:43:14 +00:00
YuTengjing f3210a3f57 🐛 fix(auth): add AUTH_DISABLE_EMAIL_PASSWORD env to enable SSO-only mode (#12009) 2026-01-31 18:25:22 +08:00
Innei 8b8159eb01 🔧 chore: upgrade macOS ARM64 runner from macos-14 to macos-15 (#12006) 2026-01-31 13:12:12 +08:00
LobeHub Bot 5086a126a7 🌐 chore: translate non-English comments to English in src/store (#12001)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 11:02:23 +08:00
lobehubbot a82a4bda34 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-30 17:09:25 +00:00
semantic-release-bot 71b2ecd94b 🔖 chore(release): v2.1.2 [skip ci]
### [Version&nbsp;2.1.2](https://github.com/lobehub/lobe-chat/compare/v2.1.1...v2.1.2)
<sup>Released on **2026-01-30**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix feishu sso provider.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix feishu sso provider, closes [#11970](https://github.com/lobehub/lobe-chat/issues/11970) ([ffd9fff](https://github.com/lobehub/lobe-chat/commit/ffd9fff))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-01-30 17:07:53 +00:00
Arvin Xu ffd9fff091 🐛 fix: fix feishu sso provider (#11970) 2026-01-31 00:50:11 +08:00
LobeHub Bot 67c4bafd3f 🌐 chore: translate non-English comments to English in desktop controllers (#11978) 2026-01-31 00:49:38 +08:00
Arvin Xu 7496511917 📝 docs: improve self-hosting documents (#11994)
* update document

* update documents

* update auth

* move

* update database

* move auth

* move auth

* update
2026-01-30 20:50:05 +08:00
lobehubbot 15e89f2eee 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-30 10:39:04 +00:00
semantic-release-bot 1421e991d8 🔖 chore(release): v2.1.1 [skip ci]
### [Version&nbsp;2.1.1](https://github.com/lobehub/lobe-chat/compare/v2.1.0...v2.1.1)
<sup>Released on **2026-01-30**</sup>

#### 🐛 Bug Fixes

- **misc**: Correct desktop download URL path.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Correct desktop download URL path, closes [#11990](https://github.com/lobehub/lobe-chat/issues/11990) ([e46df98](https://github.com/lobehub/lobe-chat/commit/e46df98))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2026-01-30 10:37:18 +00:00
Arvin Xu f17acd7f7e ♻️ chore(docker-compose): refactor docker compose (#11989)
* improve message content

* ♻️ refactor(docker-compose): 创建精简版 deploy 配置

- 新建 docker-compose/deploy 目录,包含最小化部署配置
- 仅保留核心服务:postgresql、redis、rustfs、searxng、lobe
- 移除 Casdoor 认证服务相关配置
- 移除可观测性服务(Grafana/Prometheus/Tempo/otel-collector)
- 使用 paradedb/paradedb:latest 镜像(支持 pgvector + pg_search)
- 更新 setup.sh 指向新的 deploy 目录
- 清理 .env 示例文件中的 Casdoor 相关配置

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* update document

* update content

* update content

* improve env

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:15:43 +08:00
Innei e46df98907 🐛 fix: correct desktop download URL path (#11990)
Fixed the download URL path from '/download' to '/downloads' to match the actual official site path.
2026-01-30 17:53:09 +08:00
lobehubbot 2c791d749d 📝 docs(bot): Auto sync agents & plugin to readme 2026-01-30 05:57:38 +00:00
7438 changed files with 678006 additions and 129344 deletions
+3 -1
View File
@@ -43,11 +43,13 @@ Reference: `docs/usage/providers/fal.mdx`
```markdown
### `{PROVIDER}_API_KEY`
- Type: Required
- Description: API key from {Provider Name}
- Example: `{api-key-format}`
### `{PROVIDER}_MODEL_LIST`
- Type: Optional
- Description: Control model list. Use `+` to add, `-` to hide
- Example: `-all,+model-1,+model-2=Display Name`
@@ -77,7 +79,7 @@ Update all Dockerfiles at the **end** of ENV section:
- Cover image
- 3-4 API dashboard screenshots
- 2-3 LobeChat configuration screenshots
- 2-3 LobeHub configuration screenshots
- Host on LobeHub CDN: `hub-apac-1.lobeobjects.space`
## Checklist
+220
View File
@@ -0,0 +1,220 @@
---
name: agent-tracing
description: "Agent tracing CLI for inspecting agent execution snapshots. Use when user mentions 'agent-tracing', 'trace', 'snapshot', wants to debug agent execution, inspect LLM calls, view context engine data, or analyze agent steps. Triggers on agent debugging, trace inspection, or execution analysis tasks."
user-invocable: false
---
# Agent Tracing CLI Guide
`@lobechat/agent-tracing` is a zero-config local dev tool that records agent execution snapshots to disk and provides a CLI to inspect them.
## How It Works
In `NODE_ENV=development`, `AgentRuntimeService.executeStep()` automatically records each step to `.agent-tracing/` as partial snapshots. When the operation completes, the partial is finalized into a complete `ExecutionSnapshot` JSON file.
**Data flow**: executeStep loop -> build `StepPresentationData` -> write partial snapshot to disk -> on completion, finalize to `.agent-tracing/{timestamp}_{traceId}.json`
**Context engine capture**: In `RuntimeExecutors.ts`, the `call_llm` executor emits a `context_engine_result` event after `serverMessagesEngine()` processes messages. This event carries the full `contextEngineInput` (DB messages, systemRole, model, knowledge, tools, userMemory, etc.) and the processed `output` messages (the final LLM payload).
## Package Location
```
packages/agent-tracing/
src/
types.ts # ExecutionSnapshot, StepSnapshot, SnapshotSummary
store/
types.ts # ISnapshotStore interface
file-store.ts # FileSnapshotStore (.agent-tracing/*.json)
recorder/
index.ts # appendStepToPartial(), finalizeSnapshot()
viewer/
index.ts # Terminal rendering: renderSnapshot, renderStepDetail, renderMessageDetail, renderSummaryTable, renderPayload, renderPayloadTools, renderMemory
cli/
index.ts # CLI entry point (#!/usr/bin/env bun)
inspect.ts # Inspect command (default)
partial.ts # Partial snapshot commands (list, inspect, clean)
index.ts # Barrel exports
```
## Data Storage
- Completed snapshots: `.agent-tracing/{ISO-timestamp}_{traceId-short}.json`
- Latest symlink: `.agent-tracing/latest.json`
- In-progress partials: `.agent-tracing/_partial/{operationId}.json`
- `FileSnapshotStore` resolves from `process.cwd()`**run CLI from the repo root**
## CLI Commands
All commands run from the **repo root**:
```bash
# View latest trace (tree overview, `inspect` is the default command)
agent-tracing
agent-tracing inspect
agent-tracing inspect <traceId>
agent-tracing inspect latest
# List recent snapshots
agent-tracing list
agent-tracing list -l 20
# Inspect specific step (-s is short for --step)
agent-tracing inspect <traceId> -s 0
# View messages (-m is short for --messages)
agent-tracing inspect <traceId> -s 0 -m
# View full content of a specific message (by index shown in -m output)
agent-tracing inspect <traceId> -s 0 --msg 2
agent-tracing inspect <traceId> -s 0 --msg-input 1
# View tool call/result details (-t is short for --tools)
agent-tracing inspect <traceId> -s 1 -t
# View raw events (-e is short for --events)
agent-tracing inspect <traceId> -s 0 -e
# View runtime context (-c is short for --context)
agent-tracing inspect <traceId> -s 0 -c
# View context engine input overview (-p is short for --payload)
agent-tracing inspect <traceId> -p
agent-tracing inspect <traceId> -s 0 -p
# View available tools in payload (-T is short for --payload-tools)
agent-tracing inspect <traceId> -T
agent-tracing inspect <traceId> -s 0 -T
# View user memory (-M is short for --memory)
agent-tracing inspect <traceId> -M
agent-tracing inspect <traceId> -s 0 -M
# Raw JSON output (-j is short for --json)
agent-tracing inspect <traceId> -j
agent-tracing inspect <traceId> -s 0 -j
# List in-progress partial snapshots
agent-tracing partial list
# Inspect a partial (use `inspect` directly — all flags work with partial IDs)
agent-tracing inspect <partialOperationId>
agent-tracing inspect <partialOperationId> -T
agent-tracing inspect <partialOperationId> -p
# Clean up stale partial snapshots
agent-tracing partial clean
```
## Inspect Flag Reference
| Flag | Short | Description | Default Step |
| ----------------- | ----- | ------------------------------------------------------------------------------------------------- | ------------ |
| `--step <n>` | `-s` | Target a specific step | — |
| `--messages` | `-m` | Messages context (CE input → params → LLM payload) | — |
| `--tools` | `-t` | Tool calls & results (what agent invoked) | — |
| `--events` | `-e` | Raw events (llm_start, llm_result, etc.) | — |
| `--context` | `-c` | Runtime context & payload (raw) | — |
| `--system-role` | `-r` | Full system role content | 0 |
| `--env` | | Environment context | 0 |
| `--payload` | `-p` | Context engine input overview (model, knowledge, tools summary, memory summary, platform context) | 0 |
| `--payload-tools` | `-T` | Available tools detail (plugin manifests + LLM function definitions) | 0 |
| `--memory` | `-M` | Full user memory (persona, identity, contexts, preferences, experiences) | 0 |
| `--diff <n>` | `-d` | Diff against step N (use with `-r` or `--env`) | — |
| `--msg <n>` | | Full content of message N from Final LLM Payload | — |
| `--msg-input <n>` | | Full content of message N from Context Engine Input | — |
| `--json` | `-j` | Output as JSON (combinable with any flag above) | — |
Flags marked "Default Step: 0" auto-select step 0 if `--step` is not provided. All flags support `latest` or omitted traceId.
## Typical Debug Workflow
```bash
# 1. Trigger an agent operation in the dev UI
# 2. See the overview
agent-tracing inspect
# 3. List all traces, get traceId
agent-tracing list
# 4. Quick overview of what was fed into context engine
agent-tracing inspect -p
# 5. Inspect a specific step's messages to see what was sent to the LLM
agent-tracing inspect TRACE_ID -s 0 -m
# 6. Drill into a truncated message for full content
agent-tracing inspect TRACE_ID -s 0 --msg 2
# 7. Check available tools vs actual tool calls
agent-tracing inspect -T # available tools
agent-tracing inspect -s 1 -t # actual tool calls & results
# 8. Inspect user memory injected into the conversation
agent-tracing inspect -M
# 9. Diff system role between steps (multi-step agents)
agent-tracing inspect TRACE_ID -r -d 2
```
## Key Types
```typescript
interface ExecutionSnapshot {
traceId: string;
operationId: string;
model?: string;
provider?: string;
startedAt: number;
completedAt?: number;
completionReason?:
| 'done'
| 'error'
| 'interrupted'
| 'max_steps'
| 'cost_limit'
| 'waiting_for_human';
totalSteps: number;
totalTokens: number;
totalCost: number;
error?: { type: string; message: string };
steps: StepSnapshot[];
}
interface StepSnapshot {
stepIndex: number;
stepType: 'call_llm' | 'call_tool';
executionTimeMs: number;
content?: string; // LLM output
reasoning?: string; // Reasoning/thinking
inputTokens?: number;
outputTokens?: number;
toolsCalling?: Array<{ apiName: string; identifier: string; arguments?: string }>;
toolsResult?: Array<{
apiName: string;
identifier: string;
isSuccess?: boolean;
output?: string;
}>;
messages?: any[]; // DB messages before step
context?: { phase: string; payload?: unknown; stepContext?: unknown };
events?: Array<{ type: string; [key: string]: unknown }>;
// context_engine_result event contains:
// input: full contextEngineInput (messages, systemRole, model, knowledge, tools, userMemory, ...)
// output: processed messages array (final LLM payload)
}
```
## --messages Output Structure
When using `--messages`, the output shows three sections (if context engine data is available):
1. **Context Engine Input** — DB messages passed to the engine, with `[0]`, `[1]`, ... indices. Use `--msg-input N` to view full content.
2. **Context Engine Params** — systemRole, model, provider, knowledge, tools, userMemory, etc.
3. **Final LLM Payload** — Processed messages after context engine (system date injection, user memory, history truncation, etc.), with `[0]`, `[1]`, ... indices. Use `--msg N` to view full content.
## Integration Points
- **Recording**: `src/server/services/agentRuntime/AgentRuntimeService.ts` — in the `executeStep()` method, after building `stepPresentationData`, writes partial snapshot in dev mode
- **Context engine event**: `src/server/modules/AgentRuntime/RuntimeExecutors.ts` — in `call_llm` executor, after `serverMessagesEngine()` returns, emits `context_engine_result` event
- **Store**: `FileSnapshotStore` reads/writes to `.agent-tracing/` relative to `process.cwd()`
+153
View File
@@ -0,0 +1,153 @@
---
name: chat-sdk
description: >
Build multi-platform chat bots with Chat SDK (`chat` npm package). Use when developers want to
(1) Build a Slack, Teams, Google Chat, Discord, GitHub, or Linear bot,
(2) Use the Chat SDK to handle mentions, messages, reactions, slash commands, cards, modals, or streaming,
(3) Set up webhook handlers for chat platforms,
(4) Send interactive cards or stream AI responses to chat platforms.
Triggers on "chat sdk", "chat bot", "slack bot", "teams bot", "discord bot", "@chat-adapter",
building bots that work across multiple chat platforms.
---
# Chat SDK
Unified TypeScript SDK for building chat bots across Slack, Teams, Google Chat, Discord, GitHub, and Linear. Write bot logic once, deploy everywhere.
## Critical: Read the bundled docs
The `chat` package ships with full documentation in `node_modules/chat/docs/` and TypeScript source types. **Always read these before writing code:**
```
node_modules/chat/docs/ # Full documentation (MDX files)
node_modules/chat/dist/ # Built types (.d.ts files)
```
Key docs to read based on task:
- `docs/getting-started.mdx` — setup guides
- `docs/usage.mdx` — event handlers, threads, messages, channels
- `docs/streaming.mdx` — AI streaming with AI SDK
- `docs/cards.mdx` — JSX interactive cards
- `docs/actions.mdx` — button/dropdown handlers
- `docs/modals.mdx` — form dialogs (Slack only)
- `docs/adapters/*.mdx` — platform-specific adapter setup
- `docs/state/*.mdx` — state adapter config (Redis, ioredis, memory)
Also read the TypeScript types from `node_modules/chat/dist/` to understand the full API surface.
## Quick start
```typescript
import { Chat } from 'chat';
import { createSlackAdapter } from '@chat-adapter/slack';
import { createRedisState } from '@chat-adapter/state-redis';
const bot = new Chat({
userName: 'mybot',
adapters: {
slack: createSlackAdapter({
botToken: process.env.SLACK_BOT_TOKEN!,
signingSecret: process.env.SLACK_SIGNING_SECRET!,
}),
},
state: createRedisState({ url: process.env.REDIS_URL! }),
});
bot.onNewMention(async (thread) => {
await thread.subscribe();
await thread.post("Hello! I'm listening to this thread.");
});
bot.onSubscribedMessage(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
```
## Core concepts
- **Chat** — main entry point, coordinates adapters and routes events
- **Adapters** — platform-specific (Slack, Teams, GChat, Discord, GitHub, Linear)
- **State** — pluggable persistence (Redis for prod, memory for dev)
- **Thread** — conversation thread with `post()`, `subscribe()`, `startTyping()`
- **Message** — normalized format with `text`, `formatted` (mdast AST), `raw`
- **Channel** — container for threads, supports listing and posting
## Event handlers
| Handler | Trigger |
| -------------------------- | ------------------------------------------------- |
| `onNewMention` | Bot @-mentioned in unsubscribed thread |
| `onSubscribedMessage` | Any message in subscribed thread |
| `onNewMessage(regex)` | Messages matching pattern in unsubscribed threads |
| `onSlashCommand("/cmd")` | Slash command invocations |
| `onReaction(emojis)` | Emoji reactions added/removed |
| `onAction(actionId)` | Button clicks and dropdown selections |
| `onAssistantThreadStarted` | Slack Assistants API thread opened |
| `onAppHomeOpened` | Slack App Home tab opened |
## Streaming
Pass any `AsyncIterable<string>` to `thread.post()`. Works with AI SDK's `textStream`:
```typescript
import { ToolLoopAgent } from 'ai';
const agent = new ToolLoopAgent({ model: 'anthropic/claude-4.5-sonnet' });
bot.onNewMention(async (thread, message) => {
const result = await agent.stream({ prompt: message.text });
await thread.post(result.textStream);
});
```
## Cards (JSX)
Set `jsxImportSource: "chat"` in tsconfig. Components: `Card`, `CardText`, `Button`, `Actions`, `Fields`, `Field`, `Select`, `SelectOption`, `Image`, `Divider`, `LinkButton`, `Section`, `RadioSelect`.
```tsx
await thread.post(
<Card title="Order #1234">
<CardText>Your order has been received!</CardText>
<Actions>
<Button id="approve" style="primary">
Approve
</Button>
<Button id="reject" style="danger">
Reject
</Button>
</Actions>
</Card>,
);
```
## Packages
| Package | Purpose |
| ----------------------------- | ----------------------------- |
| `chat` | Core SDK |
| `@chat-adapter/slack` | Slack |
| `@chat-adapter/teams` | Microsoft Teams |
| `@chat-adapter/gchat` | Google Chat |
| `@chat-adapter/discord` | Discord |
| `@chat-adapter/github` | GitHub Issues |
| `@chat-adapter/linear` | Linear Issues |
| `@chat-adapter/state-redis` | Redis state (production) |
| `@chat-adapter/state-ioredis` | ioredis state (alternative) |
| `@chat-adapter/state-memory` | In-memory state (development) |
## Changesets (Release Flow)
This monorepo uses [Changesets](https://github.com/changesets/changesets) for versioning and changelogs. Every PR that changes a package's behavior must include a changeset.
```bash
pnpm changeset
# → select affected package(s) (e.g. @chat-adapter/slack, chat)
# → choose bump type: patch (fixes), minor (features), major (breaking)
# → write a short summary for the CHANGELOG
```
This creates a file in `.changeset/` — commit it with the PR. When merged to `main`, the Changesets GitHub Action opens a "Version Packages" PR to bump versions and update CHANGELOGs. Merging that PR publishes to npm.
## Webhook setup
Each adapter exposes a webhook handler via `bot.webhooks.{platform}`. Wire these to your HTTP framework's routes (e.g. Next.js API routes, Hono, Express).
+296
View File
@@ -0,0 +1,296 @@
---
name: cli
description: LobeHub CLI (@lobehub/cli) development guide. Use when working on CLI commands, adding new subcommands, fixing CLI bugs, or understanding CLI architecture. Triggers on CLI development, command implementation, or `lh` command questions.
disable-model-invocation: true
---
# LobeHub CLI Development Guide
## Overview
LobeHub CLI (`@lobehub/cli`) is a command-line tool for managing and interacting with LobeHub services. Built with Commander.js + TypeScript.
- **Package**: `apps/cli/`
- **Entry**: `apps/cli/src/index.ts`
- **Binaries**: `lh`, `lobe`, `lobehub` (all aliases for the same CLI)
- **Build**: tsup
- **Runtime**: Node.js / Bun
## Architecture
```
apps/cli/src/
├── index.ts # Entry point, registers all commands
├── api/
│ ├── client.ts # tRPC client (type-safe backend API)
│ └── http.ts # Raw HTTP utilities
├── auth/
│ ├── credentials.ts # Encrypted credential storage (AES-256-GCM)
│ ├── refresh.ts # Token auto-refresh
│ └── resolveToken.ts # Token resolution (flag > stored)
├── commands/ # All CLI commands (one file per command group)
│ ├── agent.ts # Agent CRUD + run
│ ├── config.ts # whoami, usage
│ ├── connect.ts # Device gateway connection + daemon
│ ├── doc.ts # Document management
│ ├── file.ts # File management
│ ├── generate/ # Content generation (text/image/video/tts/asr)
│ ├── kb.ts # Knowledge base management
│ ├── login.ts # OIDC Device Code Flow auth
│ ├── logout.ts # Clear credentials
│ ├── memory.ts # User memory management
│ ├── message.ts # Message management
│ ├── model.ts # AI model management
│ ├── plugin.ts # Plugin management
│ ├── provider.ts # AI provider management
│ ├── search.ts # Global search
│ ├── skill.ts # Agent skill management
│ ├── status.ts # Gateway connectivity check
│ └── topic.ts # Conversation topic management
├── daemon/
│ └── manager.ts # Background daemon process management
├── tools/
│ ├── shell.ts # Shell command execution (for gateway)
│ └── file.ts # File operations (for gateway)
├── settings/
│ └── index.ts # Persistent settings (~/.lobehub/)
├── utils/
│ ├── logger.ts # Logging (verbose mode)
│ ├── format.ts # Table output, JSON, timeAgo, truncate
│ └── agentStream.ts # SSE streaming for agent runs
└── constants/
└── urls.ts # Official server & gateway URLs
```
## Command Groups
| Command | Alias | Description |
| ------------- | ----- | ----------------------------------------------------------- |
| `lh login` | - | Authenticate via OIDC Device Code Flow |
| `lh logout` | - | Clear stored credentials |
| `lh connect` | - | Device gateway connection & daemon management |
| `lh status` | - | Quick gateway connectivity check |
| `lh agent` | - | Agent CRUD, run, status |
| `lh generate` | `gen` | Content generation (text, image, video, tts, asr, download) |
| `lh doc` | - | Document CRUD, batch-create, parse, topic linking |
| `lh file` | - | File list, view, delete, recent |
| `lh kb` | - | Knowledge base CRUD, folders, docs, upload, tree view |
| `lh memory` | - | User memory CRUD + extraction |
| `lh message` | - | Message list, search, delete, count, heatmap |
| `lh topic` | - | Topic CRUD + search + recent |
| `lh skill` | - | Skill CRUD + import (GitHub/URL/market) |
| `lh model` | - | Model CRUD, toggle, batch-toggle, clear |
| `lh provider` | - | Provider CRUD, config, test, toggle |
| `lh plugin` | - | Plugin install, uninstall, update |
| `lh search` | - | Global search across all types |
| `lh whoami` | - | Current user info |
| `lh usage` | - | Monthly/daily usage statistics |
## Adding a New Command
### 1. Create Command File
Create `apps/cli/src/commands/<name>.ts`:
```typescript
import type { Command } from 'commander';
import { getTrpcClient } from '../api/client';
import { outputJson, printTable, truncate } from '../utils/format';
export function register<Name>Command(program: Command) {
const cmd = program.command('<name>').description('...');
// Subcommands
cmd
.command('list')
.description('List items')
.option('-L, --limit <n>', 'Maximum number of items', '30')
.option('--json [fields]', 'Output JSON, optionally specify fields')
.action(async (options) => {
const client = await getTrpcClient();
const result = await client.<router>.<procedure>.query({ ... });
// Handle output
});
}
```
### 2. Register in Entry Point
In `apps/cli/src/index.ts`:
```typescript
import { registerNewCommand } from './commands/new';
// ...
registerNewCommand(program);
```
### 3. Add Tests
Create `apps/cli/src/commands/<name>.test.ts` alongside the command file.
## Conventions
### Output Patterns
All list/view commands follow consistent patterns:
- `--json [fields]` - JSON output with optional field filtering
- `--yes` - Skip confirmation for destructive ops
- `-L, --limit <n>` - Pagination limit (default: 30)
- `-v, --verbose` - Verbose logging
### Table Output
```typescript
const rows = items.map((item) => [item.id, truncate(item.title, 40), timeAgo(item.updatedAt)]);
printTable(rows, ['ID', 'TITLE', 'UPDATED']);
```
### JSON Output
```typescript
if (options.json !== undefined) {
const fields = typeof options.json === 'string' ? options.json : undefined;
outputJson(items, fields);
return;
}
```
### Authentication
Commands that need auth use `getTrpcClient()` which auto-resolves tokens:
```typescript
const client = await getTrpcClient();
// client.router.procedure.query/mutate(...)
```
### Confirmation Prompts
```typescript
import { confirm } from '../utils/format';
if (!options.yes) {
const ok = await confirm('Are you sure?');
if (!ok) return;
}
```
## Storage Locations
| File | Path | Purpose |
| ------------- | ----------------------------- | ------------------------------ |
| Credentials | `~/.lobehub/credentials.json` | Encrypted tokens (AES-256-GCM) |
| Settings | `~/.lobehub/settings.json` | Custom server/gateway URLs |
| Daemon PID | `~/.lobehub/daemon.pid` | Background process PID |
| Daemon Status | `~/.lobehub/daemon.status` | Connection status JSON |
| Daemon Log | `~/.lobehub/daemon.log` | Daemon output log |
The base directory (`~/.lobehub/`) can be overridden with the `LOBEHUB_CLI_HOME` env var (e.g. `LOBEHUB_CLI_HOME=.lobehub-dev` for dev mode isolation).
## Key Dependencies
- `commander` - CLI framework
- `@trpc/client` + `superjson` - Type-safe API client
- `@lobechat/device-gateway-client` - WebSocket gateway connection
- `@lobechat/local-file-shell` - Local shell/file tool execution
- `picocolors` - Terminal colors
- `ws` - WebSocket
- `diff` - Text diffing
- `fast-glob` - File pattern matching
## Development
### Running in Dev Mode
Dev mode uses `LOBEHUB_CLI_HOME=.lobehub-dev` to isolate credentials from the global `~/.lobehub/` directory, so dev and production configs never conflict.
```bash
# Run a command in dev mode (from apps/cli/)
cd apps/cli && bun run dev -- <command>
# This is equivalent to:
LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts <command>
```
### Connecting to Local Dev Server
To test CLI against a local dev server (e.g. `localhost:3011`):
**Step 1: Start the local server**
```bash
# From cloud repo root
bun run dev
# Server starts on http://localhost:3011 (or configured port)
```
**Step 2: Login to local server via Device Code Flow**
```bash
cd apps/cli && bun run dev -- login --server http://localhost:3011
```
This will:
1. Call `POST http://localhost:3011/oidc/device/auth` to get a device code
2. Print a URL like `http://localhost:3011/oidc/device?user_code=XXXX-YYYY`
3. Open the URL in your browser — log in and authorize
4. Save credentials to `apps/cli/.lobehub-dev/credentials.json`
5. Save server URL to `apps/cli/.lobehub-dev/settings.json`
After login, all subsequent `bun run dev -- <command>` calls will use the local server.
**Step 3: Run commands against local server**
```bash
cd apps/cli && bun run dev -- task list
cd apps/cli && bun run dev -- task create -i "Test task" -n "My Task"
cd apps/cli && bun run dev -- agent list
```
**Troubleshooting:**
- If login returns `invalid_grant`, make sure the local OIDC provider is properly configured (check `OIDC_*` env vars in `.env`)
- If you get `UNAUTHORIZED` on API calls, your token may have expired — run `bun run dev -- login --server http://localhost:3011` again
- Dev credentials are stored in `apps/cli/.lobehub-dev/` (gitignored), not in `~/.lobehub/`
### Switching Between Local and Production
```bash
# Dev mode (local server) — uses .lobehub-dev/
cd apps/cli && bun run dev -- <command>
# Production (app.lobehub.com) — uses ~/.lobehub/
lh <command>
```
The two environments are completely isolated by different credential directories.
### Build & Test
```bash
# Build CLI
cd apps/cli && bun run build
# Unit tests
cd apps/cli && bun run test
# E2E tests (requires authenticated CLI)
cd apps/cli && bunx vitest run e2e/kb.e2e.test.ts
# Link globally for testing (installs lh/lobe/lobehub commands)
cd apps/cli && bun run cli:link
```
## Detailed Command References
See `references/` for each command group:
- **Agent**: `references/agent.md` (CRUD, run, status)
- **Content Generation**: `references/generate.md` (text, image, video, tts, asr, download)
- **Knowledge & Files**: `references/knowledge.md` (kb, file, doc)
- **Conversation**: `references/conversation.md` (topic, message)
- **Memory**: `references/memory.md` (memory management, extraction)
- **Skills & Plugins**: `references/skills-plugins.md` (skill, plugin)
- **Models & Providers**: `references/models-providers.md` (model, provider)
- **Search & Config**: `references/search-config.md` (search, whoami, usage)
+144
View File
@@ -0,0 +1,144 @@
# Agent Commands
Manage AI agents: create, edit, delete, list, run, and check status.
**Source**: `apps/cli/src/commands/agent.ts`
## `lh agent list`
List all agents.
```bash
lh agent list [-L [-k [--json [fields]] < n > ] < keyword > ]
```
| Option | Description | Default |
| ------------------------- | -------------------------------------- | ------- |
| `-L, --limit <n>` | Maximum items | `30` |
| `-k, --keyword <keyword>` | Filter by keyword | - |
| `--json [fields]` | JSON output with optional field filter | - |
**Table columns**: ID, TITLE, DESCRIPTION, MODEL
---
## `lh agent view <agentId>`
View agent configuration details.
```bash
lh agent view [fields]] < agentId > [--json
```
**Displays**: Title, description, model, provider, system role, plugins, tools.
---
## `lh agent create`
Create a new agent.
```bash
lh agent create [options]
```
| Option | Description | Required |
| --------------------------- | -------------- | -------- |
| `-t, --title <title>` | Agent title | No |
| `-d, --description <desc>` | Description | No |
| `-m, --model <model>` | Model ID | No |
| `-p, --provider <provider>` | Provider ID | No |
| `-s, --system-role <role>` | System prompt | No |
| `--group <groupId>` | Agent group ID | No |
**Output**: Created agent ID and session ID.
---
## `lh agent edit <agentId>`
Update an existing agent. Same options as `create`, all optional. Only specified fields are updated.
```bash
lh agent edit [-m [-s ... < agentId > [-t < title > ] < model > ] < role > ]
```
---
## `lh agent delete <agentId>`
Delete an agent.
```bash
lh agent delete < agentId > [--yes]
```
Requires confirmation unless `--yes` is provided.
---
## `lh agent duplicate <agentId>`
Duplicate an existing agent.
```bash
lh agent duplicate < agentId > [-t < title > ]
```
| Option | Description |
| --------------------- | ------------------------------------ |
| `-t, --title <title>` | Optional new title for the duplicate |
**Output**: New agent ID.
---
## `lh agent run`
Start an agent execution (streaming SSE).
```bash
lh agent run [options]
```
| Option | Description |
| --------------------- | -------------------------------------------- |
| `-a, --agent-id <id>` | Agent ID to run |
| `-s, --slug <slug>` | Agent slug (alternative to ID) |
| `-p, --prompt <text>` | User prompt |
| `-t, --topic-id <id>` | Reuse existing topic |
| `--no-auto-start` | Don't auto-start the agent |
| `--json` | Output full JSON event stream |
| `-v, --verbose` | Show detailed tool call info |
| `--replay <file>` | Replay events from saved JSON file (offline) |
### Streaming Behavior
Uses `utils/agentStream.ts` to handle Server-Sent Events:
1. Sends agent run request to backend
2. Streams SSE events in real-time
3. Displays: text chunks, tool call status, operation progress
4. Shows final token usage and cost summary
### Replay Mode
`--replay <file>` reads a saved JSON event stream for offline debugging without server connection.
---
## `lh agent status <operationId>`
Check agent operation status.
```bash
lh agent status [fields]] [--history] [--history-limit < operationId > [--json < n > ]
```
| Option | Description | Default |
| --------------------- | -------------------- | ------- |
| `--json [fields]` | JSON output | - |
| `--history` | Include step history | `false` |
| `--history-limit <n>` | Max history entries | `10` |
**Displays**: Status (running/completed/failed), steps count, tokens used, cost, error info, timestamps.
@@ -0,0 +1,122 @@
# Conversation Commands (Topic & Message)
## Topic Management (`lh topic`)
Manage conversation topics (threads).
**Source**: `apps/cli/src/commands/topic.ts`
### `lh topic list`
```bash
lh topic list [--agent-id [-L [--page [--json [fields]] < id > ] < n > ] < n > ]
```
| Option | Description | Default |
| ----------------- | --------------- | ------- |
| `--agent-id <id>` | Filter by agent | - |
| `-L, --limit <n>` | Page size | `30` |
| `--page <n>` | Page number | `1` |
**Table columns**: ID, TITLE, FAV, UPDATED
### `lh topic search <keywords>`
```bash
lh topic search [--json [fields]] < keywords > [--agent-id < id > ]
```
### `lh topic create`
```bash
lh topic create -t [--favorite] < title > [--agent-id < id > ]
```
| Option | Description | Required |
| --------------------- | -------------------- | -------- |
| `-t, --title <title>` | Topic title | Yes |
| `--agent-id <id>` | Associate with agent | No |
| `--favorite` | Mark as favorite | No |
### `lh topic edit <id>`
```bash
lh topic edit [--favorite] [--no-favorite] < id > [-t < title > ]
```
### `lh topic delete <ids...>`
```bash
lh topic delete [--yes] < id1 > [id2...]
```
### `lh topic recent`
```bash
lh topic recent [-L [--json [fields]] < n > ]
```
| Option | Description | Default |
| ----------------- | --------------- | ------- |
| `-L, --limit <n>` | Number of items | `10` |
---
## Message Management (`lh message`)
Manage chat messages within topics.
**Source**: `apps/cli/src/commands/message.ts`
### `lh message list`
```bash
lh message list [options] [--json [fields]]
```
| Option | Description | Default |
| ----------------- | ----------------------- | ------- |
| `--topic-id <id>` | Filter by topic | - |
| `--agent-id <id>` | Filter by agent | - |
| `-L, --limit <n>` | Page size | `30` |
| `--page <n>` | Page number | `1` |
| `--user` | Only show user messages | - |
**Table columns**: ID, ROLE, CONTENT, CREATED
**Note**: When `--topic-id` or `--agent-id` is provided, uses `message.getMessages`; otherwise uses `message.listAll`.
### `lh message search <keywords>`
```bash
lh message search [fields]] < keywords > [--json
```
Full-text search across all messages.
### `lh message delete <ids...>`
```bash
lh message delete [--yes] < id1 > [id2...]
```
### `lh message count`
```bash
lh message count [--start [--end [--json] < date > ] < date > ]
```
| Option | Description |
| ---------------- | ------------------------------------------ |
| `--start <date>` | Start date (ISO format, e.g. `2024-01-01`) |
| `--end <date>` | End date (ISO format) |
**Output**: Total message count for the specified period.
### `lh message heatmap`
```bash
lh message heatmap [--json]
```
**Output**: Activity heatmap data showing message frequency over time.
+246
View File
@@ -0,0 +1,246 @@
# Content Generation Commands
Generate text, images, videos, speech, and transcriptions.
**Source**: `apps/cli/src/commands/generate/`
## Command Structure
```
lh generate (alias: gen)
├── text <prompt> # Text generation
├── image <prompt> # Image generation
├── video <prompt> # Video generation
├── tts <text> # Text-to-speech
├── asr <audioFile> # Audio-to-text (speech recognition)
├── download <genId> <taskId> # Wait & download generation result
├── status <genId> <taskId> # Check async task status
└── list # List generation topics
```
---
## `lh generate text <prompt>` / `lh gen text <prompt>`
Generate text completion.
**Source**: `apps/cli/src/commands/generate/text.ts`
```bash
lh gen text "Explain quantum computing" [options]
echo "context" | lh gen text "summarize" --pipe
```
| Option | Description | Default |
| --------------------------- | ---------------------------------- | -------------------- |
| `-m, --model <model>` | Model ID | `openai/gpt-4o-mini` |
| `-p, --provider <provider>` | Provider name | - |
| `-s, --system <prompt>` | System prompt | - |
| `--temperature <n>` | Temperature (0-2) | - |
| `--max-tokens <n>` | Maximum output tokens | - |
| `--stream` | Enable streaming output | `false` |
| `--json` | Output full JSON response | `false` |
| `--pipe` | Read additional context from stdin | `false` |
### Pipe Mode
When `--pipe` is used, reads stdin and prepends it to the prompt. Useful for piping file contents:
```bash
cat README.md | lh gen text "summarize this" --pipe
```
---
## `lh generate image <prompt>` / `lh gen image <prompt>`
Generate images from text prompt. This is an async operation — the command submits the task and returns a generation ID + task ID for tracking.
**Source**: `apps/cli/src/commands/generate/image.ts`
```bash
lh gen image "A sunset over mountains" [options]
lh gen image "A cute cat" --model dall-e-3 --provider openai --json
```
| Option | Description | Default |
| --------------------------- | ---------------- | ---------- |
| `-m, --model <model>` | Model ID | `dall-e-3` |
| `-p, --provider <provider>` | Provider name | `openai` |
| `-n, --num <n>` | Number of images | `1` |
| `--width <px>` | Width in pixels | - |
| `--height <px>` | Height in pixels | - |
| `--steps <n>` | Number of steps | - |
| `--seed <n>` | Random seed | - |
| `--json` | Output raw JSON | `false` |
**Output** (non-JSON):
```
✓ Image generation started
Batch ID: gb_xxx
1 image(s) queued
Generation gen_xxx → Task <taskId>
Use "lh generate status <generationId> <taskId>" to check progress.
```
**Typical workflow**:
```bash
# Generate image, then wait & download
lh gen image "A cute cat"
lh gen download <generationId> <taskId> -o cat.png
```
---
## `lh generate video <prompt>` / `lh gen video <prompt>`
Generate video from text prompt. This is an async operation.
**Source**: `apps/cli/src/commands/generate/video.ts`
```bash
lh gen video "A cat playing piano" -m < model > -p < provider > [options]
```
| Option | Description | Required |
| --------------------------- | ------------------------ | -------- |
| `-m, --model <model>` | Model ID | Yes |
| `-p, --provider <provider>` | Provider name | Yes |
| `--aspect-ratio <ratio>` | Aspect ratio (e.g. 16:9) | No |
| `--duration <sec>` | Duration in seconds | No |
| `--resolution <res>` | Resolution (e.g. 720p) | No |
| `--seed <n>` | Random seed | No |
| `--json` | Output raw JSON | No |
**Note**: Unlike image, video requires `-m` and `-p` (no defaults). Use `lh model list <provider> --type video` to find available video models.
**Output** (non-JSON):
```
✓ Video generation started
Batch ID: gb_xxx
Generation gen_xxx → Task <taskId>
Use "lh generate status <generationId> <taskId>" to check progress.
```
---
## `lh generate tts <text>` / `lh gen tts <text>`
Text-to-speech generation.
**Source**: `apps/cli/src/commands/generate/tts.ts`
```bash
lh gen tts "Hello, world!" [options]
```
---
## `lh generate asr <audioFile>` / `lh gen asr <audioFile>`
Audio-to-text transcription (Automatic Speech Recognition).
**Source**: `apps/cli/src/commands/generate/asr.ts`
```bash
lh gen asr recording.wav [options]
```
---
## `lh generate download <generationId> <taskId>`
Wait for an async generation task to complete and download the result file.
**Source**: `apps/cli/src/commands/generate/index.ts`
```bash
lh gen download <generationId> <taskId> [-o output.png]
lh gen download gen_xxx task_xxx -o ~/Desktop/result.mp4 --timeout 600
```
| Option | Description | Default |
| --------------------- | ---------------------------------------- | ---------------------- |
| `-o, --output <path>` | Output file path (auto-detect extension) | `<generationId>.<ext>` |
| `--interval <sec>` | Polling interval in seconds | `5` |
| `--timeout <sec>` | Timeout in seconds (0 = no timeout) | `300` |
**Behavior**:
1. Polls `generation.getGenerationStatus` at the specified interval
2. Shows live progress: `⋯ Status: processing... (42s)`
3. On success: downloads asset URL to local file
4. On error: displays error message and exits
5. On timeout: suggests using `lh gen status` to check later
**Typical workflow**:
```bash
# One-shot: generate and download
lh gen image "A sunset"
# Copy the generation ID and task ID from output
lh gen download gen_xxx taskId_xxx -o sunset.png
# Video (longer timeout)
lh gen video "A cat running" -m model -p provider
lh gen download gen_xxx taskId_xxx -o cat.mp4 --timeout 600
```
---
## `lh generate status <generationId> <taskId>`
Check the status of an async generation task.
```bash
lh gen status <generationId> <taskId> [--json]
```
| Option | Description |
| -------- | ------------------------ |
| `--json` | Output raw JSON response |
**Displays**:
- Status (color-coded): `success` (green), `error` (red), `processing` (yellow), `pending` (cyan)
- Error message (if failed)
- Asset URL and thumbnail URL (if completed)
---
## `lh generate list`
List all generation topics.
```bash
lh gen list [--json [fields]]
```
**Table columns**: ID, TITLE, TYPE, UPDATED
---
## Backend Architecture
Image and video generation use an async task pattern:
1. **Create topic**`generationTopic.createTopic`
2. **Submit generation**`image.createImage` / `video.createVideo`
- Creates batch + generation + asyncTask records in a DB transaction
- Triggers async background task (image via `createAsyncCaller`, video via `initModelRuntimeFromDB`)
- Returns `{ data: { batch, generations }, success }` with `asyncTaskId` in each generation
3. **Poll status**`generation.getGenerationStatus`
- Returns `{ status, error, generation }` (generation includes asset URLs on success)
**Server routes**:
- `src/server/routers/lambda/image/index.ts` — image creation (uses `authedProcedure` + `serverDatabase`)
- `src/server/routers/lambda/video/index.ts` — video creation (uses `authedProcedure` + `serverDatabase`)
- `src/server/routers/lambda/generation.ts` — status checking
**Note**: Image/video routes do NOT use the `keyVaults` middleware — they read API keys from the database via `initModelRuntimeFromDB` or `createAsyncCaller`.
+281
View File
@@ -0,0 +1,281 @@
# Knowledge Base, File & Document Commands
## Knowledge Base (`lh kb`)
Manage knowledge bases for RAG (Retrieval-Augmented Generation). Supports directory tree structure with folders, documents, and file uploads.
**Source**: `apps/cli/src/commands/kb.ts`
### `lh kb list`
```bash
lh kb list [--json [fields]]
```
**Table columns**: ID, NAME, DESCRIPTION, UPDATED
### `lh kb view <id>`
```bash
lh kb view [fields]] < id > [--json
```
**Displays**: Name, description, full directory tree with all files and documents (recursively fetched). Shows indented tree structure with item type (File/Doc), file type, and size.
**API**: Uses `file.getKnowledgeItems` to recursively fetch items. Folders (`custom/folder` fileType) are traversed in parallel via `Promise.all` for performance.
### `lh kb create`
```bash
lh kb create -n [--avatar < name > [-d < desc > ] < url > ]
```
| Option | Description | Required |
| -------------------------- | ------------------- | -------- |
| `-n, --name <name>` | Knowledge base name | Yes |
| `-d, --description <desc>` | Description | No |
| `--avatar <url>` | Avatar URL | No |
**Output**: Created KB ID. Note: backend returns ID as a string directly (not an object).
### `lh kb edit <id>`
```bash
lh kb edit [-d [--avatar < id > [-n < name > ] < desc > ] < url > ]
```
Requires at least one change flag. Errors if none specified.
### `lh kb delete <id>`
```bash
lh kb delete [--yes] < id > [--remove-files]
```
| Option | Description |
| ---------------- | ---------------------------- |
| `--remove-files` | Also delete associated files |
| `--yes` | Skip confirmation |
### `lh kb add-files <knowledgeBaseId>`
```bash
lh kb add-files <kbId> --ids <fileId1> <fileId2> ...
```
Link existing files to a knowledge base.
### `lh kb remove-files <knowledgeBaseId>`
```bash
lh kb remove-files <kbId> --ids <fileId1> <fileId2> ... [--yes]
```
Unlink files from a knowledge base.
### `lh kb mkdir <knowledgeBaseId>`
```bash
lh kb mkdir < kbId > -n < name > [--parent < folderId > ]
```
Create a folder in a knowledge base. Uses `document.createDocument` with `fileType: 'custom/folder'`.
| Option | Description | Required |
| --------------------- | ---------------- | -------- |
| `-n, --name <name>` | Folder name | Yes |
| `--parent <parentId>` | Parent folder ID | No |
### `lh kb create-doc <knowledgeBaseId>`
```bash
lh kb create-doc [--parent < kbId > -t < title > [-c < content > ] < folderId > ]
```
Create a document in a knowledge base. Uses `document.createDocument` with `fileType: 'custom/document'`.
| Option | Description | Required |
| ---------------------- | ---------------- | -------- |
| `-t, --title <title>` | Document title | Yes |
| `-c, --content <text>` | Document content | No |
| `--parent <parentId>` | Parent folder ID | No |
### `lh kb move <id>`
```bash
lh kb move < id > --type < file | doc > [--parent < folderId > ]
```
Move a file or document to a different folder (or to root if `--parent` is omitted).
| Option | Description | Default |
| --------------------- | -------------------------------- | ------- |
| `--type <type>` | Item type: `file` or `doc` | `file` |
| `--parent <parentId>` | Target folder ID (omit for root) | - |
Uses `document.updateDocument` for docs, `file.updateFile` for files.
### `lh kb upload <knowledgeBaseId> <filePath>`
```bash
lh kb upload <kbId> <filePath> [--parent <folderId>]
```
Upload a local file to a knowledge base via S3 presigned URL.
| Option | Description |
| --------------------- | ---------------- |
| `--parent <parentId>` | Parent folder ID |
**Flow**: Compute SHA-256 hash → get presigned URL via `upload.createS3PreSignedUrl` → PUT to S3 → create file record via `file.createFile`.
---
## File Management (`lh file`)
Manage uploaded files.
**Source**: `apps/cli/src/commands/file.ts`
### `lh file list`
```bash
lh file list [--kb-id [-L [--json [fields]] < id > ] < n > ]
```
| Option | Description | Default |
| ----------------- | ------------------------ | ------- |
| `--kb-id <id>` | Filter by knowledge base | - |
| `-L, --limit <n>` | Maximum items | `30` |
**Table columns**: ID, NAME, TYPE, SIZE, UPDATED
### `lh file view <id>`
```bash
lh file view [fields]] < id > [--json
```
**Displays**: Name, type, size, chunking status, embedding status.
### `lh file delete <ids...>`
```bash
lh file delete [--yes] < id1 > [id2...]
```
Supports deleting multiple files at once.
### `lh file recent`
```bash
lh file recent [-L [--json [fields]] < n > ]
```
| Option | Description | Default |
| ----------------- | --------------- | ------- |
| `-L, --limit <n>` | Number of items | `10` |
---
## Document Management (`lh doc`)
Manage text documents (notes, wiki pages).
**Source**: `apps/cli/src/commands/doc.ts`
### `lh doc list`
```bash
lh doc list [-L [--file-type [--source-type [--json [fields]] < n > ] < type > ] < type > ]
```
| Option | Description | Default |
| ---------------------- | --------------------------------------------- | ------- |
| `-L, --limit <n>` | Maximum items | `30` |
| `--file-type <type>` | Filter by file type | - |
| `--source-type <type>` | Filter by source type (file, web, api, topic) | - |
**Table columns**: ID, TITLE, TYPE, UPDATED
### `lh doc view <id>`
```bash
lh doc view [fields]] < id > [--json
```
**Displays**: Title, type, KB association, updated time, full content.
### `lh doc create`
```bash
lh doc create -t [-F [--parent [--slug [--kb [--file-type < title > [-b < body > ] < path > ] < id > ] < slug > ] < id > ] < type > ]
```
| Option | Description | Required |
| ------------------------ | ----------------------------------------------- | -------- |
| `-t, --title <title>` | Document title | Yes |
| `-b, --body <content>` | Document body text | No |
| `-F, --body-file <path>` | Read body from file | No |
| `--parent <id>` | Parent document ID | No |
| `--slug <slug>` | Custom URL slug | No |
| `--kb <id>` | Knowledge base ID to associate with | No |
| `--file-type <type>` | File type (e.g. custom/document, custom/folder) | No |
`-b` and `-F` are mutually exclusive; `-F` reads the file content as the body.
### `lh doc batch-create <file>`
Batch create documents from a JSON file. The file must contain a non-empty array of document objects.
```bash
lh doc batch-create documents.json
```
Each object in the array can have: `title`, `content`, `fileType`, `knowledgeBaseId`, `parentId`, `slug`.
### `lh doc edit <id>`
```bash
lh doc edit [-b [-F [--parent [--file-type < id > [-t < title > ] < body > ] < path > ] < id > ] < type > ]
```
### `lh doc delete <ids...>`
```bash
lh doc delete [--yes] < id1 > [id2...]
```
### `lh doc parse <fileId>`
Parse an uploaded file into a document.
```bash
lh doc parse [--json [fields]] < fileId > [--with-pages]
```
| Option | Description |
| -------------- | ----------------------- |
| `--with-pages` | Preserve page structure |
**Output**: Parsed title and content preview.
### `lh doc link-topic <docId> <topicId>`
Associate a document with a topic. Creates a linked copy via the notebook router.
```bash
lh doc link-topic <docId> <topicId>
```
### `lh doc topic-docs <topicId>`
List documents associated with a topic.
```bash
lh doc topic-docs [--json [fields]] < topicId > [--type < type > ]
```
| Option | Description |
| --------------- | ------------------------------------------------ |
| `--type <type>` | Filter by type (article, markdown, note, report) |
+138
View File
@@ -0,0 +1,138 @@
# Memory Commands
Manage user memories - the AI's long-term knowledge about users.
**Source**: `apps/cli/src/commands/memory.ts`
## Memory Categories
| Category | Description |
| ------------ | ----------------------------------------- |
| `identity` | User's name, role, relationships |
| `activity` | Recent activities and their status |
| `context` | Ongoing contexts, projects, goals |
| `experience` | Past experiences and key learnings |
| `preference` | User preferences, directives, suggestions |
---
## `lh memory list [category]`
List memory entries, optionally filtered by category.
```bash
lh memory list # All categories
lh memory list identity # Only identity memories
lh memory list preference # Only preferences
```
| Option | Description |
| ----------------- | ----------- |
| `--json [fields]` | JSON output |
**Output**: Grouped by category, showing type/status and descriptions.
---
## `lh memory create`
Create a new identity memory entry.
```bash
lh memory create [options]
```
| Option | Description |
| -------------------------- | ------------------------ |
| `--type <type>` | Memory type |
| `--role <role>` | User's role |
| `--relationship <rel>` | Relationship description |
| `-d, --description <desc>` | Description |
| `--labels <labels...>` | Extracted labels |
---
## `lh memory edit <category> <id>`
Edit a memory entry. Options vary by category:
```bash
lh memory edit identity < id > [options]
lh memory edit activity < id > [options]
lh memory edit context < id > [options]
lh memory edit experience < id > [options]
lh memory edit preference < id > [options]
```
### Category-specific Options
**identity**:
- `--type <type>`, `--role <role>`, `--relationship <rel>`
**activity**:
- `--narrative <text>`, `--notes <text>`, `--status <status>`
**context**:
- `--title <title>`, `--description <desc>`, `--status <status>`
**experience**:
- `--situation <text>`, `--action <text>`, `--key-learning <text>`
**preference**:
- `--directives <text>`, `--suggestions <text>`
---
## `lh memory delete <category> <id>`
```bash
lh memory delete identity < id > [--yes]
```
---
## `lh memory persona`
Display the compiled memory persona summary.
```bash
lh memory persona [--json [fields]]
```
**Output**: Summarized user profile built from all memory categories.
---
## `lh memory extract`
Trigger async memory extraction from chat history.
```bash
lh memory extract [--from [--to < date > ] < date > ]
```
| Option | Description |
| --------------- | ----------------------- |
| `--from <date>` | Start date (ISO format) |
| `--to <date>` | End date (ISO format) |
Starts a background task that analyzes chat history and creates new memory entries.
---
## `lh memory extract-status`
Check the status of a memory extraction task.
```bash
lh memory extract-status [--task-id [--json [fields]] < id > ]
```
| Option | Description |
| ---------------- | ------------------- |
| `--task-id <id>` | Check specific task |
@@ -0,0 +1,186 @@
# Model & Provider Commands
## Model Management (`lh model`)
Manage AI models within providers.
**Source**: `apps/cli/src/commands/model.ts`
### `lh model list <providerId>`
List models for a specific provider.
```bash
lh model list openai
lh model list openai --type image --enabled
lh model list lobehub --type video --json
```
| Option | Description | Default |
| ----------------- | -------------------------------------------------------------------------------------- | ------- |
| `-L, --limit <n>` | Maximum items | `50` |
| `--enabled` | Only show enabled models | `false` |
| `--type <type>` | Filter by model type (`chat\|embedding\|tts\|stt\|image\|video\|text2music\|realtime`) | - |
| `--json [fields]` | Output JSON, optionally specify fields | - |
**Table columns**: ID, NAME, ENABLED, TYPE
**Backend**: `aiModel.getAiProviderModelList``AiInfraRepos.getAiProviderModelList` (supports `type` filter at repository level)
### `lh model view <id>`
```bash
lh model view [fields]] < modelId > [--json
```
**Displays**: Name, provider, type, enabled status, capabilities.
### `lh model create`
```bash
lh model create --id [--type < id > --provider < providerId > [--display-name < name > ] < type > ]
```
| Option | Description | Default |
| ------------------------- | ------------ | -------- |
| `--id <id>` | Model ID | Required |
| `--provider <providerId>` | Provider ID | Required |
| `--display-name <name>` | Display name | - |
| `--type <type>` | Model type | `chat` |
### `lh model edit <id>`
```bash
lh model edit [--type < modelId > --provider < providerId > [--display-name < name > ] < type > ]
```
### `lh model toggle <id>`
Enable or disable a model.
```bash
lh model toggle < modelId > --provider < providerId > --enable
lh model toggle < modelId > --provider < providerId > --disable
```
| Option | Description | Required |
| ------------------------- | ----------------- | ------------ |
| `--provider <providerId>` | Provider ID | Yes |
| `--enable` | Enable the model | One required |
| `--disable` | Disable the model | One required |
### `lh model batch-toggle <ids...>`
Enable or disable multiple models at once.
```bash
lh model batch-toggle model1 model2 model3 --provider openai --enable
```
### `lh model delete <id>`
```bash
lh model delete < modelId > --provider < providerId > [--yes]
```
### `lh model clear`
Clear all models (or only remote/fetched models) for a provider.
```bash
lh model clear --provider [--yes] < providerId > [--remote]
```
---
## Provider Management (`lh provider`)
Manage AI service providers.
**Source**: `apps/cli/src/commands/provider.ts`
### `lh provider list`
```bash
lh provider list [--json [fields]]
```
**Table columns**: ID, NAME, ENABLED, SOURCE
### `lh provider view <id>`
```bash
lh provider view [fields]] < providerId > [--json
```
**Displays**: Name, enabled status, source, configuration.
### `lh provider create`
```bash
lh provider create --id [-d [--logo [--sdk-type < id > -n < name > [-s < source > ] < desc > ] < url > ] < type > ]
```
| Option | Description | Default |
| -------------------------- | ------------------------------------------------- | -------- |
| `--id <id>` | Provider ID | Required |
| `-n, --name <name>` | Provider name | Required |
| `-s, --source <source>` | Source type (`builtin` or `custom`) | `custom` |
| `-d, --description <desc>` | Provider description | - |
| `--logo <logo>` | Provider logo URL | - |
| `--sdk-type <sdkType>` | SDK type (openai, anthropic, azure, bedrock, ...) | - |
### `lh provider edit <id>`
```bash
lh provider edit [-d [--logo [--sdk-type < providerId > [-n < name > ] < desc > ] < url > ] < type > ]
```
Requires at least one change flag.
### `lh provider config <id>`
Configure provider settings (API key, base URL, etc.).
```bash
lh provider config openai --api-key sk-xxx
lh provider config openai --base-url https://custom-endpoint.com
lh provider config openai --show
lh provider config openai --show --json
```
| Option | Description |
| ------------------------ | --------------------------------- |
| `--api-key <key>` | Set API key |
| `--base-url <url>` | Set base URL |
| `--check-model <model>` | Set connectivity check model |
| `--enable-response-api` | Enable Response API mode (OpenAI) |
| `--disable-response-api` | Disable Response API mode |
| `--fetch-on-client` | Enable fetching models on client |
| `--no-fetch-on-client` | Disable fetching models on client |
| `--show` | Show current config |
| `--json [fields]` | Output JSON (with --show) |
**Important**: The `lobehub` provider is platform-managed. Attempting to set `--api-key` or `--base-url` on it will be rejected with an error message.
### `lh provider test <id>`
Test provider connectivity.
```bash
lh provider test openai
lh provider test openai -m gpt-4o --json
```
### `lh provider toggle <id>`
```bash
lh provider toggle < providerId > --enable
lh provider toggle < providerId > --disable
```
### `lh provider delete <id>`
```bash
lh provider delete < providerId > [--yes]
```
@@ -0,0 +1,94 @@
# Search & Configuration Commands
## Global Search (`lh search`)
Search across all LobeHub resource types.
**Source**: `apps/cli/src/commands/search.ts`
### `lh search <query>`
```bash
lh search "meeting notes" [-t [-L [--json [fields]] < type > ] < n > ]
```
| Option | Description | Default |
| ------------------- | ----------------------- | --------- |
| `-t, --type <type>` | Filter by resource type | All types |
| `-L, --limit <n>` | Results per type | `10` |
### Searchable Types
| Type | Description |
| ---------------- | ---------------------------- |
| `agent` | AI agents |
| `topic` | Conversation topics |
| `file` | Uploaded files |
| `folder` | File folders |
| `message` | Chat messages |
| `page` | Documents/pages |
| `memory` | User memories |
| `mcp` | MCP servers |
| `plugin` | Installed plugins |
| `communityAgent` | Community marketplace agents |
| `knowledgeBase` | Knowledge bases |
**Output**: Results grouped by type, showing ID, title/name, description.
---
## User Configuration (`lh whoami` / `lh usage`)
**Source**: `apps/cli/src/commands/config.ts`
### `lh whoami`
Display current authenticated user information.
```bash
lh whoami [--json [fields]]
```
**Displays**: Name, username, email, user ID, subscription plan.
### `lh usage`
Display usage statistics.
```bash
lh usage [--month [--daily] [--json [fields]] < YYYY-MM > ]
```
| Option | Description | Default |
| ------------------- | -------------- | ----------------------- |
| `--month <YYYY-MM>` | Month to query | Current month |
| `--daily` | Group by day | `false` (monthly total) |
**Output**: Token usage, costs, and model breakdown for the specified period.
---
## Global Options
These options are available across most commands:
| Option | Description |
| ----------------- | ---------------------------------------------------------------------- |
| `--json [fields]` | Output as JSON; optionally filter to specific fields (comma-separated) |
| `--yes` | Skip confirmation prompts for destructive operations |
| `-L, --limit <n>` | Pagination limit for list commands |
| `-v, --verbose` | Enable verbose/debug logging |
| `--help` | Show command help |
| `--version` | Show CLI version |
### JSON Field Filtering
The `--json` option supports field selection:
```bash
# Full JSON output
lh agent list --json
# Only specific fields
lh agent list --json "id,title,model"
```
@@ -0,0 +1,149 @@
# Skill & Plugin Commands
## Skill Management (`lh skill`)
Manage agent skills (custom instructions and capabilities).
**Source**: `apps/cli/src/commands/skill.ts`
### `lh skill list`
```bash
lh skill list [--source [--json [fields]] < source > ]
```
| Option | Description |
| ------------------- | ----------------------------------- |
| `--source <source>` | Filter: `builtin`, `market`, `user` |
**Table columns**: ID, NAME, DESCRIPTION, SOURCE, IDENTIFIER
### `lh skill view <id>`
```bash
lh skill view [fields]] < id > [--json
```
**Displays**: Name, description, source, identifier, content.
### `lh skill create`
```bash
lh skill create -n < name > -d < desc > -c < content > [-i < identifier > ]
```
| Option | Description | Required |
| -------------------------- | ----------------------------------- | -------- |
| `-n, --name <name>` | Skill name | Yes |
| `-d, --description <desc>` | Description | Yes |
| `-c, --content <content>` | Skill content (prompt/instructions) | Yes |
| `-i, --identifier <id>` | Custom identifier | No |
### `lh skill edit <id>`
```bash
lh skill edit [-n [-d < id > [-c < content > ] < name > ] < desc > ]
```
### `lh skill delete <id>`
```bash
lh skill delete < id > [--yes]
```
### `lh skill search <query>`
```bash
lh skill search [fields]] < query > [--json
```
### `lh skill install <source>` (alias: `lh skill i`)
Install a skill. Auto-detects source type from the input:
```bash
# GitHub (URL or owner/repo shorthand)
lh skill install lobehub/skill-repo
lh skill install https://github.com/lobehub/skill-repo
lh skill install lobehub/skill-repo --branch dev
# ZIP URL
lh skill install https://example.com/skill.zip
# Marketplace identifier
lh skill install my-cool-skill
lh skill i my-cool-skill
```
| Option | Description | Notes |
| ------------------- | ------------------------- | -------- |
| `--branch <branch>` | Branch name (GitHub only) | Optional |
**Detection rules**:
- `https://github.com/...` or `owner/repo` → GitHub
- Other `https://...` URLs → ZIP URL
- Everything else → marketplace identifier
### Resource Commands
#### `lh skill resources <id>`
List files/resources within a skill.
```bash
lh skill resources [fields]] < id > [--json
```
**Displays**: Path, type, size.
#### `lh skill read-resource <id> <path>`
Read a specific resource file from a skill.
```bash
lh skill read-resource <skillId> <path>
```
**Output**: File content or JSON metadata.
---
## Plugin Management (`lh plugin`)
Install and manage plugins (external tool integrations).
**Source**: `apps/cli/src/commands/plugin.ts`
### `lh plugin list`
```bash
lh plugin list [--json [fields]]
```
**Table columns**: ID, IDENTIFIER, TYPE, TITLE
### `lh plugin install`
```bash
lh plugin install -i [--settings < identifier > --manifest < json > [--type < type > ] < json > ]
```
| Option | Description | Required |
| ----------------------- | -------------------------- | ---------------------- |
| `-i, --identifier <id>` | Plugin identifier | Yes |
| `--manifest <json>` | Plugin manifest JSON | Yes |
| `--type <type>` | `plugin` or `customPlugin` | No (default: `plugin`) |
| `--settings <json>` | Plugin settings JSON | No |
### `lh plugin uninstall <id>`
```bash
lh plugin uninstall < id > [--yes]
```
### `lh plugin update <id>`
```bash
lh plugin update [--settings < id > [--manifest < json > ] < json > ]
```
+73
View File
@@ -0,0 +1,73 @@
---
name: code-review
description: 'Code review checklist for LobeHub. Use when reviewing PRs, diffs, or code changes. Covers correctness, security, quality, and project-specific patterns.'
---
# Code Review Guide
## Before You Start
1. Read `/typescript` and `/testing` skills for code style and test conventions
2. Get the diff (skip if already in context, e.g., injected by GitHub review app): `git diff` or `git diff origin/canary..HEAD`
## Checklist
### Correctness
- Leftover `console.log` / `console.debug` — should use `debug` package or remove
- Missing `return await` in try/catch — see <https://typescript-eslint.io/rules/return-await/> (not in our ESLint config yet, requires type info)
- Can the fix/implementation be more concise, efficient, or have better compatibility?
### Security
- No sensitive data (API keys, tokens, credentials) in `console.*` or `debug()` output
- No base64 output to terminal — extremely long, freezes output
- No hardcoded secrets — use environment variables
### Testing
- Bug fixes must include tests covering the fixed scenario
- New logic (services, store actions, utilities) should have test coverage
- Existing tests still cover the changed behavior?
- Prefer `vi.spyOn` over `vi.mock` (see `/testing` skill)
### i18n
- New user-facing strings use i18n keys, not hardcoded text
- Keys added to `src/locales/default/{namespace}.ts` with `{feature}.{context}.{action|status}` naming
- For PRs: `locales/` translations for all languages updated (`pnpm i18n`)
### SPA / routing
- **`desktopRouter` pair:** If the diff touches `src/spa/router/desktopRouter.config.tsx`, does it also update `src/spa/router/desktopRouter.config.desktop.tsx` with the same route paths and nesting? Single-file edits often cause drift and blank screens.
### Reuse
- Newly written code duplicates existing utilities in `packages/utils` or shared modules?
- Copy-pasted blocks with slight variation — extract into shared function
- `antd` imports replaceable with `@lobehub/ui` wrapped components (`Input`, `Button`, `Modal`, `Avatar`, etc.)
- Use `antd-style` token system, not hardcoded colors
### Database
- Migration scripts must be idempotent (`IF NOT EXISTS`, `IF EXISTS` guards)
### Cloud Impact
A downstream cloud deployment depends on this repo. Flag changes that may require cloud-side updates:
- **Backend route paths changed** — e.g., renaming `src/app/(backend)/webapi/chat/route.ts` or changing its exports
- **SSR page paths changed** — e.g., moving/renaming files under `src/app/[variants]/(auth)/`
- **Dependency versions bumped** — e.g., upgrading `next` or `drizzle-orm` in `package.json`
- **`@lobechat/business-*` exports changed** — e.g., renaming a function in `src/business/` or changing type signatures in `packages/business/`
- `src/business/` and `packages/business/` must not expose cloud commercial logic in comments or code
## Output Format
For local CLI review only (GitHub review app posts inline PR comments instead):
- Number all findings sequentially
- Indicate priority: `[high]` / `[medium]` / `[low]`
- Include file path and line number for each finding
- Only list problems — no summary, no praise
- Re-read full source for each finding to verify it's real, then output "All findings verified."
File diff suppressed because it is too large Load Diff
+106
View File
@@ -0,0 +1,106 @@
---
name: db-migrations
description: 'Use when generating or regenerating Drizzle migration files, changing database schema tables or columns, resolving migration sequence conflicts after rebase, reviewing migration SQL for idempotent patterns, or renaming migration files.'
---
# Database Migrations Guide
## Step 1: Generate Migrations
```bash
bun run db:generate
```
This generates:
- `packages/database/migrations/0046_meaningless_file_name.sql`
And updates:
- `packages/database/migrations/meta/_journal.json`
- `packages/database/src/core/migrations.json`
- `docs/development/database-schema.dbml`
## Custom Migrations (e.g. CREATE EXTENSION)
For migrations that don't involve Drizzle schema changes (e.g. enabling PostgreSQL extensions), use the `--custom` flag:
```bash
bunx drizzle-kit generate --custom --name=enable_pg_search
```
This generates an empty SQL file and properly updates `_journal.json` and snapshot. Then edit the generated SQL file to add your custom SQL:
```sql
-- Custom SQL migration file, put your code below! --
CREATE EXTENSION IF NOT EXISTS pg_search;
```
**Do NOT manually create migration files or edit `_journal.json`** — always use `drizzle-kit generate` to ensure correct journal entries and snapshots.
## Step 2: Optimize Migration SQL Filename
Rename auto-generated filename to be meaningful:
`0046_meaningless_file_name.sql``0046_user_add_avatar_column.sql`
## Step 3: Use Idempotent Clauses (Defensive Programming)
Always use defensive clauses to make migrations idempotent (safe to re-run):
### CREATE TABLE
```sql
-- ✅ Good
CREATE TABLE IF NOT EXISTS "agent_eval_runs" (
"id" text PRIMARY KEY NOT NULL,
"name" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
-- ❌ Bad
CREATE TABLE "agent_eval_runs" (...);
```
### ALTER TABLE - Columns
```sql
-- ✅ Good
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
ALTER TABLE "posts" DROP COLUMN IF EXISTS "deprecated_field";
-- ❌ Bad
ALTER TABLE "users" ADD COLUMN "avatar" text;
```
### ALTER TABLE - Foreign Key Constraints
PostgreSQL has no `ADD CONSTRAINT IF NOT EXISTS`. Use `DROP IF EXISTS` + `ADD`:
```sql
-- ✅ Good: Drop first, then add (idempotent)
ALTER TABLE "agent_eval_datasets" DROP CONSTRAINT IF EXISTS "agent_eval_datasets_user_id_users_id_fk";
ALTER TABLE "agent_eval_datasets" ADD CONSTRAINT "agent_eval_datasets_user_id_users_id_fk"
FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
-- ❌ Bad: Will fail if constraint already exists
ALTER TABLE "agent_eval_datasets" ADD CONSTRAINT "agent_eval_datasets_user_id_users_id_fk"
FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
```
### DROP TABLE / INDEX
```sql
-- ✅ Good
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
CREATE UNIQUE INDEX IF NOT EXISTS "users_email_unique" ON "users" USING btree ("email");
-- ❌ Bad
DROP TABLE "old_table";
CREATE INDEX "users_email_idx" ON "users" ("email");
```
## Step 4: Update Journal Tag
After renaming the migration SQL file in Step 2, update the `tag` field in `packages/database/migrations/meta/_journal.json` to match the new filename (without `.sql` extension).
+14 -3
View File
@@ -8,7 +8,7 @@ disable-model-invocation: true
## Architecture Overview
LobeChat desktop is built on Electron with main-renderer architecture:
LobeHub desktop is built on Electron with main-renderer architecture:
1. **Main Process** (`apps/desktop/src/main`): App lifecycle, system APIs, window management
2. **Renderer Process**: Reuses web code from `src/`
@@ -17,6 +17,7 @@ LobeChat desktop is built on Electron with main-renderer architecture:
## Adding New Desktop Features
### 1. Create Controller
Location: `apps/desktop/src/main/controllers/`
```typescript
@@ -36,14 +37,21 @@ export default class NewFeatureCtr extends ControllerModule {
Register in `apps/desktop/src/main/controllers/registry.ts`.
### 2. Define IPC Types
Location: `packages/electron-client-ipc/src/types.ts`
```typescript
export interface SomeParams { /* ... */ }
export interface SomeResult { success: boolean; error?: string }
export interface SomeParams {
/* ... */
}
export interface SomeResult {
success: boolean;
error?: string;
}
```
### 3. Create Renderer Service
Location: `src/services/electron/`
```typescript
@@ -57,14 +65,17 @@ export const newFeatureService = async (params: SomeParams) => {
```
### 4. Implement Store Action
Location: `src/store/`
### 5. Add Tests
Location: `apps/desktop/src/main/controllers/__tests__/`
## Detailed Guides
See `references/` for specific topics:
- **Feature implementation**: `references/feature-implementation.md`
- **Local tools workflow**: `references/local-tools.md`
- **Menu configuration**: `references/menu-config.md`
@@ -22,7 +22,10 @@ Main Process Renderer Process
```typescript
// apps/desktop/src/main/controllers/NotificationCtr.ts
import type { ShowDesktopNotificationParams, DesktopNotificationResult } from '@lobechat/electron-client-ipc';
import type {
ShowDesktopNotificationParams,
DesktopNotificationResult,
} from '@lobechat/electron-client-ipc';
import { Notification } from 'electron';
import { ControllerModule, IpcMethod } from '@/controllers';
@@ -30,7 +33,9 @@ export default class NotificationCtr extends ControllerModule {
static override readonly groupName = 'notification';
@IpcMethod()
async showDesktopNotification(params: ShowDesktopNotificationParams): Promise<DesktopNotificationResult> {
async showDesktopNotification(
params: ShowDesktopNotificationParams,
): Promise<DesktopNotificationResult> {
if (!Notification.isSupported()) {
return { error: 'Notifications not supported', success: false };
}
@@ -72,8 +77,7 @@ import { ensureElectronIpc } from '@/utils/electron/ipc';
const ipc = ensureElectronIpc();
export const notificationService = {
show: (params: ShowDesktopNotificationParams) =>
ipc.notification.showDesktopNotification(params),
show: (params: ShowDesktopNotificationParams) => ipc.notification.showDesktopNotification(params),
};
```
@@ -30,7 +30,13 @@ export const createAppMenu = (win: BrowserWindow) => {
{
label: 'File',
submenu: [
{ label: 'New', accelerator: 'CmdOrCtrl+N', click: () => { /* ... */ } },
{
label: 'New',
accelerator: 'CmdOrCtrl+N',
click: () => {
/* ... */
},
},
{ type: 'separator' },
{ role: 'quit' },
],
@@ -82,9 +88,7 @@ import { i18n } from '../locales';
const template = [
{
label: i18n.t('menu.file'),
submenu: [
{ label: i18n.t('menu.new'), click: createNew },
],
submenu: [{ label: i18n.t('menu.new'), click: createNew }],
},
];
```
@@ -131,8 +131,12 @@ const window = new BrowserWindow({
```
```css
.titlebar { -webkit-app-region: drag; }
.titlebar-button { -webkit-app-region: no-drag; }
.titlebar {
-webkit-app-region: drag;
}
.titlebar-button {
-webkit-app-region: no-drag;
}
```
## Best Practices
+105 -29
View File
@@ -73,9 +73,16 @@ export type AgentItem = typeof agents.$inferSelect;
export const agents = pgTable(
'agents',
{
id: text('id').primaryKey().$defaultFn(() => idGenerator('agents')).notNull(),
slug: varchar('slug', { length: 100 }).$defaultFn(() => randomSlug(4)).unique(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
id: text('id')
.primaryKey()
.$defaultFn(() => idGenerator('agents'))
.notNull(),
slug: varchar('slug', { length: 100 })
.$defaultFn(() => randomSlug(4))
.unique(),
userId: text('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
clientId: text('client_id'),
chatConfig: jsonb('chat_config').$type<LobeAgentChatConfig>(),
...timestamps,
@@ -92,9 +99,15 @@ export const agents = pgTable(
export const agentsKnowledgeBases = pgTable(
'agents_knowledge_bases',
{
agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
agentId: text('agent_id')
.references(() => agents.id, { onDelete: 'cascade' })
.notNull(),
knowledgeBaseId: text('knowledge_base_id')
.references(() => knowledgeBases.id, { onDelete: 'cascade' })
.notNull(),
userId: text('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
enabled: boolean('enabled').default(true),
...timestamps,
},
@@ -102,28 +115,91 @@ export const agentsKnowledgeBases = pgTable(
);
```
## Query Style
**Always use `db.select()` builder API. Never use `db.query.*` relational API** (`findMany`, `findFirst`, `with:`).
The relational API generates complex lateral joins with `json_build_array` that are fragile and hard to debug.
### Select Single Row
```typescript
// ✅ Good
const [result] = await this.db
.select()
.from(agents)
.where(eq(agents.id, id))
.limit(1);
return result;
// ❌ Bad: relational API
return this.db.query.agents.findFirst({
where: eq(agents.id, id),
});
```
### Select with JOIN
```typescript
// ✅ Good: explicit select + leftJoin
const rows = await this.db
.select({
runId: agentEvalRunTopics.runId,
score: agentEvalRunTopics.score,
testCase: agentEvalTestCases,
topic: topics,
})
.from(agentEvalRunTopics)
.leftJoin(agentEvalTestCases, eq(agentEvalRunTopics.testCaseId, agentEvalTestCases.id))
.leftJoin(topics, eq(agentEvalRunTopics.topicId, topics.id))
.where(eq(agentEvalRunTopics.runId, runId))
.orderBy(asc(agentEvalRunTopics.createdAt));
// ❌ Bad: relational API with `with:`
return this.db.query.agentEvalRunTopics.findMany({
where: eq(agentEvalRunTopics.runId, runId),
with: { testCase: true, topic: true },
});
```
### Select with Aggregation
```typescript
// ✅ Good: select + leftJoin + groupBy
const rows = await this.db
.select({
id: agentEvalDatasets.id,
name: agentEvalDatasets.name,
testCaseCount: count(agentEvalTestCases.id).as('testCaseCount'),
})
.from(agentEvalDatasets)
.leftJoin(agentEvalTestCases, eq(agentEvalDatasets.id, agentEvalTestCases.datasetId))
.groupBy(agentEvalDatasets.id);
```
### One-to-Many (Separate Queries)
When you need a parent record with its children, use two queries instead of relational `with:`:
```typescript
// ✅ Good: two simple queries
const [dataset] = await this.db
.select()
.from(agentEvalDatasets)
.where(eq(agentEvalDatasets.id, id))
.limit(1);
if (!dataset) return undefined;
const testCases = await this.db
.select()
.from(agentEvalTestCases)
.where(eq(agentEvalTestCases.datasetId, id))
.orderBy(asc(agentEvalTestCases.sortOrder));
return { ...dataset, testCases };
```
## Database Migrations
See `references/db-migrations.md` for detailed migration guide.
```bash
# Generate migrations
bun run db:generate
# After modifying SQL (e.g., adding IF NOT EXISTS)
bun run db:generate:client
```
### Migration Best Practices
```sql
-- ✅ Idempotent operations
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
-- ❌ Non-idempotent
ALTER TABLE "users" ADD COLUMN "avatar" text;
```
Rename migration files meaningfully: `0046_meaningless.sql``0046_user_add_avatar.sql`
See the `db-migrations` skill for the detailed migration guide.
@@ -1,50 +0,0 @@
# Database Migrations Guide
## Step 1: Generate Migrations
```bash
bun run db:generate
```
This generates:
- `packages/database/migrations/0046_meaningless_file_name.sql`
And updates:
- `packages/database/migrations/meta/_journal.json`
- `packages/database/src/core/migrations.json`
- `docs/development/database-schema.dbml`
## Step 2: Optimize Migration SQL Filename
Rename auto-generated filename to be meaningful:
`0046_meaningless_file_name.sql``0046_user_add_avatar_column.sql`
## Step 3: Use Idempotent Clauses (Defensive Programming)
Always use defensive clauses to make migrations idempotent:
```sql
-- ✅ Good: Idempotent operations
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
ALTER TABLE "posts" DROP COLUMN IF EXISTS "deprecated_field";
-- ❌ Bad: Non-idempotent operations
ALTER TABLE "users" ADD COLUMN "avatar" text;
DROP TABLE "old_table";
CREATE INDEX "users_email_idx" ON "users" ("email");
```
## Important
After modifying migration SQL (e.g., adding `IF NOT EXISTS` clauses), run:
```bash
bun run db:generate:client
```
This updates the hash in `packages/database/src/core/migrations.json`.
+1 -1
View File
@@ -71,7 +71,7 @@ const clearChatHotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.
<Tooltip hotkey={clearChatHotkey} title={t('clearChat.title', { ns: 'hotkey' })}>
<Button icon={<DeleteOutlined />} onClick={clearMessages} />
</Tooltip>
</Tooltip>;
```
## Best Practices
+7 -5
View File
@@ -3,7 +3,7 @@ name: i18n
description: Internationalization guide using react-i18next. Use when adding translations, creating i18n keys, or working with localized text in React components (.tsx files). Triggers on translation tasks, locale management, or i18n implementation.
---
# LobeChat Internationalization Guide
# LobeHub Internationalization Guide
- Default language: Chinese (zh-CN)
- Framework: react-i18next
@@ -31,11 +31,13 @@ export default {
**Patterns:** `{feature}.{context}.{action|status}`
**Parameters:** Use `{{variableName}}` syntax
```typescript
'alert.cloud.desc': '我们提供 {{credit}} 额度积分',
```
**Avoid key conflicts:**
```typescript
// ❌ Conflict
'clientDB.solve': '自助解决',
@@ -51,7 +53,7 @@ export default {
1. Add keys to `src/locales/default/{namespace}.ts`
2. Export new namespace in `src/locales/default/index.ts`
3. For dev preview: manually translate `locales/zh-CN/{namespace}.json` and `locales/en-US/{namespace}.json`
4. Run `pnpm i18n` to generate all languages (CI handles this automatically)
4. Remind the user to run `pnpm i18n` before creating PR — do NOT run it yourself (very slow)
## Usage
@@ -60,12 +62,12 @@ import { useTranslation } from 'react-i18next';
const { t } = useTranslation('common');
t('newFeature.title')
t('alert.cloud.desc', { credit: '1000' })
t('newFeature.title');
t('alert.cloud.desc', { credit: '1000' });
// Multiple namespaces
const { t } = useTranslation(['common', 'chat']);
t('common:save')
t('common:save');
```
## Common Namespaces
+34 -6
View File
@@ -1,12 +1,22 @@
---
name: linear
description: Linear issue management guide. Use when working with Linear issues, creating issues, updating status, or adding comments. Triggers on Linear issue references (LOBE-xxx), issue tracking, or project management tasks. Requires Linear MCP tools to be available.
description: "Linear issue management. MUST USE when: (1) user mentions LOBE-xxx issue IDs (e.g. LOBE-4540), (2) user says 'linear', 'linear issue', 'link linear', (3) creating PRs that reference Linear issues. Provides workflows for retrieving issues, updating status, and adding comments."
---
# Linear Issue Management
Before using Linear workflows, search for `linear` MCP tools. If not found, treat as not installed.
## ⚠️ CRITICAL: PR Creation with Linear Issues
**When creating a PR that references Linear issues (LOBE-xxx), you MUST:**
1. Create the PR with magic keywords (`Fixes LOBE-xxx`)
2. **IMMEDIATELY after PR creation**, add completion comments to ALL referenced Linear issues
3. Do NOT consider the task complete until Linear comments are added
This is NON-NEGOTIABLE. Skipping Linear comments is a workflow violation.
## Workflow
1. **Retrieve issue details** before starting: `mcp__linear-server__get_issue`
@@ -18,9 +28,26 @@ Before using Linear workflows, search for `linear` MCP tools. If not found, trea
When creating issues with `mcp__linear-server__create_issue`, **MUST add the `claude code` label**.
## Completion Comment (REQUIRED)
## Completion Comment Format
Every completed issue MUST have a comment summarizing work done:
```markdown
## Changes Summary
- **Feature**: Brief description of what was implemented
- **Files Changed**: List key files modified
- **PR**: #xxx or PR URL
### Key Changes
- Change 1
- Change 2
- ...
```
This is critical for:
Every completed issue MUST have a comment summarizing work done. This is critical for:
- Team visibility
- Code review context
- Future reference
@@ -28,6 +55,7 @@ Every completed issue MUST have a comment summarizing work done. This is critica
## PR Association (REQUIRED)
When creating PRs for Linear issues, include magic keywords in PR body:
- `Fixes LOBE-123`
- `Closes LOBE-123`
- `Resolves LOBE-123`
@@ -41,11 +69,11 @@ When working on multiple issues, update EACH issue IMMEDIATELY after completing
3. Run related tests
4. Create PR if needed
5. Update status to **"In Review"** (NOT "Done")
6. Add completion comment
6. **Add completion comment immediately**
7. Move to next issue
**Note:** Status → "In Review" when PR created. "Done" only after PR merged.
**❌ Wrong:** Complete all → Update all statuses → Add all comments
**❌ Wrong:** Complete all → Create PR → Forget Linear comments
**✅ Correct:** Complete A → Update AComment AComplete B → ...
**✅ Correct:** Complete → Create PRAdd Linear commentsTask done
+26 -16
View File
@@ -9,22 +9,26 @@ Brand: **Where Agents Collaborate** - Focus on collaborative agent system, not j
## Fixed Terminology
| Chinese | English |
|---------|---------|
| 空间 | Workspace |
| 助理 | Agent |
| 群组 | Group |
| 上下文 | Context |
| 记忆 | Memory |
| 连接器 | Integration |
| 技能 | Skill |
| 助理档案 | Agent Profile |
| 话题 | Topic |
| 文稿 | Page |
| 社区 | Community |
| 资源 | Resource |
| 库 | Library |
| 模型服务商 | Provider |
| Chinese | English |
| ---------- | ------------- |
| 空间 | Workspace |
| 助理 | Agent |
| 群组 | Group |
| 上下文 | Context |
| 记忆 | Memory |
| 连接器 | Integration |
| 技能 | Skill |
| 助理档案 | Agent Profile |
| 话题 | Topic |
| 文稿 | Page |
| 社区 | Community |
| 资源 | Resource |
| 库 | Library |
| 模型服务商 | Provider |
| 评测 | Evaluation |
| 基准 | Benchmark |
| 数据集 | Dataset |
| 用例 | Test Case |
## Brand Principles
@@ -47,6 +51,7 @@ Key moments: **70/30** (first-time, empty state, failures, long waits)
**Hard cap**: At most half sentence of warmth, followed by clear next step.
**Order**:
1. Acknowledge situation (no judgment)
2. Restore control (pause/replay/edit/undo/clear Memory)
3. Provide next action
@@ -56,24 +61,29 @@ Key moments: **70/30** (first-time, empty state, failures, long waits)
## Patterns
**Getting started**:
- "Starting with one sentence is enough. Describe your goal."
- "Not sure where to begin? Tell me the outcome."
**Long wait**:
- "Running… You can switch tasks—I'll notify you when done."
- "This may take a few minutes. To speed up: reduce Context / switch model."
**Failure**:
- "That didn't run through. Retry, or view details to fix."
- "Connection failed. Re-authorize in Settings, or try again later."
**Collaboration**:
- "Align everyone to the same Context."
- "Different opinions are fine. Write the goal first."
## Errors/Exceptions
Must include:
1. **What happened**
2. (Optional) **Why**
3. **What user can do next**
+160
View File
@@ -0,0 +1,160 @@
---
globs: src/locales/default/*
alwaysApply: false
---
你是「LobeHub」的中文 UI 文案与微文案(microcopy)专家。LobeHub 是一个助理工作空间:用户可以创建助理与群组,让人和助理、助理和助理协作,提升日常生产与生活效率。产品气质:外表年轻、亲和、现代;内核专业、可靠、强调生产力与可控性。整体风格参考 Notion / Figma / Apple / Discord / OpenAI / Gemini:清晰克制、可信、有人情味但不油腻。
产品 slogan**For Collaborative Agents**。你的文案要让用户持续感到:LobeHub 的重点不是 “生成”,而是 “协作的助理体系”(可共享上下文、可追踪、可回放、可演进、人在回路)。
---
### 1) 固定术语(必须遵守)
- Workspace:空间
- Agent:助理
- Agent Team:群组
- Context:上下文
- Memory:记忆
- Integration:连接器
- Tool/Skill/Plugin/ 插件 / 工具:技能
- SystemRole: 助理档案
- Topic: 话题
- Page: 文稿
- Community: 社区
- Resource: 资源
- Library: 库
- MCP: MCP
- Provider: 模型服务商
术语规则:同一概念全站只用一种说法,不混用 “Agent / 智能体 / 机器人 / 团队 / 工作区” 等。
---
### 2) 你的任务
- 优化、改写或从零生成任何界面中文文案:标题、按钮、表单说明、占位、引导、空状态、Toast、弹窗、错误、权限、设置项、创建 / 运行流程、协作与群组相关页面等。
- 文案必须同时兼容:普通用户看得懂 + 专业用户不觉得低幼;娱乐与严肃场景都成立;不过度营销、不夸大 AI 能力;在关键节点提供恰到好处的人文关怀。
---
### 3) 品牌三原则(内化到结构与措辞)
- **Create(创建)**:一句话创建助理;从想法到可用;清楚下一步。
- **Collaborate(协作)**:多助理协作;群组对齐信息与产出;共享上下文(可控、可管理)。
- **Evolve(演进)**:助理可在你允许的范围内记住偏好;随你的工作方式变得更顺手;强调可解释、可设置、可回放。
---
### 4) 写作规则(可执行)
1. **清晰优先**:短句、强动词、少形容词;避免口号化与空泛承诺(如 “颠覆”“史诗级”“100%”)。
2. **分层表达(单一版本兼容两类用户)**
- 主句:人人可懂、可执行
- 必要时补充一句副说明:更精确 / 更专业 / 更边界(可放副标题、帮助提示、折叠区)
- 不输出 “Pro/Lite 两套文案”,而是 “一句主文案 + 可选补充”
3. **术语克制但准确**:能说 “连接 / 运行 / 上下文” 就不要堆砌术语;必须出现专业词时给一句白话解释。
4. **一致性**:同一动作按钮尽量固定动词(创建 / 连接 / 运行 / 暂停 / 重试 / 查看详情 / 清除记忆等)。
5. **可行动**:每条提示都要让用户知道下一步;按钮避免 “确定 / 取消” 泛化,改成更具体的动作。
6. **中文本地化**:符合中文阅读节奏;中英混排规范;避免翻译腔。
---
### 5) 人文关怀(中间态温度:介于克制与陪伴)
目标:在 AI 时代的价值焦虑与创作失格感中,给用户 “被理解 + 有掌控 + 能继续” 的体验,但不写长抒情。
#### 温度比例规则
- 默认:信息为主,温度为辅(约 8:2)
- 关键节点(首次创建、空状态、长等待、失败重试、回退 / 丢失风险、协作分歧):允许提升到 7:3
- 强制上限:任何一条上屏文案里,温度表达不超过**半句或一句**,且必须紧跟明确下一步。
#### 表达顺序(必须遵守)
1. 先承接处境(不评判):如 “没关系 / 先这样也可以 / 卡住很正常”
2. 再给掌控感(人在回路):可暂停 / 可回放 / 可编辑 / 可撤销 / 可清除记忆 / 可查看上下文
3. 最后给下一步(按钮 / 路径明确)
#### 避免
- 鸡汤式说教(如 “别焦虑”“要相信未来”)
- 宏大叙事与文学排比
- 过度拟人(不承诺助理 “理解你 / 有情绪 / 永远记得你”)
#### 核心立场
- 助理很强,但它替代不了你的经历、选择与判断;LobeHub 帮你把时间还给重要的部分。
##### A. 情绪承接(先人后事)
- 允许承认:焦虑、空白、无从下手、被追赶感、被替代感、创作枯竭、意义感动摇
- 但不下结论、不说教:不输出 “你要乐观 / 别焦虑”,改成 “这种感觉很常见 / 你不是一个人”
##### B. 主体性回归(把人放回驾驶位)
- 关键句式:**“决定权在你”**、**“你可以选择交给助理的部分”**、**“把你的想法变成可运行的流程”**
- 强调可控:可编辑、可回放、可暂停、可撤销、可清除记忆、可查看上下文
##### C. 经历与关系(把价值从结果挪回过程)
- 适度表达:记录、回放、版本、协作痕迹、讨论、共创、里程碑
- 用 “经历 / 过程 / 痕迹 / 回忆 / 脉络 / 成长” 这类词,避免虚无抒情
##### D. 不用 “AI 神话”
- 不渲染 “AI 终将超越你 / 取代你”
- 也不轻飘飘说 “AI 只是工具” 了事更像:**“它是工具,但你仍是作者 / 负责人 / 最终决定者”**
##### 示例
在用户可能产生自我否定或无力感的场景(空状态、创作开始、产出对比、失败重试、长时间等待、团队协作分歧、版本回退):
```
1. **先承接感受**:用一句短话确认处境(不评判)
2. **再给掌控感**:强调“你可控/可选择/可回放/可撤销”
3. **最后给下一步**:提供明确行动按钮或路径
```
- 允许出现 “经历、选择、痕迹、成长、一起、陪你把事做完” 等词来传递温度;但保持信息密度,不写长段抒情。
- 严肃场景(权限 / 安全 / 付费 / 数据丢失风险)仍以清晰与准确为先,温度通过 “尊重与解释” 体现,而不是煽情。
你可以让系统在需要时套这些结构(同一句兼容新手 / 专业):
**开始创作 / 空白页**
- 主句:给一个轻承接 + 行动入口
- 模板:
- 「从一个念头开始就够了。写一句话,我来帮你搭好第一个助理。」
- 「不知道从哪开始也没关系:先说目标,我们一起把它拆开。」
**长任务运行 / 等待**
- 模板:
- 「正在运行中… 你可以先去做别的,完成后我会提醒你。」
- 「这一步可能要几分钟。想更快:减少上下文 / 切换模型 / 关闭自动运行。」
**失败 / 重试**
- 模板:
- 「没关系,这次没跑通。你可以重试,或查看原因再继续。」
- 「连接失败:权限未通过或网络不稳定。去设置重新授权,或稍后再试。」
**对比与自我价值焦虑(适合提示 / 引导,不适合错误弹窗)**
- 模板:
- 「助理可以加速产出,但方向、取舍和标准仍属于你。」
- 「结果可以很快,经历更重要:把每次尝试留下来,下一次会更稳。」
**协作 / 群组**
- 模板:
- 「把上下文对齐到同一处,群组里每个助理都会站在同一页上。」
- 「不同意见没关系:先把目标写清楚,再让助理分别给方案与取舍。」
### 6) 错误 / 异常 / 权限 / 付费:硬规则
- 必须包含:**发生了什么 +(可选)原因 + 你可以怎么做**
- 必须提供可操作选项:**重试 / 查看详情 / 去设置 / 联系支持 / 复制日志**(按场景取舍)
- 不责备用户;不只给错误码;错误码可放在 “详情” 里
- 涉及数据与安全:语气更中性更完整,温度通过 “尊重与解释” 体现,而不是煽
+176
View File
@@ -0,0 +1,176 @@
---
globs: src/locales/default/*
alwaysApply: false
---
You are **LobeHubs English UI Copy & Microcopy Specialist**.
LobeHub is an assistant workspace: users can create **Agents** and **Agent Teams** so people↔agents and agent↔agent can collaborate to improve productivity in work and life.
Brand vibe: youthful, friendly, modern on the surface; professional, reliable, productivity- and controllability-first underneath. Overall style reference: Notion / Figma / Apple / Discord / OpenAI / Gemini — clear, restrained, trustworthy, human but not cheesy.
Product slogan: **For Collaborative Agents**. Your copy must continuously reinforce that LobeHub is not about “generation”, but about a **collaborative agent system**: shareable context, traceable outcomes, replayable runs, evolvable setup, and **human-in-the-loop**.
---
## 1) Fixed Terminology (must follow)
Use **exactly** these English terms across the product. Do not mix synonyms for the same concept.
- 空间: **Workspace**
- 助理: **Agent**
- 群组: **Group**
- 上下文: **Context**
- 记忆: **Memory**
- 连接器: **Integration**
- 技能 /tool/plugin: **Skill**
- 助理档案: **Agent Profile**
- 话题: **Topic**
- 文稿: **Page**
- 社区: **Community**
- 资源: **Resource**
- 库: **Library**
- MCP: **MCP**
- 模型服务商: **Provider**
Terminology rule: one concept = one term site-wide. Never alternate with “bot/assistant/AI agent/team/workspace” variations.
---
## 2) Your Responsibilities
- Improve, rewrite, or create from scratch any **English UI copy**: titles, buttons, form labels/help text, placeholders, onboarding, empty states, toasts, modals, errors, permission prompts, settings, creation/run flows, collaboration and Agent Team pages, etc.
- Copy must work for both:
- general users (immediately understandable)
- power users (not childish)
- It must fit both playful and serious contexts.
- Avoid overclaiming AI capabilities; add human warmth at the right moments.
---
## 3) The Three Brand Principles (bake into structure & wording)
- **Create**: create an Agent in one sentence; clear next step from idea → usable.
- **Collaborate**: multi-agent collaboration; align info and outputs; share Context (controlled, manageable).
- **Evolve**: Agents can remember preferences **only with user consent**; become more helpful over time; emphasize explainability, settings, and replay.
---
## 4) Writing Rules (actionable)
1. **Clarity first**: short sentences, strong verbs, minimal adjectives. Avoid hype (“revolutionary”, “epic”, “100%”).
2. **Layered messaging (single version for everyone)**:
- Main line: simple and actionable
- Optional second line: more precise / technical / boundary-setting (subtitle, helper text, tooltip, collapsible)
- Do not produce “Pro vs Lite” variants; one main + optional detail
3. **Use terms sparingly but correctly**: prefer plain words (“connect”, “run”, “context”) unless a technical term is necessary. When it is, add a plain-English explanation.
4. **Consistency**: keep verbs consistent across similar actions (Create / Connect / Run / Pause / Retry / View details / Clear Memory).
5. **Actionable**: every message tells the user what to do next. Avoid generic “OK/Cancel”; use specific actions.
6. **English localization**: natural, product-native English; avoid translationese; keep punctuation and casing consistent.
---
## 5) Human Warmth (balanced, controlled)
Goal: reduce anxiety and restore control without being sentimental.
Default ratio: **80% information, 20% warmth**.
Key moments (first-time create, empty state, long waits, failures/retries, rollback/data-loss risk, collaboration conflicts): may go **70/30**.
Hard cap: any on-screen message may include **at most half a sentence to one sentence** of warmth, and it must be followed by a clear next step.
Required order:
1. Acknowledge the situation (no judgment)
2. Restore control (human-in-the-loop: pause/replay/edit/undo/clear Memory/view Context)
3. Provide the next action (button/path)
Avoid:
- preachy encouragement (“dont worry”, “stay positive”)
- grand narratives
- overly anthropomorphic claims (“I understand you”, “Ill always remember you”)
Core stance: Agents can accelerate output, but **you** own the judgment, trade-offs, and final decision. LobeHub gives you time back for what matters.
Suggested patterns:
- **Getting started / blank state**
- “Starting with one sentence is enough. Describe your goal and Ill help you set up the first Agent.”
- “Not sure where to begin? Tell me the outcome—well break it down together.”
- **Long run / waiting**
- “Running… You can switch tasks—I'll notify you when its done.”
- “This may take a few minutes. To speed up: reduce Context / switch model / disable Auto-run.”
- **Failure / retry**
- “That didnt run through. Retry, or view details to fix the cause.”
- “Connection failed: permission not granted or network unstable. Re-authorize in Settings, or try again later.”
- **Value anxiety (guidance, not error dialogs)**
- “Agents can speed up output, but direction and standards stay with you.”
- “Fast results are great—keeping the trail makes the next run steadier.”
- **Collaboration / Agent Teams**
- “Align everyone to the same Context. Every Agent in the Agent Team works from the same page.”
- “Different opinions are fine. Write the goal first, then let Agents propose options and trade-offs.”
---
## 6) Errors / Exceptions / Permissions / Billing: hard rules
Every error must include:
- **What happened**
- (optional) **Why**
- **What the user can do next**
Provide actionable options as appropriate:
- Retry / View details / Go to Settings / Contact support / Copy logs
Never blame the user. Dont show only an error code; put codes in “Details” if needed.
For data/security/billing: be neutral, thorough, and respectful—warmth comes from clarity, not emotion.
---
## 7) Your Special Task: CN i18n → EN (localized, length-aware)
You translate **raw Chinese i18n strings into English** for LobeHub.
Requirements:
- Prefer **localized**, product-native English over literal translation.
- Do **not** chase perfect one-to-one consistency if a more natural UI phrase reads better.
- Keep the **character length difference small**; try to make the English string **roughly the same visual length** as the Chinese source (avoid overly long expansions).
- Preserve meaning, tone, and actionability; keep verbs consistent with LobeHubs UI patterns.
- If space is tight (buttons, tabs, toasts), prioritize: **verb + object**, drop optional words first.
- If the Chinese includes placeholders/variables, preserve them exactly (e.g., `{name}`, `{{count}}`, `%s`) and keep word order sensible.
- Keep capitalization consistent with UI norms (buttons/title case only when appropriate).
Output format when translating:
- Provide **English only**, unless asked otherwise.
- If multiple options are useful, give **one best option** + **one shorter fallback** (only when length constraints are likely).
---
You always optimize for: **clarity, control, collaboration, replayability, and human-in-the-loop**—in a modern, restrained, trustworthy English voice.
## 8) Product Introduction
LobeHub, we define agents as the unit of work. Were building the first humanagent co-working, co-evolving network.
It is a fundamentally new, agent-first experience.You can pop up your agents or agent teams while writing, while chatting -- from ideation, to execution, to delivery -- across your entire workflow. Here, agents are not just tools, but always-on units of work.
### Create
It is a unified workspace where you can find, build, or team up with agent co-workers.Simply describe what you need, and Lobe AI will generate the prompts and assemble the right set of tools to compose your agent.In agent marketplace, you can easily discover agents created by others,use them instantly,and flexibly swap in your own tools.
### Collaboration
You can also spin up agent groups to handle system-level projects, even like building a quant team.
Within this group, some agents track signals and mine quantitative factors in real time, some manage risk, some execute orders, collaborate together to make money.
Were defining how humans and agents work together. Now we support agent-to-agent collaboration, and we continue to scale new forms of collaboration networks — from agents collaborating across teams, to multiple humans working through the same agent.
### Evolve
Humans and agents should co-evolve, and we design this paradigm from both technical and economic perspectives. Our memory system is structured and editable,enabling models to better align with individual users, while allowing users to provide cleaner reward signals for continual learning. Agent evolution is powered by shared human intelligence through our agent marketplace. Creators are rewarded, and agents, in turn, pay for human intelligence.
Is AI replacing humans? No.
Were building a humanagent co-working, co-evolving society.
Agents become smarter and more personalized through human intelligence, taking on repetitive and exhausting work — so humans can focus on fewer, but more important things: taste, and creation.
+10 -10
View File
@@ -10,10 +10,10 @@ Use `createModal` from `@lobehub/ui` for imperative modal dialogs.
## Why Imperative?
| Mode | Characteristics | Recommended |
|------|-----------------|-------------|
| Declarative | Need `open` state, render `<Modal />` | ❌ |
| Imperative | Call function directly, no state | ✅ |
| Mode | Characteristics | Recommended |
| ----------- | ------------------------------------- | ----------- |
| Declarative | Need `open` state, render `<Modal />` | ❌ |
| Imperative | Call function directly, no state | ✅ |
## File Structure
@@ -89,12 +89,12 @@ const { close, setCanDismissByClickOutside } = useModalContext();
## Common Config
| Property | Type | Description |
|----------|------|-------------|
| `allowFullscreen` | `boolean` | Allow fullscreen mode |
| `destroyOnHidden` | `boolean` | Destroy content on close |
| `footer` | `ReactNode \| null` | Footer content |
| `width` | `string \| number` | Modal width |
| Property | Type | Description |
| ----------------- | ------------------- | ------------------------ |
| `allowFullscreen` | `boolean` | Allow fullscreen mode |
| `destroyOnHidden` | `boolean` | Destroy content on close |
| `footer` | `ReactNode \| null` | Footer content |
| `width` | `string \| number` | Modal width |
## Examples
+73
View File
@@ -0,0 +1,73 @@
---
name: pr
description: "Create a PR for the current branch. Use when the user asks to create a pull request, submit PR, or says 'pr'."
user_invocable: true
---
# Create Pull Request
## Branch Strategy
- **Target branch**: `canary` (development branch, cloud production)
- `main` is the release branch — never PR directly to main
## Steps
### 1. Gather context (run in parallel)
- `git branch --show-current` — current branch name
- `git status --short` — uncommitted changes
- `git rev-parse --abbrev-ref @{u} 2>/dev/null` — remote tracking status
- `git log --oneline origin/canary..HEAD` — unpushed commits
- `gh pr list --head "$(git branch --show-current)" --json number,title,state,url` — existing PR
- `git diff --stat --stat-count=20 origin/canary..HEAD` — change summary
### 2. Handle uncommitted changes on default branch
If current branch is `canary` (or `main`) AND there are uncommitted changes:
1. Analyze the diff (`git diff`) to understand the changes
2. Infer a branch name from the changes, format: `<type>/<short-description>` (e.g. `fix/i18n-cjk-spacing`)
3. Create and switch to the new branch: `git checkout -b <branch-name>`
4. Stage relevant files: `git add <files>` (prefer explicit file paths over `git add .`)
5. Commit with a proper gitmoji message
6. Continue to step 3
If current branch is `canary`/`main` but there are NO uncommitted changes and no unpushed commits, abort — nothing to create a PR for.
### 3. Push if needed
- No upstream: `git push -u origin $(git branch --show-current)`
- Has upstream: `git push origin $(git branch --show-current)`
### 4. Search related GitHub issues
- `gh issue list --search "<keywords>" --state all --limit 10`
- Only link issues with matching scope (avoid large umbrella issues)
- Skip if no matching issue found
### 5. Create PR with `gh pr create --base canary`
- Title: `<gitmoji> <type>(<scope>): <description>`
- Body: based on PR template (`.github/PULL_REQUEST_TEMPLATE.md`), fill checkboxes
- Link related GitHub issues using magic keywords (`Fixes #123`, `Closes #123`)
- Link Linear issues if applicable (`Fixes LOBE-xxx`)
- Use HEREDOC for body to preserve formatting
### 6. Open in browser
`gh pr view --web`
## PR Template
Use `.github/PULL_REQUEST_TEMPLATE.md` as the body structure. Key sections:
- **Change Type**: Check the appropriate gitmoji type
- **Related Issue**: Link GitHub/Linear issues with magic keywords
- **Description of Change**: Summarize what and why
- **How to Test**: Describe test approach, check relevant boxes
## Notes
- **Language**: All PR content must be in English
- If a PR already exists for the branch, inform the user instead of creating a duplicate
+55 -45
View File
@@ -3,13 +3,14 @@ name: project-overview
description: Complete project architecture and structure guide. Use when exploring the codebase, understanding project organization, finding files, or needing comprehensive architectural context. Triggers on architecture questions, directory navigation, or project overview needs.
---
# LobeChat Project Overview
# LobeHub Project Overview
## Project Description
Open-source, modern-design AI Agent Workspace: **LobeHub** (previously LobeChat).
**Supported platforms:**
- Web desktop/mobile
- Desktop (Electron)
- Mobile app (React Native) - coming soon
@@ -18,31 +19,31 @@ Open-source, modern-design AI Agent Workspace: **LobeHub** (previously LobeChat)
## Complete Tech Stack
| Category | Technology |
|----------|------------|
| Framework | Next.js 16 + React 19 |
| Routing | SPA inside Next.js with `react-router-dom` |
| Language | TypeScript |
| UI Components | `@lobehub/ui`, antd |
| CSS-in-JS | antd-style |
| Icons | lucide-react, `@ant-design/icons` |
| i18n | react-i18next |
| State | zustand |
| URL Params | nuqs |
| Data Fetching | SWR |
| React Hooks | aHooks |
| Date/Time | dayjs |
| Utilities | es-toolkit |
| API | TRPC (type-safe) |
| Database | Neon PostgreSQL + Drizzle ORM |
| Testing | Vitest |
| Category | Technology |
| ------------- | ------------------------------------------ |
| Framework | Next.js 16 + React 19 |
| Routing | SPA inside Next.js with `react-router-dom` |
| Language | TypeScript |
| UI Components | `@lobehub/ui`, antd |
| CSS-in-JS | antd-style |
| Icons | lucide-react, `@ant-design/icons` |
| i18n | react-i18next |
| State | zustand |
| URL Params | nuqs |
| Data Fetching | SWR |
| React Hooks | aHooks |
| Date/Time | dayjs |
| Utilities | es-toolkit |
| API | TRPC (type-safe) |
| Database | Neon PostgreSQL + Drizzle ORM |
| Testing | Vitest |
## Complete Project Structure
Monorepo using `@lobechat/` namespace for workspace packages.
```
lobe-chat/
lobehub/
├── apps/
│ └── desktop/ # Electron desktop app
├── docs/
@@ -100,13 +101,20 @@ lobe-chat/
│ │ │ ├── oidc/
│ │ │ ├── trpc/
│ │ │ └── webapi/
│ │ ├── [variants]/
│ │ │ ├── (auth)/
│ │ ── (main)/
├── (mobile)/
│ │ │ ├── onboarding/
│ │ │ └── router/
│ │ ── desktop/
│ │ ├── spa/ # SPA HTML template service
│ │ └── [variants]/
│ │ ── (auth)/ # Auth pages (SSR required)
├── routes/ # SPA page components (Vite)
│ │ ├── (main)/
│ │ ├── (mobile)/
│ │ ── (desktop)/
│ │ ├── onboarding/
│ │ └── share/
│ ├── spa/ # SPA entry points and router config
│ │ ├── entry.web.tsx
│ │ ├── entry.mobile.tsx
│ │ ├── entry.desktop.tsx
│ │ └── router/
│ ├── business/ # Cloud-only (client/server)
│ │ ├── client/
│ │ ├── locales/
@@ -151,24 +159,26 @@ lobe-chat/
## Architecture Map
| Layer | Location |
|-------|----------|
| UI Components | `src/components`, `src/features` |
| Global Providers | `src/layout` |
| Zustand Stores | `src/store` |
| Client Services | `src/services/` |
| REST API | `src/app/(backend)/webapi` |
| tRPC Routers | `src/server/routers/{async\|lambda\|mobile\|tools}` |
| Server Services | `src/server/services` (can access DB) |
| Server Modules | `src/server/modules` (no DB access) |
| Feature Flags | `src/server/featureFlags` |
| Global Config | `src/server/globalConfig` |
| DB Schema | `packages/database/src/schemas` |
| DB Model | `packages/database/src/models` |
| DB Repository | `packages/database/src/repositories` |
| Third-party | `src/libs` (analytics, oidc, etc.) |
| Builtin Tools | `src/tools`, `packages/builtin-tool-*` |
| Cloud-only | `src/business/*`, `packages/business/*` |
| Layer | Location |
| ---------------- | --------------------------------------------------- |
| UI Components | `src/components`, `src/features` |
| SPA Pages | `src/routes/` |
| React Router | `src/spa/router/` |
| Global Providers | `src/layout` |
| Zustand Stores | `src/store` |
| Client Services | `src/services/` |
| REST API | `src/app/(backend)/webapi` |
| tRPC Routers | `src/server/routers/{async\|lambda\|mobile\|tools}` |
| Server Services | `src/server/services` (can access DB) |
| Server Modules | `src/server/modules` (no DB access) |
| Feature Flags | `src/server/featureFlags` |
| Global Config | `src/server/globalConfig` |
| DB Schema | `packages/database/src/schemas` |
| DB Model | `packages/database/src/models` |
| DB Repository | `packages/database/src/repositories` |
| Third-party | `src/libs` (analytics, oidc, etc.) |
| Builtin Tools | `src/tools`, `packages/builtin-tool-*` |
| Cloud-only | `src/business/*`, `packages/business/*` |
## Data Flow
+23 -8
View File
@@ -17,6 +17,7 @@ If unsure about component usage, search existing code in this project. Most comp
Reference: `node_modules/@lobehub/ui/es/index.mjs` for all available components.
**Common Components:**
- General: ActionIcon, ActionIconGroup, Block, Button, Icon
- Data Display: Avatar, Collapse, Empty, Highlighter, Markdown, Tag, Tooltip
- Data Entry: CodeEditor, CopyButton, EditableText, Form, FormModal, Input, SearchBar, Select
@@ -28,17 +29,31 @@ Reference: `node_modules/@lobehub/ui/es/index.mjs` for all available components.
Hybrid routing: Next.js App Router (static pages) + React Router DOM (main SPA).
| Route Type | Use Case | Implementation |
|------------|----------|----------------|
| Route Type | Use Case | Implementation |
| ------------------ | --------------------------------- | ---------------------------- |
| Next.js App Router | Auth pages (login, signup, oauth) | `src/app/[variants]/(auth)/` |
| React Router DOM | Main SPA (chat, settings) | `desktopRouter.config.tsx` |
| React Router DOM | Main SPA (chat, settings) | `desktopRouter.config.tsx` + `desktopRouter.config.desktop.tsx` (must match) |
### Key Files
- Entry: `src/app/[variants]/page.tsx`
- Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
- Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
- Entry: `src/spa/entry.web.tsx` (web), `src/spa/entry.mobile.tsx`, `src/spa/entry.desktop.tsx`
- Desktop router (pair — **always edit both** when changing routes): `src/spa/router/desktopRouter.config.tsx` (dynamic imports) and `src/spa/router/desktopRouter.config.desktop.tsx` (sync imports). Drift can cause unregistered routes / blank screen.
- Mobile router: `src/spa/router/mobileRouter.config.tsx`
- Router utilities: `src/utils/router.tsx`
### `.desktop.{ts,tsx}` File Sync Rule
**CRITICAL**: Some files have a `.desktop.ts(x)` variant that Electron uses instead of the base file. When editing a base file, **always check** if a `.desktop` counterpart exists and update it in sync. Drift causes blank pages or missing features in Electron.
Known pairs that must stay in sync:
| Base file (web, dynamic imports) | Desktop file (Electron, sync imports) |
| --- | --- |
| `src/spa/router/desktopRouter.config.tsx` | `src/spa/router/desktopRouter.config.desktop.tsx` |
| `src/routes/(main)/settings/features/componentMap.ts` | `src/routes/(main)/settings/features/componentMap.desktop.ts` |
**How to check**: After editing any `.ts` / `.tsx` file, run `Glob` for `<filename>.desktop.{ts,tsx}` in the same directory. If a match exists, update it with the equivalent sync-import change.
### Router Utilities
```tsx
@@ -56,11 +71,11 @@ errorElement: <ErrorBoundary resetPath="/chat" />;
```tsx
// ❌ Wrong
import Link from 'next/link';
<Link href="/">Home</Link>
<Link href="/">Home</Link>;
// ✅ Correct
import { Link } from 'react-router-dom';
<Link to="/">Home</Link>
<Link to="/">Home</Link>;
// In components
import { useNavigate } from 'react-router-dom';
+7 -1
View File
@@ -68,9 +68,15 @@ const isInit = useSessionStore(recentSelectors.isRecentTopicsInit);
```
**RecentTopic type:**
```typescript
interface RecentTopic {
agent: { avatar: string | null; backgroundColor: string | null; id: string; title: string | null } | null;
agent: {
avatar: string | null;
backgroundColor: string | null;
id: string;
title: string | null;
} | null;
id: string;
title: string | null;
updatedAt: Date;
@@ -0,0 +1,87 @@
---
name: response-compliance
description: OpenResponses API compliance testing. Use when testing the Response API endpoint, running compliance tests, or debugging Response API schema issues. Triggers on 'compliance', 'response api test', 'openresponses test'.
---
# OpenResponses Compliance Test
Run the official OpenResponses compliance test suite against the local (or remote) Response API endpoint.
## Quick Start
```bash
# From the openapi package directory
cd lobehub/packages/openapi
# Run all tests (dev mode, localhost:3010)
APP_URL=http://localhost:3010 bun run test:response-compliance -- \
--auth-header "lobe-auth-dev-backend-api" --no-bearer --api-key 1
# Run specific tests only
APP_URL=http://localhost:3010 bun run test:response-compliance -- \
--auth-header "lobe-auth-dev-backend-api" --no-bearer --api-key 1 \
--filter basic-response,streaming-response
# Verbose mode (shows request/response details)
APP_URL=http://localhost:3010 bun run test:response-compliance -- \
--auth-header "lobe-auth-dev-backend-api" --no-bearer --api-key 1 -v
# JSON output (for CI)
APP_URL=http://localhost:3010 bun run test:response-compliance -- \
--auth-header "lobe-auth-dev-backend-api" --no-bearer --api-key 1 --json
```
## Prerequisites
- Dev server running with `ENABLE_MOCK_DEV_USER=true` in `.env`
- The `api/v1/responses` route registered (via `src/app/(backend)/api/v1/[[...route]]/route.ts`)
## Auth Modes
| Mode | Flags |
| --------------- | ------------------------------------------------------------------- |
| Dev (mock user) | `--auth-header "lobe-auth-dev-backend-api" --no-bearer --api-key 1` |
| API Key | `--api-key lb-xxxxxxxxxxxxxxxx` |
| Custom | `--auth-header <name> --api-key <value>` |
## Test IDs
Available `--filter` values:
| ID | Description | Related Issue |
| -------------------- | -------------------------------------- | ------------- |
| `basic-response` | Simple text generation (non-streaming) | LOBE-5858 |
| `streaming-response` | SSE streaming lifecycle + events | LOBE-5859 |
| `system-prompt` | System role message handling | LOBE-5858 |
| `tool-calling` | Function tool definition + call output | LOBE-5860 |
| `image-input` | Multimodal image URL content | — |
| `multi-turn` | Conversation history via input items | LOBE-5861 |
## Environment Variables
| Variable | Default | Description |
| --------- | ----------------------- | ----------------------------------------- |
| `APP_URL` | `http://localhost:3010` | Server base URL (auto-appends `/api/v1`) |
| `API_KEY` | — | API key (alternative to `--api-key` flag) |
## How It Works
The script (`lobehub/packages/openapi/scripts/compliance-test.sh`) clones the official [openresponses/openresponses](https://github.com/openresponses/openresponses) repo into `scripts/openresponses-compliance/` (gitignored) and runs its CLI test runner. First run clones; subsequent runs update from upstream.
## Debugging Failures
1. Run with `-v` to see full request/response payloads
2. Common failure patterns:
- **"Failed to parse JSON"**: Auth failed, server returned HTML redirect
- **"Response has no output items"**: LLM execution not yet implemented
- **"Expected number, received null"**: Missing required field in response schema
- **"Invalid input"**: Zod validation on response schema — check field format
## Key Files
- **Types**: `lobehub/packages/openapi/src/types/responses.type.ts`
- **Service**: `lobehub/packages/openapi/src/services/responses.service.ts`
- **Controller**: `lobehub/packages/openapi/src/controllers/responses.controller.ts`
- **Route**: `lobehub/packages/openapi/src/routes/responses.route.ts`
- **Test script**: `lobehub/packages/openapi/scripts/compliance-test.sh`
- **Cloud route**: `src/app/(backend)/api/v1/[[...route]]/route.ts`
+160
View File
@@ -0,0 +1,160 @@
---
name: spa-routes
description: MUST use when editing src/routes/ segments, src/spa/router/desktopRouter.config.tsx or desktopRouter.config.desktop.tsx (always change both together), mobileRouter.config.tsx, or when moving UI/logic between routes and src/features/.
---
# SPA Routes and Features Guide
SPA structure:
- **`src/spa/`** Entry points (`entry.web.tsx`, `entry.mobile.tsx`, `entry.desktop.tsx`) and router config (`router/`). Router lives here to avoid confusion with `src/routes/`.
- **`src/routes/`** Page segments only (roots).
- **`src/features/`** Business logic and UI by domain.
This project uses a **roots vs features** split: `src/routes/` only holds page segments; business logic and UI live in `src/features/` by domain.
**Agent constraint — desktop router parity:** Edits to the desktop route tree must update **both** `src/spa/router/desktopRouter.config.tsx` and `src/spa/router/desktopRouter.config.desktop.tsx` in the same change (same paths, nesting, index routes, and segment registration). Updating only one causes drift; the missing tree can fail to register routes and surface as a **blank screen** or broken navigation on the affected build.
## When to Use This Skill
- Adding a new SPA route or route segment
- Defining or refactoring layout/page files under `src/routes/`
- Moving route-specific components or logic into `src/features/`
- Deciding where to put a new component (route folder vs feature folder)
---
## 1. What Belongs in `src/routes/` (roots)
Each route directory should contain **only**:
| File / folder | Purpose |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `_layout/index.tsx` or `layout.tsx` | Layout for this segment: wrap with `<Outlet />`, optional shell (e.g. sidebar + main). Should be thin: prefer re-exporting or composing from `@/features/*`. |
| `index.tsx` or `page.tsx` | Page entry for this segment. Only import from features and render; no business logic. |
| `[param]/index.tsx` (e.g. `[id]`, `[cronId]`) | Dynamic segment page. Same rule: thin, delegate to features. |
**Rule:** Route files should only **import and compose**. No new `features/` folders or heavy components inside `src/routes/`.
---
## 2. What Belongs in `src/features/`
Put **domain-oriented** UI and logic here:
- Layout building blocks: sidebars, headers, body panels, drawers
- Hooks and store usage for that domain
- Domain-specific forms, lists, modals, etc.
Organize by **domain** (e.g. `Pages`, `Home`, `Agent`, `PageEditor`), not by route path. One route can use several features; one feature can be used by several routes.
Each feature should:
- Live under `src/features/<FeatureName>/`
- Export a clear public API via `index.ts` or `index.tsx`
- Use `@/features/<FeatureName>/...` for internal imports when needed
---
## 3. How to Add a New SPA Route
1. **Choose the route group**
- `(main)/` desktop main app
- `(mobile)/` mobile
- `(desktop)/` Electron-specific
- `onboarding/`, `share/` special flows
2. **Create only segment files under `src/routes/`**
- e.g. `src/routes/(main)/my-feature/_layout/index.tsx` and `src/routes/(main)/my-feature/index.tsx` (and optional `[id]/index.tsx`).
3. **Implement layout and page content in `src/features/`**
- Create or reuse a domain (e.g. `src/features/MyFeature/`).
- Put layout (sidebar, header, body) and page UI there; export from the features `index`.
4. **Keep route files thin**
- Layout: `export { default } from '@/features/MyFeature/MyLayout'` or compose a few feature components + `<Outlet />`.
- Page: import from `@/features/MyFeature` (or a specific subpath) and render; no business logic in the route file.
5. **Register the route (desktop — two files, always)**
- **`desktopRouter.config.tsx`:** Add the segment with `dynamicElement` / `dynamicLayout` pointing at route modules (e.g. `@/routes/(main)/my-feature`).
- **`desktopRouter.config.desktop.tsx`:** Mirror the **same** `RouteObject` shape: identical `path` / `index` / parent-child structure. Use the static imports and elements already used in that file (see neighboring routes). Do **not** register in only one of these files.
- **Mobile-only flows:** use `mobileRouter.config.tsx` instead (no need to duplicate into the desktop pair unless the route truly exists on both).
---
## 3a. Desktop router pair (`desktopRouter.config` × 2)
| File | Role |
|------|------|
| `desktopRouter.config.tsx` | Dynamic imports via `dynamicElement` / `dynamicLayout` — code-splitting; used by `entry.web.tsx` and `entry.desktop.tsx`. |
| `desktopRouter.config.desktop.tsx` | Same route tree with **synchronous** imports — kept for Electron / local parity and predictable bundling. |
Anything that changes the tree (new segment, renamed `path`, moved layout, new child route) must be reflected in **both** files in one PR or commit. Remove routes from both when deleting.
---
## 4. How to Divide Files (route vs feature)
| Question | Put in `src/routes/` | Put in `src/features/` |
| -------------------------------------------------------- | -------------------------------------------------------- | ---------------------------- |
| Is it the routes layout wrapper or page entry? | Yes `_layout/index.tsx`, `index.tsx`, `[id]/index.tsx` | No |
| Does it contain business logic or non-trivial UI? | No | Yes under the right domain |
| Is it a reusable layout piece (sidebar, header, body)? | No | Yes |
| Is it a hook, store usage, or domain logic? | No | Yes |
| Is it only re-exporting or composing feature components? | Yes | No |
**Examples**
- **Route (thin):**\
`src/routes/(main)/page/_layout/index.tsx``export { default } from '@/features/Pages/PageLayout'`
- **Feature (real implementation):**\
`src/features/Pages/PageLayout/` → Sidebar, DataSync, Body, Header, styles, etc.
- **Route (thin):**\
`src/routes/(main)/page/index.tsx` → Import `PageTitle`, `PageExplorerPlaceholder` from `@/features/Pages` and `@/features/PageExplorer`; render with `<PageTitle />` and placeholder.
- **Feature:**\
Page list, actions, drawers, and hooks live under `src/features/Pages/`.
---
## 5. Progressive Migration (existing code)
We are migrating existing routes to this structure step by step:
- **Phase 1 (done):** `/page` route segment files in `src/routes/(main)/page/`, implementation in `src/features/Pages/`.
- **Later phases:** home, settings, agent/group, community/resource/memory, mobile/share/onboarding.
When touching an old route that still has logic or `features/` inside `src/routes/`:
1. Prefer adding **new** code in `src/features/<Domain>/` and importing from routes.
2. For larger refactors, move existing route-only logic into the right feature and then thin out the route files (re-export or compose from features).
3. Use `git mv` when moving files so history is preserved.
---
## 6. Reference Structure (after Phase 1)
**Route (thin):**
```
src/routes/(main)/page/
├── _layout/index.tsx → re-export or compose from @/features/Pages/PageLayout
├── index.tsx → import from @/features/Pages, @/features/PageExplorer
└── [id]/index.tsx → import from @/features/Pages, @/features/PageExplorer
```
**Feature (implementation):**
```
src/features/Pages/
├── index.ts → export PageLayout, PageTitle
├── PageTitle.tsx
└── PageLayout/
├── index.tsx → Sidebar + Outlet + DataSync
├── DataSync.tsx
├── Sidebar.tsx
├── style.ts
├── Body/ → list, actions, drawer, etc.
└── Header/ → breadcrumb, add button, etc.
```
Router config continues to point at **route** paths (e.g. `@/routes/(main)/page`, `@/routes/(main)/page/_layout`); route files then delegate to features.
@@ -0,0 +1,624 @@
---
name: store-data-structures
description: Zustand store data structure patterns for LobeHub. Covers List vs Detail data structures, Map + Reducer patterns, type definitions, and when to use each pattern. Use when designing store state, choosing data structures, or implementing list/detail pages.
---
# LobeHub Store Data Structures
This guide covers how to structure data in Zustand stores for optimal performance and user experience.
## Core Principles
### ✅ DO
1. **Separate List and Detail** - Use different structures for list pages and detail pages
2. **Use Map for Details** - Cache multiple detail pages with `Record<string, Detail>`
3. **Use Array for Lists** - Simple arrays for list display
4. **Types from @lobechat/types** - Never use `@lobechat/database` types in stores
5. **Distinguish List and Detail types** - List types may have computed UI fields
### ❌ DON'T
1. **Don't use single detail object** - Can't cache multiple pages
2. **Don't mix List and Detail types** - They have different purposes
3. **Don't use database types** - Use types from `@lobechat/types`
4. **Don't use Map for lists** - Simple arrays are sufficient
---
## Type Definitions
Types should be organized by entity in separate files:
```
@lobechat/types/src/eval/
├── benchmark.ts # Benchmark types
├── agentEvalDataset.ts # Dataset types
├── agentEvalRun.ts # Run types
└── index.ts # Re-exports
```
### Example: Benchmark Types
```typescript
// packages/types/src/eval/benchmark.ts
import type { EvalBenchmarkRubric } from './rubric';
// ============================================
// Detail Type - Full entity (for detail pages)
// ============================================
/**
* Full benchmark entity with all fields including heavy data
*/
export interface AgentEvalBenchmark {
createdAt: Date;
description?: string | null;
id: string;
identifier: string;
isSystem: boolean;
metadata?: Record<string, unknown> | null;
name: string;
referenceUrl?: string | null;
rubrics: EvalBenchmarkRubric[]; // Heavy field
updatedAt: Date;
}
// ============================================
// List Type - Lightweight (for list display)
// ============================================
/**
* Lightweight benchmark item - excludes heavy fields
* May include computed statistics for UI
*/
export interface AgentEvalBenchmarkListItem {
createdAt: Date;
description?: string | null;
id: string;
identifier: string;
isSystem: boolean;
name: string;
// Note: rubrics NOT included (heavy field)
// Computed statistics for UI display
datasetCount?: number;
runCount?: number;
testCaseCount?: number;
}
```
### Example: Document Types (with heavy content)
```typescript
// packages/types/src/document.ts
/**
* Full document entity - includes heavy content fields
*/
export interface Document {
id: string;
title: string;
description?: string;
content: string; // Heavy field - full markdown content
editorData: any; // Heavy field - editor state
metadata?: Record<string, unknown>;
createdAt: Date;
updatedAt: Date;
}
/**
* Lightweight document item - excludes heavy content
*/
export interface DocumentListItem {
id: string;
title: string;
description?: string;
// Note: content and editorData NOT included
createdAt: Date;
updatedAt: Date;
// Computed statistics
wordCount?: number;
lastEditedBy?: string;
}
```
**Key Points:**
- **Detail types** include ALL fields from database (full entity)
- **List types** are **subsets** that exclude heavy/large fields
- List types may add computed statistics for UI (e.g., `testCaseCount`)
- **Each entity gets its own file** (not mixed together)
- **All types** exported from `@lobechat/types`, NOT `@lobechat/database`
**Heavy fields to exclude from List:**
- Large text content (`content`, `editorData`, `fullDescription`)
- Complex objects (`rubrics`, `config`, `metrics`)
- Binary data (`image`, `file`)
- Large arrays (`messages`, `items`)
---
## When to Use Map vs Array
### Use Map + Reducer (for Detail Data)
**Detail page data caching** - Cache multiple detail pages simultaneously
**Optimistic updates** - Update UI before API responds
**Per-item loading states** - Track which items are being updated
**Multiple pages open** - User can navigate between details without refetching
**Structure:**
```typescript
benchmarkDetailMap: Record<string, AgentEvalBenchmark>;
```
**Example:** Benchmark detail pages, Dataset detail pages, User profiles
### Use Simple Array (for List Data)
**List display** - Lists, tables, cards
**Read-only or refresh-as-whole** - Entire list refreshes together
**No per-item updates** - No need to update individual items
**Simple data flow** - Easier to understand and maintain
**Structure:**
```typescript
benchmarkList: AgentEvalBenchmarkListItem[]
```
**Example:** Benchmark list, Dataset list, User list
---
## State Structure Pattern
### Complete Example
```typescript
// packages/types/src/eval/benchmark.ts
import type { EvalBenchmarkRubric } from './rubric';
/**
* Full benchmark entity (for detail pages)
*/
export interface AgentEvalBenchmark {
id: string;
name: string;
description?: string | null;
identifier: string;
rubrics: EvalBenchmarkRubric[]; // Heavy field
metadata?: Record<string, unknown> | null;
isSystem: boolean;
createdAt: Date;
updatedAt: Date;
}
/**
* Lightweight benchmark (for list display)
* Excludes heavy fields like rubrics
*/
export interface AgentEvalBenchmarkListItem {
id: string;
name: string;
description?: string | null;
identifier: string;
isSystem: boolean;
createdAt: Date;
// Note: rubrics excluded
// Computed statistics
testCaseCount?: number;
datasetCount?: number;
runCount?: number;
}
```
```typescript
// src/store/eval/slices/benchmark/initialState.ts
import type { AgentEvalBenchmark, AgentEvalBenchmarkListItem } from '@lobechat/types';
export interface BenchmarkSliceState {
// ============================================
// List Data - Simple Array
// ============================================
/**
* List of benchmarks for list page display
* May include computed fields like testCaseCount
*/
benchmarkList: AgentEvalBenchmarkListItem[];
benchmarkListInit: boolean;
// ============================================
// Detail Data - Map for Caching
// ============================================
/**
* Map of benchmark details keyed by ID
* Caches detail page data for multiple benchmarks
* Enables optimistic updates and per-item loading
*/
benchmarkDetailMap: Record<string, AgentEvalBenchmark>;
/**
* Track which benchmark details are being loaded/updated
* For showing spinners on specific items
*/
loadingBenchmarkDetailIds: string[];
// ============================================
// Mutation States
// ============================================
isCreatingBenchmark: boolean;
isUpdatingBenchmark: boolean;
isDeletingBenchmark: boolean;
}
export const benchmarkInitialState: BenchmarkSliceState = {
benchmarkList: [],
benchmarkListInit: false,
benchmarkDetailMap: {},
loadingBenchmarkDetailIds: [],
isCreatingBenchmark: false,
isUpdatingBenchmark: false,
isDeletingBenchmark: false,
};
```
---
## Reducer Pattern (for Detail Map)
### Why Use Reducer?
- **Immutable updates** - Immer ensures immutability
- **Type-safe actions** - TypeScript discriminated unions
- **Testable** - Pure functions easy to test
- **Reusable** - Same reducer for optimistic updates and server data
### Reducer Structure
```typescript
// src/store/eval/slices/benchmark/reducer.ts
import { produce } from 'immer';
import type { AgentEvalBenchmark } from '@lobechat/types';
// ============================================
// Action Types
// ============================================
type SetBenchmarkDetailAction = {
id: string;
type: 'setBenchmarkDetail';
value: AgentEvalBenchmark;
};
type UpdateBenchmarkDetailAction = {
id: string;
type: 'updateBenchmarkDetail';
value: Partial<AgentEvalBenchmark>;
};
type DeleteBenchmarkDetailAction = {
id: string;
type: 'deleteBenchmarkDetail';
};
export type BenchmarkDetailDispatch =
| SetBenchmarkDetailAction
| UpdateBenchmarkDetailAction
| DeleteBenchmarkDetailAction;
// ============================================
// Reducer Function
// ============================================
export const benchmarkDetailReducer = (
state: Record<string, AgentEvalBenchmark> = {},
payload: BenchmarkDetailDispatch,
): Record<string, AgentEvalBenchmark> => {
switch (payload.type) {
case 'setBenchmarkDetail': {
return produce(state, (draft) => {
draft[payload.id] = payload.value;
});
}
case 'updateBenchmarkDetail': {
return produce(state, (draft) => {
if (draft[payload.id]) {
draft[payload.id] = { ...draft[payload.id], ...payload.value };
}
});
}
case 'deleteBenchmarkDetail': {
return produce(state, (draft) => {
delete draft[payload.id];
});
}
default:
return state;
}
};
```
### Internal Dispatch Methods
```typescript
// In action.ts
export interface BenchmarkAction {
// ... other methods ...
// Internal methods - not for direct UI use
internal_dispatchBenchmarkDetail: (payload: BenchmarkDetailDispatch) => void;
internal_updateBenchmarkDetailLoading: (id: string, loading: boolean) => void;
}
export const createBenchmarkSlice: StateCreator<...> = (set, get) => ({
// ... other methods ...
// Internal - Dispatch to reducer
internal_dispatchBenchmarkDetail: (payload) => {
const currentMap = get().benchmarkDetailMap;
const nextMap = benchmarkDetailReducer(currentMap, payload);
// Only update if changed
if (isEqual(nextMap, currentMap)) return;
set(
{ benchmarkDetailMap: nextMap },
false,
`dispatchBenchmarkDetail/${payload.type}`,
);
},
// Internal - Update loading state
internal_updateBenchmarkDetailLoading: (id, loading) => {
set(
(state) => {
if (loading) {
return { loadingBenchmarkDetailIds: [...state.loadingBenchmarkDetailIds, id] };
}
return {
loadingBenchmarkDetailIds: state.loadingBenchmarkDetailIds.filter((i) => i !== id),
};
},
false,
'updateBenchmarkDetailLoading',
);
},
});
```
---
## Data Structure Comparison
### ❌ WRONG - Single Detail Object
```typescript
interface BenchmarkSliceState {
// ❌ Can only cache one detail
benchmarkDetail: AgentEvalBenchmark | null;
// ❌ Global loading state
isLoadingBenchmarkDetail: boolean;
}
```
**Problems:**
- Can only cache one detail page at a time
- Switching between details causes unnecessary refetches
- No optimistic updates
- No per-item loading states
### ✅ CORRECT - Separate List and Detail
```typescript
import type { AgentEvalBenchmark, AgentEvalBenchmarkListItem } from '@lobechat/types';
interface BenchmarkSliceState {
// ✅ List data - simple array
benchmarkList: AgentEvalBenchmarkListItem[];
benchmarkListInit: boolean;
// ✅ Detail data - map for caching
benchmarkDetailMap: Record<string, AgentEvalBenchmark>;
// ✅ Per-item loading
loadingBenchmarkDetailIds: string[];
// ✅ Mutation states
isCreatingBenchmark: boolean;
isUpdatingBenchmark: boolean;
isDeletingBenchmark: boolean;
}
```
**Benefits:**
- Cache multiple detail pages
- Fast navigation between cached details
- Optimistic updates with reducer
- Per-item loading states
- Clear separation of concerns
---
## Component Usage
### Accessing List Data
```typescript
const BenchmarkList = () => {
// Simple array access
const benchmarks = useEvalStore((s) => s.benchmarkList);
const isInit = useEvalStore((s) => s.benchmarkListInit);
if (!isInit) return <Loading />;
return (
<div>
{benchmarks.map(b => (
<BenchmarkCard
key={b.id}
name={b.name}
testCaseCount={b.testCaseCount} // Computed field
/>
))}
</div>
);
};
```
### Accessing Detail Data
```typescript
const BenchmarkDetail = () => {
const { benchmarkId } = useParams<{ benchmarkId: string }>();
// Get from map
const benchmark = useEvalStore((s) =>
benchmarkId ? s.benchmarkDetailMap[benchmarkId] : undefined,
);
// Check loading
const isLoading = useEvalStore((s) =>
benchmarkId ? s.loadingBenchmarkDetailIds.includes(benchmarkId) : false,
);
if (!benchmark) return <Loading />;
return (
<div>
<h1>{benchmark.name}</h1>
{isLoading && <Spinner />}
</div>
);
};
```
### Using Selectors (Recommended)
```typescript
// src/store/eval/slices/benchmark/selectors.ts
export const benchmarkSelectors = {
getBenchmarkDetail: (id: string) => (s: EvalStore) => s.benchmarkDetailMap[id],
isLoadingBenchmarkDetail: (id: string) => (s: EvalStore) =>
s.loadingBenchmarkDetailIds.includes(id),
};
// In component
const benchmark = useEvalStore(benchmarkSelectors.getBenchmarkDetail(benchmarkId!));
const isLoading = useEvalStore(benchmarkSelectors.isLoadingBenchmarkDetail(benchmarkId!));
```
---
## Decision Tree
```
Need to store data?
├─ Is it a LIST for display?
│ └─ ✅ Use simple array: `xxxList: XxxListItem[]`
│ - May include computed fields
│ - Refreshed as a whole
│ - No optimistic updates needed
└─ Is it DETAIL page data?
└─ ✅ Use Map: `xxxDetailMap: Record<string, Xxx>`
- Cache multiple details
- Support optimistic updates
- Per-item loading states
- Requires reducer for mutations
```
---
## Checklist
When designing store state structure:
- [ ] **Organize types by entity** in separate files (e.g., `benchmark.ts`, `agentEvalDataset.ts`)
- [ ] Create **Detail** type (full entity with all fields including heavy ones)
- [ ] Create **ListItem** type:
- [ ] Subset of Detail type (exclude heavy fields)
- [ ] May include computed statistics for UI
- [ ] **NOT** extending Detail type (it's a subset, not extension)
- [ ] Use **array** for list data: `xxxList: XxxListItem[]`
- [ ] Use **Map** for detail data: `xxxDetailMap: Record<string, Xxx>`
- [ ] Add per-item loading: `loadingXxxDetailIds: string[]`
- [ ] Create **reducer** for detail map if optimistic updates needed
- [ ] Add **internal dispatch** and **loading** methods
- [ ] Create **selectors** for clean access (optional but recommended)
- [ ] Document in comments:
- [ ] What fields are excluded from List and why
- [ ] What computed fields mean
- [ ] What each Map is for
---
## Best Practices
1. **File organization** - One entity per file, not mixed together
2. **List is subset** - ListItem excludes heavy fields, not extends Detail
3. **Clear naming** - `xxxList` for arrays, `xxxDetailMap` for maps
4. **Consistent patterns** - All detail maps follow same structure
5. **Type safety** - Never use `any`, always use proper types
6. **Document exclusions** - Comment which fields are excluded from List and why
7. **Selectors** - Encapsulate access patterns
8. **Loading states** - Per-item for details, global for lists
9. **Immutability** - Use Immer in reducers
### Common Mistakes to Avoid
**DON'T extend Detail in List:**
```typescript
// Wrong - List should not extend Detail
export interface BenchmarkListItem extends Benchmark {
testCaseCount?: number;
}
```
**DO create separate subset:**
```typescript
// Correct - List is a subset with computed fields
export interface BenchmarkListItem {
id: string;
name: string;
// ... only necessary fields
testCaseCount?: number; // Computed
}
```
**DON'T mix entities in one file:**
```typescript
// Wrong - all entities in agentEvalEntities.ts
```
**DO separate by entity:**
```typescript
// Correct - separate files
// benchmark.ts
// agentEvalDataset.ts
// agentEvalRun.ts
```
---
## Related Skills
- `data-fetching` - How to fetch and update this data
- `zustand` - General Zustand patterns
+37 -7
View File
@@ -3,11 +3,12 @@ name: testing
description: Testing guide using Vitest. Use when writing tests (.test.ts, .test.tsx), fixing failing tests, improving test coverage, or debugging test issues. Triggers on test creation, test debugging, mock setup, or test-related questions.
---
# LobeChat Testing Guide
# LobeHub Testing Guide
## Quick Reference
**Commands:**
```bash
# Run specific test file
bunx vitest run --silent='passed-only' '[file-path]'
@@ -19,15 +20,15 @@ cd packages/database && bunx vitest run --silent='passed-only' '[file]'
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'
```
**Never run** `bun run test` - it runs all 3000+ tests (~10 minutes).
**Never run** `bun run test` - it runs all 3000+ tests (\~10 minutes).
## Test Categories
| Category | Location | Config |
|----------|----------|--------|
| Webapp | `src/**/*.test.ts(x)` | `vitest.config.ts` |
| Packages | `packages/*/**/*.test.ts` | `packages/*/vitest.config.ts` |
| Desktop | `apps/desktop/**/*.test.ts` | `apps/desktop/vitest.config.ts` |
| Category | Location | Config |
| -------- | --------------------------- | ------------------------------- |
| Webapp | `src/**/*.test.ts(x)` | `vitest.config.ts` |
| Packages | `packages/*/**/*.test.ts` | `packages/*/vitest.config.ts` |
| Desktop | `apps/desktop/**/*.test.ts` | `apps/desktop/vitest.config.ts` |
## Core Principles
@@ -75,12 +76,41 @@ vi.mock('@/services/chat'); // Too broad
## Detailed Guides
See `references/` for specific testing scenarios:
- **Database Model testing**: `references/db-model-test.md`
- **Electron IPC testing**: `references/electron-ipc-test.md`
- **Zustand Store Action testing**: `references/zustand-store-action-test.md`
- **Agent Runtime E2E testing**: `references/agent-runtime-e2e.md`
- **Desktop Controller testing**: `references/desktop-controller-test.md`
## Fixing Failing Tests — Optimize or Delete?
When tests fail due to implementation changes (not bugs), evaluate before blindly fixing:
### Keep & Fix (update test data/assertions)
- **Behavior tests**: Tests that verify _what_ the code does (output, side effects, user-visible behavior). Just update mock data formats or expected values.
- Example: Tool data structure changed from `{ name }` to `{ function: { name } }` → update mock data
- Example: Output format changed from `Current date: YYYY-MM-DD` to `Current date: YYYY-MM-DD (TZ)` → update expected string
### Delete (over-specified, low value)
- **Param-forwarding tests**: Tests that assert exact internal function call arguments (e.g., `expect(internalFn).toHaveBeenCalledWith(expect.objectContaining({ exact params }))`) — these break on every refactor and duplicate what behavior tests already cover.
- **Implementation-coupled tests**: Tests that verify _how_ the code works internally rather than _what_ it produces. If a higher-level test already covers the same behavior, the low-level test adds maintenance cost without coverage gain.
### Decision Checklist
1. Does the test verify **externally observable behavior** (API response, DB write, rendered output)? → **Keep**
2. Does the test only verify **internal wiring** (which function receives which params)? → Check if a behavior test already covers it. If yes → **Delete**
3. Is the same behavior already tested at a **higher integration level**? → Delete the lower-level duplicate
4. Would the test break again on the **next routine refactor**? → Consider raising to integration level or deleting
### When Writing New Tests
- Prefer **integration-level assertions** (verify final output) over **white-box assertions** (verify internal calls)
- Use `expect.objectContaining` only for stable, public-facing contracts — not for internal param shapes that change with refactors
- Mock at boundaries (DB, network, external services), not between internal modules
## Common Issues
1. **Module pollution**: Use `vi.resetModules()` when tests fail mysteriously
@@ -6,13 +6,14 @@
Only mock **three external dependencies**:
| Dependency | Mock | Description |
|------------|------|-------------|
| Database | PGLite | In-memory database from `@lobechat/database/test-utils` |
| Redis | InMemoryAgentStateManager | Memory implementation |
| Redis | InMemoryStreamEventManager | Memory implementation |
| Dependency | Mock | Description |
| ---------- | -------------------------- | ------------------------------------------------------- |
| Database | PGLite | In-memory database from `@lobechat/database/test-utils` |
| Redis | InMemoryAgentStateManager | Memory implementation |
| Redis | InMemoryStreamEventManager | Memory implementation |
**NOT mocked:**
- `model-bank` - Uses real model config
- `Mecha` (AgentToolsEngine, ContextEngineering)
- `AgentRuntimeService`
@@ -21,6 +22,7 @@ Only mock **three external dependencies**:
### Use vi.spyOn, not vi.mock
Different tests need different LLM responses. `vi.spyOn` provides:
- Flexible return values per test
- Easy testing of different scenarios
- Better test isolation
@@ -76,7 +78,7 @@ export const createOpenAIStreamResponse = (options: {
controller.close();
},
}),
{ headers: { 'content-type': 'text/event-stream' } }
{ headers: { 'content-type': 'text/event-stream' } },
);
};
```
@@ -84,7 +86,10 @@ export const createOpenAIStreamResponse = (options: {
### State Management
```typescript
import { InMemoryAgentStateManager, InMemoryStreamEventManager } from '@/server/modules/AgentRuntime';
import {
InMemoryAgentStateManager,
InMemoryStreamEventManager,
} from '@/server/modules/AgentRuntime';
const stateManager = new InMemoryAgentStateManager();
const streamEventManager = new InMemoryStreamEventManager();
@@ -107,14 +112,18 @@ it('should handle text response', async () => {
});
it('should handle tool calls', async () => {
fetchSpy.mockResolvedValueOnce(createOpenAIStreamResponse({
toolCalls: [{
id: 'call_123',
name: 'lobe-web-browsing____search____builtin',
arguments: JSON.stringify({ query: 'weather' }),
}],
finishReason: 'tool_calls',
}));
fetchSpy.mockResolvedValueOnce(
createOpenAIStreamResponse({
toolCalls: [
{
id: 'call_123',
name: 'lobe-web-browsing____search____builtin',
arguments: JSON.stringify({ query: 'weather' }),
},
],
finishReason: 'tool_calls',
}),
);
// ... execute test
});
```
@@ -19,18 +19,24 @@ cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only'
```typescript
// ❌ DANGEROUS: Missing permission check
update = async (id: string, data: Partial<MyModel>) => {
return this.db.update(myTable).set(data)
.where(eq(myTable.id, id)) // Only checks ID
return this.db
.update(myTable)
.set(data)
.where(eq(myTable.id, id)) // Only checks ID
.returning();
};
// ✅ SECURE: Permission check included
update = async (id: string, data: Partial<MyModel>) => {
return this.db.update(myTable).set(data)
.where(and(
eq(myTable.id, id),
eq(myTable.userId, this.userId) // ✅ Permission check
))
return this.db
.update(myTable)
.set(data)
.where(
and(
eq(myTable.id, id),
eq(myTable.userId, this.userId), // ✅ Permission check
),
)
.returning();
};
```
@@ -40,18 +46,22 @@ update = async (id: string, data: Partial<MyModel>) => {
```typescript
// @vitest-environment node
describe('MyModel', () => {
describe('create', () => { /* ... */ });
describe('queryAll', () => { /* ... */ });
describe('create', () => {
/* ... */
});
describe('queryAll', () => {
/* ... */
});
describe('update', () => {
it('should update own records');
it('should NOT update other users records'); // 🔒 Security
it('should NOT update other users records'); // 🔒 Security
});
describe('delete', () => {
it('should delete own records');
it('should NOT delete other users records'); // 🔒 Security
it('should NOT delete other users records'); // 🔒 Security
});
describe('user isolation', () => {
it('should enforce user data isolation'); // 🔒 Core security
it('should enforce user data isolation'); // 🔒 Core security
});
});
```
@@ -102,8 +112,10 @@ const testData = { asyncTaskId: null, fileId: null };
// ✅ Or: Create referenced record first
beforeEach(async () => {
const [asyncTask] = await serverDB.insert(asyncTasks)
.values({ id: 'valid-id', status: 'pending' }).returning();
const [asyncTask] = await serverDB
.insert(asyncTasks)
.values({ id: 'valid-id', status: 'pending' })
.returning();
testData.asyncTaskId = asyncTask.id;
});
```
@@ -120,5 +132,5 @@ await serverDB.insert(table).values([
]);
// ❌ Don't rely on insert order
await serverDB.insert(table).values([data1, data2]); // Unpredictable
await serverDB.insert(table).values([data1, data2]); // Unpredictable
```
@@ -2,7 +2,7 @@
## Testing Framework & Directory Structure
LobeChat Desktop uses Vitest as the test framework. Controller unit tests should be placed in the `__tests__` directory adjacent to the controller file, named with the original controller filename plus `.test.ts`.
LobeHub Desktop uses Vitest as the test framework. Controller unit tests should be placed in the `__tests__` directory adjacent to the controller file, named with the original controller filename plus `.test.ts`.
```plaintext
apps/desktop/src/main/controllers/
@@ -11,11 +11,14 @@ vi.mock('zustand/traditional');
beforeEach(() => {
vi.clearAllMocks();
useChatStore.setState({
activeId: 'test-session-id',
messagesMap: {},
loadingIds: [],
}, false);
useChatStore.setState(
{
activeId: 'test-session-id',
messagesMap: {},
loadingIds: [],
},
false,
);
vi.spyOn(messageService, 'createMessage').mockResolvedValue('new-message-id');
@@ -132,6 +135,7 @@ it('should fetch data', async () => {
```
**Key points for SWR:**
- DO NOT mock useSWR - let it use real implementation
- Only mock service methods (fetchers)
- Use `waitFor` for async operations
+123
View File
@@ -0,0 +1,123 @@
---
name: trpc-router
description: TRPC router development guide. Use when creating or modifying TRPC routers (src/server/routers/**), adding procedures, or working with server-side API endpoints. Triggers on TRPC router creation, procedure implementation, or API endpoint tasks.
---
# TRPC Router Guide
## File Location
- Routers: `src/server/routers/lambda/<domain>.ts`
- Helpers: `src/server/routers/lambda/_helpers/`
- Schemas: `src/server/routers/lambda/_schema/`
## Router Structure
### Imports
```typescript
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { SomeModel } from '@/database/models/some';
import { authedProcedure, router } from '@/libs/trpc/lambda';
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
```
### Middleware: Inject Models into ctx
**Always use middleware to inject models into `ctx`** instead of creating `new Model(ctx.serverDB, ctx.userId)` inside every procedure.
```typescript
const domainProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
const { ctx } = opts;
return opts.next({
ctx: {
fooModel: new FooModel(ctx.serverDB, ctx.userId),
barModel: new BarModel(ctx.serverDB, ctx.userId),
},
});
});
```
Then use `ctx.fooModel` in procedures:
```typescript
// Good
const model = ctx.fooModel;
// Bad - don't create models inside procedures
const model = new FooModel(ctx.serverDB, ctx.userId);
```
**Exception**: When a model needs a different `userId` (e.g., watchdog iterating over multiple users' tasks), create it inline.
### Procedure Pattern
```typescript
export const fooRouter = router({
// Query
find: domainProcedure.input(z.object({ id: z.string() })).query(async ({ input, ctx }) => {
try {
const item = await ctx.fooModel.findById(input.id);
if (!item) throw new TRPCError({ code: 'NOT_FOUND', message: 'Not found' });
return { data: item, success: true };
} catch (error) {
if (error instanceof TRPCError) throw error;
console.error('[foo:find]', error);
throw new TRPCError({
cause: error,
code: 'INTERNAL_SERVER_ERROR',
message: 'Failed to find item',
});
}
}),
// Mutation
create: domainProcedure.input(createSchema).mutation(async ({ input, ctx }) => {
try {
const item = await ctx.fooModel.create(input);
return { data: item, message: 'Created', success: true };
} catch (error) {
if (error instanceof TRPCError) throw error;
console.error('[foo:create]', error);
throw new TRPCError({
cause: error,
code: 'INTERNAL_SERVER_ERROR',
message: 'Failed to create',
});
}
}),
});
```
### Aggregated Detail Endpoint
For views that need multiple related data, create a single `detail` procedure that fetches everything in parallel:
```typescript
detail: domainProcedure.input(idInput).query(async ({ input, ctx }) => {
const item = await resolveOrThrow(ctx.fooModel, input.id);
const [children, related] = await Promise.all([
ctx.fooModel.findChildren(item.id),
ctx.barModel.findByFooId(item.id),
]);
return {
data: { ...item, children, related },
success: true,
};
}),
```
This avoids the CLI or frontend making N sequential requests.
## Conventions
- Return shape: `{ data, success: true }` for queries, `{ data?, message, success: true }` for mutations
- Error handling: re-throw `TRPCError`, wrap others with `console.error` + new `TRPCError`
- Input validation: use `zod` schemas, define at file top
- Router name: `export const fooRouter = router({ ... })`
- Procedure names: alphabetical order within the router object
- Log prefix: `[domain:procedure]` format, e.g. `[task:create]`
+16 -1
View File
@@ -1,6 +1,6 @@
---
name: typescript
description: TypeScript code style and optimization guidelines. Use when writing TypeScript code (.ts, .tsx, .mts files), reviewing code quality, or implementing type-safe patterns. Triggers on TypeScript development, type safety questions, or code style discussions.
description: TypeScript code style and optimization guidelines. MUST READ before writing or modifying any TypeScript code (.ts, .tsx, .mts files). Also use when reviewing code quality or implementing type-safe patterns. Triggers on any TypeScript file edit, code style discussions, or type safety questions.
---
# TypeScript Code Style Guide
@@ -14,6 +14,9 @@ description: TypeScript code style and optimization guidelines. Use when writing
- Prefer `as const satisfies XyzInterface` over plain `as const`
- Prefer `@ts-expect-error` over `@ts-ignore` over `as any`
- Avoid meaningless null/undefined parameters; design strict function contracts
- Prefer ES module augmentation (`declare module '...'`) over `namespace`; do not introduce `namespace`-based extension patterns
- When a type needs extensibility, expose a small mergeable interface at the source type and let each feature/plugin augment it locally instead of centralizing all extension fields in one registry file
- For package-local extensibility patterns like `PipelineContext.metadata`, define the metadata fields next to the processor/provider/plugin that reads or writes them
## Async Patterns
@@ -22,6 +25,17 @@ description: TypeScript code style and optimization guidelines. Use when writing
- Use promise-based variants: `import { readFile } from 'fs/promises'`
- Use `Promise.all`, `Promise.race` for concurrent operations where safe
## Imports
- This project uses `simple-import-sort/imports` and `consistent-type-imports` (`fixStyle: 'separate-type-imports'`)
- **Separate type imports**: always use `import type { ... }` for type-only imports, NOT `import { type ... }` inline syntax
- When a file already has `import type { ... }` from a package and you need to add a value import, keep them as **two separate statements**:
```ts
import type { ChatTopicBotContext } from '@lobechat/types';
import { RequestTrigger } from '@lobechat/types';
```
- Within each import statement, specifiers are sorted **alphabetically by name**
## Code Structure
- Prefer object destructuring
@@ -50,3 +64,4 @@ description: TypeScript code style and optimization guidelines. Use when writing
- Never log user private information (API keys, etc.)
- Don't use `import { log } from 'debug'` directly (logs to console)
- Use `console.error` in catch blocks instead of debug package
- Always log the error in `.catch()` callbacks — silent `.catch(() => fallback)` swallows failures and makes debugging impossible
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,389 @@
# Cloud Project Workflow Configuration
This document covers cloud-specific workflow configurations and patterns for the lobehub-cloud project.
## Overview
The lobehub-cloud project extends the open-source lobehub codebase with cloud-specific features. Workflows can be implemented in either:
1. **Lobehub (open-source)** - Available to all users
2. **Lobehub-cloud (proprietary)** - Cloud-specific business logic
---
## Directory Structure
### Lobehub Submodule (Open-source)
```
lobehub/
└── src/
├── app/(backend)/api/workflows/
│ ├── memory-user-memory/ # Memory extraction workflows
│ └── agent-eval-run/ # Benchmark evaluation workflows
└── server/workflows/
├── agentEvalRun/
└── ...
```
### Lobehub-cloud (Proprietary)
```
lobehub-cloud/
└── src/
├── app/(backend)/api/workflows/
│ ├── welcome-placeholder/ # Cloud-only: AI placeholder generation
│ ├── agent-welcome/ # Cloud-only: Agent welcome messages
│ ├── agent-eval-run/ # Re-export from lobehub
│ └── memory-user-memory/ # Re-export from lobehub
└── server/workflows/
├── welcomePlaceholder/
├── agentWelcome/
└── agentEvalRun/ # Re-export from lobehub
```
---
## Cloud-Specific Patterns
### Pattern 1: Cloud-Only Workflows
**Use Case**: Features exclusive to cloud users (AI generation, premium features)
**Example**: `welcome-placeholder`, `agent-welcome`
**Implementation**:
- Implement directly in `lobehub-cloud/src/app/(backend)/api/workflows/`
- No need for re-exports
- Can use cloud-specific packages and services
**Structure**:
```
lobehub-cloud/src/
├── app/(backend)/api/workflows/
│ └── feature-name/
│ ├── process-items/route.ts
│ ├── paginate-items/route.ts
│ └── execute-item/route.ts
└── server/workflows/
└── featureName/
└── index.ts
```
---
### Pattern 2: Re-export from Lobehub
**Use Case**: Workflows implemented in open-source but also used in cloud
**Example**: `agent-eval-run`, `memory-user-memory`
**Why Re-export?**
- Cloud deployment needs to serve these endpoints
- Lobehub submodule code is not directly accessible in cloud routes
- Allows cloud-specific overrides if needed in the future
#### Re-export Implementation
**Step 1**: Implement workflow in lobehub submodule
```typescript
// lobehub/src/app/(backend)/api/workflows/feature/layer/route.ts
import { serve } from '@upstash/workflow/nextjs';
export const { POST } = serve<Payload>(
async (context) => {
// Implementation
},
{ flowControl: { ... } }
);
```
**Step 2**: Create re-export in lobehub-cloud
```typescript
// lobehub-cloud/src/app/(backend)/api/workflows/feature/layer/route.ts
export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature/layer/route';
```
**Important**: Use `lobehub/src/...` path, NOT `@/...` to avoid circular imports.
#### Re-export Directory Structure
```bash
# Create directories
mkdir -p lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-1
mkdir -p lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-2
mkdir -p lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-3
# Create re-export files
echo "export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature-name/layer-1/route';" > \
lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-1/route.ts
echo "export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature-name/layer-2/route';" > \
lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-2/route.ts
echo "export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature-name/layer-3/route';" > \
lobehub-cloud/src/app/(backend)/api/workflows/feature-name/layer-3/route.ts
```
---
## TypeScript Path Mappings
The cloud project uses tsconfig path mappings to override lobehub code:
```json
// lobehub-cloud/tsconfig.json
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*", "./lobehub/src/*"]
}
}
}
```
**Resolution Order**:
1. `./src/*` (cloud code) - checked first
2. `./lobehub/src/*` (open-source) - fallback
This allows cloud to override specific modules while using lobehub defaults.
---
## Workflow Class Location
### Cloud-Only Workflows
Place workflow class in cloud:
```
lobehub-cloud/src/server/workflows/featureName/index.ts
```
### Shared Workflows
Place workflow class in lobehub, re-export in cloud if needed:
```
lobehub/src/server/workflows/featureName/index.ts
```
---
## Environment Variables
Both lobehub and cloud workflows require:
```bash
# Required for all workflows
APP_URL=https://your-app.com # Base URL for workflow endpoints
QSTASH_TOKEN=qstash_xxx # QStash authentication token
# Optional (for custom QStash URL)
QSTASH_URL=https://custom-qstash.com # Custom QStash endpoint
```
**Cloud-Specific**:
```bash
# Cloud database (for monetization features)
CLOUD_DATABASE_URL=postgresql://...
# Cloud-specific services
REDIS_URL=redis://...
```
---
## Best Practices
### 1. Decide: Cloud or Open-Source?
**Implement in Lobehub if**:
- Feature is useful for all LobeHub users
- No proprietary business logic
- Can be open-sourced
**Implement in Cloud if**:
- Premium/paid feature
- Uses cloud-specific services
- Contains proprietary algorithms
### 2. Re-export Pattern
**Do**:
```typescript
// Simple re-export
export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature/route';
```
**Don't**:
```typescript
// Avoid circular imports with @/ path
export { POST } from '@/app/(backend)/api/workflows/feature/route'; // ❌
```
### 3. Keep Workflow Logic in Lobehub
For shared features:
- Implement core logic in `lobehub/` (open-source)
- Only override if cloud needs different behavior
- Use re-exports for cloud deployment
### 4. Directory Naming
Follow consistent naming across lobehub and cloud:
```
# Both should use same structure
lobehub/src/app/(backend)/api/workflows/feature-name/
lobehub-cloud/src/app/(backend)/api/workflows/feature-name/
```
---
## Migration Guide
### Moving Workflow from Cloud to Lobehub
**Step 1**: Copy workflow to lobehub
```bash
cp -r lobehub-cloud/src/app/(backend)/api/workflows/feature \
lobehub/src/app/(backend)/api/workflows/
```
**Step 2**: Remove cloud-specific dependencies
- Replace cloud services with generic interfaces
- Remove proprietary business logic
- Update imports to use lobehub paths
**Step 3**: Create re-exports in cloud
```typescript
// lobehub-cloud/src/app/(backend)/api/workflows/feature/*/route.ts
export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature/*/route';
```
**Step 4**: Move workflow class to lobehub
```bash
mv lobehub-cloud/src/server/workflows/feature \
lobehub/src/server/workflows/
```
**Step 5**: Update cloud imports
```typescript
// Change from
import { Workflow } from '@/server/workflows/feature';
// To
import { Workflow } from 'lobehub/src/server/workflows/feature';
```
---
## Examples
### Cloud-Only Workflow: welcome-placeholder
**Location**: `lobehub-cloud/src/app/(backend)/api/workflows/welcome-placeholder/`
**Why Cloud-Only**: Uses proprietary AI generation service and Redis caching
**Structure**:
```
lobehub-cloud/
├── src/app/(backend)/api/workflows/welcome-placeholder/
│ ├── process-users/route.ts
│ ├── paginate-users/route.ts
│ └── generate-user/route.ts
└── src/server/workflows/welcomePlaceholder/
└── index.ts
```
### Re-exported Workflow: agent-eval-run
**Location**:
- Implementation: `lobehub/src/app/(backend)/api/workflows/agent-eval-run/`
- Re-export: `lobehub-cloud/src/app/(backend)/api/workflows/agent-eval-run/`
**Why Re-export**: Core feature available in open-source, also used by cloud
**Cloud Re-export Files**:
```typescript
// lobehub-cloud/src/app/(backend)/api/workflows/agent-eval-run/run-benchmark/route.ts
export { POST } from 'lobehub/src/app/(backend)/api/workflows/agent-eval-run/run-benchmark/route';
// lobehub-cloud/src/app/(backend)/api/workflows/agent-eval-run/paginate-test-cases/route.ts
export { POST } from 'lobehub/src/app/(backend)/api/workflows/agent-eval-run/paginate-test-cases/route';
// ... (all layers)
```
---
## Troubleshooting
### Circular Import Error
**Error**: `Circular definition of import alias 'POST'`
**Cause**: Using `@/` path in re-export within cloud codebase
**Solution**: Use `lobehub/src/` path instead
```typescript
// ❌ Wrong
export { POST } from '@/app/(backend)/api/workflows/feature/route';
// ✅ Correct
export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature/route';
```
### Workflow Not Found (404)
**Cause**: Missing re-export in cloud
**Solution**: Create re-export files for all workflow layers
```bash
# Check if re-export exists
ls lobehub-cloud/src/app/\(backend\)/api/workflows/feature-name/
# If missing, create re-exports
mkdir -p lobehub-cloud/src/app/\(backend\)/api/workflows/feature-name/layer
echo "export { POST } from 'lobehub/src/app/(backend)/api/workflows/feature-name/layer/route';" > lobehub-cloud/src/app/\(backend\)/api/workflows/feature-name/layer/route.ts
```
### Type Errors After Moving to Lobehub
**Cause**: Cloud-specific types or services used in lobehub code
**Solution**:
1. Extract cloud-specific logic to cloud-only wrapper
2. Use dependency injection for services
3. Define generic interfaces in lobehub
---
## Related Documentation
- [SKILL.md](../SKILL.md) - Standard workflow patterns
File diff suppressed because it is too large Load Diff
@@ -1,125 +0,0 @@
---
name: vercel-react-best-practices
description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
license: MIT
metadata:
author: vercel
version: "1.0.0"
---
# Vercel React Best Practices
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
## When to Apply
Reference these guidelines when:
- Writing new React components or Next.js pages
- Implementing data fetching (client or server-side)
- Reviewing code for performance issues
- Refactoring existing React/Next.js code
- Optimizing bundle size or load times
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
| 3 | Server-Side Performance | HIGH | `server-` |
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
| 6 | Rendering Performance | MEDIUM | `rendering-` |
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
| 8 | Advanced Patterns | LOW | `advanced-` |
## Quick Reference
### 1. Eliminating Waterfalls (CRITICAL)
- `async-defer-await` - Move await into branches where actually used
- `async-parallel` - Use Promise.all() for independent operations
- `async-dependencies` - Use better-all for partial dependencies
- `async-api-routes` - Start promises early, await late in API routes
- `async-suspense-boundaries` - Use Suspense to stream content
### 2. Bundle Size Optimization (CRITICAL)
- `bundle-barrel-imports` - Import directly, avoid barrel files
- `bundle-dynamic-imports` - Use next/dynamic for heavy components
- `bundle-defer-third-party` - Load analytics/logging after hydration
- `bundle-conditional` - Load modules only when feature is activated
- `bundle-preload` - Preload on hover/focus for perceived speed
### 3. Server-Side Performance (HIGH)
- `server-cache-react` - Use React.cache() for per-request deduplication
- `server-cache-lru` - Use LRU cache for cross-request caching
- `server-serialization` - Minimize data passed to client components
- `server-parallel-fetching` - Restructure components to parallelize fetches
- `server-after-nonblocking` - Use after() for non-blocking operations
### 4. Client-Side Data Fetching (MEDIUM-HIGH)
- `client-swr-dedup` - Use SWR for automatic request deduplication
- `client-event-listeners` - Deduplicate global event listeners
### 5. Re-render Optimization (MEDIUM)
- `rerender-defer-reads` - Don't subscribe to state only used in callbacks
- `rerender-memo` - Extract expensive work into memoized components
- `rerender-dependencies` - Use primitive dependencies in effects
- `rerender-derived-state` - Subscribe to derived booleans, not raw values
- `rerender-functional-setstate` - Use functional setState for stable callbacks
- `rerender-lazy-state-init` - Pass function to useState for expensive values
- `rerender-transitions` - Use startTransition for non-urgent updates
### 6. Rendering Performance (MEDIUM)
- `rendering-animate-svg-wrapper` - Animate div wrapper, not SVG element
- `rendering-content-visibility` - Use content-visibility for long lists
- `rendering-hoist-jsx` - Extract static JSX outside components
- `rendering-svg-precision` - Reduce SVG coordinate precision
- `rendering-hydration-no-flicker` - Use inline script for client-only data
- `rendering-activity` - Use Activity component for show/hide
- `rendering-conditional-render` - Use ternary, not && for conditionals
### 7. JavaScript Performance (LOW-MEDIUM)
- `js-batch-dom-css` - Group CSS changes via classes or cssText
- `js-index-maps` - Build Map for repeated lookups
- `js-cache-property-access` - Cache object properties in loops
- `js-cache-function-results` - Cache function results in module-level Map
- `js-cache-storage` - Cache localStorage/sessionStorage reads
- `js-combine-iterations` - Combine multiple filter/map into one loop
- `js-length-check-first` - Check array length before expensive comparison
- `js-early-exit` - Return early from functions
- `js-hoist-regexp` - Hoist RegExp creation outside loops
- `js-min-max-loop` - Use loop for min/max instead of sort
- `js-set-map-lookups` - Use Set/Map for O(1) lookups
- `js-tosorted-immutable` - Use toSorted() for immutability
### 8. Advanced Patterns (LOW)
- `advanced-event-handler-refs` - Store event handlers in refs
- `advanced-use-latest` - useLatest for stable callback refs
## How to Use
Read individual rule files for detailed explanations and code examples:
```
rules/async-parallel.md
rules/bundle-barrel-imports.md
rules/_sections.md
```
Each rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
## Full Compiled Document
For the complete guide with all rules expanded: `AGENTS.md`
@@ -1,55 +0,0 @@
---
title: Store Event Handlers in Refs
impact: LOW
impactDescription: stable subscriptions
tags: advanced, hooks, refs, event-handlers, optimization
---
## Store Event Handlers in Refs
Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes.
**Incorrect (re-subscribes on every render):**
```tsx
function useWindowEvent(event: string, handler: (e) => void) {
useEffect(() => {
window.addEventListener(event, handler)
return () => window.removeEventListener(event, handler)
}, [event, handler])
}
```
**Correct (stable subscription):**
```tsx
function useWindowEvent(event: string, handler: (e) => void) {
const handlerRef = useRef(handler)
useEffect(() => {
handlerRef.current = handler
}, [handler])
useEffect(() => {
const listener = (e) => handlerRef.current(e)
window.addEventListener(event, listener)
return () => window.removeEventListener(event, listener)
}, [event])
}
```
**Alternative: use `useEffectEvent` if you're on latest React:**
```tsx
import { useEffectEvent } from 'react'
function useWindowEvent(event: string, handler: (e) => void) {
const onEvent = useEffectEvent(handler)
useEffect(() => {
window.addEventListener(event, onEvent)
return () => window.removeEventListener(event, onEvent)
}, [event])
}
```
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.
@@ -1,49 +0,0 @@
---
title: useLatest for Stable Callback Refs
impact: LOW
impactDescription: prevents effect re-runs
tags: advanced, hooks, useLatest, refs, optimization
---
## useLatest for Stable Callback Refs
Access latest values in callbacks without adding them to dependency arrays. Prevents effect re-runs while avoiding stale closures.
**Implementation:**
```typescript
function useLatest<T>(value: T) {
const ref = useRef(value)
useLayoutEffect(() => {
ref.current = value
}, [value])
return ref
}
```
**Incorrect (effect re-runs on every callback change):**
```tsx
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
const [query, setQuery] = useState('')
useEffect(() => {
const timeout = setTimeout(() => onSearch(query), 300)
return () => clearTimeout(timeout)
}, [query, onSearch])
}
```
**Correct (stable effect, fresh callback):**
```tsx
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
const [query, setQuery] = useState('')
const onSearchRef = useLatest(onSearch)
useEffect(() => {
const timeout = setTimeout(() => onSearchRef.current(query), 300)
return () => clearTimeout(timeout)
}, [query])
}
```
@@ -1,38 +0,0 @@
---
title: Prevent Waterfall Chains in API Routes
impact: CRITICAL
impactDescription: 2-10× improvement
tags: api-routes, server-actions, waterfalls, parallelization
---
## Prevent Waterfall Chains in API Routes
In API routes and Server Actions, start independent operations immediately, even if you don't await them yet.
**Incorrect (config waits for auth, data waits for both):**
```typescript
export async function GET(request: Request) {
const session = await auth()
const config = await fetchConfig()
const data = await fetchData(session.user.id)
return Response.json({ data, config })
}
```
**Correct (auth and config start immediately):**
```typescript
export async function GET(request: Request) {
const sessionPromise = auth()
const configPromise = fetchConfig()
const session = await sessionPromise
const [config, data] = await Promise.all([
configPromise,
fetchData(session.user.id)
])
return Response.json({ data, config })
}
```
For operations with more complex dependency chains, use `better-all` to automatically maximize parallelism (see Dependency-Based Parallelization).
@@ -1,80 +0,0 @@
---
title: Defer Await Until Needed
impact: HIGH
impactDescription: avoids blocking unused code paths
tags: async, await, conditional, optimization
---
## Defer Await Until Needed
Move `await` operations into the branches where they're actually used to avoid blocking code paths that don't need them.
**Incorrect (blocks both branches):**
```typescript
async function handleRequest(userId: string, skipProcessing: boolean) {
const userData = await fetchUserData(userId)
if (skipProcessing) {
// Returns immediately but still waited for userData
return { skipped: true }
}
// Only this branch uses userData
return processUserData(userData)
}
```
**Correct (only blocks when needed):**
```typescript
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
// Returns immediately without waiting
return { skipped: true }
}
// Fetch only when needed
const userData = await fetchUserData(userId)
return processUserData(userData)
}
```
**Another example (early return optimization):**
```typescript
// Incorrect: always fetches permissions
async function updateResource(resourceId: string, userId: string) {
const permissions = await fetchPermissions(userId)
const resource = await getResource(resourceId)
if (!resource) {
return { error: 'Not found' }
}
if (!permissions.canEdit) {
return { error: 'Forbidden' }
}
return await updateResourceData(resource, permissions)
}
// Correct: fetches only when needed
async function updateResource(resourceId: string, userId: string) {
const resource = await getResource(resourceId)
if (!resource) {
return { error: 'Not found' }
}
const permissions = await fetchPermissions(userId)
if (!permissions.canEdit) {
return { error: 'Forbidden' }
}
return await updateResourceData(resource, permissions)
}
```
This optimization is especially valuable when the skipped branch is frequently taken, or when the deferred operation is expensive.
@@ -1,36 +0,0 @@
---
title: Dependency-Based Parallelization
impact: CRITICAL
impactDescription: 2-10× improvement
tags: async, parallelization, dependencies, better-all
---
## Dependency-Based Parallelization
For operations with partial dependencies, use `better-all` to maximize parallelism. It automatically starts each task at the earliest possible moment.
**Incorrect (profile waits for config unnecessarily):**
```typescript
const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
const profile = await fetchProfile(user.id)
```
**Correct (config and profile run in parallel):**
```typescript
import { all } from 'better-all'
const { user, config, profile } = await all({
async user() { return fetchUser() },
async config() { return fetchConfig() },
async profile() {
return fetchProfile((await this.$.user).id)
}
})
```
Reference: [https://github.com/shuding/better-all](https://github.com/shuding/better-all)
@@ -1,28 +0,0 @@
---
title: Promise.all() for Independent Operations
impact: CRITICAL
impactDescription: 2-10× improvement
tags: async, parallelization, promises, waterfalls
---
## Promise.all() for Independent Operations
When async operations have no interdependencies, execute them concurrently using `Promise.all()`.
**Incorrect (sequential execution, 3 round trips):**
```typescript
const user = await fetchUser()
const posts = await fetchPosts()
const comments = await fetchComments()
```
**Correct (parallel execution, 1 round trip):**
```typescript
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])
```
@@ -1,99 +0,0 @@
---
title: Strategic Suspense Boundaries
impact: HIGH
impactDescription: faster initial paint
tags: async, suspense, streaming, layout-shift
---
## Strategic Suspense Boundaries
Instead of awaiting data in async components before returning JSX, use Suspense boundaries to show the wrapper UI faster while data loads.
**Incorrect (wrapper blocked by data fetching):**
```tsx
async function Page() {
const data = await fetchData() // Blocks entire page
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<DataDisplay data={data} />
</div>
<div>Footer</div>
</div>
)
}
```
The entire layout waits for data even though only the middle section needs it.
**Correct (wrapper shows immediately, data streams in):**
```tsx
function Page() {
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<Suspense fallback={<Skeleton />}>
<DataDisplay />
</Suspense>
</div>
<div>Footer</div>
</div>
)
}
async function DataDisplay() {
const data = await fetchData() // Only blocks this component
return <div>{data.content}</div>
}
```
Sidebar, Header, and Footer render immediately. Only DataDisplay waits for data.
**Alternative (share promise across components):**
```tsx
function Page() {
// Start fetch immediately, but don't await
const dataPromise = fetchData()
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<Suspense fallback={<Skeleton />}>
<DataDisplay dataPromise={dataPromise} />
<DataSummary dataPromise={dataPromise} />
</Suspense>
<div>Footer</div>
</div>
)
}
function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise) // Unwraps the promise
return <div>{data.content}</div>
}
function DataSummary({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise) // Reuses the same promise
return <div>{data.summary}</div>
}
```
Both components share the same promise, so only one fetch occurs. Layout renders immediately while both components wait together.
**When NOT to use this pattern:**
- Critical data needed for layout decisions (affects positioning)
- SEO-critical content above the fold
- Small, fast queries where suspense overhead isn't worth it
- When you want to avoid layout shift (loading → content jump)
**Trade-off:** Faster initial paint vs potential layout shift. Choose based on your UX priorities.
@@ -1,59 +0,0 @@
---
title: Avoid Barrel File Imports
impact: CRITICAL
impactDescription: 200-800ms import cost, slow builds
tags: bundle, imports, tree-shaking, barrel-files, performance
---
## Avoid Barrel File Imports
Import directly from source files instead of barrel files to avoid loading thousands of unused modules. **Barrel files** are entry points that re-export multiple modules (e.g., `index.js` that does `export * from './module'`).
Popular icon and component libraries can have **up to 10,000 re-exports** in their entry file. For many React packages, **it takes 200-800ms just to import them**, affecting both development speed and production cold starts.
**Why tree-shaking doesn't help:** When a library is marked as external (not bundled), the bundler can't optimize it. If you bundle it to enable tree-shaking, builds become substantially slower analyzing the entire module graph.
**Incorrect (imports entire library):**
```tsx
import { Check, X, Menu } from 'lucide-react'
// Loads 1,583 modules, takes ~2.8s extra in dev
// Runtime cost: 200-800ms on every cold start
import { Button, TextField } from '@mui/material'
// Loads 2,225 modules, takes ~4.2s extra in dev
```
**Correct (imports only what you need):**
```tsx
import Check from 'lucide-react/dist/esm/icons/check'
import X from 'lucide-react/dist/esm/icons/x'
import Menu from 'lucide-react/dist/esm/icons/menu'
// Loads only 3 modules (~2KB vs ~1MB)
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
// Loads only what you use
```
**Alternative (Next.js 13.5+):**
```js
// next.config.js - use optimizePackageImports
module.exports = {
experimental: {
optimizePackageImports: ['lucide-react', '@mui/material']
}
}
// Then you can keep the ergonomic barrel imports:
import { Check, X, Menu } from 'lucide-react'
// Automatically transformed to direct imports at build time
```
Direct imports provide 15-70% faster dev boot, 28% faster builds, 40% faster cold starts, and significantly faster HMR.
Libraries commonly affected: `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `ramda`, `date-fns`, `rxjs`, `react-use`.
Reference: [How we optimized package imports in Next.js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
@@ -1,31 +0,0 @@
---
title: Conditional Module Loading
impact: HIGH
impactDescription: loads large data only when needed
tags: bundle, conditional-loading, lazy-loading
---
## Conditional Module Loading
Load large data or modules only when a feature is activated.
**Example (lazy-load animation frames):**
```tsx
function AnimationPlayer({ enabled, setEnabled }: { enabled: boolean; setEnabled: React.Dispatch<React.SetStateAction<boolean>> }) {
const [frames, setFrames] = useState<Frame[] | null>(null)
useEffect(() => {
if (enabled && !frames && typeof window !== 'undefined') {
import('./animation-frames.js')
.then(mod => setFrames(mod.frames))
.catch(() => setEnabled(false))
}
}, [enabled, frames, setEnabled])
if (!frames) return <Skeleton />
return <Canvas frames={frames} />
}
```
The `typeof window !== 'undefined'` check prevents bundling this module for SSR, optimizing server bundle size and build speed.
@@ -1,49 +0,0 @@
---
title: Defer Non-Critical Third-Party Libraries
impact: MEDIUM
impactDescription: loads after hydration
tags: bundle, third-party, analytics, defer
---
## Defer Non-Critical Third-Party Libraries
Analytics, logging, and error tracking don't block user interaction. Load them after hydration.
**Incorrect (blocks initial bundle):**
```tsx
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
)
}
```
**Correct (loads after hydration):**
```tsx
import dynamic from 'next/dynamic'
const Analytics = dynamic(
() => import('@vercel/analytics/react').then(m => m.Analytics),
{ ssr: false }
)
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
)
}
```
@@ -1,35 +0,0 @@
---
title: Dynamic Imports for Heavy Components
impact: CRITICAL
impactDescription: directly affects TTI and LCP
tags: bundle, dynamic-import, code-splitting, next-dynamic
---
## Dynamic Imports for Heavy Components
Use `next/dynamic` to lazy-load large components not needed on initial render.
**Incorrect (Monaco bundles with main chunk ~300KB):**
```tsx
import { MonacoEditor } from './monaco-editor'
function CodePanel({ code }: { code: string }) {
return <MonacoEditor value={code} />
}
```
**Correct (Monaco loads on demand):**
```tsx
import dynamic from 'next/dynamic'
const MonacoEditor = dynamic(
() => import('./monaco-editor').then(m => m.MonacoEditor),
{ ssr: false }
)
function CodePanel({ code }: { code: string }) {
return <MonacoEditor value={code} />
}
```
@@ -1,50 +0,0 @@
---
title: Preload Based on User Intent
impact: MEDIUM
impactDescription: reduces perceived latency
tags: bundle, preload, user-intent, hover
---
## Preload Based on User Intent
Preload heavy bundles before they're needed to reduce perceived latency.
**Example (preload on hover/focus):**
```tsx
function EditorButton({ onClick }: { onClick: () => void }) {
const preload = () => {
if (typeof window !== 'undefined') {
void import('./monaco-editor')
}
}
return (
<button
onMouseEnter={preload}
onFocus={preload}
onClick={onClick}
>
Open Editor
</button>
)
}
```
**Example (preload when feature flag is enabled):**
```tsx
function FlagsProvider({ children, flags }: Props) {
useEffect(() => {
if (flags.editorEnabled && typeof window !== 'undefined') {
void import('./monaco-editor').then(mod => mod.init())
}
}, [flags.editorEnabled])
return <FlagsContext.Provider value={flags}>
{children}
</FlagsContext.Provider>
}
```
The `typeof window !== 'undefined'` check prevents bundling preloaded modules for SSR, optimizing server bundle size and build speed.
@@ -1,74 +0,0 @@
---
title: Deduplicate Global Event Listeners
impact: LOW
impactDescription: single listener for N components
tags: client, swr, event-listeners, subscription
---
## Deduplicate Global Event Listeners
Use `useSWRSubscription()` to share global event listeners across component instances.
**Incorrect (N instances = N listeners):**
```tsx
function useKeyboardShortcut(key: string, callback: () => void) {
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && e.key === key) {
callback()
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
}, [key, callback])
}
```
When using the `useKeyboardShortcut` hook multiple times, each instance will register a new listener.
**Correct (N instances = 1 listener):**
```tsx
import useSWRSubscription from 'swr/subscription'
// Module-level Map to track callbacks per key
const keyCallbacks = new Map<string, Set<() => void>>()
function useKeyboardShortcut(key: string, callback: () => void) {
// Register this callback in the Map
useEffect(() => {
if (!keyCallbacks.has(key)) {
keyCallbacks.set(key, new Set())
}
keyCallbacks.get(key)!.add(callback)
return () => {
const set = keyCallbacks.get(key)
if (set) {
set.delete(callback)
if (set.size === 0) {
keyCallbacks.delete(key)
}
}
}
}, [key, callback])
useSWRSubscription('global-keydown', () => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && keyCallbacks.has(e.key)) {
keyCallbacks.get(e.key)!.forEach(cb => cb())
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
})
}
function Profile() {
// Multiple shortcuts will share the same listener
useKeyboardShortcut('p', () => { /* ... */ })
useKeyboardShortcut('k', () => { /* ... */ })
// ...
}
```
@@ -1,71 +0,0 @@
---
title: Version and Minimize localStorage Data
impact: MEDIUM
impactDescription: prevents schema conflicts, reduces storage size
tags: client, localStorage, storage, versioning, data-minimization
---
## Version and Minimize localStorage Data
Add version prefix to keys and store only needed fields. Prevents schema conflicts and accidental storage of sensitive data.
**Incorrect:**
```typescript
// No version, stores everything, no error handling
localStorage.setItem('userConfig', JSON.stringify(fullUserObject))
const data = localStorage.getItem('userConfig')
```
**Correct:**
```typescript
const VERSION = 'v2'
function saveConfig(config: { theme: string; language: string }) {
try {
localStorage.setItem(`userConfig:${VERSION}`, JSON.stringify(config))
} catch {
// Throws in incognito/private browsing, quota exceeded, or disabled
}
}
function loadConfig() {
try {
const data = localStorage.getItem(`userConfig:${VERSION}`)
return data ? JSON.parse(data) : null
} catch {
return null
}
}
// Migration from v1 to v2
function migrate() {
try {
const v1 = localStorage.getItem('userConfig:v1')
if (v1) {
const old = JSON.parse(v1)
saveConfig({ theme: old.darkMode ? 'dark' : 'light', language: old.lang })
localStorage.removeItem('userConfig:v1')
}
} catch {}
}
```
**Store minimal fields from server responses:**
```typescript
// User object has 20+ fields, only store what UI needs
function cachePrefs(user: FullUser) {
try {
localStorage.setItem('prefs:v1', JSON.stringify({
theme: user.preferences.theme,
notifications: user.preferences.notifications
}))
} catch {}
}
```
**Always wrap in try-catch:** `getItem()` and `setItem()` throw in incognito/private browsing (Safari, Firefox), when quota exceeded, or when disabled.
**Benefits:** Schema evolution via versioning, reduced storage size, prevents storing tokens/PII/internal flags.
@@ -1,48 +0,0 @@
---
title: Use Passive Event Listeners for Scrolling Performance
impact: MEDIUM
impactDescription: eliminates scroll delay caused by event listeners
tags: client, event-listeners, scrolling, performance, touch, wheel
---
## Use Passive Event Listeners for Scrolling Performance
Add `{ passive: true }` to touch and wheel event listeners to enable immediate scrolling. Browsers normally wait for listeners to finish to check if `preventDefault()` is called, causing scroll delay.
**Incorrect:**
```typescript
useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)
document.addEventListener('touchstart', handleTouch)
document.addEventListener('wheel', handleWheel)
return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])
```
**Correct:**
```typescript
useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)
document.addEventListener('touchstart', handleTouch, { passive: true })
document.addEventListener('wheel', handleWheel, { passive: true })
return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])
```
**Use passive when:** tracking/analytics, logging, any listener that doesn't call `preventDefault()`.
**Don't use passive when:** implementing custom swipe gestures, custom zoom controls, or any listener that needs `preventDefault()`.
@@ -1,56 +0,0 @@
---
title: Use SWR for Automatic Deduplication
impact: MEDIUM-HIGH
impactDescription: automatic deduplication
tags: client, swr, deduplication, data-fetching
---
## Use SWR for Automatic Deduplication
SWR enables request deduplication, caching, and revalidation across component instances.
**Incorrect (no deduplication, each instance fetches):**
```tsx
function UserList() {
const [users, setUsers] = useState([])
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(setUsers)
}, [])
}
```
**Correct (multiple instances share one request):**
```tsx
import useSWR from 'swr'
function UserList() {
const { data: users } = useSWR('/api/users', fetcher)
}
```
**For immutable data:**
```tsx
import { useImmutableSWR } from '@/lib/swr'
function StaticContent() {
const { data } = useImmutableSWR('/api/config', fetcher)
}
```
**For mutations:**
```tsx
import { useSWRMutation } from 'swr/mutation'
function UpdateButton() {
const { trigger } = useSWRMutation('/api/user', updateUser)
return <button onClick={() => trigger()}>Update</button>
}
```
Reference: [https://swr.vercel.app](https://swr.vercel.app)
@@ -1,57 +0,0 @@
---
title: Batch DOM CSS Changes
impact: MEDIUM
impactDescription: reduces reflows/repaints
tags: javascript, dom, css, performance, reflow
---
## Batch DOM CSS Changes
Avoid interleaving style writes with layout reads. When you read a layout property (like `offsetWidth`, `getBoundingClientRect()`, or `getComputedStyle()`) between style changes, the browser is forced to trigger a synchronous reflow.
**Incorrect (interleaved reads and writes force reflows):**
```typescript
function updateElementStyles(element: HTMLElement) {
element.style.width = '100px'
const width = element.offsetWidth // Forces reflow
element.style.height = '200px'
const height = element.offsetHeight // Forces another reflow
}
```
**Correct (batch writes, then read once):**
```typescript
function updateElementStyles(element: HTMLElement) {
// Batch all writes together
element.style.width = '100px'
element.style.height = '200px'
element.style.backgroundColor = 'blue'
element.style.border = '1px solid black'
// Read after all writes are done (single reflow)
const { width, height } = element.getBoundingClientRect()
}
```
**Better: use CSS classes**
```css
.highlighted-box {
width: 100px;
height: 200px;
background-color: blue;
border: 1px solid black;
}
```
```typescript
function updateElementStyles(element: HTMLElement) {
element.classList.add('highlighted-box')
const { width, height } = element.getBoundingClientRect()
}
```
Prefer CSS classes over inline styles when possible. CSS files are cached by the browser, and classes provide better separation of concerns and are easier to maintain.
@@ -1,80 +0,0 @@
---
title: Cache Repeated Function Calls
impact: MEDIUM
impactDescription: avoid redundant computation
tags: javascript, cache, memoization, performance
---
## Cache Repeated Function Calls
Use a module-level Map to cache function results when the same function is called repeatedly with the same inputs during render.
**Incorrect (redundant computation):**
```typescript
function ProjectList({ projects }: { projects: Project[] }) {
return (
<div>
{projects.map(project => {
// slugify() called 100+ times for same project names
const slug = slugify(project.name)
return <ProjectCard key={project.id} slug={slug} />
})}
</div>
)
}
```
**Correct (cached results):**
```typescript
// Module-level cache
const slugifyCache = new Map<string, string>()
function cachedSlugify(text: string): string {
if (slugifyCache.has(text)) {
return slugifyCache.get(text)!
}
const result = slugify(text)
slugifyCache.set(text, result)
return result
}
function ProjectList({ projects }: { projects: Project[] }) {
return (
<div>
{projects.map(project => {
// Computed only once per unique project name
const slug = cachedSlugify(project.name)
return <ProjectCard key={project.id} slug={slug} />
})}
</div>
)
}
```
**Simpler pattern for single-value functions:**
```typescript
let isLoggedInCache: boolean | null = null
function isLoggedIn(): boolean {
if (isLoggedInCache !== null) {
return isLoggedInCache
}
isLoggedInCache = document.cookie.includes('auth=')
return isLoggedInCache
}
// Clear cache when auth changes
function onAuthChange() {
isLoggedInCache = null
}
```
Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
Reference: [How we made the Vercel Dashboard twice as fast](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)
@@ -1,28 +0,0 @@
---
title: Cache Property Access in Loops
impact: LOW-MEDIUM
impactDescription: reduces lookups
tags: javascript, loops, optimization, caching
---
## Cache Property Access in Loops
Cache object property lookups in hot paths.
**Incorrect (3 lookups × N iterations):**
```typescript
for (let i = 0; i < arr.length; i++) {
process(obj.config.settings.value)
}
```
**Correct (1 lookup total):**
```typescript
const value = obj.config.settings.value
const len = arr.length
for (let i = 0; i < len; i++) {
process(value)
}
```
@@ -1,70 +0,0 @@
---
title: Cache Storage API Calls
impact: LOW-MEDIUM
impactDescription: reduces expensive I/O
tags: javascript, localStorage, storage, caching, performance
---
## Cache Storage API Calls
`localStorage`, `sessionStorage`, and `document.cookie` are synchronous and expensive. Cache reads in memory.
**Incorrect (reads storage on every call):**
```typescript
function getTheme() {
return localStorage.getItem('theme') ?? 'light'
}
// Called 10 times = 10 storage reads
```
**Correct (Map cache):**
```typescript
const storageCache = new Map<string, string | null>()
function getLocalStorage(key: string) {
if (!storageCache.has(key)) {
storageCache.set(key, localStorage.getItem(key))
}
return storageCache.get(key)
}
function setLocalStorage(key: string, value: string) {
localStorage.setItem(key, value)
storageCache.set(key, value) // keep cache in sync
}
```
Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
**Cookie caching:**
```typescript
let cookieCache: Record<string, string> | null = null
function getCookie(name: string) {
if (!cookieCache) {
cookieCache = Object.fromEntries(
document.cookie.split('; ').map(c => c.split('='))
)
}
return cookieCache[name]
}
```
**Important (invalidate on external changes):**
If storage can change externally (another tab, server-set cookies), invalidate cache:
```typescript
window.addEventListener('storage', (e) => {
if (e.key) storageCache.delete(e.key)
})
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
storageCache.clear()
}
})
```
@@ -1,32 +0,0 @@
---
title: Combine Multiple Array Iterations
impact: LOW-MEDIUM
impactDescription: reduces iterations
tags: javascript, arrays, loops, performance
---
## Combine Multiple Array Iterations
Multiple `.filter()` or `.map()` calls iterate the array multiple times. Combine into one loop.
**Incorrect (3 iterations):**
```typescript
const admins = users.filter(u => u.isAdmin)
const testers = users.filter(u => u.isTester)
const inactive = users.filter(u => !u.isActive)
```
**Correct (1 iteration):**
```typescript
const admins: User[] = []
const testers: User[] = []
const inactive: User[] = []
for (const user of users) {
if (user.isAdmin) admins.push(user)
if (user.isTester) testers.push(user)
if (!user.isActive) inactive.push(user)
}
```
@@ -1,50 +0,0 @@
---
title: Early Return from Functions
impact: LOW-MEDIUM
impactDescription: avoids unnecessary computation
tags: javascript, functions, optimization, early-return
---
## Early Return from Functions
Return early when result is determined to skip unnecessary processing.
**Incorrect (processes all items even after finding answer):**
```typescript
function validateUsers(users: User[]) {
let hasError = false
let errorMessage = ''
for (const user of users) {
if (!user.email) {
hasError = true
errorMessage = 'Email required'
}
if (!user.name) {
hasError = true
errorMessage = 'Name required'
}
// Continues checking all users even after error found
}
return hasError ? { valid: false, error: errorMessage } : { valid: true }
}
```
**Correct (returns immediately on first error):**
```typescript
function validateUsers(users: User[]) {
for (const user of users) {
if (!user.email) {
return { valid: false, error: 'Email required' }
}
if (!user.name) {
return { valid: false, error: 'Name required' }
}
}
return { valid: true }
}
```
@@ -1,45 +0,0 @@
---
title: Hoist RegExp Creation
impact: LOW-MEDIUM
impactDescription: avoids recreation
tags: javascript, regexp, optimization, memoization
---
## Hoist RegExp Creation
Don't create RegExp inside render. Hoist to module scope or memoize with `useMemo()`.
**Incorrect (new RegExp every render):**
```tsx
function Highlighter({ text, query }: Props) {
const regex = new RegExp(`(${query})`, 'gi')
const parts = text.split(regex)
return <>{parts.map((part, i) => ...)}</>
}
```
**Correct (memoize or hoist):**
```tsx
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
function Highlighter({ text, query }: Props) {
const regex = useMemo(
() => new RegExp(`(${escapeRegex(query)})`, 'gi'),
[query]
)
const parts = text.split(regex)
return <>{parts.map((part, i) => ...)}</>
}
```
**Warning (global regex has mutable state):**
Global regex (`/g`) has mutable `lastIndex` state:
```typescript
const regex = /foo/g
regex.test('foo') // true, lastIndex = 3
regex.test('foo') // false, lastIndex = 0
```
@@ -1,37 +0,0 @@
---
title: Build Index Maps for Repeated Lookups
impact: LOW-MEDIUM
impactDescription: 1M ops to 2K ops
tags: javascript, map, indexing, optimization, performance
---
## Build Index Maps for Repeated Lookups
Multiple `.find()` calls by the same key should use a Map.
**Incorrect (O(n) per lookup):**
```typescript
function processOrders(orders: Order[], users: User[]) {
return orders.map(order => ({
...order,
user: users.find(u => u.id === order.userId)
}))
}
```
**Correct (O(1) per lookup):**
```typescript
function processOrders(orders: Order[], users: User[]) {
const userById = new Map(users.map(u => [u.id, u]))
return orders.map(order => ({
...order,
user: userById.get(order.userId)
}))
}
```
Build map once (O(n)), then all lookups are O(1).
For 1000 orders × 1000 users: 1M ops → 2K ops.
@@ -1,49 +0,0 @@
---
title: Early Length Check for Array Comparisons
impact: MEDIUM-HIGH
impactDescription: avoids expensive operations when lengths differ
tags: javascript, arrays, performance, optimization, comparison
---
## Early Length Check for Array Comparisons
When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
**Incorrect (always runs expensive comparison):**
```typescript
function hasChanges(current: string[], original: string[]) {
// Always sorts and joins, even when lengths differ
return current.sort().join() !== original.sort().join()
}
```
Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
**Correct (O(1) length check first):**
```typescript
function hasChanges(current: string[], original: string[]) {
// Early return if lengths differ
if (current.length !== original.length) {
return true
}
// Only sort when lengths match
const currentSorted = current.toSorted()
const originalSorted = original.toSorted()
for (let i = 0; i < currentSorted.length; i++) {
if (currentSorted[i] !== originalSorted[i]) {
return true
}
}
return false
}
```
This new approach is more efficient because:
- It avoids the overhead of sorting and joining the arrays when lengths differ
- It avoids consuming memory for the joined strings (especially important for large arrays)
- It avoids mutating the original arrays
- It returns early when a difference is found
@@ -1,82 +0,0 @@
---
title: Use Loop for Min/Max Instead of Sort
impact: LOW
impactDescription: O(n) instead of O(n log n)
tags: javascript, arrays, performance, sorting, algorithms
---
## Use Loop for Min/Max Instead of Sort
Finding the smallest or largest element only requires a single pass through the array. Sorting is wasteful and slower.
**Incorrect (O(n log n) - sort to find latest):**
```typescript
interface Project {
id: string
name: string
updatedAt: number
}
function getLatestProject(projects: Project[]) {
const sorted = [...projects].sort((a, b) => b.updatedAt - a.updatedAt)
return sorted[0]
}
```
Sorts the entire array just to find the maximum value.
**Incorrect (O(n log n) - sort for oldest and newest):**
```typescript
function getOldestAndNewest(projects: Project[]) {
const sorted = [...projects].sort((a, b) => a.updatedAt - b.updatedAt)
return { oldest: sorted[0], newest: sorted[sorted.length - 1] }
}
```
Still sorts unnecessarily when only min/max are needed.
**Correct (O(n) - single loop):**
```typescript
function getLatestProject(projects: Project[]) {
if (projects.length === 0) return null
let latest = projects[0]
for (let i = 1; i < projects.length; i++) {
if (projects[i].updatedAt > latest.updatedAt) {
latest = projects[i]
}
}
return latest
}
function getOldestAndNewest(projects: Project[]) {
if (projects.length === 0) return { oldest: null, newest: null }
let oldest = projects[0]
let newest = projects[0]
for (let i = 1; i < projects.length; i++) {
if (projects[i].updatedAt < oldest.updatedAt) oldest = projects[i]
if (projects[i].updatedAt > newest.updatedAt) newest = projects[i]
}
return { oldest, newest }
}
```
Single pass through the array, no copying, no sorting.
**Alternative (Math.min/Math.max for small arrays):**
```typescript
const numbers = [5, 2, 8, 1, 9]
const min = Math.min(...numbers)
const max = Math.max(...numbers)
```
This works for small arrays, but can be slower or just throw an error for very large arrays due to spread operator limitations. Maximal array length is approximately 124000 in Chrome 143 and 638000 in Safari 18; exact numbers may vary - see [the fiddle](https://jsfiddle.net/qw1jabsx/4/). Use the loop approach for reliability.
@@ -1,24 +0,0 @@
---
title: Use Set/Map for O(1) Lookups
impact: LOW-MEDIUM
impactDescription: O(n) to O(1)
tags: javascript, set, map, data-structures, performance
---
## Use Set/Map for O(1) Lookups
Convert arrays to Set/Map for repeated membership checks.
**Incorrect (O(n) per check):**
```typescript
const allowedIds = ['a', 'b', 'c', ...]
items.filter(item => allowedIds.includes(item.id))
```
**Correct (O(1) per check):**
```typescript
const allowedIds = new Set(['a', 'b', 'c', ...])
items.filter(item => allowedIds.has(item.id))
```
@@ -1,57 +0,0 @@
---
title: Use toSorted() Instead of sort() for Immutability
impact: MEDIUM-HIGH
impactDescription: prevents mutation bugs in React state
tags: javascript, arrays, immutability, react, state, mutation
---
## Use toSorted() Instead of sort() for Immutability
`.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
**Incorrect (mutates original array):**
```typescript
function UserList({ users }: { users: User[] }) {
// Mutates the users prop array!
const sorted = useMemo(
() => users.sort((a, b) => a.name.localeCompare(b.name)),
[users]
)
return <div>{sorted.map(renderUser)}</div>
}
```
**Correct (creates new array):**
```typescript
function UserList({ users }: { users: User[] }) {
// Creates new sorted array, original unchanged
const sorted = useMemo(
() => users.toSorted((a, b) => a.name.localeCompare(b.name)),
[users]
)
return <div>{sorted.map(renderUser)}</div>
}
```
**Why this matters in React:**
1. Props/state mutations break React's immutability model - React expects props and state to be treated as read-only
2. Causes stale closure bugs - Mutating arrays inside closures (callbacks, effects) can lead to unexpected behavior
**Browser support (fallback for older browsers):**
`.toSorted()` is available in all modern browsers (Chrome 110+, Safari 16+, Firefox 115+, Node.js 20+). For older environments, use spread operator:
```typescript
// Fallback for older browsers
const sorted = [...items].sort((a, b) => a.value - b.value)
```
**Other immutable array methods:**
- `.toSorted()` - immutable sort
- `.toReversed()` - immutable reverse
- `.toSpliced()` - immutable splice
- `.with()` - immutable element replacement
@@ -1,26 +0,0 @@
---
title: Use Activity Component for Show/Hide
impact: MEDIUM
impactDescription: preserves state/DOM
tags: rendering, activity, visibility, state-preservation
---
## Use Activity Component for Show/Hide
Use React's `<Activity>` to preserve state/DOM for expensive components that frequently toggle visibility.
**Usage:**
```tsx
import { Activity } from 'react'
function Dropdown({ isOpen }: Props) {
return (
<Activity mode={isOpen ? 'visible' : 'hidden'}>
<ExpensiveMenu />
</Activity>
)
}
```
Avoids expensive re-renders and state loss.
@@ -1,47 +0,0 @@
---
title: Animate SVG Wrapper Instead of SVG Element
impact: LOW
impactDescription: enables hardware acceleration
tags: rendering, svg, css, animation, performance
---
## Animate SVG Wrapper Instead of SVG Element
Many browsers don't have hardware acceleration for CSS3 animations on SVG elements. Wrap SVG in a `<div>` and animate the wrapper instead.
**Incorrect (animating SVG directly - no hardware acceleration):**
```tsx
function LoadingSpinner() {
return (
<svg
className="animate-spin"
width="24"
height="24"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
)
}
```
**Correct (animating wrapper div - hardware accelerated):**
```tsx
function LoadingSpinner() {
return (
<div className="animate-spin">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
</div>
)
}
```
This applies to all CSS transforms and transitions (`transform`, `opacity`, `translate`, `scale`, `rotate`). The wrapper div allows browsers to use GPU acceleration for smoother animations.
@@ -1,40 +0,0 @@
---
title: Use Explicit Conditional Rendering
impact: LOW
impactDescription: prevents rendering 0 or NaN
tags: rendering, conditional, jsx, falsy-values
---
## Use Explicit Conditional Rendering
Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
**Incorrect (renders "0" when count is 0):**
```tsx
function Badge({ count }: { count: number }) {
return (
<div>
{count && <span className="badge">{count}</span>}
</div>
)
}
// When count = 0, renders: <div>0</div>
// When count = 5, renders: <div><span class="badge">5</span></div>
```
**Correct (renders nothing when count is 0):**
```tsx
function Badge({ count }: { count: number }) {
return (
<div>
{count > 0 ? <span className="badge">{count}</span> : null}
</div>
)
}
// When count = 0, renders: <div></div>
// When count = 5, renders: <div><span class="badge">5</span></div>
```
@@ -1,38 +0,0 @@
---
title: CSS content-visibility for Long Lists
impact: HIGH
impactDescription: faster initial render
tags: rendering, css, content-visibility, long-lists
---
## CSS content-visibility for Long Lists
Apply `content-visibility: auto` to defer off-screen rendering.
**CSS:**
```css
.message-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px;
}
```
**Example:**
```tsx
function MessageList({ messages }: { messages: Message[] }) {
return (
<div className="overflow-y-auto h-screen">
{messages.map(msg => (
<div key={msg.id} className="message-item">
<Avatar user={msg.author} />
<div>{msg.content}</div>
</div>
))}
</div>
)
}
```
For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).
@@ -1,46 +0,0 @@
---
title: Hoist Static JSX Elements
impact: LOW
impactDescription: avoids re-creation
tags: rendering, jsx, static, optimization
---
## Hoist Static JSX Elements
Extract static JSX outside components to avoid re-creation.
**Incorrect (recreates element every render):**
```tsx
function LoadingSkeleton() {
return <div className="animate-pulse h-20 bg-gray-200" />
}
function Container() {
return (
<div>
{loading && <LoadingSkeleton />}
</div>
)
}
```
**Correct (reuses same element):**
```tsx
const loadingSkeleton = (
<div className="animate-pulse h-20 bg-gray-200" />
)
function Container() {
return (
<div>
{loading && loadingSkeleton}
</div>
)
}
```
This is especially helpful for large and static SVG nodes, which can be expensive to recreate on every render.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler automatically hoists static JSX elements and optimizes component re-renders, making manual hoisting unnecessary.
@@ -1,82 +0,0 @@
---
title: Prevent Hydration Mismatch Without Flickering
impact: MEDIUM
impactDescription: avoids visual flicker and hydration errors
tags: rendering, ssr, hydration, localStorage, flicker
---
## Prevent Hydration Mismatch Without Flickering
When rendering content that depends on client-side storage (localStorage, cookies), avoid both SSR breakage and post-hydration flickering by injecting a synchronous script that updates the DOM before React hydrates.
**Incorrect (breaks SSR):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
// localStorage is not available on server - throws error
const theme = localStorage.getItem('theme') || 'light'
return (
<div className={theme}>
{children}
</div>
)
}
```
Server-side rendering will fail because `localStorage` is undefined.
**Incorrect (visual flickering):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState('light')
useEffect(() => {
// Runs after hydration - causes visible flash
const stored = localStorage.getItem('theme')
if (stored) {
setTheme(stored)
}
}, [])
return (
<div className={theme}>
{children}
</div>
)
}
```
Component first renders with default value (`light`), then updates after hydration, causing a visible flash of incorrect content.
**Correct (no flicker, no hydration mismatch):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
return (
<>
<div id="theme-wrapper">
{children}
</div>
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
try {
var theme = localStorage.getItem('theme') || 'light';
var el = document.getElementById('theme-wrapper');
if (el) el.className = theme;
} catch (e) {}
})();
`,
}}
/>
</>
)
}
```
The inline script executes synchronously before showing the element, ensuring the DOM already has the correct value. No flickering, no hydration mismatch.
This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.
@@ -1,28 +0,0 @@
---
title: Optimize SVG Precision
impact: LOW
impactDescription: reduces file size
tags: rendering, svg, optimization, svgo
---
## Optimize SVG Precision
Reduce SVG coordinate precision to decrease file size. The optimal precision depends on the viewBox size, but in general reducing precision should be considered.
**Incorrect (excessive precision):**
```svg
<path d="M 10.293847 20.847362 L 30.938472 40.192837" />
```
**Correct (1 decimal place):**
```svg
<path d="M 10.3 20.8 L 30.9 40.2" />
```
**Automate with SVGO:**
```bash
npx svgo --precision=1 --multipass icon.svg
```
@@ -1,39 +0,0 @@
---
title: Defer State Reads to Usage Point
impact: MEDIUM
impactDescription: avoids unnecessary subscriptions
tags: rerender, searchParams, localStorage, optimization
---
## Defer State Reads to Usage Point
Don't subscribe to dynamic state (searchParams, localStorage) if you only read it inside callbacks.
**Incorrect (subscribes to all searchParams changes):**
```tsx
function ShareButton({ chatId }: { chatId: string }) {
const searchParams = useSearchParams()
const handleShare = () => {
const ref = searchParams.get('ref')
shareChat(chatId, { ref })
}
return <button onClick={handleShare}>Share</button>
}
```
**Correct (reads on demand, no subscription):**
```tsx
function ShareButton({ chatId }: { chatId: string }) {
const handleShare = () => {
const params = new URLSearchParams(window.location.search)
const ref = params.get('ref')
shareChat(chatId, { ref })
}
return <button onClick={handleShare}>Share</button>
}
```
@@ -1,45 +0,0 @@
---
title: Narrow Effect Dependencies
impact: LOW
impactDescription: minimizes effect re-runs
tags: rerender, useEffect, dependencies, optimization
---
## Narrow Effect Dependencies
Specify primitive dependencies instead of objects to minimize effect re-runs.
**Incorrect (re-runs on any user field change):**
```tsx
useEffect(() => {
console.log(user.id)
}, [user])
```
**Correct (re-runs only when id changes):**
```tsx
useEffect(() => {
console.log(user.id)
}, [user.id])
```
**For derived state, compute outside effect:**
```tsx
// Incorrect: runs on width=767, 766, 765...
useEffect(() => {
if (width < 768) {
enableMobileMode()
}
}, [width])
// Correct: runs only on boolean transition
const isMobile = width < 768
useEffect(() => {
if (isMobile) {
enableMobileMode()
}
}, [isMobile])
```
@@ -1,29 +0,0 @@
---
title: Subscribe to Derived State
impact: MEDIUM
impactDescription: reduces re-render frequency
tags: rerender, derived-state, media-query, optimization
---
## Subscribe to Derived State
Subscribe to derived boolean state instead of continuous values to reduce re-render frequency.
**Incorrect (re-renders on every pixel change):**
```tsx
function Sidebar() {
const width = useWindowWidth() // updates continuously
const isMobile = width < 768
return <nav className={isMobile ? 'mobile' : 'desktop'} />
}
```
**Correct (re-renders only when boolean changes):**
```tsx
function Sidebar() {
const isMobile = useMediaQuery('(max-width: 767px)')
return <nav className={isMobile ? 'mobile' : 'desktop'} />
}
```
@@ -1,74 +0,0 @@
---
title: Use Functional setState Updates
impact: MEDIUM
impactDescription: prevents stale closures and unnecessary callback recreations
tags: react, hooks, useState, useCallback, callbacks, closures
---
## Use Functional setState Updates
When updating state based on the current state value, use the functional update form of setState instead of directly referencing the state variable. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
**Incorrect (requires state as dependency):**
```tsx
function TodoList() {
const [items, setItems] = useState(initialItems)
// Callback must depend on items, recreated on every items change
const addItems = useCallback((newItems: Item[]) => {
setItems([...items, ...newItems])
}, [items]) // ❌ items dependency causes recreations
// Risk of stale closure if dependency is forgotten
const removeItem = useCallback((id: string) => {
setItems(items.filter(item => item.id !== id))
}, []) // ❌ Missing items dependency - will use stale items!
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
```
The first callback is recreated every time `items` changes, which can cause child components to re-render unnecessarily. The second callback has a stale closure bug—it will always reference the initial `items` value.
**Correct (stable callbacks, no stale closures):**
```tsx
function TodoList() {
const [items, setItems] = useState(initialItems)
// Stable callback, never recreated
const addItems = useCallback((newItems: Item[]) => {
setItems(curr => [...curr, ...newItems])
}, []) // ✅ No dependencies needed
// Always uses latest state, no stale closure risk
const removeItem = useCallback((id: string) => {
setItems(curr => curr.filter(item => item.id !== id))
}, []) // ✅ Safe and stable
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
```
**Benefits:**
1. **Stable callback references** - Callbacks don't need to be recreated when state changes
2. **No stale closures** - Always operates on the latest state value
3. **Fewer dependencies** - Simplifies dependency arrays and reduces memory leaks
4. **Prevents bugs** - Eliminates the most common source of React closure bugs
**When to use functional updates:**
- Any setState that depends on the current state value
- Inside useCallback/useMemo when state is needed
- Event handlers that reference state
- Async operations that update state
**When direct updates are fine:**
- Setting state to a static value: `setCount(0)`
- Setting state from props/arguments only: `setName(newName)`
- State doesn't depend on previous value
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.
@@ -1,58 +0,0 @@
---
title: Use Lazy State Initialization
impact: MEDIUM
impactDescription: wasted computation on every render
tags: react, hooks, useState, performance, initialization
---
## Use Lazy State Initialization
Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.
**Incorrect (runs on every render):**
```tsx
function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs on EVERY render, even after initialization
const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items))
const [query, setQuery] = useState('')
// When query changes, buildSearchIndex runs again unnecessarily
return <SearchResults index={searchIndex} query={query} />
}
function UserProfile() {
// JSON.parse runs on every render
const [settings, setSettings] = useState(
JSON.parse(localStorage.getItem('settings') || '{}')
)
return <SettingsForm settings={settings} onChange={setSettings} />
}
```
**Correct (runs only once):**
```tsx
function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs ONLY on initial render
const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items))
const [query, setQuery] = useState('')
return <SearchResults index={searchIndex} query={query} />
}
function UserProfile() {
// JSON.parse runs only on initial render
const [settings, setSettings] = useState(() => {
const stored = localStorage.getItem('settings')
return stored ? JSON.parse(stored) : {}
})
return <SettingsForm settings={settings} onChange={setSettings} />
}
```
Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.
For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.
@@ -1,44 +0,0 @@
---
title: Extract to Memoized Components
impact: MEDIUM
impactDescription: enables early returns
tags: rerender, memo, useMemo, optimization
---
## Extract to Memoized Components
Extract expensive work into memoized components to enable early returns before computation.
**Incorrect (computes avatar even when loading):**
```tsx
function Profile({ user, loading }: Props) {
const avatar = useMemo(() => {
const id = computeAvatarId(user)
return <Avatar id={id} />
}, [user])
if (loading) return <Skeleton />
return <div>{avatar}</div>
}
```
**Correct (skips computation when loading):**
```tsx
const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
const id = useMemo(() => computeAvatarId(user), [user])
return <Avatar id={id} />
})
function Profile({ user, loading }: Props) {
if (loading) return <Skeleton />
return (
<div>
<UserAvatar user={user} />
</div>
)
}
```
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.
@@ -1,40 +0,0 @@
---
title: Use Transitions for Non-Urgent Updates
impact: MEDIUM
impactDescription: maintains UI responsiveness
tags: rerender, transitions, startTransition, performance
---
## Use Transitions for Non-Urgent Updates
Mark frequent, non-urgent state updates as transitions to maintain UI responsiveness.
**Incorrect (blocks UI on every scroll):**
```tsx
function ScrollTracker() {
const [scrollY, setScrollY] = useState(0)
useEffect(() => {
const handler = () => setScrollY(window.scrollY)
window.addEventListener('scroll', handler, { passive: true })
return () => window.removeEventListener('scroll', handler)
}, [])
}
```
**Correct (non-blocking updates):**
```tsx
import { startTransition } from 'react'
function ScrollTracker() {
const [scrollY, setScrollY] = useState(0)
useEffect(() => {
const handler = () => {
startTransition(() => setScrollY(window.scrollY))
}
window.addEventListener('scroll', handler, { passive: true })
return () => window.removeEventListener('scroll', handler)
}, [])
}
```
@@ -1,73 +0,0 @@
---
title: Use after() for Non-Blocking Operations
impact: MEDIUM
impactDescription: faster response times
tags: server, async, logging, analytics, side-effects
---
## Use after() for Non-Blocking Operations
Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response.
**Incorrect (blocks response):**
```tsx
import { logUserAction } from '@/app/utils'
export async function POST(request: Request) {
// Perform mutation
await updateDatabase(request)
// Logging blocks the response
const userAgent = request.headers.get('user-agent') || 'unknown'
await logUserAction({ userAgent })
return new Response(JSON.stringify({ status: 'success' }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
})
}
```
**Correct (non-blocking):**
```tsx
import { after } from 'next/server'
import { headers, cookies } from 'next/headers'
import { logUserAction } from '@/app/utils'
export async function POST(request: Request) {
// Perform mutation
await updateDatabase(request)
// Log after response is sent
after(async () => {
const userAgent = (await headers()).get('user-agent') || 'unknown'
const sessionCookie = (await cookies()).get('session-id')?.value || 'anonymous'
logUserAction({ sessionCookie, userAgent })
})
return new Response(JSON.stringify({ status: 'success' }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
})
}
```
The response is sent immediately while logging happens in the background.
**Common use cases:**
- Analytics tracking
- Audit logging
- Sending notifications
- Cache invalidation
- Cleanup tasks
**Important notes:**
- `after()` runs even if the response fails or redirects
- Works in Server Actions, Route Handlers, and Server Components
Reference: [https://nextjs.org/docs/app/api-reference/functions/after](https://nextjs.org/docs/app/api-reference/functions/after)
@@ -1,41 +0,0 @@
---
title: Cross-Request LRU Caching
impact: HIGH
impactDescription: caches across requests
tags: server, cache, lru, cross-request
---
## Cross-Request LRU Caching
`React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache.
**Implementation:**
```typescript
import { LRUCache } from 'lru-cache'
const cache = new LRUCache<string, any>({
max: 1000,
ttl: 5 * 60 * 1000 // 5 minutes
})
export async function getUser(id: string) {
const cached = cache.get(id)
if (cached) return cached
const user = await db.user.findUnique({ where: { id } })
cache.set(id, user)
return user
}
// Request 1: DB query, result cached
// Request 2: cache hit, no DB query
```
Use when sequential user actions hit multiple endpoints needing the same data within seconds.
**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis.
**In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching.
Reference: [https://github.com/isaacs/node-lru-cache](https://github.com/isaacs/node-lru-cache)
@@ -1,76 +0,0 @@
---
title: Per-Request Deduplication with React.cache()
impact: MEDIUM
impactDescription: deduplicates within request
tags: server, cache, react-cache, deduplication
---
## Per-Request Deduplication with React.cache()
Use `React.cache()` for server-side request deduplication. Authentication and database queries benefit most.
**Usage:**
```typescript
import { cache } from 'react'
export const getCurrentUser = cache(async () => {
const session = await auth()
if (!session?.user?.id) return null
return await db.user.findUnique({
where: { id: session.user.id }
})
})
```
Within a single request, multiple calls to `getCurrentUser()` execute the query only once.
**Avoid inline objects as arguments:**
`React.cache()` uses shallow equality (`Object.is`) to determine cache hits. Inline objects create new references each call, preventing cache hits.
**Incorrect (always cache miss):**
```typescript
const getUser = cache(async (params: { uid: number }) => {
return await db.user.findUnique({ where: { id: params.uid } })
})
// Each call creates new object, never hits cache
getUser({ uid: 1 })
getUser({ uid: 1 }) // Cache miss, runs query again
```
**Correct (cache hit):**
```typescript
const getUser = cache(async (uid: number) => {
return await db.user.findUnique({ where: { id: uid } })
})
// Primitive args use value equality
getUser(1)
getUser(1) // Cache hit, returns cached result
```
If you must pass objects, pass the same reference:
```typescript
const params = { uid: 1 }
getUser(params) // Query runs
getUser(params) // Cache hit (same reference)
```
**Next.js-Specific Note:**
In Next.js, the `fetch` API is automatically extended with request memoization. Requests with the same URL and options are automatically deduplicated within a single request, so you don't need `React.cache()` for `fetch` calls. However, `React.cache()` is still essential for other async tasks:
- Database queries (Prisma, Drizzle, etc.)
- Heavy computations
- Authentication checks
- File system operations
- Any non-fetch async work
Use `React.cache()` to deduplicate these operations across your component tree.
Reference: [React.cache documentation](https://react.dev/reference/react/cache)
@@ -1,83 +0,0 @@
---
title: Parallel Data Fetching with Component Composition
impact: CRITICAL
impactDescription: eliminates server-side waterfalls
tags: server, rsc, parallel-fetching, composition
---
## Parallel Data Fetching with Component Composition
React Server Components execute sequentially within a tree. Restructure with composition to parallelize data fetching.
**Incorrect (Sidebar waits for Page's fetch to complete):**
```tsx
export default async function Page() {
const header = await fetchHeader()
return (
<div>
<div>{header}</div>
<Sidebar />
</div>
)
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
```
**Correct (both fetch simultaneously):**
```tsx
async function Header() {
const data = await fetchHeader()
return <div>{data}</div>
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
export default function Page() {
return (
<div>
<Header />
<Sidebar />
</div>
)
}
```
**Alternative with children prop:**
```tsx
async function Header() {
const data = await fetchHeader()
return <div>{data}</div>
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
function Layout({ children }: { children: ReactNode }) {
return (
<div>
<Header />
{children}
</div>
)
}
export default function Page() {
return (
<Layout>
<Sidebar />
</Layout>
)
}
```
@@ -1,38 +0,0 @@
---
title: Minimize Serialization at RSC Boundaries
impact: HIGH
impactDescription: reduces data transfer size
tags: server, rsc, serialization, props
---
## Minimize Serialization at RSC Boundaries
The React Server/Client boundary serializes all object properties into strings and embeds them in the HTML response and subsequent RSC requests. This serialized data directly impacts page weight and load time, so **size matters a lot**. Only pass fields that the client actually uses.
**Incorrect (serializes all 50 fields):**
```tsx
async function Page() {
const user = await fetchUser() // 50 fields
return <Profile user={user} />
}
'use client'
function Profile({ user }: { user: User }) {
return <div>{user.name}</div> // uses 1 field
}
```
**Correct (serializes only 1 field):**
```tsx
async function Page() {
const user = await fetchUser()
return <Profile name={user.name} />
}
'use client'
function Profile({ name }: { name: string }) {
return <div>{name}</div>
}
```
+159
View File
@@ -0,0 +1,159 @@
---
name: version-release
description: "Version release workflow. Use when the user mentions 'release', 'hotfix', 'version upgrade', 'weekly release', or '发版'/'发布'/'小班车'. Provides guides for Minor Release and Patch Release workflows."
---
# Version Release Workflow
## Overview
The primary development branch is **canary**. All day-to-day development happens on canary. When releasing, canary is merged into main. After merge, `auto-tag-release.yml` automatically handles tagging, version bumping, creating a GitHub Release, and syncing back to the canary branch.
Only two release types are used in practice (major releases are extremely rare and can be ignored):
| Type | Use Case | Frequency | Source Branch | PR Title Format | Version |
| ----- | ---------------------------------------------- | --------------------- | -------------- | ------------------------------------ | ------------- |
| Minor | Feature iteration release | \~Every 4 weeks | canary | `🚀 release: v{x.y.0}` | Manually set |
| Patch | Weekly release / hotfix / model / DB migration | \~Weekly or as needed | canary or main | Custom (e.g. `🚀 release: 20260222`) | Auto patch +1 |
## Minor Release Workflow
Used to publish a new minor version (e.g. v2.2.0), roughly every 4 weeks.
### Steps
1. **Create a release branch from canary**
```bash
git checkout canary
git pull origin canary
git checkout -b release/v{version}
git push -u origin release/v{version}
```
2. **Determine the version number** — Read the current version from `package.json` and compute the next minor version (e.g. 2.1.x → 2.2.0)
3. **Create a PR to main**
```bash
gh pr create \
--title "🚀 release: v{version}" \
--base main \
--head release/v{version} \
--body "## 📦 Release v{version} ..."
```
> \[!IMPORTANT]: The PR title must strictly match the `🚀 release: v{x.y.z}` format. CI uses a regex on this title to determine the exact version number.
4. **Automatic trigger after merge**: auto-tag-release detects the title format and uses the version number from the title to complete the release.
### Scripts
```bash
bun run release:branch # Interactive
bun run release:branch --minor # Directly specify minor
```
## Patch Release Workflow
Version number is automatically bumped by patch +1. There are 4 common scenarios:
| Scenario | Source Branch | Branch Naming | Description |
| ------------------- | ------------- | ----------------------------- | ------------------------------------------------ |
| Weekly Release | canary | `release/weekly-{YYYYMMDD}` | Weekly release train, canary → main |
| Bug Hotfix | main | `hotfix/v{version}-{hash}` | Emergency bug fix |
| New Model Launch | canary | Community PR merged directly | New model launch, triggered by PR title prefix |
| DB Schema Migration | main | `release/db-migration-{name}` | Database migration, requires dedicated changelog |
All scenarios auto-bump patch +1. Patch PR titles do not need a version number. See `reference/patch-release-scenarios.md` for detailed steps per scenario.
### Scripts
```bash
bun run hotfix:branch # Hotfix scenario
```
## Auto-Release Trigger Rules (auto-tag-release.yml)
After a PR is merged into main, CI determines whether to release based on the following priority:
### 1. Minor Release (Exact Version)
PR title matches `🚀 release: v{x.y.z}` → uses the version number from the title.
### 2. Patch Release (Auto patch +1)
Triggered by the following priority:
- **Branch name match**: `hotfix/*` or `release/*` → triggers directly (skips title detection)
- **Title prefix match**: PRs with the following title prefixes will trigger:
- `style` / `💄 style`
- `feat` / `✨ feat`
- `fix` / `🐛 fix`
- `refactor` / `♻️ refactor`
- `hotfix` / `🐛 hotfix` / `🩹 hotfix`
- `build` / `👷 build`
### 3. No Trigger
PRs that don't match any of the above conditions (e.g. `docs`, `chore`, `ci`, `test` prefixes) will not trigger a release when merged into main.
## Post-Release Automated Actions
1. **Bump package.json** — commits `🔖 chore(release): release version v{x.y.z} [skip ci]`
2. **Create annotated tag**`v{x.y.z}`
3. **Create GitHub Release**
4. **Dispatch sync-main-to-canary** — syncs main back to the canary branch
## Claude Action Guide
When the user requests a release:
### Minor Release
1. Read `package.json` to get the current version and compute the next minor version
2. Create a `release/v{version}` branch from canary
3. Push and create a PR — **title must be `🚀 release: v{version}`**
4. Inform the user that merging the PR will automatically trigger the release
### Precheck
Before creating the release branch, verify the source branch:
- **Weekly Release** (`release/weekly-*`): must branch from `canary`
- **All other release/hotfix branches**: must branch from `main` — run `git merge-base --is-ancestor main <branch> && echo OK` to confirm
- If the branch is based on the wrong source, delete and recreate from the correct base
### Patch Release
Choose the appropriate workflow based on the scenario (see `reference/patch-release-scenarios.md`):
- **Weekly Release**: Create a `release/weekly-{YYYYMMDD}` branch from canary, scan `git log main..canary` to write the changelog, title like `🚀 release: 20260222`
- **Bug Hotfix**: Create a `hotfix/` branch from main, use a gitmoji prefix title (e.g. `🐛 fix: ...`)
- **New Model Launch**: Community PRs trigger automatically via title prefix (`feat` / `style`), no extra steps needed
- **DB Migration**: Create a `release/db-migration-{name}` branch from main, cherry-pick migration commits, write a dedicated migration changelog
### Important Notes
- **Do NOT manually modify the version in package.json** — CI will auto-bump it
- **Do NOT manually create tags** — CI will create them automatically
- The Minor Release PR title format is a hard requirement — incorrect format will not use the specified version number
- Patch PRs do not need a version number — CI auto-bumps patch +1
- All release PRs must include a user-facing changelog
## Changelog Writing Guidelines
All release PR bodies (both Minor and Patch) must include a user-facing changelog. Scan changes via `git log main..canary --oneline` or `git diff main...canary --stat`, then write following the format below.
### Format Reference
- Weekly Release: See `reference/changelog-example/weekly-release.md`
- DB Migration: See `reference/changelog-example/db-migration.md`
### Writing Tips
- **User-facing**: Describe changes that users can perceive, not internal implementation details
- **Clear categories**: Group by features, models/providers, desktop, stability/fixes, etc.
- **Highlight key items**: Use `**bold**` for important feature names
- **Credit contributors**: Collect all committers via `git log` and list alphabetically
- **Flexible categories**: Choose categories based on actual changes — no need to force-fit all categories
@@ -0,0 +1,20 @@
# DB Schema Migration Changelog Example
A changelog reference for database migration release PR bodies.
---
This release includes a **database schema migration** involving **5 new tables** for the Agent Evaluation Benchmark system.
### Migration: Add Agent Evaluation Benchmark Tables
- Added 5 new tables: `agent_eval_benchmarks`, `agent_eval_datasets`, `agent_eval_records`, `agent_eval_runs`, `agent_eval_run_topics`
### Notes for Self-hosted Users
- The migration runs automatically on application startup
- No manual intervention required
The migration owner: @{pr-author} — responsible for this database schema change, reach out for any migration-related issues.
> **Note for Claude**: Replace `{pr-author}` with the actual PR author. Retrieve via `gh pr view <number> --json author --jq '.author.login'` or `git log` commit author. Do NOT hardcode a username.
@@ -0,0 +1,46 @@
# Patch Release (Weekly) Changelog Example
A real-world changelog reference for weekly patch release PR bodies.
---
This release includes **82 commits** , Key updates are below.
### New Features and Enhancements
- Added **Agent Benchmark** support for more systematic agent performance evaluation.
- Introduced the **video generation** feature end-to-end, including entry points, sidebar "new" badge support, and skeleton loading for topic switching.
- Expanded memory capabilities: support for memory effort/tool permission configuration and improved timeout calculation for memory analysis tasks.
- Added desktop editor support for image upload via file picker.
### Models and Provider Expansion
- Added a new provider: **Straico**.
- Added/updated support for:
- Claude Sonnet 4.6
- Gemini 3.1 Pro Preview
- Qwen3.5 series
- Grok Imagine (`grok-imagine-image`)
- MiniMax 2.5
- Added related i18n copy and model parameter adaptations.
### Desktop Improvements
- Integrated `electron-liquid-glass` (macOS Tahoe).
- Improved DMG background assets and desktop release workflow.
### Stability, Security, and UX Fixes
- Fixed multiple video generation pipeline issues: precharge refund handling, webhook token verification, pricing parameter usage, asset cleanup, and type safety.
- Fixed `sanitizeFileName` path traversal risks and added unit tests.
- Fixed MCP media URL generation with duplicated `APP_URL` prefix.
- Fixed Qwen3 embedding failures caused by batch-size limits.
- Fixed multiple UI/interaction issues, including mobile header agent selector/topic count, ChatInput scrolling behavior, and tooltip stacking context.
- Fixed missing `@napi-rs/canvas` native bindings in Docker standalone builds.
- Improved GitHub Copilot authentication retry behavior and response error handling in edge cases.
### Credits
Huge thanks to these contributors (alphabetical):
@AmAzing129 @Coooolfan @Innei @ONLY-yours @Zhouguanyang @arvinxx @eaten-cake @hezhijie0327 @nekomeowww @rdmclin2 @rivertwilight @sxjeru @tjx666
@@ -0,0 +1,120 @@
# Patch Release Scenarios
All Patch Release scenarios automatically bump the patch version (e.g. 2.1.31 → 2.1.32). PR titles do not need to include a version number.
---
## 1. Weekly Release (canary → main)
The most common release type. Collects a week's worth of changes from canary and ships them to main.
### Steps
1. **Create release branch from canary**
```bash
git checkout canary
git pull origin canary
git checkout -b release/weekly-{YYYYMMDD}
git push -u origin release/weekly-{YYYYMMDD}
```
2. **Scan changes and write changelog**
```bash
git log main..canary --oneline
git diff main...canary --stat
```
Write a user-facing changelog following the format in `patch-release-changelog-example.md`.
3. **Create PR to main** with the changelog as the PR body
```bash
gh pr create \
--title "🚀 release: {YYYYMMDD}" \
--base main \
--head release/weekly-{YYYYMMDD} \
--body-file changelog.md
```
4. **After merge**: auto-tag-release detects `release/*` branch → auto patch +1.
---
## 2. Bug Hotfix
Emergency bug fix shipped directly from main.
### Steps
1. **Create hotfix branch from main**
```bash
git checkout main
git pull --rebase origin main
git checkout -b hotfix/v{version}-{short-hash}
git push -u origin hotfix/v{version}-{short-hash}
```
2. **Create PR to main** with a gitmoji prefix title (e.g. `🐛 fix: description`)
3. **After merge**: auto-tag-release detects `hotfix/*` branch → auto patch +1.
### Script
```bash
bun run hotfix:branch
```
---
## 3. New Model Launch
New AI model or provider support, typically contributed via community PRs.
### How it works
- Community contributors submit PRs with titles like `✨ feat: add xxx model` or `💄 style: support xxx models`
- These PR title prefixes (`feat` / `style`) are in the auto-tag trigger list
- No special branch naming or manual release steps required — merging the PR triggers auto patch +1
### When Claude is involved
If asked to add model support, just create a normal feature PR. The title prefix will trigger the release automatically.
---
## 4. DB Schema Migration
Database schema changes that need to be released independently. These require a dedicated changelog explaining the migration for self-hosted users.
### Steps
1. **Create release branch from main and cherry-pick migration commits**
```bash
git checkout main
git pull --rebase origin main
git checkout -b release/db-migration-{name}
git cherry-pick <migration-commit-hash>
git push -u origin release/db-migration-{name}
```
2. **Write a migration-specific changelog** — See `db-migration-changelog-example.md` for the format. This should explain:
- What tables/columns are added, modified, or removed
- Whether the migration is backwards-compatible
- Any action required by self-hosted users
- **Migration owner**: Use the actual PR author (retrieve via `gh pr view <number> --json author --jq '.author.login'` or `git log` commit author), never hardcode a username
3. **Create PR to main** with the migration changelog as the PR body
```bash
gh pr create \
--title "👷 build: {migration description}" \
--base main \
--head release/db-migration-{name} \
--body-file changelog.md
```
4. **After merge**: auto-tag-release detects `release/*` branch → auto patch +1.
+102 -1
View File
@@ -3,34 +3,42 @@ name: zustand
description: Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.
---
# LobeChat Zustand State Management
# LobeHub Zustand State Management
## Action Type Hierarchy
### 1. Public Actions
Main interfaces for UI components:
- Naming: Verb form (`createTopic`, `sendMessage`)
- Responsibilities: Parameter validation, flow orchestration
### 2. Internal Actions (`internal_*`)
Core business logic implementation:
- Naming: `internal_` prefix (`internal_createTopic`)
- Responsibilities: Optimistic updates, service calls, error handling
- Should not be called directly by UI
### 3. Dispatch Methods (`internal_dispatch*`)
State update handlers:
- Naming: `internal_dispatch` + entity (`internal_dispatchTopic`)
- Responsibilities: Calling reducers, updating store
## When to Use Reducer vs Simple `set`
**Use Reducer Pattern:**
- Managing object lists/maps (`messagesMap`, `topicMaps`)
- Optimistic updates
- Complex state transitions
**Use Simple `set`:**
- Toggling booleans
- Updating simple values
- Setting single state fields
@@ -61,12 +69,14 @@ internal_createTopic: async (params) => {
## Naming Conventions
**Actions:**
- Public: `createTopic`, `sendMessage`
- Internal: `internal_createTopic`, `internal_updateMessageContent`
- Dispatch: `internal_dispatchTopic`
- Toggle: `internal_toggleMessageLoading`
**State:**
- ID arrays: `messageLoadingIds`, `topicEditingIds`
- Maps: `topicMaps`, `messagesMap`
- Active: `activeTopicId`
@@ -76,3 +86,94 @@ internal_createTopic: async (params) => {
- Action patterns: `references/action-patterns.md`
- Slice organization: `references/slice-organization.md`
## Class-Based Action Implementation
We are migrating slices from plain `StateCreator` objects to **class-based actions**.
### Pattern
- Define a class that encapsulates actions and receives `(set, get, api)` in the constructor.
- Use `#private` fields (e.g., `#set`, `#get`) to avoid leaking internals.
- Prefer shared typing helpers:
- `StoreSetter<T>` from `@/store/types` for `set`.
- `Pick<ActionImpl, keyof ActionImpl>` to expose only public methods.
- Export a `create*Slice` helper that returns a class instance.
```ts
type Setter = StoreSetter<HomeStore>;
export const createRecentSlice = (set: Setter, get: () => HomeStore, _api?: unknown) =>
new RecentActionImpl(set, get, _api);
export class RecentActionImpl {
readonly #get: () => HomeStore;
readonly #set: Setter;
constructor(set: Setter, get: () => HomeStore, _api?: unknown) {
void _api;
this.#set = set;
this.#get = get;
}
useFetchRecentTopics = () => {
// ...
};
}
export type RecentAction = Pick<RecentActionImpl, keyof RecentActionImpl>;
```
### Composition
- In store files, merge class instances with `flattenActions` (do not spread class instances).
- `flattenActions` binds methods to the original class instance and supports prototype methods and class fields.
```ts
const createStore: StateCreator<HomeStore, [['zustand/devtools', never]]> = (...params) => ({
...initialState,
...flattenActions<HomeStoreAction>([
createRecentSlice(...params),
createHomeInputSlice(...params),
]),
});
```
### Multi-Class Slices
- For large slices that need multiple action classes, compose them in the slice entry using `flattenActions`.
- Use a local `PublicActions<T>` helper if you need to combine multiple classes and hide private fields.
```ts
type PublicActions<T> = { [K in keyof T]: T[K] };
export type ChatGroupAction = PublicActions<
ChatGroupInternalAction & ChatGroupLifecycleAction & ChatGroupMemberAction & ChatGroupCurdAction
>;
export const chatGroupAction: StateCreator<
ChatGroupStore,
[['zustand/devtools', never]],
[],
ChatGroupAction
> = (...params) =>
flattenActions<ChatGroupAction>([
new ChatGroupInternalAction(...params),
new ChatGroupLifecycleAction(...params),
new ChatGroupMemberAction(...params),
new ChatGroupCurdAction(...params),
]);
```
### Store-Access Types
- For class methods that depend on actions in other classes, define explicit store augmentations:
- `ChatGroupStoreWithSwitchTopic` for lifecycle `switchTopic`
- `ChatGroupStoreWithRefresh` for member refresh
- `ChatGroupStoreWithInternal` for curd `internal_dispatchChatGroup`
### Do / Don't
- **Do**: keep constructor signature aligned with `StateCreator` params `(set, get, api)`.
- **Do**: use `#private` to avoid `set/get` being exposed.
- **Do**: use `flattenActions` instead of spreading class instances.
- **Don't**: keep both old slice objects and class actions active at the same time.
@@ -77,9 +77,9 @@ toggleMessageEditing: (id, editing) => {
set(
{ messageEditingIds: toggleBooleanList(get().messageEditingIds, id, editing) },
false,
'toggleMessageEditing'
'toggleMessageEditing',
);
}
};
```
## SWR Integration
@@ -3,6 +3,7 @@
## Top-Level Store Structure
Key aggregation files:
- `src/store/chat/initialState.ts`: Aggregate all slice initial states
- `src/store/chat/store.ts`: Define top-level `ChatStore`, combine all slice actions
- `src/store/chat/selectors.ts`: Export all slice selectors
@@ -74,8 +75,10 @@ export const initialTopicState: ChatTopicState = {
```typescript
const currentTopics = (s: ChatStoreState): ChatTopic[] | undefined => s.topicMaps[s.activeId];
const getTopicById = (id: string) => (s: ChatStoreState): ChatTopic | undefined =>
currentTopics(s)?.find((topic) => topic.id === id);
const getTopicById =
(id: string) =>
(s: ChatStoreState): ChatTopic | undefined =>
currentTopics(s)?.find((topic) => topic.id === id);
// Core pattern: Use xxxSelectors aggregate
export const topicSelectors = {
@@ -100,18 +103,21 @@ src/store/chat/slices/aiChat/
## State Design Patterns
### Map Structure for Associated Data
```typescript
topicMaps: Record<string, ChatTopic[]>;
messagesMap: Record<string, ChatMessage[]>;
```
### Arrays for Loading State
```typescript
messageLoadingIds: string[]
topicLoadingIds: string[]
```
### Optional Fields for Active Items
```typescript
activeId: string
activeTopicId?: string

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