Previously `agentId` was only used to boost relevance in SearchRepo,
so results from other agents still leaked into CMD+K when scoped to
an agent. Strictly filter topics/messages by `agentId` when provided,
and surface the active agent (avatar + title) as the scope chip so
users can see what the search is limited to.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(types): break circular dep between types and const packages
Types package should only carry types, not values. Moved hotkey type
definitions to be owned by @lobechat/types and removed the @lobechat/const
runtime dependency from @lobechat/types. @lobechat/const now imports its
hotkey types from @lobechat/types via import type and uses satisfies to
keep enum values aligned.
* ✨ feat(types): add desktop hotkey types and configuration
Introduced new types for desktop hotkeys, including `DesktopHotkeyId`, `DesktopHotkeyItem`, and `DesktopHotkeyConfig`. These types facilitate the management of hotkeys in the desktop application, ensuring better type safety and clarity in the codebase. Updated documentation to reflect the relationship with `@lobechat/const` entrypoints.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(onboarding): persist topic onboarding analytics snapshot
* fix(onboarding): allow null in syncTopicOnboardingSession metadata option
Resolves TS2322 where topic?.metadata (ChatTopicMetadata | null | undefined)
was not assignable to metadata?: ChatTopicMetadata (undefined only).
The function already safely handles null via the ?? fallback, so widening
the parameter type is the minimal correct fix.
* fix(test): add ShikiLobeTheme to @lobehub/ui mock in WorkflowCollapse test
Resolves vitest error where @lobehub/editor tries to load
ShikiLobeTheme from the mocked module.
💄 style(shared-tool-ui): wrap RunCommand inspector in a rounded chip
Put the terminal-prompt icon and the mono command text inside a single
pill-shaped chip (colorFillTertiary background) so the command reads as
one unit instead of two loose elements next to the "Bash:" label. Row
goes back to center-aligned since the chip has its own vertical padding.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(error): refine error page layout and stack panel
Replace Collapse with Accordion for a clickable full-row header, move
stack below action buttons as a secondary branch, and wrap in a Block
that softens to filled when collapsed and outlined when expanded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(cc): boost topic loading ring contrast in light mode
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(error): reload page on retry instead of no-op navigate
The retry button called navigate(resetPath) which often landed on the
same path and re-triggered the same error, feeling broken. Switch to
window.location.reload() so the error page actually recovers, and drop
the now-unused resetPath prop across route configs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(cc-agent): send prompt via stdin stream-json to avoid CLI arg parsing
Previously the Claude Code prompt was appended as a positional CLI arg,
so any prompt starting with `-` / `--` (dashes, 破折号) got
misinterpreted as a flag by the CC CLI's argparser.
Switch the claude-code preset to `--input-format stream-json` and write
the prompt as a newline-delimited JSON user message on stdin for all
messages (not just image-attached ones). Unifies the image and text
paths and paves the way for LOBE-7346 Phase 2 (persistent process +
native queue/interrupt).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(cc): extract per-tool inspectors into Inspector/ folder
Mirrors the Inspector/<Tool>/index.tsx convention used by builtin-tool-skills,
builtin-tool-skill-store, and builtin-tool-activator.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(cc): flatten Inspector/ to per-tool tsx files
Drop the per-tool subfolder wrapper (Inspector/Edit/index.tsx → Inspector/Edit.tsx)
since each tool is a single file — no co-located assets to justify the folder.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(topic): add filter with By project grouping and sort-by option
Split the legacy topicDisplayMode enum into independent topicGroupMode
(byTime / byProject / flat) and topicSortBy (createdAt / updatedAt), and
surface them from a new sidebar Filter dropdown. Adds groupTopicsByProject
so topics can be grouped by their workingDirectory, with favorites pinned
and the "no project" bucket placed last.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(cc): show Claude Code account and subscription on profile
Add a getClaudeAuthStatus IPC that shells out to claude auth status --json,
and render the returned email + subscription tag on the CC Status Card.
The auth fetch runs independently of tool detection so a failure can't
flip the CLI card to unavailable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(home): show running spinner badge on agent/inbox avatars
Replace NavItem's generic loading state with a bottom-right spinner badge
on the avatar, so a running agent stays clearly labelled without hiding
the avatar. Inbox entries switch to per-agent isAgentRunning so only the
actively running inbox shows the badge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(cc): default-expand Edit and Write tool renderers
Add ClaudeCodeApiName.Edit and Write to ClaudeCodeRenderDisplayControls
so their inspectors render expanded by default, matching TodoWrite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔧 chore(cc): drop default system prompt when creating Claude Code agent
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update avatar URL for Claude Code
* ✅ test(workflow-collapse): stub ShikiLobeTheme on @lobehub/ui mock
@lobehub/editor's init code reads ShikiLobeTheme from @lobehub/ui, which
some transitive import pulls in during the test. Add the stub to match
the pattern used in WorkingSidebar/index.test.tsx.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(cc): fall back to Desktop path instead of `/` when no cwd is set
- Selector prefers desktopPath over homePath before it resolves nothing,
so the renderer always forwards a sensible cwd.
- Main-process spawn mirrors the same fallback with app.getPath('desktop'),
covering cases where Electron is launched from Finder (parent cwd is `/`).
Fixes LOBE-7354
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(topic): use remote app origin for topic copy link
Desktop 下 window.location.origin 是 app://renderer,复制出来的链接无法分享。
改用 useAppOrigin(),与分享链接保持一致(web 用 window.location.origin,
desktop 用 electron store 的 remoteServerUrl)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(web-onboarding): rename doc tools and drive incremental persona writes
- Rename writeDocument (full rewrite) and updateDocument (SEARCH/REPLACE patch) so tool
names match model intuition; the old updateDocument (full) is now writeDocument and the
old patchDocument (patch) is now updateDocument.
- Rework systemRole, toolSystemRole, and OnboardingActionHintInjector to require per-turn
persistence: seed persona on user_identity, patch on every discovery turn where a new
fact is learned, and stop the one-shot full-write pattern.
- Add a Pre-Finish Checklist so agents verify soul/persona reflect the session before
calling finishOnboarding.
Eval (deepseek-chat, web-onboarding-v3):
- fe-intj-crud-v1: write=2, updateDocument=6/6 success
- extreme-minimal-response-v1: write=2, updateDocument=4/4 success
- Previously 0 patch usage; now patch dominates incremental edits.
* 🐛 fix(web-onboarding): decouple fullName persistence from role discovery
Persona seeding and saveUserQuestion(fullName) were gated on learning both
name AND role in the same turn, which regressed the prior behavior of saving
the name the moment it was provided. If the user shared only a name (or left
early before role was clarified), the agent could skip the save and end
onboarding with missing identity data.
Split the hint:
1. saveUserQuestion(fullName) fires as soon as the name is known, regardless
of role.
2. Persona seeding fires on ANY useful fact (name alone, role alone, or both).
Thanks to codex review for catching this.
* ✨ feat(cc-desktop): git-aware runtime config + topic rename modal + inspectors
Cluster of desktop UX improvements around the Claude Code integration:
- CC chat input runtime bar: branch switcher, git status, and a richer
working-directory bar powered by a new SystemCtr git API
(branch list / current status) and `useGitInfo` hook.
- Topic rename: switch to a dedicated RenameModal component; add an
auto-rename action in the conversation header menu.
- ToolSearch inspector for the CC tool client.
- Shared DotsLoading indicator.
- Operation slice tidy-ups for CC flows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(types): rename heterogeneous provider type `claudecode` → `claude-code`
Align the type literal with the npm/CLI naming convention used elsewhere
(@lobechat/builtin-tool-claude-code, claude-code provider id) so the union
matches the rest of the codebase.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(cc-desktop): polish TodoWrite labels, branch switcher refresh, and chat input affordances
- TodoWrite render + inspector: i18n the header label (Todos / Current step
/ All tasks completed), surface the active step inline as highlighted text,
and switch the in-progress accent from primary to info for better contrast.
- BranchSwitcher: move the refresh button into the dropdown's section header,
switch the search and create-branch inputs to the filled variant, and
reuse DropdownMenuItem for the create-branch entry instead of a custom
footer chip.
- GitStatus: drop the inline refresh affordance (now lives in the switcher),
collapse trigger styles, and split the PR badge with its own separator.
- WorkingDirectory / WorkingDirectoryBar: tighten paddings and gaps so the
runtime config row reads at a consistent height.
- InputEditor: skip inline placeholder completion when the cursor is not at
end of paragraph — inserting a placeholder mid-text triggered nested
editor updates that froze the input.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(cc-desktop): probe repoType for working dirs not cached in recents
GitStatus was gated on the `repoType` stored in `recentDirs`, but legacy
string entries and agent-config-driven paths that never went through the
folder picker have no cached `repoType`. As a result, branch / PR status
silently disappeared for valid git repos until users re-selected the
folder.
Promote `detectRepoType` to a public IPC method and add a `useRepoType`
hook that uses the cached value as a fast path, otherwise probes the
filesystem via SWR and backfills the recents entry so subsequent reads
hit cache. Both runtime config bars (CC mode + heterogeneous chat input)
now resolve `repoType` through the hook.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(shared-tool-ui): rework Bash/Grep/Glob inspector rows
- RunCommand: terminal-prompt icon + mono command text instead of underline highlight
- Grep: split pattern by `|` into mono tag chips
- Glob: single mono tag chip matching Grep
- Switch rows to baseline alignment so the smaller mono text lines up with the label
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(DotsLoading): allow optional color in styles params
The Required<StyleArgs> generic forced color to string, but it's only
defaulted at the CSS level via fallback to token.colorTextSecondary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(cc-agent-profile): swap model/skills pickers for CC CLI status in CC mode
When an agent runs under the Claude Code heterogeneous runtime, its model and tools are
owned by the external CLI, so the profile page's model selector and integration-skills
block are misleading. Replace them with a card that re-detects `claude --version` on
mount and shows the resolved binary path — useful when CLAUDE_CODE_BIN or similar
points at a non-default CLI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(cc-agent-profile): hide cron for CC agent and polish render previews
- Hide cron sidebar entry when current agent is heterogeneous (CC)
- Allow model avatar in agent header emoji picker
- Add padding to Glob/Grep/Read/Write preview boxes for consistent spacing
- Simplify NavPanelDraggable by removing slide animation layer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor(shared-tool-ui): extract ToolResultCard for Read/Write/Glob/Grep renders
Hoist the shared card shell (icon + header + preview box) into
@lobechat/shared-tool-ui/components so the four Claude Code Render
files no longer duplicate container/header/previewBox styles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(agent-header): restyle title and expand actions menu
Bold the topic title, render the working directory as plain text (no chip/icon), move the "..." menu to the left, and expand it with pin/rename/copy working directory/copy session ID/delete. Fall back to "New Topic" when no topic is active.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(topic-list): replace spinning loader with ring-and-arc loading icon
Adds a reusable RingLoadingIcon (static track + rotating arc, mirroring the send-button style) and swaps the topic-item loader over to it so the loading state reads as a polished ring rather than a thin spinning dash.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(topic-list): switch unread indicator to a radar ping effect
Replaces the glowing neon-dot pulse with a smaller 6px core dot plus a CSS-keyframe ripple ring that scales out and fades, giving the unread marker a subtler, more refined cadence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 💄 style(cc-chat-input): drop file upload in CC mode, surface typo toggle
Claude Code brings its own file handling and knowledge context, so the
paperclip dropdown only showed "Upload Image" + a useless "View More"
link — confusing and not clean. Replace fileUpload with typo in the
heterogeneous chat input, and fold ServerMode back into a single
Upload/index.tsx now that the ClientMode/ServerMode split is gone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(cc-resume): guard resume against cwd mismatch (LOBE-7336)
Claude Code CLI stores sessions per-cwd under `~/.claude/projects/<encoded-cwd>/`,
so resuming a session from a different working directory fails with
"No conversation found with session ID". Persist the cwd alongside the session
id on each turn and skip `--resume` when the current cwd can't be verified
against the stored one, falling back to a fresh session plus a toast explaining
the reset.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(cc-desktop): Claude Code desktop polish + completion notifications
Bundles the follow-on UX improvements for Claude Code on desktop:
- Completion notifications: CC / Codex / ACP runs now fire a desktop
notification (when the window is hidden) plus dock badge when the turn
finishes, matching the Gateway client-mode behavior.
- Inspector + renders: add Skill and TodoWrite inspectors, wire them
through Render/index + renders registry, expose shared displayControls.
- Adapter: extend claude-code adapter with additional event coverage and
regression tests.
- Sidebar / home menu: clean up Topic list item and dropdown menu, rename
"Claude Code Agent" entry point to "Add Claude Code" across EN/ZH.
- Assorted: NotificationCtr, Browser, WorkflowCollapse, ServerMode upload,
agent/tool selectors — small follow-ups surfaced while building the
above.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✅ test(browser): mock electron.app for badge-clear on focus
Browser.focus handler now calls app.setBadgeCount / app.dock.setBadge to
clear the completion badge when the user returns. Tests imported the
Browser module without exposing app on the electron mock, causing a
module-load failure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(cc-topic): folder chip + unify cwd into workingDirectory (#13949)
✨ feat(cc-topic): show bound folder chip and unify cwd into workingDirectory
Replace the separate `ccSessionCwd` metadata field with the existing
`workingDirectory` so a CC topic's bound cwd has one source of truth:
persisted on first CC execution, read back by resume validation, and
surfaced in a clickable folder chip next to the topic title on desktop.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Let users finish agent onboarding explicitly once they've engaged
enough, instead of waiting for the agent to trigger finishOnboarding.
- New WrapUpHint component above ChatInput; shows in summary phase or
discovery phase after ≥3 user messages
- Confirm modal before finish; reuses existing finishOnboarding service
- Tightened Phase 2 (user_identity) system prompt: MUST save fullName
before leaving phase, handle ambiguous name responses explicitly
* Keep heterogeneous-agent attachment cache writes inside the cache root
The desktop heterogeneous-agent controller used raw image ids as path
segments for cache payload and metadata files. Path-like ids could
escape the intended cache directory, and pre-seeded traversal targets
could be treated as cache hits. Hashing the cache key removes any path
semantics from user-controlled ids while preserving stable cache reuse.
A regression test covers both out-of-root write prevention and ignoring
pre-seeded traversal cache files.
Constraint: The fix must preserve deterministic cache hits without trusting user-controlled path segments
Rejected: path.basename(image.id) | collapses distinct ids onto the same filename and leaves edge-case normalization concerns
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Any future cache layout change must keep user-controlled identifiers out of direct filesystem path composition
Tested: Custom local reproduction against current controller source; custom local validation against patched source; regression test added for desktop controller path handling
Not-tested: Upstream vitest/CI run in this workspace (desktop dependencies unavailable locally)
* Keep heterogeneous-agent cache regression aligned with runtime MIME behavior
The traversal regression test uses a data:text/plain URL under the desktop
node test environment, so the controller returns text/plain from the fetch
response headers. The expectation now matches the actual runtime behavior
instead of assuming the image/png fallback path.
Constraint: The regression should validate cache isolation rather than rely on an incorrect MIME fallback assumption
Rejected: Mock fetch in the regression test | adds extra indirection without improving the path traversal coverage
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep this test focused on path safety and cache-hit behavior; avoid coupling it to unrelated transport mocks unless the controller logic changes
Tested: Local patched-controller validation harness; static review against desktop vitest node environment behavior
Not-tested: Upstream vitest/CI run in this workspace (desktop dependencies unavailable locally)
* Keep heterogeneous-agent cache regression isolated to the temp test namespace
The first regression test used a fixed traversal target name under the shared
system temp directory. Switching that escape target to a unique name derived
from the test's temporary appStoragePath preserves the same out-of-root check
while avoiding accidental interaction with unrelated files under /tmp.
Constraint: The regression must still verify escape prevention beyond appStoragePath without touching shared fixed temp paths
Rejected: Remove the out-of-root assertion entirely | weakens coverage for the exact traversal behavior this PR is meant to guard
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep filesystem regressions hermetic; if a test needs to reason about escaped paths, derive them from per-test temp namespaces whenever possible
Tested: Static review of resolved path behavior before/after the change
Not-tested: Upstream vitest/CI run in this workspace (desktop dependencies unavailable locally)
---------
Co-authored-by: OpenAI Codex <codex@example.com>
✨ feat(cc-partial-messages): stream token-level deltas via --include-partial-messages
Enables Claude Code's --include-partial-messages flag so the CLI emits
token-level deltas wrapped in stream_event events. The adapter surfaces
these deltas as incremental stream_chunk events and suppresses the
trailing full-block emission from handleAssistant for any message.id
whose text/thinking has already been streamed.
Message-boundary handling is refactored into an idempotent
openMainMessage() helper so stepIndex advances on the first signal of a
new turn (delta or assistant), keeping deltas attached to the correct
step.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ♻️ refactor: adopt Notebook list + EditorCanvas for agent documents
The agent working sidebar previously used a FileTree directory view and
a hand-rolled Markdown+TextArea editor with manual save. Agent documents
already back onto the canonical `documents` table via an FK, so they can
reuse the exact same rendering surface as Notebook.
- AgentDocumentsGroup: replace FileTree with a flat card list styled
after Portal/Notebook/DocumentItem (icon + title + description + delete).
- AgentDocumentEditorPanel: drop the bespoke draft/save/segmented view
logic; mount the shared <EditorCanvas documentId={doc.documentId}
sourceType="notebook" /> inside an EditorProvider so auto-save and
rich editing are handled by useDocumentStore.
* ✨ feat: promote agent documents as the primary workspace panel
- Replace the agent-document sidebar with a Notebook-style list: pill
filter (All/Docs/Web), per-item createdAt, globe icon for sourceType=web.
- Add a stable panel header "Resources" with a close button (small size,
consistent with other chat header actions); no border divider.
- Wire clicks to the shared Portal Document view via openDocument(),
retiring the inline AgentDocumentEditorPanel.
- Portal/Document/Header now resolves title directly from documentId
via documentService.getDocumentById + a skeleton loading state.
- Portal top-right close icon switched to `X`.
- Layout: move AgentWorkingSidebar to the rightmost position; auto-collapse
the left navigation sidebar while Portal is open (PortalAutoCollapse).
- Header: remove dead NotebookButton, drop the Notebook menu item; add a
WorkingPanelToggle visible only when the working panel is collapsed.
- ProgressSection hides itself when the topic has no GTD todos.
- Builtin tool list removes Notebook; migrate CreateDocument Render and
Streaming renderers to builtin-tool-agent-documents (notebook package
kept for legacy rendering of historical tool calls).
- agent_documents list UI now reads from a separate SWR key
(documentsList) so the agent-store context mapping doesn't strip
documentId/sourceType/createdAt from the UI payload.
- i18n: add workingPanel.resources.filter.{all,documents,web},
viewMode.{list,tree}, and the expanded empty-state copy; zh-CN
translations seeded for preview.
- New local-testing reference: agent-browser-login (inject better-auth
cookie for authenticated agent-browser sessions).
* update
* 🐛 fix: satisfy tsc strict i18next keys, remove duplicate getDocumentById, coerce showLeftPanel
* ♻️ refactor: graduate agent working panel out of labs
🐛 fix(auth): clear current-browser OIDC session on sign-out
When a user signs out and signs back in as a different account,
the oidc-provider session cookie (_session) still references the
old accountId. The next /authorize silently reuses it, issuing
tokens for the wrong user.
Fix: add a POST /oidc/clear-session endpoint that:
1. Reads the _session cookie from the current request
2. Deletes the matching row in oidc_sessions (by primary key)
3. Expires the _session cookies in the response
The frontend logout action calls this endpoint *before* signOut()
while the better-auth session is still valid.
Only the current browser's OIDC session is affected — other
devices (desktop, CLI, mobile) keep their sessions intact.
* ✨ feat(onboarding): enhance agent onboarding experience and add feature flags
- Added new promotional messages for agent onboarding in both Chinese and default locales.
- Updated HighlightNotification component to support action handling and target attributes.
- Introduced feature flags for agent onboarding in the configuration schema and tests.
- Implemented logic to conditionally display onboarding options based on feature flags and user state.
- Added tests for the onboarding flow and promotional notifications in the footer.
This update aims to improve the user experience during the onboarding process and ensure proper feature management through flags.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(home): add footer promotion pipeline with feature-flag gating
Extract resolveFooterPromotionState for agent onboarding vs Product Hunt promos.
Normalize isMobile boolean, refine HighlightNotification CTA layout, extend tests.
Made-with: Cursor
* ✨ feat(locales): add agent onboarding promotional messages in multiple languages
Added new promotional messages for agent onboarding across various locales, enhancing the user experience with localized action labels, descriptions, and titles. This update supports a more engaging onboarding process for users globally.
Signed-off-by: Innei <tukon479@gmail.com>
* 💄 chore: refresh quick wizard onboarding promo
* 🐛 fix(chat): keep long mixed assistant content outside workflow fold
* ✨ feat(onboarding): add agent onboarding feedback panel and service
LOBE-7210
Made-with: Cursor
* ✨ feat(markdown-patch): add shared markdown patch tool with SEARCH/REPLACE hunks
Introduce @lobechat/markdown-patch util and expose patchDocument API on the
web-onboarding and agent-documents builtin tools so agents can apply
byte-exact SEARCH/REPLACE hunks instead of resending full document content.
* ✨ feat(onboarding): prefer patchDocument for non-empty documents
Teach the onboarding agent (systemRole) and context engine
(OnboardingActionHintInjector) to prefer patchDocument over updateDocument
when SOUL.md or User Persona already has content, keeping updateDocument
reserved for the initial seed write or full rewrites.
* 🐛 fix(conversation): add rightActions to ChatInput component
Updated the AgentOnboardingConversation component to include rightActions in the ChatInput, enhancing the functionality of the onboarding conversation interface.
Signed-off-by: Innei <tukon479@gmail.com>
* Add specialized onboarding approval UI
* 🐛 fix(serverConfig): handle fetch errors in server config actions
Updated the server configuration action to include error handling for fetch failures, ensuring that the server config is marked as initialized when an error occurs. Additionally, modified the SWR mock to simulate error scenarios in tests.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(tests): update Group component tests with new data-testid attributes
Added data-testid attributes for workflow and answer segments in the Group component tests to improve test targeting. Adjusted the isFirstBlock property for consistency and ensured the component renders correctly with the provided props.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor(acp): move agent provider to agencyConfig + restore creation entry
- Move AgentProviderConfig from chatConfig to agencyConfig.heterogeneousProvider
- Rename type from 'acp' to 'claudecode' for clarity
- Restore Claude Code agent creation entry in sidebar + menu
- Prioritize heterogeneousProvider check over gateway mode in execution flow
- Remove ACP settings from AgentChat form (provider is set at creation time)
- Add getAgencyConfigById selector for cleaner access
- Use existing agent workingDirectory instead of duplicating in provider config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✨ feat(acp): defer terminal events + extract model/usage per turn
Three improvements to ACP stream handling:
1. Defer agent_runtime_end/error: Previously the adapter emitted terminal
events from result.type directly into the Gateway handler. The handler
immediately fires fetchAndReplaceMessages which reads stale DB state
(before we persist final content/tools). Fix: intercept terminal events
in the executor's event loop and forward them only AFTER content +
metadata has been written to DB.
2. Extract model/usage per assistant event: Claude Code sets model name
and token usage on every assistant event. Adapter now emits a
'step_complete' event with phase='turn_metadata' carrying these.
Executor accumulates input/output/cache tokens across turns and
persists them onto the assistant message (model + metadata.totalTokens).
3. Missing final text fix: The accumulated assistant text was being
written AFTER agent_runtime_end triggered fetchAndReplaceMessages,
so the UI rendered stale (empty) content. Deferred terminals solve this.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix(acp): eliminate orphan-tool warning flicker during streaming
Root cause:
LobeHub's conversation-flow parser (collectToolMessages) filters tool
messages by matching `tool_call_id` against `assistant.tools[].id`. The
previous flow created tool messages FIRST, then updated assistant.tools[],
which opened a brief window where the UI saw tool messages that had no
matching entry in the parent's tools array — rendering them as "orphan"
with a scary "请删除" warning to the user.
Fix:
Reorder persistNewToolCalls into three phases:
1. Pre-register tool entries in assistant.tools[] (id only, no result_msg_id)
2. Create the tool messages in DB (tool_call_id matches pre-registered ids)
3. Back-fill result_msg_id and re-write assistant.tools[]
Between phase 1 and phase 3 the UI always sees consistent state: every
tool message in DB has a matching entry in the parent's tools array.
Verified: orphan count stays at 0 across all sampled timepoints during
streaming (vs 1+ before fix).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🐛 fix(acp): dedupe tool_use + capture tool_result + persist result_msg_id
Three critical fixes to ACP tool-call handling, discovered via live testing:
1. **tool_use dedupe** — Claude Code stream-json previously produced 15+
duplicate tool messages per tool_call_id. The adapter now tracks emitted
ids so each tool_use → exactly one tool message.
2. **tool_result content capture** — tool_result blocks live in
`type: 'user'` events in Claude Code's stream-json, not in assistant
events. The adapter now handles the 'user' event type and emits a new
`tool_result` HeterogeneousAgentEvent which the executor consumes to
call messageService.updateToolMessage() with the actual result content.
Previously all tool messages had empty content.
3. **result_msg_id on assistant.tools[]** — LobeHub's parse() step links
tool messages to their parent assistant turn via tools[].result_msg_id.
Without it, the UI renders orphan-message warnings. The executor now
captures the tool message id returned by messageService.createMessage
and writes it back into the assistant.tools[] JSONB.
Also adds vitest config + 9 unit tests for the adapter covering lifecycle,
content mapping, and tool_result handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✨ feat(acp): integrate external AI agents via ACP protocol
Adds support for connecting external AI agents (Claude Code and future
agents like Codex, Kimi CLI) into LobeHub Desktop via a new heterogeneous
agent layer that adapts agent-specific protocols to the unified Gateway
event stream.
Architecture:
- New @lobechat/heterogeneous-agents package: pluggable adapters that
convert agent-specific outputs to AgentStreamEvent
- AcpCtr (Electron main): agent-agnostic process manager with CLI
presets registry, broadcasts raw stdout lines to renderer
- acpExecutor (renderer): subscribes to broadcasts, runs events through
adapter, feeds into existing createGatewayEventHandler
- Tool call persistence: creates role='tool' messages via messageService
before emitting tool_start/tool_end to the handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: rename acpExecutor to heterogeneousAgentExecutor
- Rename file acpExecutor.ts → heterogeneousAgentExecutor.ts
- Rename ACPExecutorParams → HeterogeneousAgentExecutorParams
- Rename executeACPAgent → executeHeterogeneousAgent
- Change operation type from execAgentRuntime to execHeterogeneousAgent
- Change operation label to "Heterogeneous Agent Execution"
- Change error type from ACPError to HeterogeneousAgentError
- Rename acpData/acpContext variables to heteroData/heteroContext
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: rename AcpCtr and acp service to heterogeneousAgent
Desktop side:
- AcpCtr.ts → HeterogeneousAgentCtr.ts
- groupName 'acp' → 'heterogeneousAgent'
- IPC channels: acpRawLine → heteroAgentRawLine, etc.
Renderer side:
- services/electron/acp.ts → heterogeneousAgent.ts
- ACPService → HeterogeneousAgentService
- acpService → heterogeneousAgentService
- Update all IPC channel references in executor
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: switch CC permission mode to bypassPermissions
Use bypassPermissions to allow Bash and other tool execution.
Previously acceptEdits only allowed file edits, causing Bash tool
calls to fail during CC execution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: don't fallback activeAgentId to empty string in AgentIdSync
Empty string '' causes chat store to have a truthy but invalid
activeAgentId, breaking message routing. Pass undefined instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: use AI_RUNTIME_OPERATION_TYPES for loading and cancel states
stopGenerateMessage and cancelOperation were hardcoding
['execAgentRuntime', 'execServerAgentRuntime'], missing
execHeterogeneousAgent. This caused:
- CC execution couldn't be cancelled via stop button
- isAborting flag wasn't set for heterogeneous agent operations
Now uses AI_RUNTIME_OPERATION_TYPES constant everywhere to ensure
all AI runtime operation types are handled consistently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: split multi-step CC execution into separate assistant messages
Claude Code's multi-turn execution (thinking → tool → final text) was
accumulating everything onto a single assistant message, causing the
final text response to appear inside the tool call message.
Changes:
- ClaudeCodeAdapter: detect message.id changes and emit stream_end +
stream_start with newStep flag at step boundaries
- heterogeneousAgentExecutor: on newStep stream_start, persist previous
step's content, create a new assistant message, reset accumulators,
and forward the new message ID to the gateway handler
This ensures each LLM turn gets its own assistant message, matching
how Gateway mode handles multi-step agent execution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: fix multi-step CC execution and add DB persistence tests
Adapter fixes:
- Fix false step boundary on first assistant after init (ghost empty message)
Executor fixes:
- Fix parentId chain: new-step assistant points to last tool message
- Fix content contamination: sync snapshot of content accumulators on step boundary
- Fix type errors (import path, ChatToolPayload casts, sessionId guard)
Tests:
- Add ClaudeCodeAdapter unit tests (multi-step, usage, flush, edge cases)
- Add ClaudeCodeAdapter E2E test (full multi-step session simulation)
- Add registry tests
- Add executor DB persistence tests covering:
- Tool 3-phase write (pre-register → create → backfill)
- Tool result content + error persistence
- Multi-step parentId chain (assistant → tool → assistant)
- Final content/reasoning/model/usage writes
- Sync snapshot preventing cross-step contamination
- Error handling with partial content persistence
- Full multi-step E2E (Read → Write → text)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: add orphan tool regression tests and debug trace
- Add orphan tool regression tests for multi-turn tool execution
- Add __HETERO_AGENT_TRACE debug instrumentation for event flow capture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: support image attachments in CC via stream-json stdin
- Main process downloads files by ID from cloud (GET {domain}/f/{fileId})
- Local disk cache at lobehub-storage/heteroAgent/files/ (by fileId)
- When fileIds present, switches to --input-format stream-json + stdin pipe
- Constructs user message with text + image content blocks (base64)
- Pass fileIds through executor → service → IPC → controller
Closes LOBE-7254
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: pass imageList instead of fileIds for CC vision support
- Use imageList (with url) instead of fileIds — Main downloads from URL directly
- Cache by image id at lobehub-storage/heteroAgent/files/
- Only images (not arbitrary files) are sent to CC via stream-json stdin
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: read imageList from persisted DB message instead of chatUploadFileList
chatUploadFileList is cleared after sendMessageInServer, so tempImages
was empty by the time the executor ran. Now reads imageList from the
persisted user message in heteroData.messages instead.
Also removes debug console.log/console.error statements.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update i18n
* 🐛 fix: prevent orphan tool UI by deferring handler events during step transition
Root cause: when a CC step boundary occurs, the adapter produces
[stream_end, stream_start(newStep), stream_chunk(tools_calling)] in one batch.
The executor deferred stream_start via persistQueue but forwarded stream_chunk
synchronously — handler received tools_calling BEFORE stream_start, dispatching
tools to the OLD assistant message → UI showed orphan tool warning.
Fix: add pendingStepTransition flag that defers ALL handler-bound events through
persistQueue until stream_start is forwarded, guaranteeing correct event ordering.
Also adds:
- Minimal regression test in gatewayEventHandler confirming correct ordering
- Multi-tool per turn regression test from real LOBE-7240 trace
- Data-driven regression replaying 133 real CC events from regression.json
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add lab toggle for heterogeneous agent (Claude Code)
- Add enableHeterogeneousAgent to UserLabSchema + defaults (off by default)
- Add selector + settings UI toggle (desktop only)
- Gate "Claude Code Agent" sidebar menu item behind the lab setting
- Remove regression.json (no longer needed)
- Add i18n keys for the lab feature
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: gate heterogeneous agent execution behind isDesktop check
Without this, web users with an agent that has heterogeneousProvider
config would hit the CC execution path and fail (no Electron IPC).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: rename tool identifier from acp-agent to claude-code
Also update operation label to "External agent running".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: add CLI agent detectors for system tools settings
Detect agentic coding CLIs installed on the system:
- Claude Code, Codex, Gemini CLI, Qwen Code, Kimi CLI, Aider
- Uses validated detection (which + --version keyword matching)
- New "CLI Agents" category in System Tools settings
- i18n for en-US and zh-CN
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: fix token usage over-counting in CC execution
Two bugs fixed:
1. Adapter: same message.id emitted duplicate step_complete(turn_metadata)
for each content block (thinking/text/tool_use) — all carry identical
usage. Now deduped by message.id, only emits once per turn.
2. Executor: CC result event contains authoritative session-wide usage
totals but was ignored. Now adapter emits step_complete(result_usage)
from the result event, executor uses it to override accumulated values.
Fixes LOBE-7261
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: gitignore cc-stream.json and .heterogeneous-tracing/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🔧 chore: untrack .heerogeneous-tracing/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: wire CC session resume for multi-turn conversations
Reads `ccSessionId` from topic metadata and passes it as `resumeSessionId`
into the heterogeneous-agent executor, which forwards it into the Electron
main-process controller. `sendPrompt` then appends `--resume <id>` so the
next turn continues the same Claude Code session instead of starting fresh.
After each run, the CC init-event session_id (captured by the adapter) is
persisted back onto the topic so the chain survives page reloads.
Also stops killing the session in `finally` — it needs to stay alive for
subsequent turns; cleanup happens on topic deletion or app quit.
* 🐛 fix: record cache token breakdown in CC execution metadata
The prior token-usage fix only wrote totals — `inputCachedTokens`,
`inputWriteCacheTokens` and `inputCacheMissTokens` were dropped, so the
pricing card rendered zero cached/write-cache tokens even though CC had
reported them. Map the accumulated Anthropic-shape usage to the same
breakdown the anthropic usage converter emits, so CC turns display
consistently with Gateway turns.
Refs LOBE-7261
* ♻️ refactor: write CC usage under metadata.usage instead of flat fields
Flat `inputCachedTokens / totalInputTokens / ...` on `MessageMetadata` are
the legacy shape; new code should put usage under `metadata.usage`. Move
the CC executor to the nested shape so it matches the convention the rest
of the runtime is migrating to.
Refs LOBE-7261
* ♻️ refactor(types): mark flat usage fields on MessageMetadata as deprecated
Stop extending `ModelUsage` and redeclare each token field inline with a
`@deprecated` JSDoc pointing to `metadata.usage` (nested). Existing readers
still type-check, but IDEs now surface the deprecation so writers migrate
to the nested shape.
* ♻️ refactor(types): mark flat performance fields on MessageMetadata as deprecated
Stop extending `ModelPerformance` and redeclare `duration` / `latency` /
`tps` / `ttft` inline with `@deprecated`, pointing at `metadata.performance`.
Mirrors the same treatment just done for the token usage fields.
* ✨ feat: CC agent gets claude avatar + lands on chat page directly
Skip the shared createAgent hook's /profile redirect for the Claude Code
variant — its config is fixed so the profile editor would be noise — and
preseed the Claude avatar from @lobehub/icons-static-avatar so new CC
agents aren't blank.
* 🐛 fix(conversation-flow): read usage/performance from nested metadata
`splitMetadata` only scraped the legacy flat token/perf fields, so messages
written under the new canonical shape (`metadata.usage`, `metadata.performance`)
never populated `UIChatMessage.usage` and the Extras panel rendered blank.
- Prefer nested `metadata.usage` / `metadata.performance` when present; keep
flat scraping as fallback for pre-migration rows.
- Add `usage` / `performance` to FlatListBuilder's filter sets so the nested
blobs don't leak into `otherMetadata`.
- Drop the stale `usage! || metadata` fallback in the Assistant / CouncilMember
Extra renders — with splitMetadata fixed, `item.usage` is always populated
when usage data exists, and passing raw metadata as ModelUsage is wrong now
that the flat fields are gone.
* 🐛 fix: skip stores.reset on initial dataSyncConfig hydration
`useDataSyncConfig`'s SWR onSuccess called `refreshUserData` (which runs
`stores.reset()`) whenever the freshly-fetched config didn't deep-equal the
hard-coded initial `{ storageMode: 'cloud' }` — which happens on every
first load. The reset would wipe `chat.activeAgentId` just after
`AgentIdSync` set it from the URL, and because `AgentIdSync`'s sync
effects are keyed on `params.aid` (which hasn't changed), they never re-fire
to restore it. Result: topic SWR saw `activeAgentId === ''`, treated the
container as invalid, and left the sidebar stuck on the loading skeleton.
Gate the reset on `isInitRemoteServerConfig` so it only runs when the user
actually switches sync modes, not on the first hydration.
* ✨ feat(claude-code): wire Inspector layer for CC tool calls
Mirrors local-system: each CC tool now has an inspector rendered above the
tool-call output instead of an opaque default row.
- `Inspector.tsx` — registry that passes the CC tool name itself as the
shared factories' `translationKey`. react-i18next's missing-key fallback
surfaces the literal name (Bash / Edit / Glob / Grep / Read / Write), so
we don't add CC-specific entries to the plugin locale.
- `ReadInspector.tsx` / `WriteInspector.tsx` — thin adapters that map
Anthropic-native args (`file_path` / `offset` / `limit`) onto the shared
inspectors' shape (`path` / `startLine` / `endLine`), so shared stays
pure. Bash / Edit / Glob / Grep reuse shared factories directly.
- Register `ClaudeCodeInspectors` under `claude-code` in the builtin-tools
inspector dispatch.
Also drops the redundant `Render/Bash/index.tsx` wrapper and pipes the
shared `RunCommandRender` straight into the registry.
* ♻️ refactor: use agentSelectors.isCurrentAgentHeterogeneous
Two callsites (ConversationArea / useActionsBarConfig) were reaching into
`currentAgentConfig(...)?.agencyConfig?.heterogeneousProvider` inline.
Switch them to the existing `isCurrentAgentHeterogeneous` selector so the
predicate lives in one place.
* update
* ♻️ refactor: drop no-op useCallback wrapper in AgentChat form
`handleFinish` just called `updateConfig(values)` with no extra logic; the
zustand action is already a stable reference so the wrapper added no
memoization value. Leftover from the ACP refactor (930ba41fe3) where the
handler once did more work — hand the action straight to `onFinish`.
* update
* ⏪ revert: roll back conversation-flow nested-shape reads
Unwind the `splitMetadata` nested-preference + `FlatListBuilder` filter
additions from 306fd6561f. The nested `metadata.usage` / `metadata.performance`
promotion now happens in `parse.ts` (and a `?? metadata?.usage` fallback at
the UI callsites), so conversation-flow's transformer layer goes back to
its original flat-field-only behavior.
* update
* 🐛 fix(cc): wire Stop to cancel the external Claude Code process
Previously hitting Stop only flipped the `execHeterogeneousAgent` operation
to `cancelled` in the store — the spawned `claude -p` process kept
running and kept streaming/persisting output for the user. The op's abort
signal had no listeners and no `onCancelHandler` was registered.
- On session start, register an `onCancelHandler` that calls
`heterogeneousAgentService.cancelSession(sessionId)` (SIGINT to the CLI).
- Read the op's `abortController.signal` and short-circuit `onRawLine` so
late events the CLI emits between SIGINT and exit don't leak into DB
writes.
- Skip the error-event forward in `onError` / the outer catch when the
abort came from the user, so the UI doesn't surface a misleading error
toast on top of the already-cancelled operation.
Verified end-to-end: prompt that runs a long sequence of Reads → click
Stop → `claude -p` process is gone within 2s, op status = cancelled, no
error message written to the conversation.
* ✨ feat(sidebar): mark heterogeneous agents with an "External" tag
Pipes the agent's `agencyConfig.heterogeneousProvider.type` through the
sidebar data flow and renders a `<Tag>` next to the title for any agent
driven by an external CLI runtime (Claude Code today, more later). Mirrors
the group-member External pattern so future provider types just need a
label swap — the field is a string, not a boolean.
- `SidebarAgentItem.heterogeneousType?: string | null` on the shared type
- `HomeRepository.getSidebarAgentList` selects `agents.agencyConfig` and
derives the field via `cleanObject`
- `AgentItem` shows `<Tag>{t('group.profile.external')}</Tag>` when the
field is present
Verified client-side by injecting `heterogeneousType: 'claudecode'` into
a sidebar item at runtime — the "外部" tag renders next to the title in
the zh-CN locale.
* ♻️ refactor(i18n): dedicated key for the sidebar external-agent tag
Instead of reusing `group.profile.external` (which is about group members
that are user-linked rather than virtual), add `agentSidebar.externalTag`
specifically for the heterogeneous-runtime tag. Keeps the two concepts
separate so we can swap this one to "Claude Code" / provider-specific
labels later without touching the group UI copy.
Remember to run `pnpm i18n` before the PR so the remaining locales pick
up the new key.
* 🐛 fix: clear remaining CI type errors
Three small fixes so `tsgo --noEmit` exits clean:
- `AgentIdSync`: `useChatStoreUpdater` is typed off the chat-store key, whose
`activeAgentId` is `string` (initial ''). Coerce the optional URL param to
`''` so the store key type matches; `createStoreUpdater` still skips the
setState when the value is undefined-ish.
- `heterogeneousAgentExecutor.test.ts`: `scope: 'session'` isn't a valid
`MessageMapScope` (the union dropped that variant); switch the fixture to
`'main'`, which is the correct scope for agent main conversations.
- Same test file: `Array.at(-1)` is `T | undefined`; non-null assert since
the preceding calls guarantee the slot is populated.
* 🐛 fix: loosen createStoreUpdater signature to accept nullable values
Upstream `createStoreUpdater` types `value` as exactly `T[Key]`, so any
call site feeding an optional source (URL param, selector that may return
undefined) fails type-check — even though the runtime already guards
`typeof value !== 'undefined'` and no-ops in that case.
Wrap it once in `store/utils/createStoreUpdater.ts` with a `T[Key] | null
| undefined` value type so callers can pass `params.aid` directly, instead
of the lossy `?? ''` fallback the previous commit used (which would have
written an empty-string sentinel into the chat store).
Swap the import in `AgentIdSync.tsx`.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: return full brief data in task activities (LOBE-7266)
The activity feed for tasks previously emitted a stripped `brief` row that
concatenated `resolvedAction` and `resolvedComment` and omitted everything
BriefCard needs (taskId, topicId, agentId, cronJobId, agents, actions,
artifacts, readAt, resolvedAt, etc.). Map the full `BriefItem` into each
activity row and reuse `BriefService.enrichBriefsWithAgents` to populate
the participant avatars. The CLI and prompt formatter now compose the
action + comment display string themselves.
* 🐛 fix: degrade gracefully when brief agent enrichment fails
getTaskDetail was calling BriefService.enrichBriefsWithAgents inside
Promise.all without a fallback, so a failure in the agent-tree lookup
would reject the whole request — a regression vs. the existing
.catch(() => []) pattern used by other activity reads in this method.
Fall back to agentless briefs on error so the task detail keeps
rendering.
* fix: slove the manual mode cant use some builtin tools
* refactor: change the active skill tools from lobe-activtor to lobe-skill tools
* fix: only inject the avaiable skill when use the auto mode
* fix: update the desktop tools skill
* fix: add the some test to ensure the builin tools will use in manual mode
* 🐛 fix: show success status for tool calls with no return value
When a tool call completes without returning content, the status indicator
was incorrectly showing a loading spinner instead of a success checkmark.
This fix passes the isToolCalling operation state to StatusIndicator to
correctly determine when a tool has finished executing.
https://claude.ai/code/session_01EBaKqzVTeEmrUXgFdNk7WH
* 🐛 fix(conversation): improve tool execution status handling
Updated the logic for determining tool execution states in both the Tool and Inspector components. The changes ensure that the status indicator accurately reflects when a tool is actively processing, even if no result is returned. This prevents misleading loading indicators and enhances user experience during tool interactions.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(DocumentHistoryDiff): correct JSX syntax for CircleLoading component
Removed unnecessary semicolon from CircleLoading component in DocumentHistoryDiff to ensure proper rendering. This minor fix enhances code clarity and maintains JSX standards.
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(ModeSwitch.test): refactor tests to improve readability and performance
Updated the ModeSwitch test suite by removing unnecessary async/await patterns, simplifying the mock configuration, and ensuring consistent cleanup after each test. These changes enhance the clarity and efficiency of the test cases for the onboarding mode switch functionality.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix: should inject the user Locals Language into systemRole
* fix: slove the ts
* fix: update the snapshot test
* fix: update the test.ts
* fix: test fixed
🐛 fix: persist ccSessionId in topic metadata for CC multi-turn resume
The renderer writes `ccSessionId` to topic metadata after each Claude Code
execution so the next turn can spawn `claude --resume <id>`, but the server
zod schema on `updateTopicMetadata` didn't list `ccSessionId`, so zod silently
stripped it — every turn started a fresh CC session and lost prior context.
* ♻️ refactor(desktop): consolidate global shortcuts and remove default showApp hotkey
- Add desktopGlobalShortcuts.ts as single source for Electron + renderer defaults
- Wire ShortcutManager and store to DEFAULT_ELECTRON_DESKTOP_SHORTCUTS
- Use DesktopHotkeyId for @shortcut; drop local shortcuts barrel
- Stop re-exporting DESKTOP_HOTKEYS_REGISTRATION from hotkeys
Fixes LOBE-7181
Made-with: Cursor
* ✨ feat(desktop): introduce new stubs for business constants and types
- Added `@lobechat/business-const` and `@lobechat/types` packages to support workspace dependency resolution.
- Updated `package.json` and `pnpm-workspace.yaml` to include new stubs.
- Refactored imports in `index.ts` to utilize the new constants structure.
- Enhanced `desktopGlobalShortcuts.ts` with improved type definitions for hotkeys.
This change streamlines the management of constants and types across the desktop application.
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor(hotkeys): consolidate desktop global shortcut definitions (LOBE-7181)
Made-with: Cursor
* ✨ feat(session, user): replace direct type imports with constants
- Updated session.ts to use constants for session types instead of direct imports from @lobechat/types.
- Updated user.ts to use a constant for the default topic display mode, enhancing consistency and maintainability.
This change improves code clarity and reduces dependencies on external type definitions.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix(desktop): prevent invalid proxy toggle saves
* 🩹 fix: close proxy form ci gaps
* ✨ style: enhance SaveBar component with updated styles and improved color variables
Signed-off-by: Innei <tukon479@gmail.com>
* 🩹 fix(test): increase ProxyForm test timeout and add explicit delay: null
CI runs with coverage instrumentation cause these form-interaction
tests to take ~4–6s each, exceeding the default 5000ms timeout.
Increase describe timeout to 10000ms and add { delay: null } to
all user.type() calls to keep them stable under coverage.
* 🩹 fix(test): resolve ProxyForm test type errors with user-event v14
---------
Signed-off-by: Innei <tukon479@gmail.com>
* Add document history versioning and TRPC APIs
* 🩹 Improve document history patching for rekeyed editor nodes
* Refine PageEditor history timeline UI
* Enhance modal API documentation and update modal implementation guidelines. Introduce new modal components and migration notes for transitioning from legacy `@lobehub/ui` to `@lobehub/ui/base-ui`. Update version history localization for improved clarity in UI. Add new CompareModal components for document history comparison.
Signed-off-by: Innei <tukon479@gmail.com>
* 🔥 chore(docs): remove document history tech spec
Made-with: Cursor
* Enhance document history management by introducing a 30-day limit for history queries and updating related APIs. Refactor history service methods to support new options for filtering history based on the saved date. Improve UI elements in the PageEditor history timeline for better user experience.
Signed-off-by: Innei <tukon479@gmail.com>
* Add document history management features and improve API integration
- Introduced constants for document history retention and limits.
- Updated document history service to compact history based on new retention limits.
- Refactored PageEditor to utilize constants for document history limits.
- Added new TRPC router for document history management.
- Enhanced JSON diffing capabilities for better patching of document history.
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor: sync document history schema and simplify history service
- Sync simplified document_history table from feat/document-history-db
- Remove version/storage_kind/payload/base_version, use editor_data + saved_at
- Rewrite pagination with composite (savedAt, id) cursor
- Update TRPC APIs from version-based to historyId-based
- Replace DocumentVersionControl with AutoSaveHint
- Add integration tests for history service
* ✨ feat: add per-source document history retention limits
- autosave / manual: retain 20 entries each
- restore / system: retain 5 entries each
- trimHistoryBySource now deletes in batches of 100 to avoid unbounded overflow
- removed obsolete constants: PATCH_THRESHOLD, RETENTION_LIMIT, SNAPSHOT_INTERVAL
- added integration tests for large overflow trimming
* ✨ add llm_call history source and queue-based snapshot for page agent
* 💄 restyle document history list to Notion timeline
* 💄 fix history timeline alignment, unify fonts and highlight current
* ✨ feat(PageEditor): refine document history compare UI and date formatting
Made-with: Cursor
* ✨ feat(editor): add validation for editor data and update related interfaces
- Introduced `isValidEditorData` function to validate editor data structure.
- Updated `GetHistoryItemOutput` and `DocumentHistoryItemResult` interfaces to allow `editorData` to be `null`.
- Modified `getDocumentEditorData` to return `null` for invalid editor data.
- Added integration tests to ensure proper handling of invalid editor data in document history service.
- Enhanced editor actions to prevent saving of invalid editor data.
Signed-off-by: Innei <tukon479@gmail.com>
* 💾 chore(database): split document history indexes
* Fix manual saves and optimize history item rendering
* 🌐 locale: add missing llm_call translation key in en-US file.json
Add pageEditor.history.saveSource.llm_call = \"AI Edit\" to match
the default locale and prevent raw i18n key from showing in the
history panel.
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: associate web crawl documents with agent documents
- Add `associate` method to AgentDocumentModel for linking existing documents
- Add `associateDocument` to AgentDocumentsService, TRPC router, and client service
- Update web browsing executor to associate crawled pages with agent after notebook save
- Add server-side crawl-to-agent-document persistence in webBrowsing runtime
- Add `findOrCreateFolder` to DocumentModel for folder hierarchy support
- Extract `DOCUMENT_FOLDER_TYPE` constant from hardcoded 'custom/folder' strings
- Add tests for associate, findOrCreateFolder, and service layer
Fixes LOBE-7242
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: log errors in web crawl agent document association
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: add onCrawlComplete callback to WebBrowsingExecutionRuntime
Replace monkey-patching of crawlMultiPages with a proper onCrawlComplete
callback in the runtime constructor options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: move document save logic into WebBrowsingExecutionRuntime
Replace onCrawlComplete callback with documentService dependency injection.
The runtime now directly handles createDocument + associateDocument internally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: pass per-call context to documentService via crawlMultiPages
Add WebBrowsingDocumentContext (topicId, agentId) as a parameter to
crawlMultiPages, which flows through to documentService methods. This
allows a singleton runtime with per-call context on the client side.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: enforce document ownership in associate and match root folders by null parentId
- associate: verify documentId belongs to current user before creating link
- findOrCreateFolder: add parentId IS NULL condition for root-level lookup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update changelog documentation format across all historical changelog files
- Merge release-changelog-style skill into version-release skill
- Update changelog examples with improved formatting and structure
Made-with: Cursor
#### 💻 Change Type
- [ ] ✨ feat
- [ ] 🐛 fix
- [ ] ♻️ refactor
- [ ] 💄 style
- [x] 👷 build
- [ ] ⚡️ perf
- [ ] ✅ test
- [ ] 📝 docs
- [ ] 🔨 chore
#### 🔗 Related Issue
- None
#### 🔀 Description of Change
- Extract the document history database changes from the feature branch
onto a branch based on main.
- Add the document history migration, schema, relations, model, and
database tests only.
- Exclude UI, router, and service-layer changes so the PR stays focused
on the database layer.
#### 🧪 How to Test
- Run: cd packages/database && bunx vitest run --silent=passed-only
src/models/__tests__/document.test.ts
src/models/__tests__/documentHistory.test.ts
- [x] Tested locally
- [x] Added or updated tests
- [ ] No tests needed
#### 📸 Screenshots / Videos
| Before | After |
| ------ | ----- |
| N/A | N/A |
#### 📝 Additional Information
- This PR intentionally targets main because the database migration
needs to land on the release branch first.
* update
* update
* 🔧 chore: update CLI build command in electron-builder and ensure proper newline in package.json
* Changed the CLI build command from 'npm run build' to 'npm run build:cli' in electron-builder.mjs.
* Added a newline at the end of package.json for consistency.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Innei <tukon479@gmail.com>
* feat: add some lost lobe-kb builtin tools
* feat: add the list files and get file detail
* feat: add the list files and get file detail
* fix: update the search limit
* ♻️ refactor: add backgroundColor to TaskParticipant and rename name to title
Add backgroundColor field and rename name→title in TaskParticipant interface
to match agent avatar data. Add LobeAI fallback for inbox agent in
getAgentAvatarsByIds when avatar/title are missing.