- Split enableProxy into instant-apply (no save required)
- Floating pill SaveBar fixed bottom-center, visible only when dirty
- Test connection feedback moved to toast (@lobehub/ui)
- Refresh style guidance: prefer createStaticStyles + cssVar
Fixes LOBE-7071
## 📦 Weekly Release 20260410
This release includes **67 commits**. Key user-facing updates below.
### New Features and Enhancements
- Introduced **Prompt Rewrite & Translate** feature for assisted input
editing.
- Added **Skill Panel** with dedicated skills tab in the skill store and
fixed skill icon rendering.
- Introduced `lh notify` CLI command for external agent callbacks.
- Added `migrate openclaw` CLI command.
- Added **GraphAgent** and `agentFactory` for graph-driven agent
execution (experimental).
- New topic auto-creation every 4 hours for long-running sessions.
### Models and Provider Expansion
- Added a new provider: **StreamLake (快手万擎)**.
- Added **GLM-5.1** model support with Kimi CodingPlan fixes.
- Added **Seedance 2.0** & **Seedance 2.0 Fast** video generation models
(pricing adjusted with 20% service fee).
- Expanded AIGC parameter support for image and video generation.
- Improved model type normalization for better provider compatibility.
- Multi-media and multiple connection mode support for ComfyUI
integration.
### Desktop Improvements
- **Embedded CLI** in the desktop app with PATH installation support.
- Added Electron version display in system tools settings.
- Fixed RuntimeConfig instant-apply working directory with recent list.
- Fixed desktop locale restore — now uses stored URL parameter instead
of system locale.
- Improved remote re-auth for batched tRPC and clean OIDC on gateway
disconnect.
### Stability, Security, and UX Fixes
- **Security**: prevented path traversal in
`TempFileManager.writeTempFile`; patched IDOR in
`addFilesToKnowledgeBase`; upgraded `better-auth` with hardened
`humanIntervention` requirement in builtin-tool-activator.
- **Context engine**: added `typeof` guard before `.trim()` calls to
prevent runtime crashes.
- **Agent runtime**: preserved reasoning state across OpenAI providers;
fixed service error serialization producing `[object Object]`; surfaced
error `reasonDetail` in `agent_runtime_end` events.
- **Knowledge Base**: cleaned up vector storage when deleting knowledge
bases.
- **Templates**: allow templates to specify `policyLoad` so default docs
are fully injected.
- **Skills**: inject current agents information when `lobehub_skill` is
activated; filter current agent out of available agents list; fix
`agents_documents` overriding `systemRole`.
- **Google Tools**: use `parametersJsonSchema` for Google tool schemas.
- **Web Crawler**: prevent happy-dom CSS parsing crash in
`htmlToMarkdown`.
- **Mobile/UI**: fixed video page icon collision, missing locale keys,
model query param; hidden LocalFile actions on topic share page; allow
manual close of hidden builtin tools.
- **Auth**: `ENABLE_MOCK_DEV_USER` now supported in `checkAuth` and
openapi auth middleware.
- **Sandbox**: stopped using `sanitizeHTMLContent` to block scripts &
sandbox styles.
### Refactors
- Library/resource tree store for hierarchy and move sync.
- Removed legacy `messageLoadingIds` from chat store.
- Removed promptfoo configs and dependencies.
- `OnboardingContextInjector` wired into context engine.
### Credits
Huge thanks to these contributors (alphabetical):
@arvinxx @canisminor1990 @cy948 @hardy-one @hezhijie0327 @Innei
@MarcellGu @ONLY-yours @rdmclin2 @rivertwilight @sxjeru @tjx666
Add `typeof !== 'string'` checks before `.trim()` calls in BaseSystemRoleProvider,
SystemRoleInjector, and BaseProcessor to prevent TypeError when a non-string truthy
value (e.g. object, array, number) is passed at runtime.
* fix(builtin-tool-activator): add humanIntervention required field to activateTools manifest
- Add humanIntervention: "required" to the activateTools API manifest
- Update better-auth dependency from 1.4.6 to 1.4.9 (GHSA-xg6x-h9c9-2m83, 分数: 7.4)
* Downgrade better-auth version to 1.4.6
Thanks for your correction.
* ✨ feat: add gateway mode branch to regenerateUserMessage
When gateway mode is enabled, regenerateUserMessage now calls
executeGatewayAgent with parentMessageId instead of running
internal_execAgentRuntime locally. The server handles branching
and agent execution.
Fixes LOBE-6934
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: switch branch before gateway regeneration and keep operation open
- Move switchMessageBranch before the gateway/client branch so
activeBranchIndex is advanced and the UI shows the new response
immediately (fixes regression from client path)
- Add onComplete callback to executeGatewayAgent so callers can
run cleanup when the gateway session finishes
- Keep regenerate operation running until onComplete fires,
preventing duplicate concurrent regenerations via isMessageRegenerating
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: fix Kimi K2.5 model icon display by using deploymentName
- Change model id from 'k2p5' to 'kimi-k2.5' to match Moonshot icon keywords
- Add deploymentName 'k2p5' for API calls to use original model name
- Add KimiCodingPlan to providersWithDeploymentName list
This allows the model icon to display correctly while maintaining
backward compatibility with the API using the original 'k2p5' name.
* 🐛 fix: normalize messages for KimiCodingPlan thinking models
Add message normalization for Kimi K2.5 and K2 Thinking models to ensure
every assistant message has a thinking block when thinking is enabled.
This fixes the issue where regenerating with KimiCodingPlan after using
other providers would fail with "thinking is enabled but reasoning_content
is missing" error, because historical messages from other providers don't
have reasoning fields.
The normalization adds a placeholder thinking block when:
1. Thinking is enabled for Kimi K2.5/K2 Thinking models
2. Assistant message doesn't have reasoning content
* ✨ feat(siliconcloud): add GLM-5.1 model support
Add GLM-5.1 (Pro) model configuration with:
- 198K context window
- Function call and reasoning capabilities
- Tiered pricing (0-32k / 32k+)
- reasoningBudgetToken32k extension parameter
* 🐛 fix: use hardcoded maxOutput mapping for KimiCodingPlan models
Replace getModelPropertyWithFallback with a simple hardcoded mapping to fix
the issue where max_tokens lookup fails when using deploymentName (k2p5).
The model id is converted to deploymentName in ChatService layer before
reaching the provider, causing getModelPropertyWithFallback('k2p5', ...) to
fail since the model card uses id 'kimi-k2.5'.
By using a hardcoded mapping that supports both model id and deploymentName,
we avoid the lookup issue while keeping the code simple (KimiCodingPlan only
has a few models).
* ✅ test(kimiCodingPlan): add tests for thinking and max_tokens handling
Add comprehensive tests for KimiCodingPlan provider covering:
- Hardcoded maxOutput mapping for k2p5, kimi-k2.5, kimi-k2-thinking
- Thinking parameter handling for kimi-k2.5 and kimi-k2-thinking models
- Message normalization with forceThinking for assistant messages
- Tool calls with reasoning content to prevent API error
* ✅ test(kimiCodingPlan): add tests for thinking and max_tokens handling
Add comprehensive tests for KimiCodingPlan provider covering:
- Hardcoded maxOutput mapping for k2p5, kimi-k2.5, kimi-k2-thinking
- Thinking parameter handling for kimi-k2.5 and kimi-k2-thinking models
- Message normalization with forceThinking for assistant messages
- Tool calls with reasoning content to prevent API error
* refactor(workflow): rewrite WorkflowSummary with status dot and minimal flat style
* refactor(workflow): rewrite WorkflowCollapse with unified borderless container
* ✨ feat(workflow): add WorkflowExpandedList component and fix type errors
* ♻️ refactor(workflow): add missing Workflow components with Minimal Flat design
- WorkflowReasoningLine: cssVar tokens, aligned padding
- WorkflowToolDetail: new expandable result panel with motion animation
- WorkflowToolLine: expand chevron, getToolColor, detail panel integration
- WorkflowExpandedList: flat rendering with reasoning + tool lines
* Add tool call collapse support
Made-with: Cursor
* 💄 style(workflow): align WorkflowCollapse UI with @lobehub/ui design system
- Align border-radius, gap, padding tokens across all Workflow components
- Replace chevron expand/collapse with status icons (CheckCircle2, CircleX, Loader2)
- Use @lobehub/ui Highlighter for tool detail panel with JSON auto-formatting
- Use @lobehub/ui Flexbox for WorkflowExpandedList with proper gap and padding
- Fix delete action to use removeToolFromMessage instead of deleteAssistantMessage
- Wire debug button to existing Tool/Debug panel with full tabs
- Fix auto-collapse to only trigger on incomplete→complete transition
- Single ChevronDown with rotation for WorkflowSummary (match @lobehub/ui pattern)
* 💄 style(workflow): use AccordionItem and inspectorTextStyles for WorkflowCollapse
- Replace custom WorkflowSummary with @lobehub/ui AccordionItem
- Use StatusIndicator pattern (Block outlined 24x24) for status icon
- Apply inspectorTextStyles.root for title text (colorTextSecondary)
- Remove WorkflowSummary.tsx (dead code)
- Match Tool component AccordionItem usage (paddingBlock/Inline=4, borderless)
* 💄 style(workflow): remove divider and gap from WorkflowExpandedList
* 💄 style(workflow): align WorkflowCollapse title bar with Thinking component
* 💄 style(workflow): unify inner item spacing, font size, and colors
* ✨ feat(workflow): add streaming scroll behavior with max-height and auto-scroll
* 💄 refactor(assistant-group): refine workflow collapse UI and duration
- Use Accordion for collapse; align tool/reasoning lines with generation state
- Show workflow header duration from summed block performance, not reasoning only
Made-with: Cursor
* ✨ feat(inspector): enhance ActivateToolsInspector to display not found tools count
- Added localization for not found tools message in English, Chinese, and default locales.
- Updated ActivateToolsInspector to show a tooltip with the count of tools not found.
- Modified StatusIndicator to support a warning state for scenarios where no tools are activated but some are not found.
Signed-off-by: Innei <tukon479@gmail.com>
* 💄 style(workflow): simplify padding in WorkflowExpandedList component
- Removed unnecessary paddingInline from Flexbox elements in WorkflowExpandedList for cleaner layout.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(assistant-group): introduce constants and utility functions for workflow management
- Added constants for workflow timing, limits, and tool display names to enhance the assistant group's functionality.
- Implemented utility functions for processing and scoring post-tool answers, improving the workflow's response handling.
- Created new components for rendering content blocks and managing scroll behavior in the assistant group.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(assistant-group): enhance ContentBlock and Group components with content handling logic
- Added logic to conditionally render message content based on content availability and tool presence in ContentBlock.
- Introduced utility functions to determine substantive content and reasoning in Group, improving block partitioning for workflow management.
- Updated partitioning logic to handle trailing reasoning candidates and streamline answer and working block separation.
Signed-off-by: Innei <tukon479@gmail.com>
* 🙈 chore(gitignore): clarify superpowers local paths
Document that `.superpowers/` and `docs/superpowers/` are plugin/local outputs
and must not be committed.
Made-with: Cursor
* 👷 chore(ci): restore auto-tag-release workflow from canary
Revert unintended workflow edits so release tagging stays on main with
sync-main-to-canary dispatch.
Made-with: Cursor
---------
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 feat(db): add findExclusiveFileIds, deleteWithFiles, deleteAllWithFiles to KnowledgeBaseModel
Add methods to safely clean up vector storage when deleting knowledge bases:
- findExclusiveFileIds: identifies files belonging only to a specific KB
- deleteWithFiles: deletes KB and its exclusive files with chunks/embeddings
- deleteAllWithFiles: bulk version for deleting all user KBs
* 🐛 fix(kb): wire vector cleanup in TRPC router, OpenAPI service, and client
- TRPC removeKnowledgeBase: use deleteWithFiles when removeFiles=true + S3 cleanup
- TRPC removeAllKnowledgeBases: use deleteAllWithFiles + S3 cleanup
- OpenAPI deleteKnowledgeBase: use deleteWithFiles + S3 cleanup
- Client service: default removeFiles=true when deleting knowledge base
* 🐛 fix(knowledgeBase): change default behavior of deleteKnowledgeBase to not remove files and update related tests
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(knowledgeBase): add optional query parameter to deleteKnowledgeBase for file removal
- Introduced `removeFiles` query parameter to control the deletion of exclusive files and derived data when deleting a knowledge base.
- Updated `KnowledgeBaseController`, `KnowledgeBaseService`, and related schemas to support this new functionality.
This change enhances the flexibility of the delete operation, allowing users to choose whether to remove associated files.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix: cascade knowledge base deletion and add orphan cleanup runbook
* ✨ feat(knowledgeRepo): implement cascading deletion for file-backed documents
- Enhanced the `KnowledgeRepo` to ensure that when a document with an associated file is deleted, all related data (files, chunks, embeddings) are also removed.
- Introduced a new method `deleteDocumentWithRelations` to handle the cascading deletion logic.
- Updated tests to verify that all related entities are deleted when a file-backed document is removed.
This change improves data integrity by ensuring that no orphaned records remain after deletions.
Signed-off-by: Innei <tukon479@gmail.com>
* Defer DocumentService file initialization
* Fix flaky database tests and knowledge repo fixtures
* Add deletion regression tests for folders and external files
* ⏪ chore: remove kb orphan cleanup files from pr
---------
Signed-off-by: Innei <tukon479@gmail.com>
* 🌐 chore: update execServerAgentRuntime i18n copy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: extend execAgent with parentMessageId for regeneration/continue via Gateway
Add parentMessageId support to the execAgent API, enabling regeneration and continue-generation flows through the Gateway WebSocket path. When parentMessageId is provided, user message creation is skipped (resume mode) and the new assistant message branches from the specified parent.
Fixes LOBE-6933
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: propagate parentMessageId through execAgents batch and fix test types
- Forward parentMessageId in execAgents executeTask to maintain batch parity with execAgent
- Fix ExecAgentResult mock types in gateway tests
- Fix messages table insert type cast in server router 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>
* feat(modelParse): enhance model type normalization and add tests for invalid types
* feat(modelParse): optimize imports and improve model type handling
* 🐛 fix: buffer and deduplicate events during resume to prevent out-of-order display
When reconnecting with empty lastEventId (page reload), live broadcast
events can arrive before resume replay completes, causing content to
appear out of order. Now AgentStreamClient enters resume mode: buffers
all events, waits for a 500ms gap (resume replay is dense, live events
are sparse), then deduplicates by event ID and emits in order.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: clear runningOperation on agent finish + resume timeout for completed sessions
- RuntimeExecutors.finish clears topic metadata.runningOperation when
agent reaches terminal state, so stale entries don't trigger reconnect
- AgentStreamClient resume mode: add 3s timeout for empty buffer —
if no events arrive after resume request, session has already completed,
emit session_complete and disconnect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: eagerly fetch messages after topic switch to avoid skeleton flash
After switchTopic in Gateway mode, immediately fetch messages from DB
and replace in store, so the UI renders content right away instead of
showing a skeleton loading state while SWR re-fetches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: eliminate skeleton flash on gateway topic switch
Match the client-mode pattern: fetch messages from DB and replaceMessages
BEFORE calling switchTopic with skipRefreshMessage: true. This ensures
messages are already in the store when the topic switches, preventing
a skeleton loading flash.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: flush resume buffer on session_complete before disconnect
session_complete is a top-level ServerMessage (not an agent_event), so
it bypassed the resume buffer. When it arrived during resume mode,
disconnect() cleared the buffer and all replayed events were lost.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: limit resume buffering to explicit reconnect scenarios only
Resume mode was triggered for ALL new connections (lastEventId always
empty on first connect), delaying live streaming for normal operations.
Now resume buffering requires explicit opt-in via resumeOnConnect option,
which is only set by reconnectToGatewayOperation (page-reload reconnect).
Normal executeGatewayAgent connections stream events immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: should inject current agnets information when actived the lobehub skill
* fix: not inject the agent systemRole in lobehub skill inject
* fix: should use the isLobeHubSkillActive hook to judge
* fix: change the tools inject to vars replace function
* fix: add the lost topic id & agent title
* fix: later the PlaceholderVariablesProcessor
* fix: update the description
* ✨ feat: add StreamLake (快手) support
* style: add thinking support
style: add thinking support
style: add thinking support
style: add thinking support
style: add thinking support
🐛 fix(server): prevent path traversal in TempFileManager.writeTempFile
Use path.basename() to strip directory components from user-supplied
filenames before writing temp files, preventing arbitrary file write
via crafted filenames like "../../app/startServer.js".
Fixes LOBE-6904
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: persist runningOperation to topic metadata for gateway reconnect
- Add runningOperation field to ChatTopicMetadata type
- execAgent writes { operationId, assistantMessageId } to topic metadata
after creating the operation
- onSessionComplete clears runningOperation from metadata (best-effort)
- Extend updateTopicMetadata tRPC schema + service to support the field
Fixes LOBE-6905
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add refreshGatewayToken tRPC endpoint
Signs a fresh JWT for Gateway WebSocket reconnection after page reload.
The token is scoped to the authenticated user via signUserJWT.
Fixes LOBE-6906
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: auto-reconnect to running Gateway operation on topic load
- Add reconnectToGatewayOperation to GatewayActionImpl — refreshes JWT,
creates local operation, and connects WebSocket with event replay
- Add useGatewayReconnect hook — checks topic metadata.runningOperation
when entering a topic and triggers reconnection
- Wire hook into ConversationArea
Fixes LOBE-6907
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: preserve thread scope in reconnect context and subscribe to topic metadata
- Store scope + threadId in topic metadata.runningOperation
- reconnectToGatewayOperation uses stored scope/threadId instead of
hardcoded main/null
- useGatewayReconnect subscribes to runningOperation via useChatStore
selector so it triggers when topic data arrives from SWR (not just
on mount when data may be empty)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: update device tests to allow runningOperation metadata writes
The tests asserted updateMetadata was never called, but now execAgent
persists runningOperation. Changed to assert no device-binding metadata
was written (boundDeviceId), which is the actual intent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: use SWR for gateway reconnect lifecycle
Replace useEffect + ref with useSWR keyed by operationId. SWR
naturally deduplicates (same key = no re-fetch), handles the async
reconnect, and doesn't fire when key is null (no runningOperation).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: validate topic has running operation before issuing gateway token
refreshGatewayToken now requires topicId, verifies the topic belongs to
the user and has a runningOperation in metadata before signing a JWT.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: break signin title into two lines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix signin.title formatting in auth.json
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: allow templates to specify policyLoad so default docs are fully injected
All documents were hardcoded to PolicyLoad.PROGRESSIVE on creation,
causing CLAW template docs (IDENTITY, SOUL, BOOTSTRAP, AGENTS) to be
progressively disclosed instead of fully injected into context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: forward policyLoad through upsertDocument and persist on update
- Add policyLoad to UpsertDocumentParams and pass it through to model
- Add policyLoad param to update() so upsert's existing-document path
writes the value instead of silently discarding it
- Ensures re-running template init migrates pre-existing docs to ALWAYS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: change update() to use named params object instead of positional args
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: change create() and upsert() to use named params object
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: improve agentDocuments test coverage to 99%
Add tests for uncovered branches:
- normalizeLoadRule default branch (unknown rule)
- explicit 'always' rule match
- by-time-range with NaN dates
- resolveDocumentLoadPosition fallback paths
- composeToolPolicyUpdate with existing context values
- upsert create path for new filenames
- getAgentContext empty docs path
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: preserve policyLoad when copying documents
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ fix: align test assertion with refactored create() params object signature
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix(database): add ownership check in addFilesToKnowledgeBase to prevent IDOR
Verify that the target knowledge base belongs to the authenticated user
before inserting files, preventing unauthorized file injection into
other users' knowledge bases.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: reuse existing messages in execAgent when existingMessageIds provided
When existingMessageIds contains [userMsgId, assistantMsgId], skip
creating new messages and reuse the existing ones. This fixes duplicate
messages in Gateway mode where sendMessageInServer already created
the messages before execAgentTask is called.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: allow clicking NavItem while loading
Loading state should only show a visual indicator, not block onClick.
This fixes topic sidebar items being unclickable during agent execution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "🐛 fix: reuse existing messages in execAgent when existingMessageIds provided"
This reverts commit 43b808024d5c4a0074b692a85083a72046ab47e0.
* 🐛 fix: skip sendMessageInServer in Gateway mode to avoid duplicate messages
Gateway mode now calls execAgentTask directly instead of going through
sendMessageInServer first. The backend creates user + assistant messages
and topic in one call. executeGatewayAgent handles topic switching
internally after receiving the server response.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🌐 chore: add i18n for execServerAgentRuntime operation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: move temp message cleanup after executeGatewayAgent succeeds
Keep temp messages visible during the gateway call so the UI isn't
blank. On failure, mark the operation as failed instead of silently
returning — temp messages remain so the user sees something went wrong.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove manual temp message cleanup in gateway mode
switchTopic handles new topic navigation, and fetchAndReplaceMessages
replaces the message list from DB — no need to manually delete temp
messages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: clear _new key temp messages when gateway creates new topic
Pass clearNewKey: true to switchTopic so temp messages from the
optimistic create don't persist in the _new key after switching
to the server-created topic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: import ExecAgentResult from @lobechat/types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(desktop): embed CLI in app and PATH install
Made-with: Cursor
* ✨ feat(desktop): add CLI command execution feature and UI integration
- Implemented `runCliCommand` method in `ElectronSystemService` to execute CLI commands.
- Added `CliTestSection` component for testing CLI commands within the app.
- Updated `SystemCtr` to include CLI command execution functionality.
- Enhanced `generateCliWrapper` to create short aliases for CLI commands.
- Integrated CLI testing UI in the system tools settings page.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance working directory handling for desktop
- Updated working directory logic to prioritize topic-level settings over agent-level.
- Introduced local storage management for agent working directories.
- Modified tests to reflect changes in working directory behavior.
- Added checks to ensure working directory retrieval is only performed on desktop environments.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(desktop): implement CLI command routing and cleanup
- Introduced `CliCtr` for executing CLI commands, enhancing the desktop application with CLI capabilities.
- Updated `ShellCommandCtr` to route specific commands to `CliCtr`, improving command handling.
- Removed legacy CLI path installation methods from `SystemCtr` and related services.
- Cleaned up localization files by removing obsolete entries related to CLI path installation.
Signed-off-by: Innei <tukon479@gmail.com>
* 🚸 settings(system-tools): show CLI embedded test only in dev mode
Made-with: Cursor
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: integrate Gateway connection management into chat store
Add GatewayActionImpl to aiChat slice for managing Agent Gateway
WebSocket connections per operationId. Includes connect, disconnect,
interrupt, and status tracking. Also type the execAgentTask return value.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add Gateway mode branch in sendMessage for server-side agent execution
When agentGatewayUrl is set in server config (enableQueueAgentRuntime),
sendMessage now triggers server-side agent execution via execAgentTask
and receives events through the Agent Gateway WebSocket, instead of
running the agent loop client-side.
Includes:
- Expose agentGatewayUrl in GlobalServerConfig when queue mode is enabled
- Gateway event handler mapping stream events to UI message updates
- Fallback to client-side agent loop when Gateway is not configured
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: emit disconnected event on intentional disconnect
disconnect() was only calling setStatus('disconnected') but not emitting
the 'disconnected' event. This caused the store's cleanup listener to
never fire after terminal events (agent_runtime_end), leaving stale
connections in gatewayConnections.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: enhance Gateway event handler for multi-step agent streaming
Support multi-step agent execution display (LLM → tool calls → next LLM)
using hybrid approach: real-time streaming for current step, DB refresh at
step transitions.
Fixes LOBE-6874
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: wire up Gateway JWT token from execAgent to connectToGateway
Pass the RS256 JWT token returned by execAgentTask to connectToGateway
for WebSocket authentication. Also use ExecAgentResult from @lobechat/types
instead of local duplicate definition.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: handle wss:// protocol in AgentStreamClient buildWsUrl
When gatewayUrl already uses ws:// or wss:// protocol, use it directly
instead of stripping and re-adding the protocol prefix. Previously,
wss://host would become ws://wss://host (double protocol).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: queue gateway events to ensure stream_chunk waits for refreshMessages
Use a sequential Promise chain to process gateway events, so that
stream_chunk dispatches only run after stream_start's refreshMessages
resolves. Previously, chunks arrived before the new assistant message
existed in dbMessagesMap, causing updates to be silently dropped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: pass operationId context to internal_dispatchMessage in gateway handler
Without operationId, internal_dispatchMessage falls back to global state
to compute the messageMapKey, which may differ from the key where
refreshMessages stored the server-created messages. Passing operationId
ensures the correct conversation context is resolved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: resolve gateway streaming display issues
- Use fetchAndReplaceMessages (direct DB fetch + replaceMessages) instead
of refreshMessages which mutates an orphaned SWR key
- Create dedicated execServerAgentRuntime operation with correct topicId
context for internal_dispatchMessage to resolve the right messageMapKey
- Complete operation on agent_runtime_end instead of relying on
onSessionComplete callback
- Keep loading state active between steps (only clear on agent_runtime_end)
so users don't think the session ended during tool execution gaps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: maintain loading state across gateway step transitions
- Create dedicated execServerAgentRuntime operation with correct topicId
- Use fetchAndReplaceMessages instead of orphaned refreshMessages SWR key
- Re-apply loading after tool_end refresh so UI stays active between steps
- Complete operation on agent_runtime_end
- Add record-app-screen.sh for automated screen recording
- Output recordings to .records/ (gitignored)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: show loading on assistant message immediately in stream_start
Set loading on the current assistant message BEFORE awaiting
fetchAndReplaceMessages, so the UI shows a loading indicator while
waiting for the DB response instead of appearing frozen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: drive gateway loading state via operation system instead of messageLoadingIds
Associate the assistant message with the gateway operation via
associateMessageWithOperation so the Conversation store's operation-based
loading detection (isGenerating) works correctly. This shows the proper
loading skeleton on the assistant message while waiting for gateway events.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove unused internal_toggleMessageLoading from gateway handler
Loading state is now fully driven by the operation system via
associateMessageWithOperation + completeOperation. The old
messageLoadingIds-based approach is no longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: rewrite record-app-screen.sh to use CDP screenshot assembly
Replace broken ffmpeg avfoundation live recording (corrupts on kill) with
agent-browser CDP screenshot capture + ffmpeg assembly on stop. This works
reliably on any screen including external monitors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add Gateway Mode lab toggle and fix CI type error
- Add enableGatewayMode to UserLabSchema as experimental feature
- Add lab selector and settings UI toggle in Advanced > Labs
- Gateway mode now requires both server config (agentGatewayUrl) AND
user opt-in via Labs toggle
- Fix TS2322: result.token (string | undefined) → fallback to ''
- Add i18n keys for gateway mode feature
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: hide Gateway Mode toggle when agentGatewayUrl is not configured
Only show the lab toggle when the server has AGENT_GATEWAY_URL set,
so users without gateway infrastructure don't see the option.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: move Gateway Mode toggle below Input Markdown in labs section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: remove default AGENT_GATEWAY_URL value and make schema optional
Without an explicit env var, the gateway URL should be undefined so the
lab toggle and gateway mode are not available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 docs: update SKILL.md to reference record-app-screen.sh
Replace outdated record-gateway-demo.sh references with the renamed
record-app-screen.sh and its start/stop lifecycle documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 docs: add record-app-screen reference doc and slim down SKILL.md
Move detailed recording documentation to references/record-app-screen.md
and keep SKILL.md concise with a link to the full reference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: guard GatewayStreamNotifier with AGENT_GATEWAY_URL check
AGENT_GATEWAY_URL is now optional, so check both URL and service token
before wrapping with GatewayStreamNotifier to avoid TS2345.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: extract gateway execution logic to GatewayActionImpl
Move server-side gateway execution logic from conversationLifecycle.ts
into GatewayActionImpl.startGatewayExecution(). The sendMessage flow
now does a simple early return when gateway mode is active, keeping
the existing client-mode code path untouched.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: split gateway into isGatewayModeEnabled check + executeGatewayAgent
Replace fire-and-forget startGatewayExecution with explicit check/execute
pattern. Caller does: if (check) { await execute(); return; } — giving
proper error handling and clearer control flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(ResourceManager): integrate tree store for folder management and enhance file operations
- Added `useTreeStore` to manage folder structure and state, replacing previous file store dependencies.
- Updated `EmptyPlaceholder` to utilize `currentFolderId` for file uploads.
- Refactored `MoveToFolderModal` to use tree store for moving items, improving folder navigation.
- Enhanced drag-and-drop functionality in `DndContextWrapper` to support moving items between folders.
- Removed obsolete `LibraryHierarchy` state management, streamlining folder operations.
- Improved file renaming and deletion processes to ensure tree state consistency.
This update enhances the overall file management experience by leveraging a dedicated tree store for better performance and maintainability.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(TreeAction): enhance resource movement and update handling
- Updated mutation logic for moving resources to differentiate between items visible in the Explorer and those not visible, improving performance and user experience.
- Added refresh functionality for the file list after resource updates (move, update, delete) to ensure the Explorer reflects the latest state.
- Refactored mutation methods to use async/await for better readability and error handling.
This update streamlines resource management within the tree structure, ensuring a more responsive and consistent user interface.
Signed-off-by: Innei <tukon479@gmail.com>
* Fix file updates and tree move fallback regressions
---------
Signed-off-by: Innei <tukon479@gmail.com>
🐛 fix: hide LocalFile actions (Open/Show in Folder) in share page
In topic share pages, the LocalFile component was showing 'Open' and
'Show in Folder' action buttons on hover, which are desktop-only
operations not available to share page viewers.
- Add 'readonly' prop to LocalFile component to disable interactive actions
- Detect share page context via topicShareId in LocalFile Render plugin
- Skip Popover rendering when readonly is true
* ♻️ refactor: remove legacy messageLoadingIds from chat store
The messageLoadingIds state and internal_toggleMessageLoading action in the
chat store have been fully superseded by the operation system. The state was
being written to but never read by any consumer — all UI components and
selectors already use operation-based selectors (isMessageGenerating,
isMessageProcessing, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 chore: update skill docs to remove messageLoadingIds references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: replace messageLoadingIds with operationSelectors in generation action
The Conversation store's regenerateUserMessage was reading messageLoadingIds
from the chat store to check if a message is already being processed. Replace
with operationSelectors.isMessageProcessing which is the correct way to check
operation state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add operationsByMessage to test mocks for operation selector
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): add `lh notify` command for external agent callbacks
Add a new `lh notify` CLI command and server-side TRPC endpoint that allows
external agents (e.g. Claude Code) to send callback messages to a topic and
trigger the agent loop to process them.
Fixes LOBE-6888
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore(cli): replace sessionId with agentId and threadId in notify command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
♻️ refactor: remove promptfoo configs and dependencies from packages
Migrate all prompt evaluation tests to the cloud repo's agent-evals framework.
Remove promptfoo directories, configs, dependencies, and generator scripts
from @lobechat/prompts, @lobechat/memory-user-memory, and @lobechat/builtin-tool-memory.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: use parametersJsonSchema for Google tool schemas to support full JSON Schema
Replace Google's restrictive Schema subset with parametersJsonSchema, which accepts
standard JSON Schema directly. This eliminates the need for resolveRefs and
sanitizeSchemaForGoogle, fixing nullable enum (LOBE-6607) and $ref (LOBE-6680) issues.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: update remaining tests to use parametersJsonSchema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 fix(RuntimeConfig): instant-apply working directory with recent list
Remove Save/Cancel buttons from working directory selector.
Directories now apply immediately on click. Show recent directories
list with checkmark for active selection and "Choose a different folder"
entry at bottom.
* ✨ feat(SystemCtr): enhance folder selection to return repository type
Updated the `selectFolder` method to return an object containing the selected folder path and its repository type (either 'git' or 'github'). Added a new private method `detectRepoType` to determine the repository type based on the presence of a `.git/config` file. Introduced a new utility for managing recent directories, allowing the application to display appropriate icons based on the repository type in the UI.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor: remove redundant update-status call from GatewayStreamNotifier
Gateway now handles session completion directly in pushEvent when it
receives agent_runtime_end, so the separate update-status HTTP call
is no longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: update GatewayStreamNotifier tests for removed update-status call
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✨ feat: generate JWT token for Gateway WebSocket auth in execAgent
Sign a short-lived RS256 JWT via signUserJWT(userId) when creating an agent
operation, and return it in ExecAgentResult.token so the client can
authenticate with the Agent Gateway WebSocket.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Disable CSS file loading and JS evaluation in happy-dom Window (root cause)
- Add try-catch around Readability.parse() for defense in depth
- Add regression tests for invalid CSS selectors and external stylesheet links
Closes LOBE-6869
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: support nested subtask tree in task.detail
Replace flat subtask list with recursive nested tree structure.
Backend builds the complete subtask tree in one response,
eliminating the need for separate getTaskTree API calls.
Fixes LOBE-6814
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: return empty array for root subtasks instead of undefined
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 docs: add cli-backend-testing skill
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Each instruction interface now extends AgentInstructionBase directly instead of intersection
- Group instructions by category: LLM, Tool, Task, Human Interaction, Control
- Extract AgentHookType and AgentHookEvent into agent-runtime package
- Keep AgentHook, AgentHookWebhook, SerializedHook in server layer (webhook is server-specific)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add GraphAgent and agentFactory for graph-driven agent execution
- Add GraphAgent: a decorator around GeneralChatAgent that drives execution via declarative ReasoningGraph
- Agent nodes: delegate to GeneralChatAgent for tool-calling loops, then extract structured output
- LLM nodes: single structured LLM call
- Programmatic transition evaluation (not LLM-driven)
- Backtracking with configurable limits
- Add AgentInstruction.stepLabel: allows any Agent to label steps for display in stream events and hooks
- Add agentFactory to AgentRuntimeServiceOptions: external injection of custom Agent implementations
- Add stepLabel propagation: stream_start/stream_end events and afterStep hooks carry the label
- Fix: sanitize null bytes in MessageModel.create content (consistent with existing plugin argument sanitization)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(agent-runtime): validate graph node existence and preserve transitions at backtrack limit
- Add node existence check in startNode to prevent runtime crash on invalid entry/transition targets
- Evaluate all transitions even when backtrack limit is reached; only suppress actual backtrack targets
* 🐛(device-gateway-client): prevent uncaught error when closing connecting WebSocket
Detach ws event listeners safely, temporarily handle close-phase errors, and guard ws.close() so logout/token clear does not surface a main-process uncaught exception.
Made-with: Cursor
* 🧹 refactor(tests): remove unused mockProps from ComfyUIForm test
Cleaned up the ComfyUIForm test by removing the unused mockProps object, streamlining the test setup for better clarity and maintainability.
Signed-off-by: Innei <tukon479@gmail.com>
* Hide onboarding finish tool call and preserve close error listener
---------
Signed-off-by: Innei <tukon479@gmail.com>
🐛 fix(desktop): use stored locale from URL parameter instead of system language
When the desktop app restarts, the UI language was reverting to the system
language instead of respecting the user's saved language preference.
Root cause: The inline script in index.html was setting document.documentElement.lang
from navigator.language (system language) before i18n initialization could read
the stored locale from Electron store.
Fix: Check the URL's `lng` query parameter first (which is set by Electron main
process from stored settings in Browser.ts:buildUrlWithLocale()), then fall back
to navigator.language.
Fixes#13616https://claude.ai/code/session_0128LZAbJL1a5vkGboH4U5FP
Co-authored-by: Claude <noreply@anthropic.com>
* 🐛 fix(desktop): remote re-auth for batched tRPC and clean OIDC on disconnect
- Notify authorization required when X-Auth-Required is set, not only on HTTP 401 (207 batch)
- Show AuthRequiredModal after remote config init; do not gate on dataSyncConfig.active
- Desktop: market 401 only silent refresh; avoid community sign-in UI (AuthRequiredModal handles cloud)
- Disconnect: clearRemoteServerConfig to wipe encrypted OIDC tokens
Made-with: Cursor
* 🐛 Reset user-data Zustand stores on remote disconnect and sync refresh
- Add ResetableStoreAction helper and batched reset via userDataStores
- Wire reset into Electron remote disconnect and refreshUserData
- Handle refreshUserData failures in data sync SWR onSuccess
Made-with: Cursor
* 🐛 fix(useUserAvatar): refactor desktop environment checks to use mockConstEnv
- Replace direct manipulation of mockIsDesktop with mockConstEnv.isDesktop for better encapsulation.
- Update all relevant test cases to utilize the new mock structure, ensuring consistent behavior across tests.
This change improves the clarity and maintainability of the test code.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 test: update mocks for ShikiLobeTheme and refactor session/agent mocks
- Added ShikiLobeTheme mock to ComfyUIForm and AddFilesToKnowledgeBase tests for consistent theming.
- Refactored session and agent mocks to use async imports, improving test isolation and performance.
This enhances the clarity and maintainability of the test suite.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* 🤖 chore(skills): add electron-dev.sh script and update local-testing skill
Add reusable electron-dev.sh script with start/stop/status/restart commands
that reliably manages all Electron processes (main + helpers + vite).
Update SKILL.md to reference the script instead of inline bash commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add AgentStreamClient for Agent Gateway WebSocket communication
Browser-compatible WebSocket client for receiving agent execution events
from the Agent Gateway. Supports auto-reconnect with exponential backoff,
heartbeat keep-alive, and event replay via lastEventId resume.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add the availableAgents into the prompt inject
* fix: should auto inject the avaiable agents into context when use the auto model
* fix: update the prompt
* fix: test fixed
* ♻️ refactor(onboarding): add OnboardingContextInjector and wire context engine
Made-with: Cursor
* 🔧 refactor(onboarding): update tool call references to use `lobe-user-interaction________builtin`
Modified onboarding documentation and utility functions to standardize the use of the `lobe-user-interaction________builtin` tool call for structured input collection, enhancing clarity and consistency across the codebase.
Signed-off-by: Innei <tukon479@gmail.com>
* 🔧 refactor(onboarding): standardize tool call references to `lobe-user-interaction____askUserQuestion____builtin`
Updated documentation and utility functions to replace instances of the `lobe-user-interaction________builtin` tool call with `lobe-user-interaction____askUserQuestion____builtin`, ensuring consistency in structured input collection across the onboarding process.
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor(onboarding): move onboarding context before first user
* ♻️ refactor(context-engine): add virtual last user provider
* update v3
* 🐛 fix(onboarding): add early exit escape hatch for boundary cases
The `<next_actions>` directive only prompted finishOnboarding in the
summary phase, but phase transition required all fields + 5 discovery
exchanges — a condition extreme cases rarely meet. This left the model
stuck in discovery, never calling finishOnboarding.
- Add EARLY EXIT hint in discovery phase next_actions
- Add universal completion-signal REMINDER across all phases
- Add minimum-viable discovery fallback in systemRole
- Add explicit completion signal list in Early Exit section
- Add off-topic redirect limit in Boundaries
- Add CRITICAL persistence rule in toolSystemRole
* ✅ test(context-engine): fix OnboardingContextInjector tests to match BaseFirstUserContentProvider
Remove brittle MessagesEngine onboarding test that hardcoded XML content.
---------
Signed-off-by: Innei <tukon479@gmail.com>
🐛 fix(prompts): enforce user perspective in input completion prompt
The autocomplete prompt was generating completions from the AI assistant's
perspective (e.g., "How can I help you?") instead of the user's perspective.
Added explicit perspective constraints with good/bad examples.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add WebSocket gateway support to CLI agent run
CLI `agent run` now connects to Agent Gateway via WebSocket by default,
falling back to SSE when `--sse` is passed. After auth, sends `resume`
to fetch buffered events (covers race between exec and WS connect).
- Add `streamAgentEventsViaWebSocket` in agentStream.ts
- Add `resolveAgentGatewayUrl` in settings
- Add `OFFICIAL_AGENT_GATEWAY_URL` constant
- Support `AGENT_GATEWAY_SERVICE_TOKEN` env for gateway auth
- Add `--sse` flag for forced SSE fallback
Fixes LOBE-6800
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add WebSocket gateway stream tests for CLI
Cover auth flow, resume, event rendering, JSON mode, auth failure,
heartbeat_ack, URL construction, and a multi-step tool-call scenario.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: persist agentGatewayUrl in saveSettings/loadSettings
saveSettings and loadSettings now handle agentGatewayUrl so custom
gateway configuration survives across CLI runs. Default URL is
stripped like serverUrl to keep the settings file minimal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: remove AGENT_GATEWAY_SERVICE_TOKEN and fix JSON double-print in WS stream
1. Remove AGENT_GATEWAY_SERVICE_TOKEN env var — gateway auth should
only use Oidc-Auth / X-API-Key from the existing auth flow.
2. Fix --json mode printing duplicate JSON arrays: agent_runtime_end,
session_complete, and onclose all called console.log independently.
Add jsonPrinted guard so only the first path outputs JSON.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Google Gemini / Vertex AI rejects `additionalProperties` and `$ref` in
function declaration schemas. The previous fix (PR #13524) resolved most
`$ref` via `resolveRefs()` but missed two cases:
1. `additionalProperties` was never stripped
2. `$ref` survived when `resolveRefs` hit its depth limit (>10) on
recursive schemas
Add both keys to UNSUPPORTED_SCHEMA_KEYS so `sanitizeSchemaForGoogle()`
strips them after ref resolution.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix(github-copilot): surface quota exhaustion 429 instead of retrying
When the GitHub Copilot API returns a 429 with a Retry-After header
exceeding 5 minutes (indicating quota exhaustion rather than transient
rate limiting), throw the error immediately instead of retrying up to
MAX_RATE_LIMIT_RETRIES times with a silently capped 10s delay.
Fixes#13572
* 🐛 fix: use main scope messages for thread fork to fix subtopic re-fork failure
When inside a subtopic (activeThreadId set), openThreadCreator and portalAIChats
used activeDisplayMessages which included activeThreadId in the key, returning
thread-scoped messages instead of main conversation messages. This caused
genParentMessages to fail finding the target message, resulting in empty parent
messages and a broken/loading fork UI.
Fix: use messageMapKey with only agentId/topicId to always get main scope messages.
Closes LOBE-5023
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: include groupId in main scope key for group session support
Address Codex review: pass activeGroupId to messageMapKey so that
fork and thread selectors work correctly in group conversations
where messages are keyed by group scope instead of main scope.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: disable input completion by default
The input auto-completion experience is not polished enough yet,
so disable it by default. Users can still enable it manually in
Settings > Agent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: update snapshot for disabled input completion default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add GatewayStreamNotifier for Agent Gateway WebSocket push
Add a decorator that wraps IStreamEventManager to additionally push
events to the Agent Gateway via HTTP (fire-and-forget). When
AGENT_GATEWAY_SERVICE_TOKEN is configured, the factory automatically
wraps the base stream manager with the gateway notifier. Redis SSE
remains the primary event channel; the gateway is an additive push
layer for WebSocket delivery.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add GatewayStreamNotifier and factory gateway wrapping tests
Ensure the decorator always delegates to the inner stream event manager
first, gateway failure never drops Redis events, and the factory
correctly wraps/skips based on AGENT_GATEWAY_SERVICE_TOKEN.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add timeout, bounded concurrency and url-join to gateway notifier
- 5s AbortSignal timeout on every gateway POST to prevent hanging sockets
- Max 20 inflight requests; excess silently dropped with a debug log
- Use url-join for URL construction instead of string concatenation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: resolve TS18048 possibly undefined in test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: move gateway env vars to appEnv
Read AGENT_GATEWAY_SERVICE_TOKEN and AGENT_GATEWAY_URL from the
validated appEnv config instead of raw process.env.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: move gateway URL default into appEnv
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔒 fix: remove XOR auth header and legacy apiKey bypass (GHSA-5mwj-v5jw-5c97)
Completely remove the forgeable X-lobe-chat-auth XOR obfuscation mechanism:
- Remove apiKey fallback in checkAuthMethod (auth bypass vector)
- Rewrite checkAuth to use session/OIDC userId only, never trust client header
- Delete XOR encoding/decoding utilities and tests
- Delete dead keyVaults TRPC middleware (no consumers)
- Simplify createHeaderWithAuth (no longer sends XOR payload)
- Remove SECRET_XOR_KEY constant
- Remove authorizationHeader from TRPC lambda context
- Clean up CLI to only send Oidc-Auth header
- Update all affected tests
The LOBE_CHAT_AUTH_HEADER constant is retained for the async caller
(server-to-server) path which uses AES encryption via KeyVaultsGateKeeper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: restore createPayloadWithKeyVaults for fetchOnClient path
The client-side model runtime (fetchOnClient) needs getProviderAuthPayload
and createPayloadWithKeyVaults to build provider SDK init params directly
in the browser. These functions are unrelated to XOR encoding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: guard against null session before accessing user id
Add explicit null check before accessing session.user.id to prevent
TypeError when session is null (e.g. unauthenticated requests).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add missing AgentRuntimeError import
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: remove dead createRuntime code path causing type error
The createRuntime property was removed from checkAuth's RequestHandler
type but still referenced in the route handler, causing TS2339.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- clarify in the channels overview that WeChat currently requires an
active subscription
- note that community edition users may not see the WeChat option in
channel settings yet
- keep the English and Chinese overview pages aligned
## Testing
- `git diff --check`
Related to #13461.
* ♻️ refactor(bot): migrate Bot service to Agent Runtime Hooks framework
Migrate the last consumer (Bot/AgentBridgeService) from legacy
completionWebhook/stepWebhook/stepCallbacks dual-track pattern
to the unified hooks API. This completes LOBE-6208 Step 4.
- Enrich AgentHookEvent with step presentation + tracking data
- Enrich afterStep hook dispatch with full step context
- Merge executeWithWebhooks + executeWithInMemoryCallbacks into unified hooks
- Remove legacy triggerCompletionWebhook, triggerStepWebhook, stepCallbacks
- Remove completionWebhook/stepWebhook/webhookDelivery from params
LOBE-6675
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(hooks): dispatch completion hooks on early-terminal return and fix totalToolCalls lag
- Add dispatchCompletionHooks in early-terminal branch of executeStep
so onComplete hooks fire when operation is already interrupted/done/error
between queued steps (e.g., via /stop)
- Include current step's toolsCalling in afterStep totalToolCalls so
consumers get an accurate cumulative count instead of lagging by one step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: update tests to match hooks-based architecture
- Rewrite executeStep tests to use hookDispatcher spies instead of
removed registerStepCallbacks/getStepCallbacks API
- Rewrite completionWebhook tests to use hooks param and _hooks metadata
instead of removed completionWebhook param
- Delete stepLifecycleCallbacks.test.ts (tests removed API, coverage
now provided by HookDispatcher.test.ts + executeStep.test.ts)
- Update AgentRuntimeService.test.ts abort test to remove stepCallbacks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: resolve remaining CI failures from hooks migration
- Fix TS18048 errors: guard metadata access with null check in
_stepTracking block
- Migrate remaining registerStepCallbacks usage in
AgentRuntimeService.test.ts to hookDispatcher.dispatch spies:
onComplete error tests and onAfterStep tool result extraction tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(bot): update AgentBridgeService tests for hooks-based execution
Old tests expected execAgent to NOT be called (because APP_URL check
would throw in queue mode). With hooks migration, the APP_URL check
is gone (hooks use relative URLs resolved by HookDispatcher), so
execAgent is now called. Update tests to verify hooks are passed
correctly instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(bot): add hook payload compatibility tests for BotCallbackService
Add tests verifying that webhook payloads from HookDispatcher (containing
hookId/hookType fields) are correctly handled by BotCallbackService.
This validates the critical contract between the hooks framework and
the bot callback endpoint for step progress, completion, and error paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add hooks integration tests for e2e payload verification
Add integration tests that verify the full executeStep → hookDispatcher
chain produces events with all fields bot consumers depend on:
- afterStep event includes content, stepType, totalTokens, executionTimeMs
- afterStep event includes cross-step tracking (lastLLMContent, totalToolCalls)
- afterStep event includes toolsResult for tool_result phases
- onComplete fires on early-terminal states (interrupted) with lastAssistantContent
- All RenderStepParams-required fields are present and correctly typed
These tests catch payload format regressions without needing production
infrastructure (Redis, QStash, real bot platforms).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): memoize mentionOption and slashOption to prevent page freeze on paste
Stabilize mentionOption and slashOption references with useMemo/useCallback to break the
infinite re-render loop that occurs when pasting text triggers autocomplete.
Fixes LOBE-6684
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): trim trailing newlines from autocomplete result to prevent empty lines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): skip autocomplete during IME composition to prevent interrupting Chinese input
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): add `migrate openclaw` command for importing OpenClaw workspace
Add a new CLI command `lh migrate openclaw` that imports all files from the
OpenClaw workspace (~/.openclaw/workspace) as agent documents into the LobeHub
inbox agent. Supports --source, --agent-id, --slug, --dry-run, and --yes options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor(cli): restructure migrate as directory for future providers
Refactor `migrate` command from a single file to a directory structure
(`migrate/index.ts` + `migrate/openclaw.ts`) to support future migration
sources like ChatGPT, Claude, Codex, etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(cli): remove unnecessary `as any` casts in migrate openclaw
Use proper TrpcClient type instead of casting to any. Extract
resolveInboxAgentId helper with correct typing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor(cli): migrate openclaw creates a new "OpenClaw" agent by default
Instead of importing into the inbox, the default behavior now creates a
dedicated "OpenClaw" agent and imports workspace files as its documents.
Use --agent-id to import into an existing agent instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): restore --agent-id and --slug options for migrate openclaw
Support three modes: --agent-id (by ID), --slug (by slug, e.g. "inbox"),
or default (create a new "OpenClaw" agent).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): print agent URL after migrate openclaw completes
Show a clickable link (e.g. https://app.lobehub.com/agent/<id>) at the
end of the import so users can open the agent directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): check login state early in migrate openclaw
Verify authentication before scanning files so users get a clear
"Run 'lh login' first" message upfront instead of after confirmation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): read agent name, description, avatar from OpenClaw workspace
Parse IDENTITY.md (or SOUL.md) for Name, Creature/Vibe/Description, and
Emoji fields to populate the new agent's title, description, and avatar
instead of hardcoding "OpenClaw".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style(cli): show emoji + name instead of agent ID in migrate output
Display the agent avatar emoji and title throughout the migrate flow
(confirmation, creation, importing). The agent ID only appears in the
final URL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(cli): exclude .venv from openclaw workspace scan
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore(cli): expand excluded dirs/files for openclaw workspace scan
Filter out IDE configs, VCS dirs, OS artifacts, dependency dirs, Python
caches, build outputs, env files, and other common non-content items.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update version
* ✨ feat(cli): use `ignore` package for gitignore-based file filtering & improve output
- Replace hardcoded EXCLUDED_NAMES set with `ignore` package (gitignore syntax)
- Respect workspace .gitignore if present, plus comprehensive default rules
- Cover all common languages/tools: Python, Ruby, Rust, Go, Java, .NET, etc.
- Improve final output: friendlier completion message with agent name + URL
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(cli): add tests for migrate openclaw command
Cover profile parsing, file filtering (gitignore + default rules),
dry-run, agent resolution (--agent-id, --slug, default create),
confirmation flow, error handling, and output formatting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): filter placeholder emoji and binary/database files
- Skip avatar values like (待定), _(待定)_, TBD, N/A, etc.
- Add ignore rules for database files (*.sqlite, *.db, *.mdb, etc.),
images, media, fonts, lock files, and compiled binaries
- Runtime binary detection: check first 8KB for null bytes and skip
binary files that slip through the extension filter
- Add tests for placeholder emoji filtering, binary skip, and db exclusion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(api,cli): support optional createdAt for agent document upsert
Thread an optional `createdAt` parameter through all layers:
- Model: AgentDocumentModel.create/upsert accept optional createdAt,
set both createdAt and updatedAt on documents + agent_documents rows
- Service: UpsertDocumentParams includes createdAt
- Router: agentDocument.upsertDocument accepts optional z.date()
- CLI: migrate openclaw passes file mtime as createdAt to preserve
original file timestamps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style(cli): add npx usage hint to auth error message
Show 'npx -y @lobehub/cli login' alongside 'lh login' so users who
haven't installed the CLI globally know how to authenticate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update version
* ✨ feat(api,cli): support optional updatedAt for agent document upsert
Add updatedAt alongside createdAt through all layers. When both are
provided, updatedAt is used independently; when only createdAt is
given, updatedAt falls back to createdAt.
CLI now passes file birthtime as createdAt and mtime as updatedAt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(cli): use os.homedir() for default source & wrap file reads in try
- Replace process.env.HOME || '~' with os.homedir() so the default
--source path resolves correctly on Windows and when HOME is unset
- Move fs.readFileSync/statSync inside the try block so a single
unreadable file doesn't abort the entire 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>
* 🐛 fix(openapi): fix response.completed output missing message, wrong tool name & id
Fix three bugs in extractOutputItems for the Response API:
1. Assistant message with text+tool_calls was dropped from output
2. Function call names kept internal ____-separated format instead of identifier/apiName
3. Function call IDs were off by one due to missing message item
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(openapi): exercise real ResponsesService in regression tests
Replace local reimplementation with vi.mock stubs + real class import
so the tests fail if the production extractOutputItems regresses.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: move skills/tools from slash menu to @ mention with direct context injection
Separates slash menu (/) and @ mention responsibilities:
- Slash menu: only commands (compact, newTopic)
- @ mention: agents, topics, skills, tools
Replaces fake activateSkill tool-call preload messages with direct
content injection via SelectedSkillInjector/SelectedToolInjector,
preventing models from mimicking activateSkill calls.
Fixes LOBE-6048
* ♻️ refactor: skip activateSkill when skill content already injected via selected_skill_context
Fixes LOBE-6048
* ♻️ refactor: align @-mention skills/tools with context injectors and preload
Made-with: Cursor
* 🐛 fix(chat): preserve editorData across queue and home input sends
* Update home send APIs and align related tests
Remove hardcoded pnpm versions in the model-bank release workflow so CI uses the repository packageManager setting and avoids pnpm version mismatch failures. Also align release commit identity with the lobehub bot account used by other release workflows.
Made-with: Cursor
* fix: add the cronjob tools executiors
* fix: should use mutate to refresh the cronjob when it changes && add it into backend runtime
* fix: add the lost deps
* fix: should await the delete servers
* 🐛 fix(model-runtime): resolve Vertex AI $ref schema error and toolConfig incompatibility
1. Dereference $ref in JSON Schema before sending to Google/Vertex AI — the memory
tool manifest (from neko's recent refactor) uses $ref which Vertex AI rejects.
2. Skip includeServerSideToolInvocations for Vertex AI — only Google AI supports it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(model-runtime): preserve sibling schema fields when resolving $ref
When a schema node has $ref plus sibling keys (e.g. description from
allOf unwrapping), the resolved definition now merges with those siblings
instead of dropping them. This preserves argument-level descriptions for
fields like timeIntent, improving tool-call quality.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔒 fix: sanitize HTML artifact content and sandbox iframe to prevent XSS-to-RCE
- Add sanitizeHTMLContent() using DOMPurify to strip dangerous tags (script, embed, object, etc.) and all on* event handler attributes
- Add sandbox="" attribute to HTML artifact iframe to block all script execution and parent frame access
- Replace doc.write() with srcDoc for cleaner rendering
- Extract shared FORBID_EVENT_HANDLERS list to DRY up SVG and HTML sanitization
Ref: GHSA-xq4x-622m-q8fq
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: correct import path from @lobehub/utils to @lobechat/utils
The package name is @lobechat/utils, not @lobehub/utils. This caused a build failure in Electron desktop app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: implement AI input auto-completion with ReactAutoCompletePlugin
Adds GitHub Copilot-style ghost text completion to the chat input,
powered by a configurable system agent (disabled by default).
Key changes:
- Add `inputCompletion` system agent config (type, default, selector, i18n)
- Create `chainInputCompletion` prompt chain (V2 few-shot, benchmarked)
- Mount `ReactAutoCompletePlugin` in InputEditor when enabled
- Wire `getMessages` through ChatInput store for conversation context
- Add settings UI in Service Model page with enable toggle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: update systemAgent snapshot for inputCompletion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: restrict auto-complete context to visible user/assistant turns
Filter getMessages to use displayMessages (active visible thread)
instead of dbMessages (raw DB records including tool messages and
inactive branches). Also limit to last 10 user/assistant turns to
keep payload small and relevant.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: enable input completion by default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ⚡️ perf: use non-streaming for input completion requests
Autocomplete needs the full result before displaying ghost text,
so streaming adds unnecessary overhead. Setting stream: false
reduces latency by avoiding SSE chunking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: revert stream:false for input completion
fetchPresetTaskResult uses fetchSSE internally which cannot handle
non-streaming JSON responses, causing the editor to freeze after
receiving the completion result.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ⚡️ perf: use non-streaming for input completion requests
Autocomplete waits for the full result before displaying ghost text.
fetchSSE handles non-streaming responses via its fallback path
(response.clone().text()), avoiding SSE chunking overhead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ⚡️ perf: skip contextEngineering for input completion
Call getChatCompletion directly instead of fetchPresetTaskResult
to avoid triggering agentDocument.getDocuments on every autocomplete
request. Input completion only needs a simple LLM call with the
prompt chain, not the full context engineering pipeline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: revert to fetchPresetTaskResult for input completion
Use the standard contextEngineering pipeline. The agentDocument
overhead will be addressed separately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: stream tool call arguments incrementally in Response API
The tool_calling stream chunks contain accumulated arguments (not
deltas), but the Response API was treating each chunk as a complete
independent output_item — creating a new lifecycle (added → delta →
done) per token and incrementing output_index to 90+.
Fix: track active tool calls by call_id and compute true incremental
deltas by slicing off previously-seen content. Each tool call now
gets a single stable output_item with proper streaming deltas,
finalized only when the stream ends or tool execution begins.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: clear stale tool-call state on LLM stream retry
When call_llm retries after a failed attempt, activeToolCalls may
contain entries from the failed stream that never received a
tool_end. Without clearing, finishActiveToolCalls would emit
phantom function_call done events and misalign output_index for
the successful attempt. Reset the map on stream_retry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(cli): register task command and add kanban board view
Register the missing `registerTaskCommand` in program.ts so `lh task` commands are accessible. Add `--board` flag to `task list` that renders a kanban-style view grouping tasks by status columns (backlog, running, paused, completed, etc.) with color-coded borders.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove @lobehub/chat-plugin-sdk dependency
Plugins have been deprecated. This removes the SDK entirely:
- Define built-in ToolManifest, ToolManifestSettings, ToolErrorType types
- Delete src/features/PluginsUI/ (plugin iframe rendering)
- Delete src/store/tool/slices/oldStore/ (deprecated plugin store)
- Delete src/server/services/pluginGateway/ (plugin gateway)
- Delete src/app/(backend)/webapi/plugin/gateway/ (plugin API route)
- Migrate all ~50 files from SDK imports to @lobechat/types
- Remove @lobehub/chat-plugin-sdk, @lobehub/chat-plugins-gateway deps
- Remove @swagger-api/apidom-reference override and patch
Fixes LOBE-6655
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add missing getInstalledPlugins mock in customPlugin test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: increase Vercel build memory limit to 8192MB
The 6144MB limit was causing OOM during Vite SPA chunk rendering.
Aligned with other build commands that already use 8192MB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: unify default tool type to builtin and fix CustomRender
- Remove `invokeDefaultTypePlugin` — default type now falls through to builtin in both server and client execution paths
- Fix `CustomRender` to actually render builtin tool components via `getBuiltinRender` instead of always returning null
- Increase SPA build memory limit from 7168MB to 8192MB to fix OOM
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove legacy plugin gateway and type-specific invocations
- Delete `runPluginApi`, `internal_callPluginApi`, `invokeMarkdownTypePlugin`, `invokeStandaloneTypePlugin`
- Remove plugin gateway endpoint (`/webapi/plugin/gateway`) from URL config
- Remove special `builtin → default` runtimeType mapping in plugin model
- Clean up unused imports and related tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add 'builtin' to runtimeType union to fix type error
Use ToolManifestType instead of inline union for runtimeType fields
so that 'builtin' is included as a valid type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix(electron): add nodrag to userinfo dropdown menus
Add `-webkit-app-region: no-drag` to ThemeButton and LangButton
dropdown popups to prevent Electron from capturing click events
when the dropdown appears in the titlebar drag region.
https://claude.ai/code/session_01K6FLLJ4PMhKWqbRmrGEZkS
Co-authored-by: Claude <noreply@anthropic.com>
* ♻️ refactor: unify tool content formatting with ComputerRuntime and shared UI components
Introduce `@lobechat/tool-runtime` with `ComputerRuntime` abstract class to ensure consistent
content formatting (via `formatCommandResult`, `formatFileContent`, etc.) across local-system,
cloud-sandbox, and skills packages. Create `@lobechat/shared-tool-ui` to share Render and
Inspector components, eliminating duplicated UI code across tool packages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: address review issues — state mapping for renders and IPC param denormalization
- Add legacy state field mappings in local-system executor (listResults, fileContent,
searchResults) for backward compatibility with existing render components
- Add denormalizeParams in LocalSystemExecutionRuntime to map ComputerRuntime params
back to IPC-expected field names (file_path, items, shell_id, etc.)
- Fix i18n type casting for dynamic translation keys in shared-tool-ui inspectors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: inject render capabilities via context, unify state shape for cross-package render reuse
- Add ToolRenderContext with injectable capabilities (openFile, openFolder,
isLoading, displayRelativePath) to shared-tool-ui
- Update local-system render components (ReadLocalFile, ListFiles, SearchFiles,
MoveLocalFiles, FileItem) to use context instead of direct Electron imports
- Enrich ReadFileState with render-compatible fields (filename, fileType,
charCount, loc, totalCharCount)
- Cloud-sandbox now fully reuses local-system renders — renders degrade
gracefully when capabilities are not provided (no open file buttons in sandbox)
- Remove executor-level state mapping hacks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: fix sandbox render bugs — SearchFiles, GrepContent, MoveFiles, GlobFiles
- SearchFiles: ensure results is always an array (not object passthrough)
- GrepContent: update formatGrepResults to support object matches
`{path, content, lineNumber}` alongside string matches
- MoveFiles: render now handles both IPC format (items/oldPath/newPath) and
ComputerRuntime format (operations/source/destination)
- GlobFiles: fallback totalCount to files.length when API returns 0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: unify SearchLocalFiles inspector with shared factory
SearchLocalFiles inspector now supports all keyword field variants
(keyword, keywords, query) and reads from unified state (results/totalCount).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: handle missing path in grep matches to avoid undefined display
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: improve render field compatibility for sandbox
- EditLocalFile render: support both file_path (IPC) and path (sandbox) args
- SearchFiles render: support keyword/keywords/query arg variants
- FileItem: derive name from path when not provided
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add missing cloud-sandbox i18n key for noResults
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(task): add task.groupList API for kanban board view
Support querying tasks grouped by status in a single request, with per-group independent pagination. Returns array structure with hasMore/limit/offset for each group.
LOBE-6589
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(task): bound groupList groups and statuses array size
Prevent query storms from oversized requests by capping groups to 20
and statuses per group to 10.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore(task): reduce groupList max groups from 20 to 10
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(task): add generic updateTaskConfig method for safe config merging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add updateTaskConfig tests and use deep merge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add agent avatar data to brief list API
Enrich brief list and listUnresolved endpoints with agent avatars
from the task tree. For each brief's associated task, walks up to
find the root task, then collects all agents (assignee + creator)
across the full tree.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add BriefService and unit tests for brief agent enrichment
Extract enrichBriefsWithAgents logic into BriefService for reuse.
Add unit tests for TaskModel.getTreeAgentIdsForTaskIds,
AgentModel.getAgentAvatarsByIds, and BriefService.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔒 fix: scope recursive CTE to current user in getTreeAgentIdsForTaskIds
Add created_by_user_id filter to both the ancestor walk-up and
descendant walk-down recursive legs to prevent cross-tenant tree
traversal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): preserve editor state and behavior in fullscreen
Keep chat input content and interaction consistent when toggling fullscreen by restoring editor JSON state, adjusting Enter/Cmd+Enter semantics, and rendering fullscreen input in the desktop layout container.
Made-with: Cursor
* 🐛 fix(chat-input): auto-collapse fullscreen after send
Automatically exit fullscreen after sending from chat input so users do not need a second manual collapse action, and clear saved editor snapshot to avoid stale restore.
Made-with: Cursor
🐛 fix: hide loading placeholder when AI generation is stopped
Only render ContentLoading for LOADING_FLAT messages when actively generating.
Previously, stopping AI mid-generation left the "..." placeholder visible
with a loading animation even though nothing was being generated.
* 🐛 fix(fetch-sse): stop injecting contextBody into structured provider errors
Structured errors (ProviderBizError etc.) already contain complete context.
Spreading contextBody into their body overwrites fields like `provider` and
pollutes the error structure that downstream renderers depend on.
Fixes#13476
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(fetch-sse): add regression test for structured error body pollution
Ensures structured provider errors (e.g. ProviderBizError) are passed through
unchanged without contextBody injection, and that contextBody is only applied
to unknown/unstructured errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: gate agent onboarding with dedicated business flag
Made-with: Cursor
* 🗑️ chore(migrations): remove agent onboarding column from users table
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): enable agent onboarding based on environment and add redirect to classic onboarding
- Updated AGENT_ONBOARDING_ENABLED to be true in development mode.
- Introduced RedirectToClassicOnboarding component to handle navigation to classic onboarding.
- Simplified ClassicOnboardingPage by removing the mode switch button for non-development environments.
- Adjusted OnBoardingContainer to conditionally render the skip onboarding button based on the current route.
This change enhances the onboarding experience by ensuring that the agent onboarding feature is only available in development, while also improving navigation for users.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(test): inline emoji-mart and @lobehub/* deps in Vitest to fix ESM JSON import error
Widen server.deps.inline to include `emoji-mart` and all `@lobehub/*`
packages so their transitive `@emoji-mart/data` import (a .json main
entry) goes through Vite's transform pipeline instead of Node's native
ESM loader, which requires `with { type: "json" }`.
---------
Signed-off-by: Innei <tukon479@gmail.com>
Restores the original body.message / body.name fields that downstream error
handlers rely on. The previous PR renamed them to errorMessage / errorName
which broke existing error renderers.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(model-runtime): add toolConfig for Gemini 3+ combined tools
When Gemini 3+ models combine built-in tools (googleSearch/urlContext)
with functionDeclarations, the API requires
toolConfig.includeServerSideToolInvocations to be set to true.
Without this flag, requests return 400: "Please enable
tool_config.include_server_side_tool_invocations to use Built-in tools
with Function calling."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test(google): fix incomplete grounding metadata test
The test defined grounding response data but never used it as mock
input and had no assertions. Rewrote to properly feed grounding chunks
through the stream and verify the output contains grounding events
with citations and search queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(test): use type assertion for grounding test data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✨ feat(fetch-sse): enrich error context with provider, model, and network diagnostics
When a fetch error occurs (e.g. TypeError: Failed to fetch), the error body now
includes provider, model, apiMode, fetchOnClient, elapsedMs, networkStatus, and
traceId to help diagnose issues instead of only showing a useless minified stack.
Fixes LOBE-6594
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add disableTools option to execAgent for eval/benchmark scenarios
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: short-circuit tool discovery when disableTools is set
Move all tool-related fetches (plugin DB query, LobeHub/Klavis manifest
fetches, device list probing, model-bank import) inside the disableTools
guard so they are fully skipped in eval/benchmark runs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add unit tests for disableTools short-circuit behavior
Verify that when disableTools=true, all expensive tool discovery
(plugin query, manifest fetches, ToolsEngine creation) is skipped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: hoist variables referenced outside disableTools guard
Move lobehubSkillManifests, klavisManifests, agentPlugins, and
LOBE_DEFAULT_MODEL_LIST declarations outside the else block since
they are also used by agent management context and skill engine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: support per-task model/provider override via task.config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: extract agent execution types into dedicated agentExecution module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add unit tests for execAgent model/provider override
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 👷 chore(ci): unify CI package manager from bun to pnpm
Replace bun with pnpm across all GitHub Actions workflows to ensure
lockfile consistency with pnpm-lock.yaml as single source of truth.
* 👷 chore(ci): replace bun run with pnpm run in package.json scripts
Fix build failure in CI where bun is not installed. Replace bun run
references in root and e2e package.json scripts with pnpm run.
* 👷 chore(e2e): replace bunx with npx in e2e server startup
* 👷 chore(ci): create unified setup-env action, use pnpm install + bun run
- Add .github/actions/setup-env composite action (pnpm + bun + node)
- Refactor desktop-build-setup to use setup-env internally
- All workflows: pnpm install for deps, bun run for scripts
- Revert package.json/e2e scripts back to bun run
- Remove all direct pnpm/action-setup and oven-sh/setup-bun from workflows
* 🐛 fix(test): inline lexical ESM deps for vitest under pnpm
pnpm's strict node_modules layout causes vitest ESM resolution to fail
for lexical's named exports. Add lexical and @lexical/* to inline deps.
* ✨ feat: show live elapsed timer during tool execution
Display a real-time elapsed timer on tool call inspector while the tool is executing.
The timer automatically hides once execution completes.
Fixes LOBE-6331
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: stop execution timer for rejected tool calls and reset elapsed on restart
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix: auto-reload on chunk load error instead of showing toast
When a chunk fails to load the old version is already unusable,
so reload the page automatically. Uses sessionStorage guard to
prevent infinite reload loops.
Fixes LOBE-6572
♻️ refactor(tool): inject topic reference runtime in app layer
Move topic-reference executor to runtime injection so package code no longer imports app-level TRPC client aliases. Keep the TRPC call in store executor wiring for clear package/app boundaries.
Made-with: Cursor
* ✨ feat: add imageAspectRatio support and update payload handling for image models
* ✨ feat: enhance image model handling and support imageAspectRatio configuration
* ✨ feat: add support for new image model "Nano Banana 2" and enhance image configuration handling
* ✨ feat: add 'thinkingLevel4' to extendParams and improve image configuration handling
* ✨ feat: add new AI models including DeepSeek V3.2 and Ministral 3 series, enhancing model capabilities and configurations
* ✨ feat: update context window tokens and add new models in AIChatModelCard
* ✨ feat: update Mistral model IDs and add new models; change AiHubMix base URL to API endpoint
🐛 fix: set context before replaceMessages in layout effect
replaceMessages calls onMessagesChange(messages, get().context) internally.
Without updating context first, it writes new topic's messages to the old
topic's key in ChatStore, corrupting cached data.
* ⬆️ chore: bump Lexical to 0.42 and align editor imports
- Bump lexical and @lexical/utils; pin lexical in pnpm overrides
- Return serialized nodes from ActionTag/ReferTopic XML readers (no INodeHelper require)
- Drop IEditorPlugin implements; import MenuRenderProps and IEditor from @lobehub/editor barrel
Made-with: Cursor
* ✨ chore: add lexical dependency version 0.42.0 to package.json
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ test: enhance MCPClient Stdio Transport tests with local stdio entry
- Updated the test configuration to use a local stdio entry instead of `npx`, improving test reliability in CI environments.
- Added necessary imports for path resolution to support the new configuration.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(glmCodingPlan): update default URL and add GLM-5.1 model
- Change default URL to open.bigmodel.cn/api/coding/paas/v4
- Add GLM-5.1 model with 200K context window, 128K max output, reasoning support
* 🐛 fix: update test baseline URL for GLM Coding Plan provider
* 🐛 fix: support multiple artifacts rendering in the same message
When a message contains multiple `<lobeArtifact>` tags, only the first one
rendered correctly. The rest stayed in loading state or showed incorrect content.
Root causes:
- processWithArtifact used non-global regex, only removing newlines from first artifact
- artifactCode selector only extracted first artifact's content
- isArtifactTagClosed returned true if ANY artifact was closed
- Render onClick compared only messageId, closing portal instead of switching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add comprehensive tests for multiple artifacts rendering
- rehypePlugin: test multiple artifact tags in same tree (both p-wrapped and raw)
- action: test openArtifact switching between artifacts (same message, different messages)
- selectors: test artifactCode/isArtifactTagClosed with identifier edge cases
(non-existent identifier, unclosed artifact, both closed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: resolve type error in rehypePlugin test
Cast tree.children elements to any when accessing tagName property
to fix TS2339 error in the raw node test case.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: escape regex special characters in artifact identifier
Artifact identifiers interpolated directly into `new RegExp()` could cause
SyntaxError or incorrect matching when containing regex metacharacters
like (, [, +, etc. Now escapes identifiers before building regex patterns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: support client-side function tool execution in Response API
Implement LOBE-6543: when the Response API receives tools with type='function',
inject them into the LLM and pause execution when the LLM calls them, allowing
the client to provide results via function_call_output input items.
Key changes:
- Add 'client' to ToolSource type
- Inject function tools into LLM via execAgent with source='client' in sourceMap
- Pause agent loop (interrupt) when LLM calls a client function tool
- Handle function_call_output resume flow via previous_response_id
- Add response.function_call_arguments.done streaming event
- Emit response.incomplete when interrupted for client tool execution
- Use original function name for client tools instead of identifier/apiName
- Simplify response ID to use topicId directly (includes LOBE-6536 fix)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: remove MessageModel import, use prompt-based resume flow
MessageModel is not exported from @lobechat/database package.
Replace direct DB writes with prompt-based approach for tool result resume.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: use separator-safe client function identifier and add client to ToolSource
CLIENT_FN_IDENTIFIER `__fn__` caused ambiguous splits with PLUGIN_SCHEMA_SEPARATOR `____`,
breaking tool name resolution. Renamed to `lobe-client-fn` and added `client` to the
ToolSource union in @lobechat/types to match context-engine's definition.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(model-runtime): allow Gemini 3+ models to combine search tools with function declarations
Gemini 3+ models support urlContext, googleSearch, and functionDeclarations coexisting in the tools array. Previously, enabling search/urlContext would exclude function declarations (MCP tools/skills), causing them to silently fail.
Fixes LOBE-6450
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(model-runtime): restore hasToolCalls guard for pre-Gemini 3 multi-turn tool sessions
Restores the hasToolCalls check for pre-Gemini 3 models so that when
tool_calls exist in message history, functionDeclarations are prioritized
over search tools to maintain multi-turn tool-calling sessions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: mount DynamicFavicon to enable favicon state switching during agent operations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add favicon link tags to SPA HTML templates and handle missing links in updateFaviconDOM
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: resolve InterventionBar context errors and rendering issues
- Replace useMessageAggregationContext with prop drilling for assistantGroupId,
fixing crash when ApprovalActions renders outside MessageAggregationContext
- Filter out tmp_ message IDs from pending interventions to prevent
disabled buttons during message creation
- Portal ApprovalActions outside scroll container in InterventionBar
so buttons are always accessible for long content
- Clear stale displayMessages synchronously on topic change to prevent
old interventions from persisting during transitions
* 🐛 fix: use useLayoutEffect to clear stale interventions on topic switch
Replace render-phase side effect with useLayoutEffect to properly clear
displayMessages before browser paint when context changes, preventing
old topic interventions from flashing during transitions.
* 🐛 fix: synchronously reset store on context change to prevent stale data flash
Use React's "setState during render" pattern instead of useLayoutEffect.
When contextKey changes, React bails out and re-renders StoreUpdater
before rendering sibling components (ChatList/ChatInput), ensuring they
read fresh store state with no visible flash of old topic data.
* 🐛 fix: remount store on context change to eliminate stale data flash
Add key={contextKey} to zustand Provider so the store is recreated on
topic switch. Seed the new store with initialMessages in createStore to
render correct data on first mount — no intermediate skeleton or stale
flash. Remove render-phase reset hack from StoreUpdater as it's no
longer needed.
* 🐛 fix: revert Provider key approach, use useLayoutEffect for context reset
Provider key={contextKey} caused ChatHydration to remount and reset
activeTopicId from URL query, preventing topic switches entirely.
Reverted to stable Provider. Instead, use useLayoutEffect in StoreUpdater
to atomically reset displayMessages + messagesInit when contextKey changes.
This fires after commit but before paint, and React processes store updates
from layout effects synchronously, ensuring subscribers re-render with
correct state before the browser paints.
🐛 fix: add ReactMentionPlugin to ChatInput so mention nodes render
The ChatInput editor plugins did not include ReactMentionPlugin, causing
mention nodes inserted via @ to be invisible. Move the plugin into
CHAT_INPUT_EMBED_PLUGINS so all ChatInput instances (including Home)
render mention nodes, and remove the now-duplicate entry from EditorCanvas.
Fixes LOBE-6270
* ♻️ refactor: move Marketplace below Resources in sidebar
Move the Marketplace (Community) nav item from topNavItems to bottomMenuItems,
positioning it below Resources in the sidebar navigation.
Closes LOBE-6320
* 🐛 fix(cli): auto-reconnect on auth expiry instead of exit
- Add `updateToken()` and `reconnect()` methods to GatewayClient
- On `auth_expired`, refresh JWT then reconnect automatically (no more process.exit)
- Add heartbeat ack timeout detection: force reconnect after 3 missed acks
- Reset missed heartbeat counter on `heartbeat_ack` receipt
- Add comprehensive tests for updateToken, reconnect, and missed heartbeat scenarios
Closes connection drop issue when JWT expires after long-running sessions.
* ✨ feat: add cross-platform message tool for AI bot channel operations
Implement a unified message tool (`lobe-message`) that provides AI with
messaging capabilities across Discord, Telegram, Slack, Google Chat,
and IRC through a single interface with platform-specific extensions.
Core APIs: sendMessage, readMessages, editMessage, deleteMessage,
searchMessages, reactToMessage, getReactions, pin/unpin management,
channel/member info, thread operations, and polls.
Architecture follows the established builtin-tool pattern:
- Package: @lobechat/builtin-tool-message (manifest, types, executor,
ExecutionRuntime, client components)
- Registry: registered in builtin-tools (renders, inspectors,
interventions, streamings)
- Server runtime: stub service ready for platform adapter integration
https://claude.ai/code/session_011sHc6R7V4cSYKere9RY1QM
* feat: implement platform specific message service
* chore: add wechat platform
* chore: update wechat api service
* chore: update protocol implementation
* chore: optimize platform api test
* fix: lark domain error
* feat: support bot message cli
* chore: refactor adapter to service
* chore: optimize bot status fetch
* fix: bot status
* fix: channel nav ignore
* feat: message tool support bot manage
* feat: add lobe-message runtime
* feat: support direct message
* feat: add history limit
* chore: update const limit
* feat: optimize server id message history limit
* chore: optimize system role & inject platform environment info
* chore: update readMessages vibe
* fix: form body width 50%
* chore: optimize tool prompt
* chore: update i18n files
* chore: optimize read message system role and update bot message lh
* updage readMessage api rate limit
* chore: comatible for readMessages
* fix: feishu readMessage implementation error
* fix: test case
* chore: update i18n files
* fix: lint error
* chore: add timeout for conversaction case
* fix: message test case
* fix: vite gzip error
---------
Co-authored-by: Claude <noreply@anthropic.com>
♻️ refactor(store): migrate slices to class actions with flattenActions
- Video store: generationConfig/Topic/Batch/createVideo as *ActionImpl; aggregate with flattenActions
- Eval store: benchmark/dataset/run/testCase as classes; top-level flattenActions
- Tool agentSkills: AgentSkillsActionImpl + Pick typing
- groupProfile: flattenActions around ActionImpl instead of spreading instance
- agentGroup: wrap chatGroupAction with flattenActions for consistent aggregation
Made-with: Cursor
* ✨ feat: use skill-specific icons in slash menu instead of generic wrench icon
Each skill/tool in the slash menu now displays its own avatar (emoji or image URL)
instead of the generic 🔧 wrench icon for all items.
https://claude.ai/code/session_01KbUecMiAUDHvFtEULkSDvr
* ♻️ refactor: use SkillsIcon as default slash menu skill icon
https://claude.ai/code/session_01KbUecMiAUDHvFtEULkSDvr
* ✨ feat: enhance slash action item rendering and mention menu styles
- Updated `useSlashActionItems.ts` to improve icon rendering for URLs, now supporting blob and data-URI images.
- Modified `MenuItem.tsx` to conditionally apply additional styles for items with extra categories.
- Added new style for `itemWithCategoryExtra` in `style.ts` to enhance layout consistency.
These changes aim to improve the visual presentation and functionality of the chat input components.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(mention-menu): satisfy cx ClassNamesArg types in MenuItem
Made-with: Cursor
---------
Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
* ✨ docs: add screenshots to Telegram channel guide
* 📝 docs: Remove "feature in development" callout and developer mode requirement from channels documentation.
* docs: Migrate Telegram channel images to local assets and update CDN cache.
* docs: Add screenshots to channel setup guides for various platforms.
* chore: Update documentation image paths from GitHub user attachments to local blog assets.
---------
Co-authored-by: Rdmclin2 <rdmclin2@gmail.com>
* 🐛 fix: defer scroll-to-user-message until spacer is mounted
The scroll that pins a user message to the top of the viewport was
racing with the conversation spacer mount. When the spacer hadn't
rendered yet, there wasn't enough scrollable height, so the scroll
had no effect.
Now `useScrollToUserMessage` accepts a `spacerActive` flag and
defers the scroll until the spacer is mounted, guaranteeing the
fill height is available before scrolling.
https://claude.ai/code/session_016GDASpf7Rh5yN7BJTdXYwT
* 🐛 fix: always scroll immediately, re-scroll when spacer mounts
The previous fix deferred scrolling entirely until spacerActive was
true. This regressed the no-spacer case (content fills viewport,
spacer height = 0, mounted stays false) — the scroll never fired.
Now the hook always scrolls immediately on message send (preserving
original behavior), and additionally fires a follow-up scroll when
spacerActive transitions to true. This covers both cases:
- Content fills viewport: immediate scroll works, no spacer needed
- Content is short: immediate scroll may under-scroll, but the
follow-up scroll after spacer mounts corrects the position
https://claude.ai/code/session_016GDASpf7Rh5yN7BJTdXYwT
* 🐛 fix(conversation): shrink bottom spacer on scroll-up when idle
- Track scroll delta to reduce spacer height while not streaming
- Disable height transition during scroll-shrink for immediate feedback
- Reset reduction on new user/assistant pair and generation state changes
Made-with: Cursor
---------
Co-authored-by: Claude <noreply@anthropic.com>
Remove resp_ prefix and random suffix encoding from response IDs.
Response ID now equals topicId directly, simplifying multi-turn
conversation support via previous_response_id.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(openapi): support hosted builtin tools in Response API
Allow declaring builtin tools via { type: 'lobe-xxx' } syntax in the
tools array of POST /api/v1/responses. Hosted tool identifiers are
extracted and passed as additionalPluginIds to execAgent, where the
existing ToolsEngine handles manifest resolution automatically.
LOBE-6535
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(openapi): stream tool calls and results in Response API
Add full streaming support for tool execution events in the Response
API. Previously only text deltas were streamed; tool calls and results
were only visible in the final response.completed event.
Now emits:
- response.output_item.added (function_call) when LLM invokes a tool
- response.function_call_arguments.delta for tool arguments
- response.output_item.done (function_call) when tool call is complete
- response.output_item.added/done (function_call_output) when tool
execution finishes with results
- Proper text message lifecycle (added/delta/done) across multi-step
agent loops
LOBE-6535
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix(openapi): handle nullable tools param in extractHostedToolIds
The tools field from CreateResponseRequest uses .nullish() in zod,
so it can be null. Accept null in the parameter type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add unread completion notification for group topic orchestration
Group orchestration was missing markUnreadCompleted() call after completion,
and group topic NavItem lacked the unread completion indicator UI.
Fixes LOBE-4878
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: extract neon dot inline styles to createStaticStyles
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add test screenshot 01.jpg for LOBE-4878
* docs: add test screenshot 02.jpg for LOBE-4878
* docs: add test screenshot 03.jpg for LOBE-4878
* 🔥 chore: remove temporary test screenshots
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: change unread neon dot color from green to blue (colorInfo)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: replace remaining successColor references with infoColor in group topic item
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(onboarding): add agent-guided web onboarding flow
Made-with: Cursor
* Update onboarding prompts
Co-authored-by: Codex <noreply@openai.com>
* 🐛 fix web onboarding builtin tool flow
* ✨ feat(onboarding): enhance agent onboarding flow with new dimensions and refined rules
- Updated onboarding structure to include new nodes: agentIdentity, userIdentity, workStyle, workContext, and painPoints.
- Revised system role instructions to emphasize a conversational approach and concise interactions.
- Adjusted manifest and type definitions to reflect the new onboarding schema.
- Implemented tests to ensure proper functionality of the onboarding context and flow.
This update aims to improve user experience during onboarding by making it more engaging and structured.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): enhance onboarding experience with localized welcome messages and interaction hints
- Added localized welcome messages for onboarding in English and Chinese.
- Refactored system role handling to support dynamic interaction hints based on user locale.
- Updated onboarding context to include interaction hints for improved user engagement.
- Implemented tests to validate the new interaction hint functionality.
This update aims to create a more personalized and engaging onboarding experience for users across different languages.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): overhaul onboarding flow with new question structure and refined interaction rules
- Replaced existing interaction hints with a focused question structure to enhance user engagement.
- Updated system role instructions to clarify onboarding protocols and improve conversational flow.
- Refactored type definitions and manifest to align with the new onboarding schema.
- Removed deprecated interaction hint components and tests to streamline the codebase.
This update aims to create a more structured and engaging onboarding experience for users, ensuring clarity and efficiency in interactions.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): introduce builtin agent onboarding package with structured roles and prompts
- Added a new package for agent onboarding, including a package.json configuration and initial TypeScript files.
- Implemented system role templates and tool prompts to guide the onboarding process.
- Established a client interface for rendering questions and handling user interactions.
- Updated dependencies in related packages to integrate the new onboarding functionality.
This update aims to enhance the onboarding experience by providing a structured approach for agents, ensuring clarity and efficiency in user interactions.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): enhance agent onboarding with new question renderer and refined interaction logic
- Introduced a new `QuestionRendererView` component to streamline the rendering of onboarding questions.
- Refactored the `QuestionRenderer` to utilize a runtime hook for improved state management and separation of concerns.
- Updated the onboarding context to fallback to stored questions when the current question is empty, enhancing user experience.
- Simplified the onboarding API by removing unnecessary read token requirements from various endpoints.
- Added tests to validate the new question rendering logic and ensure proper functionality.
This update aims to create a more efficient and user-friendly onboarding experience by improving the question handling and rendering process.
Signed-off-by: Innei <tukon479@gmail.com>
* Add dev history view for onboarding
* remove: prosetting
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): inline response language step in agent conversation
- Add ResponseLanguageInlineStep and wire into Conversation flow
- Extend agent onboarding context and update ResponseLanguageStep route
- Add tests and onboarding agent document design spec
Made-with: Cursor
* ✨ feat(onboarding): enhance onboarding flow with inbox integration and schema refactor
- Updated onboarding process to migrate conversation topics to the inbox upon completion, ensuring users can revisit their onboarding discussions.
- Introduced a new schema-driven normalizer and node handler registry to streamline onboarding data handling, reducing code duplication and improving maintainability.
- Added comprehensive tests for new document builders and onboarding service methods to ensure functionality and reliability.
- Refactored existing components to support the new onboarding structure and improve user experience.
This update aims to create a more cohesive onboarding experience by integrating user identity data into the inbox and simplifying the underlying code structure.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(agent-documents): add listDocuments, readDocumentByFilename, upsertDocumentByFilename APIs
* ✨ feat(onboarding): add generic user interaction builtin tool
* ✨ feat(onboarding): wire generic tool interaction semantics
Register user-interaction tool in builtin-tools registry with manifest,
intervention components, client executor, and server runtime. Extend
BuiltinInterventionProps with interactionMode and onInteractionAction
to support custom (non-approval) interaction UIs. Add submit/skip/cancel
actions to conversation store with full operation lifecycle management.
* 🔧 fix: add builtin-tool-user-interaction to root workspace dependencies
* ♻️ refactor(onboarding): remove onboarding-owned question persistence
Drop askUserQuestion from the web-onboarding tool and remove
questionSurface from persisted state. Question presentation is now
delegated to the generic lobe-user-interaction tool.
* ♻️ refactor(onboarding): switch UI to generic interaction tool
Enable UserInteraction and AgentDocuments tools in web-onboarding and
inbox agent configs. Remove obsolete inline question renderers
(QuestionRenderer, QuestionRendererView, questionRendererRuntime,
questionRendererSchema, ResponseLanguageInlineStep) and simplify
Conversation component to only render summary CTA.
* 🔥 refactor(onboarding): remove identity doc and rewrite soul sync
* 🐛 fix(user-interaction): add humanIntervention to manifest and implement form UI
* 🐛 fix(onboarding): create user message on interaction submit instead of re-executing tool
* ♻️ refactor(onboarding): rebuild generic interaction flow
Align agent/tool roles and onboarding UI/runtime around the generic interaction rebuild.
Made-with: Cursor
* ✨ feat(onboarding): implement onboarding document and persona management
Introduce a new onboarding document structure that separates agent identity and user persona data. Replace existing `readSoulDocument` and `updateSoulDocument` APIs with `readDocument` and `updateDocument` to handle both SOUL.md and user persona documents. Update related services, client executors, and localization keys to reflect these changes. Ensure document updates are driven by the agent, allowing for incremental updates and improved content management.
Signed-off-by: Innei <tukon479@gmail.com>
* refactor
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(workflow): introduce unified tool call collapse UI and supporting components
Add a new workflow collapse feature that groups tool calls and reasoning into a single collapsible unit, enhancing the user interface for tool call progress. This includes the creation of several components: `WorkflowCollapse`, `WorkflowSummary`, `WorkflowExpandedList`, `WorkflowToolLine`, and `WorkflowReasoningLine`. Update the design specifications and implementation plans to reflect this new structure, aiming for a more cohesive and user-friendly experience.
Signed-off-by: Innei <tukon479@gmail.com>
* feat(types): add discovery pacing types and constant
* feat(onboarding): add countTopicUserMessages and pacing gate to derivePhase
* feat(onboarding): capture discovery baseline and return pacing data in getState
* ✨ feat(onboarding): add pacing hints to discovery phase tool result
* test(onboarding): add discovery pacing gate tests
* ♻️ refactor(onboarding): soften discovery pacing gate and add early exit exception
- MIN_DISCOVERY_USER_MESSAGES lowered from 4 to 2 (hard floor)
- RECOMMENDED_DISCOVERY_USER_MESSAGES = 4 (advisory hint)
- Tool protocol rule 2 now has explicit early exit exception
- Pacing hint text changed from imperative to advisory
* ✨ feat(onboarding): update .gitignore and remove outdated onboarding plans
- Added `docs/superpowers` to .gitignore to exclude documentation files from version control.
- Deleted several outdated onboarding implementation plans, including those for onboarding inbox integration, generic interaction rebuild, and user question simplification, to streamline project documentation.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): refine agent onboarding, streaming, and AskUserQuestion
Made-with: Cursor
* ✨ feat(store): add pending interventions selector
* 🐛 fix(store): handle standalone tool messages and structural children traversal in pending interventions selector
* ✨ feat(conversation): create InterventionBar component
Add InterventionBar UI component with tab bar for multiple pending
interventions, reusing the existing Intervention detail component.
* 🐛 fix(conversation): use stable toolCallId for active tab state and add min-height: 0
Track active intervention by toolCallId instead of array index to prevent
stale selection when interventions are resolved. Add min-height: 0 to
scrollable content for correct overflow in flex column layout.
* feat(chatinput): show InterventionBar when pending interventions exist
* feat(tool): collapse inline intervention to one-line summary with scroll-to-bottom
* feat(i18n): add intervention bar translation keys
* 🐛 fix(chatinput): prevent infinite render loop from pendingInterventions selector
* 🐛 fix(chatinput): use equality function for pendingInterventions to break render loop
* refactor(tool): remove CollapsedIntervention, return null for pending inline
* feat(i18n): add form.other translation key
* feat(tool): add styles for select field with Other option
* feat(tool): add SelectFieldInput with Other option row
* feat(tool): wire SelectFieldInput and update validation in AskUserQuestion
* fix(tool): add keyboard handler to Other row, fix label flex
* refactor(tool): restore Select dropdown, add Other toggle row below
* refactor(tool): change Other to form-level escape hatch, restore antd Select
* refactor(tool): replace checkbox toggle with minimal text link escape hatch
* feat(tool): use lucide icons, auto-focus on escape toggle, createStaticStyles
* refactor(onboarding): update onboarding model references and improve styling in ModeSwitch component
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): add greeting entry animation keyframes and card styles
* ✨ feat(onboarding): add LogoThree and entry animations to greeting card
* ✨ feat(onboarding): add View Transition morph from greeting to conversation
* refactor(onboarding): simplify ModeSwitch component by removing segmentedGlass styling
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): increase maximum onboarding steps to 5 and add ProSettingsStep component
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance user interaction question handling with validation schema
- Introduced Zod validation for askUserQuestion arguments to ensure correct structure.
- Updated test to reflect new question format with fields.
- Added error handling in AskUserQuestion component to log submission errors.
This improves the robustness of user interactions by enforcing schema validation and enhancing error reporting.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance agent metadata handling and onboarding synchronization
- Updated `useAgentMeta` to prioritize custom titles from the database, falling back to the default Lobe AI title if none exists.
- Integrated `refreshBuiltinAgent` into the onboarding process to ensure the latest agent data is reflected during user interactions.
- Adjusted the `InboxItem` component to display the correct agent title and avatar based on the updated metadata.
- Refactored optimistic update actions to improve message handling and synchronization across components.
This improves the user experience by ensuring that the most relevant agent information is displayed and updated in real-time during onboarding and conversation flows.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance conversation lifecycle and onboarding agent synchronization
- Updated `ConversationLifecycleActionImpl` to include additional context parameters (agentId, groupId, threadId, topicId) when updating message plugins for aborted interactions.
- Integrated `refreshBuiltinAgent` for the inbox during the onboarding process to ensure the latest agent data is synchronized.
These changes improve the handling of conversation lifecycle events and ensure that onboarding reflects the most current agent information, enhancing user experience during interactions.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: implement agent onboarding feature toggle and enhance ModeSwitch component
- Introduced `AGENT_ONBOARDING_ENABLED` configuration to control the visibility of the agent onboarding options.
- Updated `ModeSwitch` component to conditionally render onboarding options based on the feature toggle.
- Enhanced tests for `ModeSwitch` to cover scenarios for both enabled and disabled states of agent onboarding.
- Refactored `AgentOnboardingRoute` to navigate to the classic onboarding if the agent onboarding feature is disabled.
These changes improve the onboarding experience by allowing dynamic control over the agent onboarding feature, ensuring that users only see relevant options based on the configuration.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: update agent onboarding feature toggle to include development mode
- Modified `AGENT_ONBOARDING_ENABLED` to also activate in development mode using `isDev`.
- This change allows for easier testing and development of the agent onboarding feature without needing to alter production configurations.
Signed-off-by: Innei <tukon479@gmail.com>
* Prevent welcome message when onboard
* 🐛 fix: satisfy ToolExecutionContext and updateMessageTools typings
Made-with: Cursor
* 🐛 fix: update tests for custom builtin agent title and discovery phase constants
* 🐛 fix: use custom inbox agent title and avatar in InboxWelcome
* 🧹 chore(onboarding): remove HistoryPanel unit test
Made-with: Cursor
* 🐛 fix: add missing onboarding/agent and onboarding/classic routes to desktop config
* ✅ test: fix failing tests for onboarding container, document helpers, and executor
* ✅ test: mock LogoThree to prevent Spline runtime fetch errors in CI
---------
Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
* ✨ feat: show interrupted hint when AI generation is stopped
Display "Interrupted · What should I do instead?" text below the message
when user stops AI generation, replacing the infinite dotting animation.
Fixes LOBE-4462
Fixes LOBE-5726
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add edit button to queued messages tray
Allow users to edit queued messages by clicking the pencil icon,
which removes the message from the queue and restores its content
to the input editor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 chore: move record-electron-demo.sh to electron-testing skill
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: derive isInterrupted from latest runtime operation only
Previously isInterrupted used .some() to check if any cancelled AI
runtime operation existed for a message. In stop-then-retry flows,
the old cancelled op persisted alongside the new completed one,
causing the interrupted hint to reappear after the retry finished.
Now only the latest AI runtime operation is checked, so completed
retries correctly clear the interrupted state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: read group interruption from active block ID
For assistant groups, continuation runs attach cancelled operations to
lastBlockId (contentId) rather than the group root. Check isInterrupted
on both the group root and the active block so the interrupted hint
is shown correctly for stopped group continuations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: update test to expect cancelled status after user stop
The test for resolving aborted tools after cancellation now correctly
expects 'cancelled' status, since completeOperation preserves the
user's intentional cancellation rather than overwriting it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix: use Anthropic SDK for Kimi Coding Plan provider
- Switch from OpenAI SDK to Anthropic SDK for Kimi Coding Plan
- Update baseURL from `/coding/v1` to `/coding` (Anthropic-compatible endpoint)
- Update model IDs: `kimi-k2.5` → `k2p5`, remove `kimi-k2`
- Fix max_tokens resolution to use KimiCodingPlan model list
- Rewrite tests for Anthropic SDK compatibility
🔥 refactor: remove DefaultAgentForm UI from settings pages
Remove the user-facing Default Agent configuration form from both
the agent settings page and the service-model settings page.
The underlying store action and selectors are preserved for
programmatic use (e.g. onboarding).
Fixes LOBE-1125
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add businessElement and getFetchOptions plumbing to signin page
Add extension points to the signin flow so cloud overrides can inject
custom UI elements and modify fetch options for social sign-in requests.
- Add businessElement slot to SignInEmailStep component
- Pass getFetchOptions to signIn.social() and signIn.oauth2() calls
- Add businessElement and getFetchOptions defaults to useBusinessSignin
* 🐛 fix: resolve TS error on signIn.social result type with fetchOptions
♻️ refactor: move Marketplace below Resources in sidebar
Move the Marketplace (Community) nav item from topNavItems to bottomMenuItems,
positioning it below Resources in the sidebar navigation.
Closes LOBE-6320
* ✨ feat: add message queue for agent runtime (soft interrupt)
Implement per-context message queue that allows users to send messages
while the agent is executing. Messages are queued and consumed via two
paths: injected at step boundaries during execution (Path A), or
triggering a new sendMessage after completion (Path B).
- Add QueuedMessage type and queuedMessages state in operation store
- Add enqueue/drain/remove/clear actions and selectors
- Modify sendMessage to enqueue when execAgentRuntime is running
- Add queue checkpoint in step loop (streamingExecutor)
- Add Path B: drain remaining queue after completion → new sendMessage
- Keep input enabled during agent execution (remove isInputLoading guard)
- Add QueueTray component showing "N Queued" above ChatInput
- Add electron-testing skill for agent-browser CLI automation
Fixes LOBE-6001
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: Path B deferred execution to avoid recursive internal_execAgentRuntime
Use setTimeout(0) to break out of the current execution context when
triggering a new agent runtime for queued messages after completion.
Direct recursive calls caused issues with zustand state batching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: remove premature Path A drain, fix Path B with fresh store ref
Path A (step checkpoint injection) was draining the queue before the
last LLM step, leaving nothing for Path B. For agents without tool
calls, this meant queued messages were consumed but never acted upon.
Fix: remove Path A for now (will be re-added for tool-call scenarios),
and use useChatStore.getState() in Path B setTimeout to get a fresh
store reference instead of a stale closure capture.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📝 docs: update electron-testing skill with real-world patterns
Based on lessons learned during message queue testing:
- Must cd to apps/desktop before npx electron-vite dev
- Use polling loop for startup detection
- snapshot -i -C required for contenteditable (chat input)
- Use sleep + screenshot instead of agent-browser wait for long ops
- Access store via window.__LOBE_STORES.chat()
- Add error interceptor and store inspection patterns
- Document all gotchas (HMR, daemon blocking, fill vs type)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add Path A - early handoff to Path B at tool completion
When tools finish and queue has messages, break the step loop early
and let Path B create user message + start new operation. The new
LLM call sees full context including tool results + new user message.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: Path B use sendMessage for proper message creation
Use sendMessage instead of optimisticCreateMessage + internal_execAgentRuntime.
sendMessage handles the full lifecycle correctly: creates user message
on server, creates assistant message placeholder, and triggers
internal_execAgentRuntime — ensuring both messages are visible in UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: redesign QueueTray to Codex-style card layout
Each queued message shows as a card with icon, text preview,
and delete button. Uses antd CSS variables for consistent theming.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: connect QueueTray with ChatInput as unified container
QueueTray and ChatInput now share a connected border:
- QueueTray has top-rounded corners, no bottom border
- ChatInput gets bottom-only rounded corners when queue has items
- Uses cssVar for proper theme token styling
- Zero gap between tray and input
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: move queue check logic into GeneralChatAgent
Move the "finish early when queue has messages" decision from
streamingExecutor into GeneralChatAgent.runner(). The agent now
checks stepContext.hasQueuedMessages at tools_batch_result phase
and returns finish instruction, which is architecturally cleaner.
- Add hasQueuedMessages to RuntimeStepContext and computeStepContext
- GeneralChatAgent returns finish when tools complete + queue non-empty
- Remove Path A/B labels from comments
- streamingExecutor just passes hasQueuedMessages via stepContext
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: forward queued files in sendMessage and drain only on success
- Forward merged file attachments when replaying queued messages
(sendMessage now receives files from merged queue)
- Move drainQueuedMessages inside the status==='done' branch so
queued messages are preserved on error/interrupted states
- Add queued_message_interrupt to FinishReason enum
- Add hasQueuedMessages check to tool_result and tasks_batch_result
phases in GeneralChatAgent (not just tools_batch_result)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: use full operationContext for context key indexing
- operationsByContext index now uses messageMapKey(context) with full
context (including threadId, scope, etc.) instead of stripped key
- Fixes key mismatch where thread/scoped contexts couldn't find
running operations, causing overlapping generations
- Move mergeQueuedMessages from services/messageQueue.ts into
operation/types.ts alongside QueuedMessage type
- Delete services/messageQueue.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(resource): add select all hint and improve resource explorer selection
Made-with: Cursor
* ♻️ refactor(resource): flatten store actions and improve type imports
Made-with: Cursor
* ♻️ refactor resource explorer list view
* refactor: engine
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: checkpoint current workspace updates
* ♻️ refine resource explorer fetch ownership
* 🐛 fix: resolve resource manager ci regressions
* 🐛 fix(lambda): delete page-backed knowledge items by document id
* 🐛 fix(lambda): include knowledge-base files in remove-all
* 🐛 fix(resource): preserve cross-page select-all exclusions
* 🐛 fix(resource): retain off-screen optimistic resources
* 🐛 fix(resource): hide moved root items from current query
* 🐛 fix(resource): reset explorer selection on query change
* 🐛 fix(resource): fix select-all batchChunking and optimistic replace visibility
- batchChunking: pass through server-resolved IDs not in local resourceMap
when selectAllState is 'all', letting server filter unsupported types
- replaceLocalResource: keep replacement visible if the optimistic item was
already in the list, avoiding slug-vs-UUID mismatch in visibility check
* 🐛 fix(resource): reset selectAllState after batch operations and preserve off-screen optimistic items
- Reset selectAllState to 'none' after delete, removeFromKnowledgeBase,
and batchChunking to prevent stale 'all' state causing unintended
re-selection of remaining items
- Preserve off-screen optimistic resources in clearCurrentQueryResources
so background uploads from other folders survive delete-all-by-query
* 🐛 fix: satisfy import-x/first in resource action test
Made-with: Cursor
* 🎨 lint: sort imports in ResourceExplorer
Made-with: Cursor
* 🐛 fix: widen searchQuery type in useResetSelectionOnQueryChange test
Made-with: Cursor
---------
Signed-off-by: Innei <tukon479@gmail.com>
* fix: add the user github oauth in community home page profiles
* fix: change the oauth from social Profiles into skill connector way
* feat: add the claims user mcp and skills in community profiles
* fix: improve some claim model and skills/mcp
* 🐛 fix(github-copilot): switch codex models to responses api
* ♻️ refactor(github-copilot): simplify responses api routing
style: update model list
style: update model list
🐛 fix: align github copilot payload mapping and tests
style: update model list
style: update model list
* chore: add debug stream support
* refactor: use anthropic sdk for claude
* fix: fix ci error
* fix: fix github copilot reasoning_text chunk
* style: update Raptor mini base config, same as gpt-5-mini
style: update Raptor mini base config, same as gpt-5-mini
style: update Raptor mini base config, same as gpt-5-mini
* style: update model contextWindowTokens
* style: set default reasoning.summary to detailed, default as vscode
Introduce a unified SafeBoundary component (silent/alert variants) to
replace scattered custom ErrorBoundary class components. Automatically
wraps Inspector, ContentBlock sub-components, MessageItem, and
EditorCanvas to prevent individual component crashes from propagating
to the entire app.
* ✨ feat: improve error messages for Google AI block reasons and enhance handling of blocked content
* ✨ feat: add error localization for Google provider in createAgentExecutors
* ♻️ refactor: implement SkillResolver to replace ad-hoc skill assembly
Introduces a two-layer skill resolution architecture mirroring ToolsEngine + ToolResolver:
- SkillEngine (assembly layer): accepts raw skills + enableChecker, outputs OperationSkillSet
- SkillResolver (resolution layer): merges operation + step delta + accumulated activations
Key changes:
- Add SkillResolver, OperationSkillSet, StepSkillDelta, ActivatedStepSkill types
- Enhance SkillEngine with enableChecker and generate() method
- Wire SkillResolver into RuntimeExecutors call_llm
- Replace manual skillMetas assembly in aiAgent with SkillEngine.generate()
- Update client-side skillEngineering to use SkillEngine + enableChecker
- Add activatedStepSkills to AgentState for step-level skill accumulation
Fixes: agent-browser content injected into non-desktop scenarios (Discord bot)
due to missing filterBuiltinSkills call in aiAgent
LOBE-6410
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: extract agent-templates to standalone package and inject documents server-side
- Create @lobechat/agent-templates package with types, templates, and registry
- Move DocumentLoadPosition, DocumentLoadFormat, DocumentLoadRule, etc. to new package
- Move claw templates (AGENTS, BOOTSTRAP, IDENTITY, SOUL) with .md file imports
- Add BOOTSTRAP.md as new onboarding template (priority 1, system-append)
- Fix template positions: AGENTS→before-system, IDENTITY/SOUL→system-append
- Update database package to re-export from @lobechat/agent-templates
- Migrate all consumers to import directly from @lobechat/agent-templates
- Add agent documents injection in server-side RuntimeExecutors (was missing)
- Support -p CLI flag in devStartupSequence for port configuration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: correct import statement for non-type exports from agent-templates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 📦 build: add @lobechat/agent-templates to root dependencies
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove template proxy files from database package
Stop re-exporting template/templates from database — consumers import
directly from @lobechat/agent-templates. Keep types.ts re-exports for
internal database code only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: create BaseSystemRoleProvider to unify system message append pattern
All providers that append to the system message now inherit from
BaseSystemRoleProvider and only implement buildSystemRoleContent().
The base class handles find-or-create and join logic.
Migrated providers:
- EvalContextSystemInjector
- BotPlatformContextInjector
- SystemDateProvider
- ToolSystemRoleProvider
- HistorySummaryProvider
- SkillContextProvider
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: restore metadata tracking in BaseSystemRoleProvider via onInjected hook
Add onInjected() callback to BaseSystemRoleProvider so subclasses can
update pipeline metadata after successful injection. Also add raw-md
plugin to context-engine vitest config for .md imports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add enabled field to AgentDocumentInjector config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: add enabled field to all providers, remove spread conditionals in MessagesEngine
All providers now accept an `enabled` config field. MessagesEngine
pipeline is a flat array with no spread conditionals — each provider
is always instantiated and uses `enabled` to skip internally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: clean up MessagesEngine pipeline comments
Remove numbered prefixes, keep descriptive comments for each provider.
Only phase headers use separator blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: reorganize MessagesEngine pipeline phases by injection target
Phase 1: History Truncation
Phase 2: System Message Assembly (all BaseSystemRoleProvider)
Phase 3: Context Injection (before first user message, BaseFirstUserContentProvider)
Phase 4: User Message Augmentation (last user message injections)
Phase 5: Message Transformation (flatten, template, variables)
Phase 6: Content Processing & Cleanup (multimodal, tool calls, cleanup)
Moved SkillContext, ToolSystemRole, HistorySummary from Phase 3 to
Phase 2 since they append to system message, not user context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 💄 style: split Phase 6 into Content Processing (6) and Cleanup (7)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: split AgentDocumentInjector into three position-based injectors
- AgentDocumentSystemInjector (Phase 2): before-system, system-append, system-replace
- AgentDocumentContextInjector (Phase 3): before-first-user
- AgentDocumentMessageInjector (Phase 4): after-first-user, context-end
Shared utilities (filterByRules, formatDocument, sortByPriority) extracted
to AgentDocumentInjector/shared.ts. Old monolithic injector removed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: split AgentDocumentSystemInjector into three separate injectors
- AgentDocumentBeforeSystemInjector: prepends as separate system message (before-system)
- AgentDocumentSystemAppendInjector: appends to system message (system-append)
- AgentDocumentSystemReplaceInjector: replaces entire system message (system-replace)
Each has distinct semantics and correct pipeline placement:
- BeforeSystem → before SystemRoleInjector
- SystemAppend → after HistorySummary (end of Phase 2)
- SystemReplace → last in Phase 2 (destructive)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: auto-enable agent-documents tool when agent has documents
- Add AgentDocumentsManifest to defaultToolIds
- Add hasAgentDocuments rule in server createServerAgentToolsEngine
- Query agent documents in AiAgentService.execAgent to determine flag
- Pattern matches KnowledgeBase auto-enable via enableChecker rules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔨 chore: add agent documents status to execAgent operation log
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update content
* fix tests
* 🐛 fix: add raw-md plugin to database vitest configs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: prevent first assistant message re-animation on assistantGroup transition
When tool calls arrive during streaming, the message transitions from
assistant to assistantGroup, causing a full React remount. The first
content block's text was re-animating because isGenerating was still
true. Pass isFirstBlock prop through the render chain to disable
animation for the first block, since its text is guaranteed complete
by the time the group forms.
Fixes LOBE-6414
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove redundant isToolSingleLine animation check
isFirstBlock already covers the first block case, and subsequent blocks
should not have animation disabled just because they are single-line
with tools — they may still be streaming.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: sanitize search grounding image titles to prevent XSS
Replace dangerouslySetInnerHTML with stripHtml() for image result titles
in SearchGrounding and ImageSearchRef components to prevent stored XSS
attacks via malicious search result data.
Ref: GHSA-m5qx-g8hx-5f2p
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔒 fix: remove SystemJS plugin renderer to eliminate arbitrary JS execution risk
The old plugin render system (ui.mode === 'module') that used SystemJS
to dynamically load and execute JS from untrusted URLs has been fully
retired. Remove SystemJsRender and systemjs dependency entirely.
Ref: GHSA-46v7-wvmj-6vf7
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "🔒 fix: remove SystemJS plugin renderer to eliminate arbitrary JS execution risk"
This reverts commit 99a7603a72.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move `e.preventDefault()` before the `disabled || loading` early return
in NavItem's onClick handler. Previously, when a NavItem was in disabled
or loading state, the early return skipped `preventDefault()`, allowing
the underlying `<a>` tag's default navigation to trigger a full browser
page load instead of SPA routing.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: remove langchain dependency, use direct document loaders
Replace langchain and @langchain/community with self-implemented text
splitters and direct usage of underlying libraries (pdf-parse, d3-dsv,
mammoth, officeparser, epub2). This eliminates unnecessary dependency
bloat and addresses CVE-2026-26019 in @langchain/community.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add missing @types/html-to-text and @types/pdf-parse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🔒 fix: remove SystemJS plugin renderer to eliminate arbitrary JS execution risk
The old plugin render system (ui.mode === 'module') that used SystemJS
to dynamically load and execute JS from untrusted URLs has been fully
retired. Remove SystemJsRender and systemjs dependency entirely.
Ref: GHSA-46v7-wvmj-6vf7
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 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>
* ✨ 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>
* 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
## 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
* 🗃️ 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>
* 🐛 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>
* 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>
* 🐛 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>
* ✨ 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
* ✨ 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>
* 🐛 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>
* 🐛 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>
* 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
* 🐛 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>
* 👷 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>
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>
* ✨ 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>
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.
Fixeslobehub/lobehub#13071
Made-with: Cursor
* ♻️ 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>
* ✨ 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>
* ✨ 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
* ✨ 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>
* ♻️ 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>
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.
* 🐛 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
* ♻️ 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>
* 🐛 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
* ✨ 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>
* 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
* 💄 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>
* ✨ 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>
🐛 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>
* ♻️ 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
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>
* 🐛 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>
* 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>
* 🌐 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
* ✨ 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>
* 🐛 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>
* ✨ 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>
* 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>
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>
* 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
✨ 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.
* 🐛 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>
* 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
* 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>
* ✨ 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>
* ✨ 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>
* 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
* 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>
* 🐛 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>
* 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>
* 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
* ♻️ 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>
* 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
- 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
* ✨ 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>
* ✨ 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 模型的详细信息,标记为已弃用
* 🐛 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>
* ✨ 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%
🌐 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>
* ✨ 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>
* ✨ 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
* 🐛 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
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
🐛 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.
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.
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.
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.
🐛 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
* 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.
* ✨ 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.
description: 'Bot platform architecture (Discord, Slack, Telegram, Feishu/Lark, QQ, WeChat). Use when working on inbound webhooks, Chat SDK message routing, agent execution from chat platforms, queue-mode callbacks, gateway lifecycle (websocket/polling), bot provider CRUD/credentials, or platform-specific clients/adapters/schemas. Triggers on bot, channel, webhook, mention, Chat SDK, agent bot provider, gateway, bot-callback, qstash bot.'
---
# Bot System
> **Last updated: 2026-04-08.** Implementation evolves quickly — this doc is a map, not the source of truth. Always read the key files below to verify behavior, especially per-platform quirks. Update this doc when the architecture changes.
LobeChat agents can answer inside external chat platforms. Inbound messages flow through the Chat SDK (`chat` npm package), get routed to the right agent by `(platform, applicationId)`, executed via `AiAgentService`, and replied back through a per-platform `PlatformClient`. There are **two execution modes** (in-memory vs queue/QStash) and **three connection modes** (`webhook`, `websocket`, `polling`).
`supportsMarkdown=false` ⇒ outbound markdown is stripped to plain text via `stripMarkdown` and the AI is told not to use markdown. `supportsMessageEdit=false` ⇒ no progress edits — only the final reply is sent.
**Multi-mode connection** — Slack/Feishu/Lark/QQ shipped as websocket but support `webhook` per-provider via `settings.connectionMode`. Legacy rows without that field stay on `webhook` (see `LEGACY_WEBHOOK_PLATFORMS` in `platforms/utils.ts`) — **never add new platforms to that list**.
→ returns immediately, callbacks land at /api/agent/webhooks/bot-callback
```
The router caches loaded bots in memory. Cache is **invalidated** by `BotMessageRouter.invalidateBot(platform, appId)` whenever the TRPC `update`/`delete` mutations run, so new credentials/settings take effect on the next webhook.
## Execution Modes
### In-memory (default)
`AgentBridgeService.executeWithInMemoryCallbacks` wraps `execAgent` with `stepCallbacks`. Lives in one process — Promise-based wait, 30-min timeout, edits the same `progressMessage` after every step. Topic title is summarized inline via `SystemAgentService`.
### Queue (`isQueueAgentRuntimeEnabled`)
`AgentBridgeService.executeWithWebhooks`:
1. Posts the `renderStart` placeholder, captures `progressMessageId`.
2. Calls `execAgent` with `stepWebhook` and `completionWebhook` pointing at `${INTERNAL_APP_URL ?? APP_URL}/api/agent/webhooks/bot-callback`, plus `webhookDelivery: 'qstash'`.
3. Returns immediately; the bridge `finally` block keeps the active-thread marker held until the `completion` callback fires.
`/api/agent/webhooks/bot-callback/route.ts` verifies the QStash signature and hands off to `BotCallbackService.handleCallback`:
-`type: 'step'` → `handleStep` re-renders `renderStepProgress`, edits `progressMessageId` (skipped if `displayToolCalls=false` or platform `supportsMessageEdit=false`).
-`type: 'completion'` → `handleCompletion` writes the final reply (or error/interrupted message), removes the 👀 reaction, clears active-thread tracker, fires async `summarizeTopicTitle`.
`BotCallbackService.createMessenger` reloads provider + credentials from DB and rebuilds a `PlatformClient` per call (no in-memory state).
## Commands
Defined in `BotMessageRouter.buildCommands` and registered via two paths:
- **Text-based fallback** (Telegram/Feishu/QQ/Lark/WeChat): `bot.onNewMessage(/^\/(new|stop)(\s|$|@)/, ...)` plus a per-mention `tryDispatch` so commands work even before subscribe.
Built-in commands:
-`/new` — clears `topicId` in thread state, next message starts a fresh topic.
-`/stop` — interrupts the active execution (calls `AiAgentService.interruptTask` if `operationId` is known; otherwise queues a deferred stop via `requestStop`/`pendingStopThreads`, also aborts the startup phase via `startupControllers`).
To add a command, append to `buildCommands` — it auto-registers everywhere; on Telegram it also surfaces in the `/` menu via `client.registerBotCommands` → `setMyCommands`.
## Active-thread State (statics on `AgentBridgeService`)
-`activeThreads: Set<threadId>` — prevents duplicate runs per thread (must guard before stale-topic check, otherwise concurrent messages can drop).
-`activeOperations: Map<threadId, operationId>` — needed by `/stop` once `execAgent` returns.
-`startupControllers: Map<threadId, AbortController>` — cancels pre-`operationId` work (topic/tool prep).
-`pendingStopThreads: Set<threadId>` — `/stop` arrived before `operationId` existed; consumed once available.
In **queue mode**, the bridge `finally` skips cleanup so the marker persists until `BotCallbackService.handleCompletion` calls `clearActiveThread`.
## Topic Lifecycle in Threads
-`handleMention` always treats the message as the start of a new conversation.
-`handleSubscribedMessage` reads `topicId` from `thread.state`. If the topic is stale (`> 4 hours` since `updatedAt`), state is cleared and it retries as a fresh mention.
- If `execAgent` fails with a Postgres FK violation on `topic_id` (cached topic was deleted), the bridge clears state and retries as a mention.
-`subscribe()` is gated by `client.shouldSubscribe(threadId)` — Discord top-level channels return `false` so we don't follow up there.
## Attachments
`AgentBridgeService.extractFiles` resolves attachments in priority order:
1.`att.buffer` — already downloaded by the adapter (WeChat/Feishu inbound).
2.`att.fetchData()` — adapter-provided lazy download with auth (Telegram, Slack, Feishu history). **Required** when URLs are token-protected — naive `fetch(url)` later in `ingestAttachment.ts` has no credentials.
3.`att.url` — public CDN fallback (Discord, public QQ).
`inferMimeType` / `inferName` patch Telegram-style `photo` payloads (no `mimeType`/`name` from Bot API → defaults to `image/jpeg`) so vision models actually see them. Quoted-message attachments are also pulled from `raw.referenced_message.attachments` (Discord).
## Concurrency
`settings.concurrency` is `'queue'` or `'debounce'`:
-`debounce` → Chat SDK debounces inbound messages by `debounceMs`; `mergeSkippedMessages` joins skipped texts/attachments into the current message before handing to the agent.
-`queue` → Chat SDK serializes per-thread; the bridge's own `activeThreads` set is still required because in queue mode the SDK lock releases before the agent finishes.
## Gateway (persistent platforms)
Webhook platforms run fine in serverless functions. Persistent platforms (`websocket`, `polling`) need a long-running listener — that's the **gateway**.
- Iterates registered platforms and starts every enabled persistent provider with `durationMs = 10min`, then in `after(...)` polls `BotConnectQueue` every 30s for new connect requests, until the window expires.
-`getEffectiveConnectionMode(platform, settings)` is the only place that resolves per-provider mode — respect it everywhere.
**`POST /api/agent/gateway/start/route.ts`** is the non-Vercel `ensureRunning` entry point (`Bearer ${KEY_VAULTS_SECRET}`).
**Runtime status** is stored in Redis at `bot:runtime-status:platform:appId` with TTL ≈ `durationMs + 60s`. States: `starting | connected | disconnected | failed | queued`. Updated by each `PlatformClient.start/stop` and by the gateway service.
## Platform Definitions
Each platform exposes a `PlatformDefinition` registered in `platforms/index.ts`:
`schema` drives both server validation (`mergeWithDefaults`, `extractDefaults`) **and** the auto-generated UI form. Top-level keys `applicationId` / `credentials` / `settings` map to DB columns. Common settings fields live in `platforms/const.ts` (`displayToolCallsField`, `serverIdField`, `userIdField`).
Each platform implements `PlatformClient` (see `platforms/types.ts`):
`ClientFactory.validateCredentials` is called from the TRPC `testConnection` mutation — implement it to hit the platform API and return useful per-field errors.
- User-scoped: `create / update / delete / query / findById / findByAgentId / findEnabledByApplicationId`. Credentials are encrypted/decrypted via the injected `KeyVaultsGateKeeper`.
- Static (system-wide): `findByPlatformAndAppId`, `findEnabledByPlatform` — used by webhook routing & gateway sync, since they don't have a user context yet.
Client service: `src/services/agentBotProvider.ts`. Store actions: `src/store/agent/slices/bot/action.ts`. UI: `src/routes/(main)/agent/channel/{list,detail}` — settings form is auto-generated from each platform's `schema`.
## Reply Templates
`src/server/services/bot/replyTemplate.ts` exports `renderStart`, `renderStepProgress`, `renderFinalReply`, `renderError`, `renderStopped`, `splitMessage`. Step progress carries elapsed time, last LLM content, last tools, totals; final reply uses `client.formatMarkdown` then `client.formatReply` (which optionally appends `formatUsageStats`). `splitMessage(text, charLimit)` chunks at paragraph → line → hard cut.
-`const.ts` — `DEFAULT_X_CONNECTION_MODE`, history limits, etc.
-`protocol-spec.md` — protocol notes (every existing platform has one)
2. Pick the right `connectionMode` — webhook is much simpler if the platform supports it.
3. If the platform can't render markdown, set `supportsMarkdown: false` and implement `formatMarkdown` via `stripMarkdown`.
4. If it can't edit messages, set `supportsMessageEdit: false` — `BotCallbackService` will skip step edits and only send the final reply.
5. Implement `validateCredentials` so the UI's "Test connection" button gives useful errors.
6. Add the platform icon in `src/routes/(main)/agent/channel/const.ts` and register the platform in `src/server/services/bot/platforms/index.ts`.
7. Add i18n keys under `channel.*` in `src/locales/default/setting.ts` (or wherever the channel namespace lives) — the schema's `label`/`description`/`placeholder`/`enumLabels` are i18n keys.
- **If reachable** (returns any HTTP status): server is running. Skip to Step 2.
- **If unreachable**: start the server:
```bash
# From cloud repo root
pnpm run dev:next
```
To **restart** (pick up server-side code changes):
```bash
lsof -ti:3011 | xargs kill
pnpm run dev:next
```
**Important:** Server-side code changes in the submodule (`lobehub/src/server/`, `lobehub/packages/`) require a server restart. Next.js hot-reload may not pick up changes in submodule packages.
- **If file exists and contains `"serverUrl": "http://localhost:3011"`**: already authenticated. Skip to Step 3.
- **If file missing or points to wrong server**: login is needed. Ask the user to run:
```bash
! cd lobehub/apps/cli &&LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts login --server http://localhost:3011
```
> Login requires interactive browser authorization (OIDC Device Code Flow), so the user must run it themselves via `!` prefix. After login, credentials are saved to `lobehub/apps/cli/.lobehub-dev/` and persist across sessions.
### Step 3: Test with CLI Commands
CLI runs from source (`bun src/index.ts`), so CLI-side code changes take effect immediately without rebuilding.
```bash
cd lobehub/apps/cli
LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts <command>
```
### Step 4: Clean Up Test Data
Delete any test data created during verification:
```bash
LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts task delete < id > -y
LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts agent delete < id > -y
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
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/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)
-`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`.
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.
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
description: Database migration guide. Use when generating migrations, writing migration SQL, or modifying database schemas. Triggers on migration generation, schema changes, or idempotent SQL questions.
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
@@ -21,6 +21,23 @@ And updates:
-`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:
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! --
CREATEEXTENSIONIFNOTEXISTSpg_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:
@@ -84,10 +101,6 @@ DROP TABLE "old_table";
CREATEINDEX"users_email_idx"ON"users"("email");
```
## Step 4: Regenerate Client After SQL Edits
## Step 4: Update Journal Tag
After modifying the generated SQL (e.g., adding `IF NOT EXISTS`), regenerate the client:
```bash
bun run db:generate:client
```
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).
2.**Read images**: If the issue description contains images, MUST use `mcp__linear-server__extract_images` to read image content for full context
3.**Check for sub-issues**: Use`mcp__linear-server__list_issues` with `parentId` filter
4.**Mark as In Progress**: When starting to plan or implement an issue, immediately update status to **"In Progress"** via`mcp__linear-server__update_issue`
5.**Update issue status** when completing: `mcp__linear-server__update_issue`
Use `agent-browser` to automate Chromium-based apps via Chrome DevTools Protocol.
Install via `npm i -g agent-browser`, `brew install agent-browser`, or `cargo install agent-browser`. Run `agent-browser install` to download Chrome. Run `agent-browser upgrade` to update.
## Core Workflow
Every browser automation follows this pattern:
1.**Navigate**: `agent-browser open <url>`
2.**Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)
3.**Interact**: Use refs to click, fill, select
4.**Re-snapshot**: After navigation or DOM changes, get fresh refs
Use `&&` when you don't need to read intermediate output. Run commands separately when you need to parse output first (e.g., snapshot to discover refs, then interact).
## Essential Commands
```bash
# Navigation
agent-browser open <url> # Navigate (aliases: goto, navigate)
agent-browser close # Close browser
agent-browser close --all # Close all active sessions
# Snapshot
agent-browser snapshot -i # Interactive elements with refs (recommended)
agent-browser snapshot -s "#selector"# Scope to CSS selector
# Interaction (use @refs from snapshot)
agent-browser click @e1 # Click element
agent-browser click @e1 --new-tab # Click and open in new tab
agent-browser fill @e2 "text"# Clear and type text
agent-browser type @e2 "text"# Type without clearing
Refs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after clicking links/buttons that navigate, form submissions, or dynamic content loading.
## Annotated Screenshots (Vision Mode)
```bash
agent-browser screenshot --annotate
# Output includes the image path and a legend:
# [1] @e1 button "Submit"
# [2] @e2 link "Home"
agent-browser click @e2 # Click using ref from annotated screenshot
```
## Parallel Sessions
```bash
agent-browser --session site1 open https://site-a.com
agent-browser --session site2 open https://site-b.com
agent-browser --cdp 9222 snapshot # Explicit CDP port
```
## iOS Simulator (Mobile Safari)
```bash
agent-browser device list
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
agent-browser -p ios snapshot -i
agent-browser -p ios tap @e1
agent-browser -p ios swipe up
agent-browser -p ios screenshot mobile.png
agent-browser -p ios close
```
## Observability Dashboard
```bash
agent-browser dashboard install
agent-browser dashboard start # Background server on port 4848
agent-browser dashboard stop
```
## Cloud Providers
Use `-p <provider>` to run against cloud browsers: `agentcore`, `browserbase`, `browserless`, `browseruse`, `kernel`.
## Browser Engine Selection
```bash
agent-browser --engine lightpanda open example.com # 10x faster, 10x less memory
```
## Electron (LobeHub Desktop)
### Setup / Teardown
Use the `electron-dev.sh` script to manage the Electron dev environment. It handles process lifecycle, waits for SPA readiness, and reliably kills all child processes (main + helpers + vite).
# Or auto-discover running Chrome with remote debugging
agent-browser --auto-connect snapshot -i
```
---
# Part 2: osascript (Native macOS App Bot Testing)
Use AppleScript via `osascript` to control native macOS desktop apps for bot testing. Works with any app that supports macOS Accessibility, no CDP or Chromium needed.
The pattern is the same for every platform:
1.**Activate** the app (`tell application "X" to activate`)
2.**Navigate** to a channel/chat (Quick Switcher `Cmd+K` or Search `Cmd+F`)
3.**Send** a message (clipboard paste `Cmd+V` + Enter)
4.**Wait** for the bot response
5.**Screenshot** for verification (`screencapture` + `Read` tool)
## Per-Platform References
Pick the file for your target platform — each contains activation, navigation, send-message, and verification snippets specific to that app:
For **shared osascript patterns** (activate, type, paste, screenshot, read accessibility, common workflow template, gotchas), see [reference/osascript-common.md](./reference/osascript-common.md). Read this first if you're new to osascript automation.
---
# Scripts
Ready-to-use scripts in `.agents/skills/local-testing/scripts/`:
| `test-discord-bot.sh` | Send message to Discord bot via osascript |
| `test-slack-bot.sh` | Send message to Slack bot via osascript |
| `test-telegram-bot.sh` | Send message to Telegram bot via osascript |
| `test-wechat-bot.sh` | Send message to WeChat bot via osascript |
| `test-lark-bot.sh` | Send message to Lark / 飞书 bot via osascript |
| `test-qq-bot.sh` | Send message to QQ bot via osascript |
### Window Screenshot Utility
`capture-app-window.sh` captures a screenshot of a specific app window using `screencapture -l <windowID>`. It uses Swift + CGWindowList to find the window by process name, so screenshots work correctly even when the window is on an external monitor or behind other windows.
Each script: activates the app, navigates to the channel/contact, pastes the message via clipboard, sends, waits, and takes a screenshot. Use the `Read` tool on the screenshot for visual verification.
---
# Screen Recording
Record automated demos using `record-app-screen.sh` (start/stop lifecycle, CDP screenshots + ffmpeg assembly). See [references/record-app-screen.md](references/record-app-screen.md) for full documentation.
Outputs to `.records/` directory (gitignored): `<name>.mp4` (video) + `<name>/` (screenshots every 3s).
---
# Gotchas
### agent-browser
- **Daemon can get stuck** — if commands hang, `agent-browser close --all` or `pkill -f agent-browser` to reset
- **HMR invalidates everything** — after code changes, refs break. Re-snapshot or restart
- **`snapshot -i` doesn't find contenteditable** — use `snapshot -i -C` for rich text editors
- **`fill` doesn't work on contenteditable** — use `type` for chat inputs
- **Screenshots go to `~/.agent-browser/tmp/screenshots/`** — read them with the `Read` tool
- **Dialogs block all commands** — if commands time out, check `agent-browser dialog status`
- **Default timeout is 25s** — override with `AGENT_BROWSER_DEFAULT_TIMEOUT` (ms) or use explicit waits
- **Shell quoting corrupts eval** — use `eval --stdin <<'EVALEOF'` for complex JS
### Electron-specific
- **Always use `electron-dev.sh stop` to clean up** — `pkill -f "Electron"` only kills the main process; helper processes (GPU, renderer, network) survive. The script finds and kills all of them via PID matching against the project's electron binary path.
- **`npx electron-vite dev` must run from `apps/desktop/`** — running from project root fails silently. The `electron-dev.sh` script handles this automatically.
- **Don't resize the Electron window after load** — resizing triggers full SPA reload
- **Store is at `window.__LOBE_STORES`** not `window.__ZUSTAND_STORES__`
### osascript
See [reference/osascript-common.md](./reference/osascript-common.md#gotchas) for the full osascript gotchas list (accessibility permissions, `keystroke` non-ASCII issues, locale-specific app names, rate limiting, etc.).
Shared AppleScript / `osascript` patterns used by all platform bot tests. Read this first, then refer to the per-platform file for app-specific quirks.
## Core Patterns
### Activate an App
```bash
osascript -e 'tell application "Discord" to activate'
```
### Type Text
```bash
# Type character by character (reliable, but slow for long text)
osascript -e 'tell application "System Events" to keystroke "Hello world"'
# Press Enter
osascript -e 'tell application "System Events" to key code 36'
# Press Tab
osascript -e 'tell application "System Events" to key code 48'
# Press Escape
osascript -e 'tell application "System Events" to key code 53'
```
### Paste from Clipboard (fast, for long text)
```bash
# Set clipboard and paste — much faster than keystroke for long messages
osascript -e 'set the clipboard to "Your long message here"'
osascript -e 'tell application "System Events" to keystroke "v" using command down'
```
Or in one shot:
```bash
osascript -e '
set the clipboard to "Your long message here"
tell application "System Events" to keystroke "v" using command down
'
```
### Keyboard Shortcuts
```bash
# Cmd+K (quick switcher in Discord/Slack)
osascript -e 'tell application "System Events" to keystroke "k" using command down'
# Cmd+F (search)
osascript -e 'tell application "System Events" to keystroke "f" using command down'
# Cmd+N (new message/chat)
osascript -e 'tell application "System Events" to keystroke "n" using command down'
# Cmd+Shift+K (example: multi-modifier)
osascript -e 'tell application "System Events" to keystroke "k" using {command down, shift down}'
```
### Click at Position
```bash
# Click at absolute screen coordinates
osascript -e '
tell application "System Events"
click at {500, 300}
end tell
'
```
### Get Window Info
```bash
# Get window position and size
osascript -e '
tell application "System Events"
tell process "Discord"
get {position, size} of window 1
end tell
end tell
'
```
### Screenshot
```bash
# Full screen
screencapture /tmp/screenshot.png
# Interactive region select
screencapture -i /tmp/screenshot.png
# Specific window (by window ID from CGWindowList)
# Get all UI elements of the frontmost window (can be slow/large)
osascript -e '
tell application "System Events"
tell process "Discord"
entire contents of window 1
end tell
end tell
'
# Get a specific element's value
osascript -e '
tell application "System Events"
tell process "Discord"
get value of text field 1 of window 1
end tell
end tell
'
```
> **Warning:** `entire contents` can be extremely slow on complex UIs. Prefer screenshots + `Read` tool for visual verification.
### Read Screen Text via Clipboard
For reading the latest message or response from an app:
```bash
# Select all text in the focused area and copy
osascript -e '
tell application "System Events"
keystroke "a" using command down
keystroke "c" using command down
end tell
'
sleep 0.5
# Read clipboard
pbpaste
```
---
## Common Bot Testing Workflow
Regardless of platform, the pattern is:
```bash
APP_NAME="Discord"# or "Slack", "Telegram", "微信"
CHANNEL="bot-testing"
MESSAGE="Hello bot!"
WAIT_SECONDS=10
# 1. Activate
osascript -e "tell application \"$APP_NAME\" to activate"
sleep 1
# 2. Navigate to channel/chat (via Quick Switcher or Search)
osascript -e 'tell application "System Events" to keystroke "k" using command down'
sleep 0.5
osascript -e "tell application \"System Events\" to keystroke \"$CHANNEL\""
sleep 1
osascript -e 'tell application "System Events" to key code 36'
sleep 2
# 3. Send message
osascript -e "set the clipboard to \"$MESSAGE\""
osascript -e '
tell application "System Events"
keystroke "v" using command down
delay 0.3
key code 36
end tell
'
# 4. Wait for bot response
sleep "$WAIT_SECONDS"
# 5. Screenshot for verification
screencapture /tmp/"${APP_NAME,,}"-bot-test.png
echo"Result saved to /tmp/${APP_NAME,,}-bot-test.png"
```
### Tips
- **Use clipboard paste** (`Cmd+V`) for messages containing special characters or long text — `keystroke` can mangle non-ASCII
- **Add `delay`** between actions — apps need time to process UI events
- **Screenshot for verification** — use `screencapture` + `Read` tool for visual checks
- **Use a dedicated test channel/chat** — avoid polluting real conversations
- **Check app name** — some apps have different names in different locales (e.g., `微信` vs `WeChat`)
- **Accessibility permissions required** — System Events automation requires granting Accessibility access in System Preferences > Privacy & Security > Accessibility
---
## Gotchas
- **Accessibility permission required** — first run will prompt for access; grant it in System Preferences > Privacy & Security > Accessibility for Terminal / iTerm / Claude Code
- **`keystroke` is slow for long text** — always use clipboard paste (`Cmd+V`) for messages over \~20 characters
- **`keystroke` can mangle non-ASCII** — use clipboard paste for Chinese, emoji, or special characters
- **`key code 36` is Enter** — this is the hardware key code, works regardless of keyboard layout
- **`entire contents` is extremely slow** — avoid for complex UIs; use screenshots instead
- **App name varies by locale** — `微信` vs `WeChat`, `企业微信` vs `WeCom`; handle both
- **WeChat Enter sends immediately** — use `Shift+Enter` for newlines within a message
- **Rate limiting** — don't send messages too fast; platforms may throttle or flag automated input
- **Lark / 飞书 app name varies** — `Lark` (international) vs `飞书` (China mainland); scripts auto-detect
- **QQ uses `Cmd+F` for search** — not `Cmd+K` like Discord/Slack/Lark
- **Bot response times vary** — AI-powered bots may take 10-60s; use generous sleep values
General-purpose screen recording tool for the Electron app. Captures CDP screenshots as video frames and gallery snapshots, then assembles into an MP4 on stop.
## Why CDP Screenshots Instead of ffmpeg Screen Capture
- **Works on any screen** — CDP screenshots capture the browser viewport directly, so external monitors, Retina scaling, and window positioning are all handled automatically
- **No signal handling issues** — ffmpeg-static (npm) produces corrupt MP4 files when killed (missing moov atom). CDP screenshots avoid this entirely
- **Consistent output** — Screenshots are resolution-independent and don't require crop coordinate calculations
## Commands
```bash
# Start recording (Electron must be running with CDP)
agent_ref=$(echo"$snapshot"| grep 'link "'| grep -vE '"Home"|"Pages"|"Settings"|"Search"|"Resources"|"Marketplace"'| head -1 | grep -oE 'ref=e[0-9]+'| sed 's/ref=//'||true)
fi
if[ -z "$agent_ref"];then
echo"[error] No agent link found in snapshot"
echo"$snapshot"| head -30
return1
fi
echo"[demo] Clicking agent ref: @$agent_ref"
agent-browser --cdp "$port" click "@$agent_ref"
sleep 3
echo"[demo] Step 2: Send first message (triggers AI generation)"
local input_ref
input_ref=$(find_input_ref "$port")
agent-browser --cdp "$port" click "@$input_ref"
agent-browser --cdp "$port"type"@$input_ref""Write a 3000 word essay about the complete history of space exploration from Sputnik to the James Webb Space Telescope"
sleep 1
agent-browser --cdp "$port" press Enter
sleep 3
echo"[demo] Step 3: Queue message 1"
input_ref=$(find_input_ref "$port")
agent-browser --cdp "$port" click "@$input_ref"
agent-browser --cdp "$port"type"@$input_ref""This message should be edited"
echo"[demo] Queue was already drained. Retrying..."
input_ref=$(find_input_ref "$port")
agent-browser --cdp "$port" click "@$input_ref"
agent-browser --cdp "$port"type"@$input_ref""Now write another 3000 word essay about artificial intelligence from Turing to transformers covering every major breakthrough"
sleep 1
agent-browser --cdp "$port" press Enter
sleep 2
input_ref=$(find_input_ref "$port")
agent-browser --cdp "$port" click "@$input_ref"
agent-browser --cdp "$port"type"@$input_ref""This message should be edited"
@@ -6,8 +6,14 @@ description: React component development guide. Use when working with React comp
# React Component Writing Guide
- Use antd-style for complex styles; for simple cases, use inline `style` attribute
- **Prefer `createStaticStyles` with `cssVar.*`** (zero-runtime) — module-level, no hook call required
- Only fall back to `createStyles` + `token` when styles genuinely need runtime computation (dynamic props, JS color fns like `readableColor`/`chroma`)
- See `.cursor/docs/createStaticStyles_migration_guide.md` for full pattern
- Use `Flexbox` and `Center` from `@lobehub/ui` for layouts (see `references/layout-kit.md`)
- 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.
**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.
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 -- \
| `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
description: SPA route and feature structure. Use when adding or modifying SPA routes in src/routes, defining new route segments, or moving route logic into src/features. Covers how to keep routes thin and how to divide files between routes and features.
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
@@ -13,6 +13,8 @@ SPA structure:
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
@@ -73,8 +75,21 @@ Each feature should:
- 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**
-Add the segment to `src/spa/router/desktopRouter.config.tsx` (or the right router config) with `dynamicElement` / `dynamicLayout` pointing at the new route paths (e.g. `@/routes/(main)/my-feature`).
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).
| `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.
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
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.
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
| 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.
@@ -116,6 +116,14 @@ When the user requests a release:
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`):
@@ -123,7 +131,7 @@ Choose the appropriate workflow based on the scenario (see `reference/patch-rele
- **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 canary, write a dedicated migration changelog
- **DB Migration**: Create a `release/db-migration-{name}` branch from main, cherry-pick migration commits, write a dedicated migration changelog
@@ -15,4 +15,6 @@ This release includes a **database schema migration** involving **5 new tables**
- The migration runs automatically on application startup
- No manual intervention required
The migration owner: @arvinxx — responsible for this database schema change, reach out for any migration-related issues.
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.
- 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
if grep -iq "^${ISSUE_AUTHOR}$" .github/maintainers.txt; then
echo "is_team=true" >> "$GITHUB_OUTPUT"
else
echo "is_team=false" >> "$GITHUB_OUTPUT"
fi
- name:Copy triage prompts
run:|
mkdir -p /tmp/claude-prompts
@@ -62,7 +72,7 @@ jobs:
**IMPORTANT**:
- Follow ALL steps in the issue-triage.md guide
- Apply labels according to the guide's rules
- Post a mention comment to the appropriate team member(s) based on team-assignment.md
- ${{ steps.check-team.outputs.is_team == 'true' && 'The issue author is a team member. Do NOT post any @mention comment.' || 'Post a mention comment to the appropriate team member(s) based on team-assignment.md' }}
'You need to maintain the component format of the mdx file; the output text does not need to be wrapped in any code block syntax on the outermost layer.\n'+
- New branches should be created from `canary`; PRs should target `canary`
- Use rebase for git pull
- Git commit messages should prefix with gitmoji
- Git branch name format: `username/feat/feature-name`
- Git branch name format: `feat/feature-name`
- Use `.github/PULL_REQUEST_TEMPLATE.md` for PR descriptions
-PR titles with `✨ feat/` or `🐛 fix` trigger releases
-**Protection of local changes**: Never use `git restore`, `git checkout --`, `git reset --hard`, or any other command or workflow that can forcibly overwrite, discard, or silently replace user-owned uncommitted changes. Before any revert or restoration affecting existing files, inspect the working tree carefully and obtain explicit user confirmation.
### Package Management
@@ -86,30 +86,15 @@ cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path
- **Dev**: Translate `locales/zh-CN/namespace.json` locale file only for preview
- DON'T run `pnpm i18n`, let CI auto handle it
## Linear Issue Management
Follow [Linear rules in CLAUDE.md](CLAUDE.md#linear-issue-management-ignore-if-not-installed-linear-mcp) when working with Linear issues.
## SPA Routes and Features
- **`src/routes/`** holds only page segments (layout + page entry files). Keep route files thin; they should import from `@/features/*` and compose.
- **`src/features/`** holds business components by domain. Put layout pieces, hooks, and domain UI here.
-See [CLAUDE.md – SPA Routes and Features](CLAUDE.md#spa-routes-and-features) and the **spa-routes** skill for how to add new routes and how to split files.
- **`src/routes/`** holds only page segments (`_layout/index.tsx`, `index.tsx`, `[id]/index.tsx`). Keep route files **thin** — import from `@/features/*` and compose, no business logic.
- **`src/features/`** holds business components by **domain** (e.g. `Pages`, `PageEditor`, `Home`). Layout pieces, hooks, and domain UI go here.
-**Desktop router parity:** When changing the main SPA route tree, update **both**`src/spa/router/desktopRouter.config.tsx` (dynamic imports) and `src/spa/router/desktopRouter.config.desktop.tsx` (sync imports) so paths and nesting match. Changing only one can leave routes unregistered and cause **blank screens**.
- See the **spa-routes** skill (`.agents/skills/spa-routes/SKILL.md`) for the full convention and file-division rules.
## Skills (Auto-loaded)
All AI development skills are available in `.agents/skills/` directory:
All AI development skills are available in `.agents/skills/` directory and auto-loaded by Claude Code when relevant.
- **misc**: when use trustclient not register market m2m token, closes [#12762](https://github.com/lobehub/lobe-chat/issues/12762) ([400a020](https://github.com/lobehub/lobe-chat/commit/400a020))
@@ -6,15 +6,15 @@ Guidelines for using Claude Code in this LobeHub repository.
- Next.js 16 + React 19 + TypeScript
- SPA inside Next.js with `react-router-dom`
-`@lobehub/ui`, antd for components; antd-style for CSS-in-JS
-`@lobehub/ui`, antd for components; antd-style for CSS-in-JS — **prefer `createStaticStyles` with `cssVar.*`** (zero-runtime); only fall back to `createStyles` + `token` when styles genuinely need runtime computation. See `.cursor/docs/createStaticStyles_migration_guide.md`.
- react-i18next for i18n; zustand for state management
- SWR for data fetching; TRPC for type-safe backend
@@ -60,6 +60,7 @@ When adding or changing SPA routes:
1. In `src/routes/`, add only the route segment files (layout + page) that delegate to features.
2. Implement layout and page content under `src/features/<Domain>/` and export from there.
3. In route files, use `import { X } from '@/features/<Domain>'` (or `import Y from '@/features/<Domain>/...'`). Do not add new `features/` folders inside `src/routes/`.
4.**Register the desktop route tree in both configs:**`src/spa/router/desktopRouter.config.tsx` and `src/spa/router/desktopRouter.config.desktop.tsx` must stay in sync (same paths and nesting). Updating only one can cause **blank screens** if the other build path expects the route.
See the **spa-routes** skill (`.agents/skills/spa-routes/SKILL.md`) for the full convention and file-division rules.
@@ -77,7 +78,7 @@ bun run dev
After `dev:spa` starts, the terminal prints a **Debug Proxy** URL:
We're thrilled that you want to contribute to Lobe Chat, the future of communication! 😄
We're thrilled that you want to contribute to LobeHub, the future of communication! 😄
Lobe Chat is an open-source project, and we welcome your collaboration. Before you jump in, let's make sure you're all set to contribute effectively and have loads of fun along the way!
LobeHub is an open-source project, and we welcome your collaboration. Before you jump in, let's make sure you're all set to contribute effectively and have loads of fun along the way!
## Table of Contents
@@ -25,7 +25,7 @@ Lobe Chat is an open-source project, and we welcome your collaboration. Before y
📦 Clone your forked repository to your local machine using the `git clone` command:
@@ -311,7 +311,7 @@ We have implemented support for the following model service providers:
<!-- PROVIDER LIST -->
At the same time, we are also planning to support more model service providers. If you would like LobeHub to support your favorite service provider, feel free to join our [💬 community discussion](https://github.com/lobehub/lobe-chat/discussions/1284).
At the same time, we are also planning to support more model service providers. If you would like LobeHub to support your favorite service provider, feel free to join our [💬 community discussion](https://github.com/lobehub/lobehub/discussions/1284).
<div align="right">
@@ -390,7 +390,7 @@ This enables a more private and immersive creative process, allowing for the sea
The plugin ecosystem of LobeHub is an important extension of its core functionality, greatly enhancing the practicality and flexibility of the LobeHub assistant.
By utilizing plugins, LobeHub assistants can obtain and process real-time information, such as searching for web information and providing users with instant and relevant news.
@@ -618,7 +618,7 @@ We provide a Docker image for deploying the LobeHub service on your own private
1. create a folder to for storage files
```fish
$ mkdir lobe-chat-db &&cd lobe-chat-db
$ mkdir lobehub-db &&cd lobehub-db
```
2. init the LobeHub infrastructure
@@ -687,9 +687,9 @@ Plugins provide a means to extend the [Function Calling][docs-function-call] cap
>
> The plugin system is currently undergoing major development. You can learn more in the following issues:
>
> - [x] [**Plugin Phase 1**](https://github.com/lobehub/lobe-chat/issues/73): Implement separation of the plugin from the main body, split the plugin into an independent repository for maintenance, and realize dynamic loading of the plugin.
> - [x] [**Plugin Phase 2**](https://github.com/lobehub/lobe-chat/issues/97): The security and stability of the plugin's use, more accurately presenting abnormal states, the maintainability of the plugin architecture, and developer-friendly.
> - [x] [**Plugin Phase 3**](https://github.com/lobehub/lobe-chat/issues/149): Higher-level and more comprehensive customization capabilities, support for plugin authentication, and examples.
> - [x] [**Plugin Phase 1**](https://github.com/lobehub/lobehub/issues/73): Implement separation of the plugin from the main body, split the plugin into an independent repository for maintenance, and realize dynamic loading of the plugin.
> - [x] [**Plugin Phase 2**](https://github.com/lobehub/lobehub/issues/97): The security and stability of the plugin's use, more accurately presenting abnormal states, the maintainability of the plugin architecture, and developer-friendly.
> - [x] [**Plugin Phase 3**](https://github.com/lobehub/lobehub/issues/149): Higher-level and more comprehensive customization capabilities, support for plugin authentication, and examples.
<div align="right">
@@ -706,8 +706,8 @@ You can use GitHub Codespaces for online development:
We only provide security fixes for the **latest 2.x release**. Older versions (including all 1.x releases) are end-of-life and will not receive patches.
| Version | Supported |
| ------------ | --------- |
| 2.x (latest) | ✅ |
| 1.x | ❌ |
| 0.x | ❌ |
If you are running a 1.x deployment, we strongly recommend upgrading to the latest 2.x release.
## Reporting a Vulnerability
Please report security vulnerabilities through the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/lobehub/lobehub/security/advisories/new) tab.
**Please do not report security vulnerabilities through public GitHub issues.**
### Response Timeline
- **Acknowledgement**: We aim to respond to all reports within **7 days**.
- **Fix**: Confirmed vulnerabilities will be addressed within **30 days**.
- **Urgent issues**: If you believe the vulnerability is critical and actively exploitable, you can reach out directly on Discord (`arvinxu`) for faster coordination.
### What to Include
A good vulnerability report should include:
- A clear description of the issue and its potential impact
- The affected version (must be the latest 2.x release)
- Step-by-step reproduction instructions or a working PoC
- Any relevant logs, screenshots, or code references
## Scope
### In Scope
- Security issues affecting the **latest 2.x release** of LobeHub
- Vulnerabilities in the **server-side deployment** (LobeHub Cloud or self-hosted server mode)
- Issues that can be exploited **without requiring admin/owner access** to the deployment
### Out of Scope (Not a Vulnerability)
The following are considered **by design** or **out of scope** and will not be accepted as vulnerability reports:
#### 1. End-of-Life Versions
Any issue that only affects 1.x or earlier versions. This includes but is not limited to the `X-lobe-chat-auth` header mechanism, `webapi` route authentication, and other 1.x-specific architectures that have been completely removed in 2.x.
#### 2. File Proxy Public Access (`/f/:id`)
The file proxy endpoint `/f/:id` uses randomly generated, non-enumerable IDs as [capability URLs](https://www.w3.org/TR/capability-urls/). This is a deliberate design choice, similar to how S3 presigned URLs or Google Docs sharing links work. Knowing the URL grants access — this is by design, not an authorization bypass.
#### 3. User Enumeration on Login Flows
Endpoints such as `check-user` that indicate whether an account exists are part of the standard login UX. This is a common and intentional pattern used by most modern authentication flows.
#### 4. Self-Hosted Client-Side API Key Storage
In self-hosted client-side mode, users configure their own API keys which are stored in the browser's local storage. This is the expected behavior for client-side deployments where the user is both the operator and the consumer.
#### 5. Issues Requiring Admin or Owner Privileges
Actions that require administrative access to the deployment (e.g., environment variable configuration, server-side settings) are not considered security vulnerabilities, as the admin is already a trusted party.
#### 6. Theoretical Attacks Without Practical Impact
Reports based on theoretical attack scenarios without a working proof of concept against a realistic deployment, or issues that require unlikely preconditions (e.g., physical access to the server, pre-existing compromise of the host system).
## Disclosure Policy
- We follow [coordinated vulnerability disclosure](https://en.wikipedia.org/wiki/Coordinated_vulnerability_disclosure).
- We will credit reporters in the security advisory unless they prefer to remain anonymous.
- Please allow us reasonable time to address the issue before any public disclosure.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.