mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
canary
1026 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
913ee4210d |
✨ feat: page/agent/agentGroup/task edit lock (#15786)
* feat: support page editor lock Squashed page-lock feature work: - support page editor lock - support agent group / agent / task edit - add edit lock to agent/agentgroup/task - refactor page lock - fix workspaceId for edit objects - align with agent/group/task * fix: collaborative edit lock * chore: update i18n * fix: redis acquire * fix: release lock * fix: test case * chore: complement page lock test cases |
||
|
|
39bce329fd | 🐛 fix: surface model list fetch failures (#15753) | ||
|
|
381e87474c |
✨ feat(device): add rename & delete actions to branch switcher (#15774)
Hover a branch row in the branch switcher to rename or delete it. Wires new renameGitBranch / deleteGitBranch operations through both transports (Electron IPC for the local machine, device.* TRPC RPCs for remote/web), mirroring the existing checkoutGitBranch / revertGitFile stack. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
f6db1361ee | ✨ feat(agent): show topic sidebar status indicators (#15739) | ||
|
|
800b534741 | 🐛 fix(chat): track operation usage in status tray (#15736) | ||
|
|
ab958a0b98 |
🐛 fix(chat): compact operation metrics on narrow inputs (#15735)
* 🐛 fix: compact operation metrics on narrow inputs * 📝 docs: improve agent testing report template |
||
|
|
09b5e926bf |
✨ feat(conversation): add op status tray above chat input (#14737)
* ✨ feat(conversation): add op status tray above chat input Show elapsed time, total tokens, and total cost while an AI-runtime operation is running in the current conversation. Lives in the floating overlay above the chat input alongside QueueTray and TodoProgress, attaches flush to the input panel below. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(conversation): read top-level message.usage in op status tray Token totals stayed at 0 during regular agent runs because the standard agent path writes usage to `message.usage` (top-level) while the heterogeneous executor writes `metadata.usage`. Read both. Also drop the fragile createdAt window — assistant messages can be created before the AI_RUNTIME op's startTime, which excluded otherwise-valid rows — and aggregate across the whole conversation instead. UI: a little more padding, a pulsing dot to mark the running state, a tokens label, and a divider between tokens and cost. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat(conversation): streaming phase, ping dot, and richer metrics in op status tray - Left side now shows the current streaming phase (thinking / calling tools / searching / compressing / generating) derived from the most recent running sub-operation; server runtimes surface no sub-ops on the client and fall back to 'generating'. - Pulse dot upgraded to an expanding ping ring animation. - Zero-valued metrics are hidden entirely (no more '0 tokens / $0'). - Long-running tasks additionally surface turns and tool-call counts next to tokens and total cost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(conversation): polish op status tray display * 💄 style(conversation): unify op status tray glyph to a single hue The activity glyph mixed purple and cyan accents into the primary color; all layers now derive from colorPrimary alone (opacity-only variation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(conversation): strip glyph halo fill and drop-shadow The halo's tinted fill plus the drop-shadow rendered as a muddy disc behind the glyph (worst in light theme). Reduce to a breathing core dot plus a single rotating dashed orbit, primary hue only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(conversation): drop dollar prefix and code font in op status tray The dollar icon already conveys currency, and the code font made the numbers feel out of place next to the body text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(conversation): show per-message cost next to the token chip Renders usage.cost beside the token count in the assistant message footer; hidden in credit mode (credits already express cost) and when the value is zero/absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(conversation): hide per-message cost below $0.20 Cheap messages don't need a cost callout — the chip only surfaces once the cost is large enough to matter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(conversation): anchor reconnected op timer to real run start, surface steps - Page-refresh reconnect recreated the gateway operation with startTime=Date.now(), resetting the tray timer to 00:00 mid-run. Anchor it to the assistant message's createdAt instead. - Mirror the server's authoritative stepIndex onto op.metadata.stepCount at every step_start event, so the steps metric shows for real server-side runs (and survives reconnects). - Drop the tool-call count metric from the tray. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✅ test(conversation): stub updateOperationMetadata in gateway event handler mock store Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
60bed5782f |
chore: update i18n (#15712)
chore: update i18n files |
||
|
|
35b6bc55b8 |
🐛 fix: workspace error (#15701)
feat: support workspace (page author, copyTo/transferTo, notifications, i18n & fixes) Squashed 13 commits from fix/workspace-error for clean rebase onto main's submodule base. |
||
|
|
87b1f39c0f |
✨ feat(skill): add delete/remove actions to settings/skill items (#15708)
* ✨ feat: add delete/uninstall actions to settings/skill items - LobehubSkillItem: show compact `...` dropdown in list mode for connected items with Disconnect action (revokes OAuth) - KlavisSkillItem: show compact `...` dropdown in list mode for connected/pending servers with Remove action (true delete via removeKlavisServer) - ConnectorDetail: add Delete button for custom (mcp) connectors; calls deleteConnector + notifies parent via onDelete - SkillDetail / Page: thread onDelete callback so selecting null after deletion triggers auto-select of next item - Locales: add tools.klavis.remove / removeConfirm.title / removeConfirm.desc in en-US, zh-CN, and default source Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(skill): gate Klavis remove by canEdit and clear selected after removal Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(skill): show dropdown for all Klavis/Lobehub items in list mode Previously, the ... button was gated behind `server` (Klavis) and `isConnected` (LobehubSkill), so disconnected/never-connected items showed no actions. Remove those guards so the dropdown always renders in list mode. handleRemove/handleDisconnect now skip the server call when no server instance exists and instead clear the selected item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(skill): move delete/uninstall actions from list dropdown to detail panel - Remove heavy ... dropdown from KlavisSkillItem / LobehubSkillItem list items - Add danger Uninstall button to builtin-skill detail header (matches ConnectorDetail style) - Add slim action bar with Uninstall to agent-skill detail panel - All actions respect canEdit / canCreate permissions with confirmModal gating Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ba6976c063 | 🐛 fix: pause input completion after errors (#15692) | ||
|
|
a810bf3dcd |
🐛 fix(agent-runtime): always persist assistant reasoning to DB (#15687)
* 🐛 fix(agent-runtime): always persist assistant reasoning to DB PR #13494 gated message reasoning persistence behind preserveThinking (agent chatConfig + model extendParams / qwen|zhipu fallback). That gate is only meant to control whether reasoning is replayed into the next LLM payload — applying it to the DB write dropped thinking content for every non-qwen/zhipu reasoning model in server-side agent mode: reasoning streamed live via stream_end but vanished after refresh. Restore unconditional reasoning persistence in messageModel.update and keep the preserveThinking gate only for state.messages payload replay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(i18n): localize callSubAgent tool labels Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1130f7df32 |
✨ feat(devices): add browser device pairing flow (#15678)
* ✨ feat: add browser device pairing flow to /settings/devices - Add "Via Browser" tab to ConnectDeviceModal with pairing code display and input - Add "Register this browser as a device" callout card above DeviceList - Support ?pair=<code> URL param to auto-open browser pairing modal with pre-filled code - Improve DeviceList empty state with method cards (Desktop + CLI) - Ship en-US and zh-CN i18n keys for all new browser/sync strings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🔨 fix(devices): fix lint warnings — import sort order and empty catch block * fix(devices): add pair API route and invalidate device list cache - Create /api/devices/pair POST handler that authenticates the user via Better Auth session, validates the code against the user's registered devices via DeviceModel.findByDeviceId, and returns JSON. - Replace the setListKey/key-prop re-mount trick with lambdaQuery.useUtils().device.listDevices.invalidate() so the tRPC React Query cache is properly busted after a successful pair (fixes staleTime: 30s preventing the new device from appearing). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ♻️ refactor(devices): drop browser pairing, fix modal close, redesign UI - Remove the "Via Browser" pairing flow entirely: browser tab in ConnectDeviceModal, the "register this browser" callout card, the ?pair=<code> deep-link, and the /api/devices/pair stub route. Only the real Desktop and CLI connection methods remain. - Fix the modal that couldn't be closed: @lobehub/ui Modal closes via onCancel (antd), not onClose — the X button was a no-op. - Redesign the connect modal (segmented tabs, numbered steps, command blocks with copy, security footer) and the empty state (onboarding hero with Desktop/CLI options + capability cards). - Clean up browser/sync i18n keys; add capabilities + footer keys for en-US and zh-CN. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 fix(devices): apply card radius — cssVar.borderRadius already has unit The radius tokens (cssVar.borderRadius / borderRadiusLG) already include their unit, so the trailing `px` produced `var(--…)px`, which browsers drop — leaving the cards with sharp corners. Drop the `px` so the cards pick up the same rounded radius as the appearance settings FormGroup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
b76992e581 |
✨ feat(file-preview): support remote read-only local previews (#15673)
* ✨ feat(file-preview): support remote read-only local previews * ✨ feat(local-file): identify tabs by context * ♻️ refactor(file-preview): route previews through project file service * 🐛 fix(desktop): clamp nav panel width * ✨ feat(file-preview): improve local preview controls * 🐛 fix(file-preview): reload html after refresh completes |
||
|
|
3a780a62f6 | ✨ feat: add AntGroup (蚂蚁百灵) provider support (#13713) | ||
|
|
686778fe51 |
✨ feat(file-preview): render HTML files inline (#15671)
✨ feat(file-preview): render html files inline
|
||
|
|
914976a52f |
✨ feat(model-bank): knowledgeCutoff batch 2, metadata skill & always-visible tab bar (#15663)
* ✨ feat(model-bank): backfill knowledgeCutoff batch 2 and restore lost Anthropic values Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 docs(skills): add model-bank-metadata skill for cutoff/family backfill Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(model-bank): Claude Fable 5 belongs to the claude-mythos family Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(desktop): always surface the tab bar by creating a tab on first navigation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ♻️ refactor(model-bank): family is the product lineage (claude-opus/sonnet/haiku), not the brand Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(agent): backfill activeAgentId before paint on tab/route switches Tab switches are plain route navigations, so leaving an agent page cleared activeAgentId via a passive useUnmount and the next page re-set it in a passive useEffect — the first painted frame always had no active id, flashing a skeleton even when agentMap already cached the config. Move both the backfill and the unmount clear to layout effects: removed-tree layout cleanups run before new-tree layout effects in one commit, so the clear can never wipe a freshly synced id and the id is in place before paint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(agent): surface agent config fetch errors with a retry action isAgentConfigLoading only knows "no data yet", so a failed fetch (e.g. a 401 that SWR deliberately does not retry, with no focus revalidation inside a single Electron window) left the agent page on a skeleton forever — only a manual reload recovered. Record per-agent fetch errors in agentConfigErrorMap (set by onError, cleared on data / retry), expose currentAgentConfigError / isAgentConfigError selectors, add a retryAgentConfigFetch action that revalidates the agent's SWR entries, and show an error alert with a retry button above the main chat input while the config is still missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(ci): sync model metadata test expectations --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
fdd955404d |
✨ feat(codex): add collab tool render (#15662)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6d47c1d07e |
✨ feat(connector): fold OAuth into the custom MCP (PluginDevModal) form (#15661)
* ✨ feat(connector): support API key / custom header / OAuth auth in custom connector Make the connector backend a full replacement for the legacy custom-MCP plugin form: - connector create/update now accept bearer/apikey/header credentials (encrypted at rest); oauth2 stays callback-only - map apikey → bearer auth and header → request headers in both the sync path (syncTools + callTool) and the agent-runtime manifest path - pass custom HTTP headers through to the MCP client - AddConnectorModal becomes a rich form: MCP type (HTTP/STDIO), auth type (None / API Key / Custom Headers / OAuth), reusing the plugin form inputs; OAuth keeps the existing popup authorize flow, others create + sync directly Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(connector): fold OAuth into the PluginDevModal MCP form Pivot the custom-MCP entry to reuse the rich PluginDevModal / MCPManifestForm instead of a bespoke connector modal, and add OAuth as an auth type inside it: - MCPManifestForm: gated `enableOAuth` adds an "OAuth" auth type with Client ID / Secret (optional) + redirect-URI hint. Only the custom-connector entry enables it, so plain custom-plugin DevModal callers (editing plugins, agent tools, …) are unaffected. - DevModal: opens the OAuth popup synchronously on the save click (browsers block window.open once an async boundary is crossed), validates, then hands the popup to onSave which navigates it to the authorize URL. - New CustomConnectorModal wraps DevModal and persists every auth type onto the connector backend (none / bearer / custom headers → create + sync; OAuth → create with OIDC config + run the authorize popup). - settings/skill entry now opens CustomConnectorModal; the standalone AddConnectorModal rich rewrite from the previous commit is reverted to the canary original (it is only referenced by the unused ConnectorList). - i18n: dev.mcp.auth.oauth* keys (default + en-US + zh-CN). Backend stays as in the prior commit (connector create/update accept bearer/apikey/header credentials; sync + manifest paths apply them). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(connector): route the OAuth auth type through the authorize flow, not the token-less manifest test Selecting OAuth and clicking "Test connection" called the plugin manifest test (getStreamableMcpServerManifest), which connects with no token and 401s on any OAuth-gated server (e.g. Linear MCP / DCR). For OAuth there is nothing to test without authorizing first, so the button now becomes "Authorize & Connect" and runs the connector OAuth flow (discovery + DCR + authorize popup), shared with the footer save button via DevModal.runOAuthFlow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(connector): make connector.create idempotent on (user, identifier) Re-adding or re-authorizing a custom connector with an existing identifier hit the user_connectors unique constraint and 500'd. Now an existing row is updated (reset to disconnected, refreshed name/url/oidcConfig/credentials) and its id reused, instead of inserting a duplicate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(skill-store): route Add Custom MCP through the connector modal, drop the Custom tab - Skill Store "Add → Add Custom MCP Skill" now opens CustomConnectorModal (connector backend + OAuth), matching the settings/skill entry, instead of the legacy plugin DevModal (installCustomPlugin + togglePlugin). - Remove the now-redundant "Custom" tab from the Skill Store (custom MCP lives in the connector list now): drop SkillStoreTab.Custom, its tab option, CustomList render, and the matching search branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
09e6f02e45 |
🔨 chore: modify workspace sidebar (#15658)
* chore: change back to user style sidebar panel * chore: optimize personal menu * chore: update i18n files |
||
|
|
a2ea314cd8 |
✨ feat(codex): refine Codex tool renders (#15651)
* 💄 style(codex): refine file change tool render * ✨ feat(codex): add web search tool render * ✨ feat(codex): add mcp tool render * ✨ feat(codex): improve tool command display * 💄 style(files): refine explorer tree icons * ✅ test: fix local file link render props |
||
|
|
b8339abc76 | 🐛 fix: show plan limit upgrade UI on desktop builds (#15628) | ||
|
|
b8b37cffa3 | ✨ feat: refresh topic sharing experience (share page + popover) (#15581) | ||
|
|
7641cda958 | 💄 style: update i18n locales (#15630) | ||
|
|
9ef76475c2 | 💄 style: add fable promo locale keys for plans page (#15622) | ||
|
|
004027ffdd |
💄 style: update free credit badge copy and add cta/dismiss keys (#15617)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0434953053 |
chore: add home free credit badge business slot (#15615)
✨ feat: add home free credit badge business slot Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4b7ef28e46 | 🐛 fix: support fable campaign UI (#15616) | ||
|
|
437b4c8968 |
💄 style: update referral copy for pay-to-unlock reward (#15614)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
aa46864df6 |
♻️ refactor(lobe-agent): remove callSubAgents in favor of parallel callSubAgent calls (#15608)
The lobe-agent manifest exposed `callSubAgents` (parallel multi-task dispatch), but the server runtime only implemented `callSubAgent`. When an agent run executed server-side and the model invoked `callSubAgents`, the builtin executor threw "Builtin tool lobe-agent's callSubAgents is not implemented". The server already supports parallel sub-agents natively: a batch parks on all deferred tools (`pendingToolsCalling`) and `tryResumeParentFromAsyncTool` enforces a K=N barrier, resuming the parent only once every pending tool_result is fulfilled. So emitting multiple `callSubAgent` calls in one turn is equivalent to the old `callSubAgents` — making the plural API redundant and the source of a server/client inconsistency. Remove `callSubAgents` end to end (manifest, types, client executor, Inspector/Render/Streaming components + registries, locale keys, display-name map, dev fixture) and update the system prompt to guide the model to fan out via multiple `callSubAgent` calls. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
64d3bdb978 |
💄 style: add preserve thinking feature for Qwen3.7 Max model (#13494)
Co-authored-by: Copilot <copilot@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: YuTengjing <ytj2713151713@gmail.com> |
||
|
|
23120f26e4 | 💄 style: update referral backfill copy (#15583) | ||
|
|
77dbe4b7b3 |
🔨 chore(google): Support External URL file input with SSRF validation to optimize transmission (#12657)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: yutengjing <ytj2713151713@gmail.com> |
||
|
|
0a6b02ccb5 |
💄 style(topic): show error alert icon with tooltip on failed topics (#15573)
* 💄 style(topic): show error alert icon with tooltip on failed topics Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(topic): merge attention-needing topics into one "Needs attention" group Collapse the unread-completion, failed, and waitingForHuman states into a single top "pending" status bucket (待处理 / Needs attention) so the sidebar surfaces everything that needs the user's attention in one place. - groupTopicsByStatus now buckets those three states into `pending`, taking a new `unreadTopicIds` set (unread completions are a client-only state). - Server STATUS_SORT_RANK floats `failed` to the top alongside `waitingForHuman` so failed topics stay on the first page and don't drop out of the group. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(topic): pin the "Needs attention" group above favorites The pending bucket already sorts above running, but the synthetic favorite group was prepended ahead of it. Hoist pending to index 0 so attention-needing topics sit at the very top of the sidebar, above both favorites and running. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(heterogeneous-agents): pin resolved cwd onto remote-CC new topics Remote CC dispatched the run with the correct working directory (the precedence chain falls back to the agent's per-device pick), but a brand-new topic was created without `metadata.workingDirectory`, so the sidebar grouped it under "No directory" / 无目录. Unify the three drifting server-side cwd-precedence sites behind one pure helper (`resolveDeviceWorkingDirectory`) and persist the resolved cwd back onto a freshly-created topic so grouping, next-turn reuse, and workspace-init scan all agree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
5dd0f0c0c9 |
✨ feat: specialize Market auth modal copy per capability scene (#15569)
Introduce a MarketAuthScene ('default' | 'sandbox' | 'mcp' | 'publish') so the
Market authorization modal can show capability-specific copy instead of the
generic "Create Community Profile" wording, while falling back to the generic
copy for unknown scenes.
- Reactive (401) path: infer scene from the tRPC procedure path in the error
link and carry it on the market-unauthorized event.
- Proactive path: callers pass the scene to signIn() (publish buttons, MCP/skill
install, in-chat market tool auth).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
ea3ae583d6 |
✨ feat(agent): unified per-device working directory + execution-device UI (#15543)
* ✨ feat(agent): unified per-device working directory + execution-device UI Client UI consuming the backend contract (#15542). User-facing — validate before merge. - New `src/store/device` (SWR fetch + cwd writes) — single source of device data; `deviceCwd` helper moves here from the chat-input feature layer. - One `WorkingDirectoryPicker` for local + remote (native dialog vs manual path). - Shared `WorkspaceControls` strip composed by both chat-input bars. - GitStatus reads remote git via `useDeviceGitInfo` (read-only). - Execution-device switcher graduates out of labs → writes only executionTarget. - One-time migration of legacy localStorage recents into device.workingDirs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): wire executionTarget→runtimeMode + workingDirByDevice cwd The runtime-decision wiring, kept out of the backend contract PR so it's reviewed/validated together with the UI that drives it. - `helpers/executionTarget`: resolveRuntimeMode / executionTarget resolvers. - server tool gate (AgentToolsEngine) derives runtimeMode from `agencyConfig.executionTarget`, with a no-regression fallback to the legacy per-platform runtimeMode. - server cwd precedence (aiAgent resolveWorkspaceInit + hetero dispatch) now consumes `workingDirByDevice[targetDeviceId]`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✅ test(agent): cover executionTarget + workingDir helpers; drop dead lab key - Unit-test resolveRuntimeMode / resolveExecutionTarget and the working-dir precedence (locks the web default→cloud graduation + legacy fallback) - Remove the now-unused `executionDeviceSwitcher` lab i18n keys (toggle deleted) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): guide web users to the desktop app in the device switcher On web with no remote device, replace the muted "no devices" dead-end with a prominent, clickable download-desktop card (and drop the now-duplicate header link). Desktop keeps the muted hint since local execution is already available. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): fix execution-device copy for desktop + web - Desktop "no devices" hint no longer tells an already-on-desktop user to "install the desktop app" — just points at `lh connect`. - Tighten the web download-card description to the desktop's real benefit (run on your computer with local file access). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): flatten the web download card to a plain row Drop the outer border/background so it reads as a normal menu row (like the sandbox option), and shorten the description to a single line so the row stops being taller than its neighbours. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): reword download-card desc to "access to your computer" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): add "no device" execution target (plain chat, no run tools) Restores the option to run an agent with no execution environment, lost when the per-platform runtimeMode was unified into executionTarget. Adds `none` to HeteroExecutionTarget (→ runtimeMode `none`), surfaces it at the top of the switcher on both web + desktop, and flips the web default back to `none` so an unconfigured web agent is plain chat again (desktop still defaults to local). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): rename HeteroExecutionTarget→DeviceExecutionTarget, reorder switcher - Rename the type (it now carries `none`, so "device" target fits better than "hetero") across types + helpers + dispatcher + switcher. - Move "no device" to the bottom of the list (real targets first, opt-out last). - Reword the download card to "let agents connect directly to your computer". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): move "no device" back to top, restore EN download copy "No device" sits above the dynamic device rows; keep the EN download-card wording as "Run agents with access to your computer". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): swap switcher icons — MonitorOff for "no device", Box for sandbox Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): clarify execution-device info tooltip + "no device" desc - Info tooltip now explains the cloud sandbox is provided by the centralized LobeHub Marketplace, and that picking a device makes it the agent's runtime for reading/writing files and operating the computer. - "No device" description now conveys "no device enabled, can't operate a computer" instead of "plain chat". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): move info icon beside the title, shorten "no device" desc - Info tooltip trigger now sits next to the "Execution Device" title instead of right-aligned; the download link stays on the right. - "No device" description trimmed to just "No device enabled". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): zh tooltip wording — "提供服务" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): reorder tooltip — device runtime first, marketplace last Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): trim tooltip — drop "设备"/devices and trailing period Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): tag the current machine's device row, drop duplicate "This device" When the desktop's own machine appears in the device list, badge that real row with a "This device" tag and hide the generic "This device" (local) option — no more two entries for the same machine. The local option still shows as a fallback when the machine isn't enrolled in the list yet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(agent): hoist this-machine device above sandbox + auto-bind on first run Switcher-only (no routing/dispatch changes): - Order is now: no device → this device → cloud sandbox → other devices. - On desktop, when this machine is enrolled and online and the agent has no explicit target yet, default to it and persist the binding once. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): widen gap between execution-device rows Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): hide "Get Desktop App" link on desktop Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): capitalize "Cloud Sandbox" label Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(agent): web working-dir entry via "Add folder" modal instead of inline input The browser folder picker can't yield an absolute path (sandboxed handle), so on web / a remote device the working directory is entered manually. Replace the inline input with an "Add folder…" row that opens a modal for absolute-path entry; the local desktop machine still opens the native folder dialog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(agent): split working-dir footer into local/remote row components Replace the scattered `isLocalDevice ?` forks (icon, label, handler) with one branch that picks between two self-contained rows: ChooseLocalFolderRow (native dialog) and AddRemoteFolderRow (absolute-path modal). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): use the device default cwd as the add-folder placeholder Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): validate manually-entered working dir via device statPath RPC Web / remote clients can't browse the target device's filesystem, so the "Add folder" modal now checks the typed path on the device before binding it. New `statPath` device RPC mirrors gitInfo end-to-end: - desktop WorkspaceCtr.statPath (fs.stat → exists / isDirectory) + RPC dispatch - server deviceGateway.statPath + device.statPath tRPC (invokeRpc relay) - modal blocks on a definitive negative (not found / not a directory); an unreachable device is treated as "can't verify" and allowed through Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(agent): route statPath through deviceService, not lambdaClient Components shouldn't import lambdaClient directly — add a thin deviceService wrapping device.statPath, and call it from the working-dir picker. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(i18n): move working-directory strings from plugin to a device ns The working-directory / git control-bar strings (53 keys) were lumped under the `plugin` namespace. Move them to a dedicated `device` namespace and drop the now-redundant `localSystem.` prefix (`plugin:localSystem.workingDirectory.X` → `device:workingDirectory.X`). Updates the 4 consumer components; the `device` ns auto-registers via defaultResources. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(agent): route all device TRPC calls through deviceService Components/hooks/stores shouldn't reach into lambdaClient.device.* directly. Expand deviceService with listDevices/updateDevice/listGitBranches/ checkoutGitBranch/checkCapability/getAgentProfile and migrate every imperative call site (device store, BranchSwitcher, CreatePlatformAgent, the remote-agent guard, RemoteAgentConfigCard) + the DeviceListItem type. lambdaQuery.device.* React-Query hooks are left as-is (a different pattern). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): pull/push a remote device's branch over RPC Wire git pull/push through the device's pullGitBranch/pushGitBranch RPC so the web/remote GitStatus bar can sync, not just the local desktop over IPC. Shows the pull/push affordances for remote devices too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(agent): route git pull/push through deviceService too Add pullGitBranch/pushGitBranch to deviceService and switch GitStatus off the direct lambdaClient.device.* calls, so no component reaches the device router directly anymore. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(agent): detect repoType for manually-added working dirs A directory added via the "Add folder" modal committed without a repoType, so a GitHub repo showed a plain folder icon. statPath now also returns the git repo type (detected on the target device); the modal threads it into the committed entry. Collapses the modal's separate validate+submit into one onSubmit that validates and enriches in a single round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(agent): create new branch via a modal instead of inline footer "Checkout new branch…" now opens a focused modal (branch-name input + create) rather than expanding an inline footer inside the branch dropdown. Always creates + checks out the branch — no checkout/overwrite options. Errors show inline in the modal; drops the dead inline-create state/styles. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(agent): route all git ops through a unified gitService Pick Electron IPC vs device RPC inside the service so UI / store / hooks stay transport-agnostic. Replace the bundled `gitInfo` device RPC with granular reads (branch / linked PR / working-tree / ahead-behind) that mirror the local IPC methods one-to-one, and move the git read SWR hooks into the device store (useFetchGitInfo / WorkingTreeStatus / AheadBehind). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): route Review git ops through device RPC (remote-capable) Extend the device-RPC git pipeline to the 4 ops the Review panel needs (getGitWorkingTreePatches / getGitBranchDiff / listGitRemoteBranches / revertGitFile), mirroring the listGitBranches pattern end-to-end: desktop RPC dispatch → deviceGateway → device.* tRPC → gitService. Adds minimal DeviceGit* mirror types to @lobechat/types. Review (useReviewPatches / useGitRemoteBranches / FileItem) now goes through gitService with a deviceId, dropping the isDesktop gate so web/remote devices get the diff + revert too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(agent): resolve repoType from device store so remote Review tab shows useRepoType now reads the persisted workingDirs[].repoType from the device store (keyed by deviceId), so a remote device's git/github type — and thus the Review tab visibility — resolves without a local-only IPC probe. The IPC probe + localStorage fallback are kept only when the target is the local machine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(agent): optimistic branch switch in the branch switcher Flip the displayed branch the instant a checkout is clicked (or a new branch created) instead of waiting for the IPC/RPC round-trip + gitInfo refetch. The git-info SWR cache is optimistically updated and reconciled on completion — a failed checkout rolls the label back and toasts the error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat: support remote device files panel * 💄 style: restore desktop this-device option * 🐛 fix: keep files panel local for this device --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a75eba5a4f |
💄 style(chat-input): use compact stats footer for skill tools popover (#15552)
* 💄 style(chat-input): use compact stats footer for skill tools popover - Replace the two full-width footer rows (store / management) with a compact stats footer: pinned / auto counts on the left, an "Add Skills / Connector" store button (icon + label) and a settings icon button on the right. - Right-align each item's type tag (MCP / Skills / builtin) so badges sit flush next to the row action instead of trailing the name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✅ test(aiAgent): mock deviceGateway in connectorOverlap exec test execAgent reads `deviceGateway.isConfigured`, which under the happy-dom test environment hits real t3-env and throws "server-side env var on the client". Mock `@/server/services/deviceGateway` like the sibling device tests do so the connector/plugin overlap cases run in isolation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
b19008ed24 | 💄 style: bring various details for better experience (#15486) | ||
|
|
dbf743cc12 |
✨ feat(verify): Agent Run delivery checker system (#15489)
* 🗃️ feat(database): add verify system tables for agent run delivery checker Implement the database layer for the Agent Run delivery checker (Verify System). Reuse / definition layer: - verify_criteria: a single reusable pass/fail standard (atomic unit), carrying its verifier config + onFail default and bound to a document for judging guidance (iteration history reuses document_history; no version columns) - verify_rubrics: a named group that aggregates criteria — the reusable unit - verify_rubric_criteria: junction, which criteria a rubric aggregates (criteria are reusable across rubrics) Mounted onto an agent via the existing agency config jsonb: - agencyConfig.verifyRubricId: a reusable rubric (criteria template) - agencyConfig.verifyCriteriaIds: ad-hoc one-off criteria A run's plan instantiates the union of both. No dedicated bindings table. Snapshot + result layer: - agent_operations.verify_plan (jsonb) + verify_plan_confirmed_at: the per-run immutable check-item snapshot lives ON the operation (1:1 — auto-repair spawns a new operation), instead of a separate plans table - agent_operations.verify_status: denormalized rollup for list-page badges - verify_check_results: per-criterion result with the Toulmin model (verdict/confidence as columns, narrative in a typed toulmin jsonb), N:1 verifier_tracing_id for batch judging, FP/FN flags for the data flywheel; relates to the plan via operation_id + stable check_item_id Ref: LOBE-10019 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ✨ feat(verify): add Agent Run delivery checker backend + frontend module Implements the verify system on top of the schema (PR #15480): - models: verifyCriterion / verifyRubric (+junction) / verifyCheckResult; agentOperation verify plan/status methods - services/verify: AI plan generation (auto-create criteria), executor with LLM Toulmin judge (per-criterion + batch), program placeholder, agent & auto-repair spawner seams, rollup chokepoint, feedback fp/fn, completion lifecycle bridge - lambda verify router (criteria/rubric CRUD, plan, results, feedback) - frontend feature module: service, SWR hooks, CheckerDock state machine, RunArtifact, verify i18n namespace - tracing scenarios: VerifyPlanGen / VerifyJudge Live UI mount (dock/artifact into chat) pending server operationId source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🐛 fix(verify): persist delivery-checker verdicts via async tracing backfill The LLM judge produced valid verdicts but they were never persisted, leaving every run stuck at `verifying`. Two root causes: 1. FK ordering: `writeVerdict` stamped `verifier_tracing_id` synchronously, but the `llm_generation_tracing` row is written asynchronously (best-effort, after the response) — so the hard FK was violated every time and the verdict write was rolled back. Now the verdict is written with a null link, and the tracing id is backfilled by an `onPersisted` callback that fires only after the tracing row commits (still non-blocking). If tracing is disabled the link simply stays null. 2. Verdict parse: the judge JSON schema is non-strict, so the provider returns optional Toulmin fields as explicit `null`. The Zod validator used `.optional()` (accepts undefined, not null), so any null failed the whole `safeParse` and discarded the batch. Switched to `.nullish()`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(cli): add `verify` command for the delivery checker Adds `lh verify` covering the full delivery-checker chain — criteria & rubric CRUD, per-run plan (generate/state/confirm/skip), execute (LLM judge), results, and feedback — calling the `verify` lambda router. Enables end-to-end backend testing of the verify system. Also adds the missing `tool-runtime` / `prompts` / `const` workspace entries to the CLI's `pnpm-workspace.yaml` so the standalone package installs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(verify): add verify message role + delivery-checker card UI Make the delivery-checker renderable in chat: - Fix the `features/Verify` components so they compile: flatten the `verify` locale to the repo's flat-dotted-key convention (keySeparator: false), import `Flexbox`/`TextArea` from `@lobehub/ui` (react-layout-kit is no longer a dep), and the token cast. - Add a `verify` UI message role + a `VerifyMessage` card that renders the Run Artifact + checker dock from `metadata.verifyOperationId`, wired into the message renderer switch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): add lobe-agent `generateVerifyPlan` tool (server runtime) Lets an agent set up the delivery checker for its run: the agent calls `generateVerifyPlan` early (per the new `<delivery_checker>` system-role guidance), which instantiates the rubric / ad-hoc criteria into a frozen plan on the current `agent_operations` row. Executed server-side only — the executor is dispatched via `runtime[apiName]` with `operationId` threaded through the tool execution context; the client `BaseExecutor` gracefully no-ops it. Also registers the metadata fields (`verifyOperationId`/`verifyRound`) on the message metadata zod schema so the role='verify' card can carry its operation id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): surface role=verify card on run completion (LOBE-10051) Connect the delivery checker to the conversation: when an Agent Run with a verify plan completes, `CompletionLifecycle` inserts a persisted `role='verify'` message (parented to the assistant, carrying `metadata.verifyOperationId`) that renders the checker card. Self-guarded — no plan → no card, failures never affect the run. `role='verify'` behaves like a `user` leaf message everywhere it flows (persistence + conversation-flow pass it through unchanged); only the context-engine treats it specially: a new `VerifyMessageProcessor` drops it from the model context (UI-only card, not a valid model role). Adds `verify` to `CreateMessageRoleType`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(verify): merge run-artifact + checker into one card The role=verify message rendered two stacked cards (Run Artifact summary + Delivery Checker) that duplicated the check-item list. Merge into a single card: the `Run Artifact · Round N` header, then the checker results + actions, then the snapshot note. RunArtifact/CheckerDock gain an `embedded` prop (header-only / body-only, no card chrome) and VerifyMessage composes them under one border. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): derive generateVerifyPlan rubric from agencyConfig A real agent calls `generateVerifyPlan` with just a `goal` and doesn't know rubric ids. When `rubricId`/`criteriaIds` params are absent, derive the mounted rubric + ad-hoc criteria from the executing agent's `agencyConfig.verifyRubricId / verifyCriteriaIds`. Params still win when given. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(cli): surface agent gateway WebSocket close code + reason The `onclose` handler logged `String(event)` → the useless "[object CloseEvent]". Surface `event.code` (+ `event.reason` when present) so a gateway disconnect before completion is actually diagnosable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 fix(verify): rename "Run Artifact" → "Verification", drop failed red border - The kicker said "Run Artifact" — it's automated verification, not an artifact. Renamed to "Verification · Round N". - Removed the red error border on a failed check — a normal card reads better. - Fixes a render crash (`useVerifyState is not defined`): the border removal left a dangling reference after the import was dropped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(cli): poll run status when the agent stream drops When the live stream (gateway WebSocket / SSE) closes before the run finishes, the run is still executing server-side — so instead of hard-exiting, fall back to polling `aiAgent.getOperationStatus` every 10s until the run reaches a terminal state (or is no longer tracked). Pairs with surfacing the WS close code/reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 feat(verify): add Render for generateVerifyPlan tool call The generateVerifyPlan tool call rendered as the default param/result dump. Add a Render that lists the generated delivery checks (title + gate/auto-fill tag), and surface the items on the tool state so the Render can read them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): auto-confirm generated plan so checks run on completion The agent generated a plan but it stayed `planned`/unconfirmed, so the completion hook (which gates on a confirmed plan) never ran the checks — the card was stuck at "awaiting confirmation" with no pass/fail. In the headless agent flow there's no one to click Confirm, so `generateVerifyPlan` now auto-confirms the plan it generates; the checks then run automatically on completion. (An interactive "review before run" gate is a future enhancement.) Also: the verify card header disappeared in the draft/planned phase (`phaseToArtifact.draft` was null). Give it a header so the card always shows its "Verification · Round N" heading. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(agent-tracing): only count opaque/presentational attrs as structural noise The first structuralNoiseRatio charged ALL markup (every <...> tag) as noise, which over-penalized legitimately structured results 3x. Grounding against real web-search output (`<item title="…" url="…">snippet</item>`) showed the tags and the title=/url= attributes ARE the signal the model reads. Now only opaque/presentational attribute names (id, class, style, data-*, aria-*, role, on*) count as noise; semantic element tags and content-bearing attributes (title, url, href, name…) are kept. On a 57-op user-interrupted sample this drops web-search noise 42%→0% and overall estimated waste 16%→5%, leaving large-payload (readDocument) and high error-rate tools as the real signal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): model-authored criteria with name/description/instruction-in-document + agent verifier Restructure the generateVerifyPlan tool to a createDocument-style full-create flow and wire up the agent verifier path: - criteria now = title + description (required one-liner) + instruction (required detailed rubric); instruction lives in a linked document (verify_criteria.documentId), description is a new verify_criteria column (migration 0111). verifierConfig no longer holds description/instruction. - generateVerifyPlan creates verify_criteria + a rubric, snapshots the plan onto the operation and confirms it; judge resolves the instruction from the document. - agent-type checks run as verifier sub-agents (execAgent + isolated thread) whose onComplete hook parses a VERDICT and writes it back to verify_check_results (renamed AgentVerifierSpawner → VerifierAgentRunner). - UI: custom Inspector for the tool header; check list shows per-verifier-type icons (llm/agent/program) + description + required/optional tag; i18n en/zh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ⚡️ perf(verify): run program/llm/agent checks concurrently on completion The three verifier kinds are independent; previously the agent spawn waited for the batched LLM judge to finish. Run them via Promise.all so agent sub-agents start immediately alongside the LLM batch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): dedicated builtin verify-agent + writeback tool, role=verify message, portal check editor - Add `@lobechat/builtin-tool-verify` (submitVerifyResult) + builtin `verify-agent`; agent-type checks now run as the dedicated verify agent (not the user's agent), which investigates and writes its verdict back via the tool during its run. - Verifier inherits the parent run's model/provider (builtin default may be unconfigured locally). - role=verify completion message no longer requires an assistantMessageId, so the delivery-checker card always surfaces when a plan exists. - Portal editor for verify checks (title/description/instruction/verifier/onFail). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(verify): restrict verify-agent to its writeback tool; fix running loader icon Root cause of stuck `running` agent checks: the verify-agent ran in agent mode and inherited all default tools (web-browsing, cloud-sandbox, skills, activator), so it went off web-searching/crawling to "investigate" and never called submitVerifyResult. - Run the verify-agent in chat mode (enableAgentMode: false, searchMode: off) — the strict whitelist — and whitelist `lobe-verify` for chat mode so the verifier gets ONLY its writeback tool. - Sharpen the verify systemRole: judge from the provided deliverable/instruction (no external tools), always reach a verdict, and always call submitVerifyResult. - CheckerDock: running check now uses the standard RingLoadingIcon (warning ring), matching the app's loader instead of a blue spinner. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): auto-repair loop — re-run the agent with failure feedback on failed checks When required checks fail with onFail=auto_repair, automatically run a second iteration instead of ending at `failed`: - createRepairRunner: re-runs the SAME agent in the same topic with the failure feedback as the prompt, re-snapshots the plan onto the repair operation and confirms it so it re-verifies on completion (the next round). Capped at MAX_REPAIR_ROUNDS via parent-chain depth to prevent runaway loops. - maybeAutoRepair: fires only once every required check has a terminal result, so it works for inline LLM checks (triggered from lifecycle) and async agent checks (triggered from the verify tool's writeback path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): open check result detail in portal & rename artifact→result - add a VerifyResult portal view: clicking any check row opens that result's detail (verdict, confidence, Toulmin sections, suggestion) on the right; agent checks expose their execution trace from inside the panel - CheckerDock rows are all clickable now (chevron affordance), status shown by icon only; verify card uses colorBgElevated - rename the run-result surface from "artifact" to "result" everywhere: RunArtifact → RunResult, phaseToArtifact → phaseToResult, and all `artifact.*` i18n keys → `result.*` - ship verify namespace zh-CN / en-US locales Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): enrich check result portal — criterion stepper, richer detail view Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): rubric run-policy config + repair feedback on the verify card Auto-repair feedback now lives on the failed round's role=verify message (content), and the VerifyMessageProcessor surfaces it into the repair run's context as a tagged user turn — so the repair op runs off history via a new execAgent `suppressUserMessage` path instead of injecting a synthetic user message. createVerifyMessage is awaited before verification to avoid a race. maxRepairRounds becomes a rubric-level config: new `verify_rubrics.config` jsonb column, read live at repair time via the plan's sourceRubricId. Adds a RubricConfig portal panel (reachable from the plan card's settings affordance) to view/edit it, wired through the verify store + TRPC. Verify domain types/vocab/config are extracted from the DB schema into @lobechat/types as the single source of truth; schema and consumers import from there. Tests: VerifyMessageProcessor dual behavior; VerifyRubricModel config round-trip; MessageModel.findVerifyMessageByOperationId. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🗃️ refactor(verify): squash the 3 verify migrations into one Collapse 0110 (tables) + 0111 (criteria.description) + 0112 (rubrics.config) into a single regenerated 0110_add_verify_tables so the PR ships one clean, idempotent migration. No schema change vs the three combined. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(cli): verify rubric run-policy config commands + shrink judging-rule editor font CLI: `verify rubric create --max-repair-rounds`, `verify rubric view`, and `verify rubric update` exercise the rubric config endpoints end-to-end; adds a mocked command test. UI: judging-rule editor font 16px → 14px. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(verify): editable rubric name in the config panel + default 3 repair rounds Add a name (title) field to the RubricConfig portal, persisted via a new updateRubricTitle store action + service (optimistic + debounced, alongside the config write-back). Bump DEFAULT_MAX_REPAIR_ROUNDS 2 → 3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(verify): extract generateVerifyPlan into installable lobe-delivery-checker tool Move the delivery-checker plan-creation flow out of the always-on lobe-agent tool into a new standalone, installable builtin tool `lobe-delivery-checker` (Skill Store, opt-in per agent — not loaded by default). lobe-agent no longer ships generateVerifyPlan. - new packages/builtin-tool-lobe-delivery-checker (manifest/types/systemRole + client Render/Inspector/Portal moved wholesale from lobe-agent) - new serverRuntimes/lobeDeliveryChecker.ts (generateVerifyPlan moved out of lobeAgent.ts), registered alongside verifyResult - registered installable in builtin-tools (no hidden/discoverable:false, not in defaultToolIds/alwaysOnToolIds/runtimeManagedToolIds); renders/inspectors/ portals/identifiers wired; lobe-agent portal entries removed - i18n keys moved builtins.lobe-agent.verifyPlan.* → builtins.lobe-delivery-checker.* Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✨ feat(agent): add `custom` tool mode; verify agent uses it instead of chat-mode Chat mode's contract is to strip ALL user/agent plugins (strict KB/memory/web allow-list) — so the verify sub-agent couldn't get its writeback tool without a leaky blanket rule. Introduce a third tool mode `custom` where the toolset is EXACTLY the agent's declared plugins (no always-on, no defaults, no activator), for focused builtin sub-agents. - chatConfig.toolMode: 'agent' | 'chat' | 'custom' (overrides enableAgentMode) - AgentToolsEngine: custom branch (defaultToolIds = plugins, rules = plugins-on, allowExplicitActivation only in agent mode); chatModeRules restored to strict - verify agent → toolMode: 'custom'; lobe-verify dropped from chatModeAllowedToolIds - test: custom mode enables exactly the declared plugin, no always-on / defaults Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c711279edf |
✨ feat(tools): show app-fixed tools in the chat-input Pinned section (#15509)
* ✨ feat(tools): show app-fixed tools in the chat-input Pinned section Surface always-on, runtime-owned tools (lobe-agent + always-on infra) read-only at the top of the Tools popover "Pinned" group, so users can see what the app keeps active for every conversation. These have no toggle — a Pin indicator with a hint replaces the per-tool policy menu. - builtin-tools: add `fixedDisplayToolIds` ([lobe-agent, ...alwaysOnToolIds]) - builtin selectors: add `fixedDisplayMetaList` (reads hidden tools by id) - useControls: render read-only fixed items, prepend to Pinned, fold into counts - i18n: add `tools.activation.fixed.hint` + `tools.builtins.lobe-agent.*` Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🐛 fix(tools): make lobe-agent actually always-on; gate fixed display to runtime The Pinned section was rendering tools that aren't enabled every turn: - lobe-agent was only enabled when injected into plugins/runtime ids (it has no rule in the engine, so it defaulted to disabled) — showing it as "always on" was a UI lie. - manual skill-activate mode strips manualModeExcludeToolIds (activator, skill-store) from the defaults, so they're off — but they still showed as fixed. Fixes: - Add lobe-agent to alwaysOnToolIds so its core capabilities (plan/todo, sub-agent dispatch, visual-media fallback) are genuinely on every agent-mode turn. Chat mode still drops alwaysOn entirely. - Derive fixedDisplayToolIds from alwaysOnToolIds (single source of truth, no drift). - Make fixedDisplayMetaList mode-aware: drop manualModeExcludeToolIds in manual mode so the Pinned list matches what the engine actually enables. - Update engine tests that asserted the old "lobe-agent off by default" behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ♻️ refactor(tools): drop fixedDisplayToolIds alias, use alwaysOnToolIds directly fixedDisplayToolIds was just `= alwaysOnToolIds`; collapse it. The selector now reads alwaysOnToolIds directly and still applies the manual-mode exclusion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e7c73bd4ce |
💄 style: support show CC subagent metrics chip (#15217)
* ✨ feat(cc): show tool count + token + model metrics on Agent inspector chip Surface per-subagent progress on the inline Agent inspector row so users can see how much work has happened without expanding the thread: - Inspector chip renders `[count] tools · [tokens]` after the description chip, with the model name in a Tooltip. Tool count = count of `role==='tool'` child messages; tokens = LAST subagent assistant's `metadata.usage.totalTokens` (CC's per-turn `message.usage` already includes the full prior context, so summing would double-count the shared history — the final turn's value matches the main-agent message-footer convention). - New `threadSelectors.getThreadDbMessages` reads the raw DB-shape child messages from `dbMessagesMap[thread_*]` (the display-bound `messagesMap` bucket only holds the parent + a virtual `assistantGroup`). - `BuiltinInspectorProps` carries `toolCallId` so the chip can join to its subagent Thread via `metadata.sourceToolCallId`; propagated from both the chat Inspector caller and the DevPanel `ToolInspectorSlot`. Adapter / executor changes so subagent token usage actually flows in: - `claudeCode.ts` `handleSubagentAssistant` emits a `step_complete{phase:turn_metadata, subagent}` event when `raw.message.usage` is present. Subagent assistant events are not partial-streamed (unlike main-agent), so `message.usage` is authoritative — no de-stale logic needed. The subagent ctx tag lets the executor route the usage write onto the in-thread assistant instead of the main agent's, so CC's `result_usage` grand-total semantics aren't double-counted. - Renderer + server `step_complete{turn_metadata}` branches check for `event.data.subagent` and route to the run's `currentAssistantMsgId`. Renderer mirrors the write into `dbMessagesMap` via `run.stream.update` so the chip's selector picks up usage as it lands. Server-side finalize rolls totals onto `thread.metadata` for the historical-view cold-load path: tool count from `lifetimeToolCallIds.size`, tokens from the last in-thread assistant's `metadata.usage.totalTokens`, plus `completedAt` / `duration`. Done via the existing `threadModel.update` with an inline metadata read-merge — no new `ThreadModel.updateMetadata` method or `threadRouter.updateThreadMetadata` endpoint introduced. i18n: 5 keys under `chat.thread.subagentMetrics.*` in `chat.ts` + zh-CN + en-US. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(cc): persist subagent metrics so the inspector chip survives cold-load The metrics chip (tool count · tokens, model in tooltip) only rendered while the run streamed — after a reload it vanished on desktop. Two gaps: - The renderer `heterogeneousAgentExecutor.finalizeSubagentRun` never rolled totals onto `thread.metadata` (only the server `HeterogeneousPersistenceHandler` did). On cold-load the child messages aren't hydrated, so the live selector had nothing to read and the chip's `hasAny` went false. Added the symmetric rollup (`totalToolCalls` / `totalTokens` / `completedAt` / `duration`), re-sending the create-time `sourceToolCallId` / `subagentType` / `startedAt` since `updateThread` replaces the whole metadata column. - Subagent assistant messages carried no `model`, so the tooltip's model line never showed. The subagent `turn_metadata` branch now writes `model` / `provider` onto the in-thread assistant (live tooltip) and persists `model` onto `thread.metadata.model` (cold-load tooltip); the chip selector falls back to `thread.metadata.model`. Also fixes a latent bug both paths shared: finalize read `totalTokens` off `currentAssistantMsgId`, which by then points at the freshly-created terminal assistant (no usage), so it always resolved `undefined`. Now tracks the last non-zero per-turn `totalTokens` on the run — matching the live selector's "last turn, not a sum" convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(cc): derive subagent chip metrics on read, drop run-state tracking The chip's tool-count / token / model metrics were captured incrementally on the subagent run (`lastTurnTokens` / `subagentModel`) and denormalized onto `thread.metadata` at finalize — in BOTH the renderer executor and the server handler, so the rule lived in three places and the two finalize paths had to be kept in sync by hand. Derive them on read instead, from the child messages (the single source of truth): - `aggregateSubagentMetrics(messages)` (new, `src/utils`) is the one rule: COUNT `role='tool'`, SUM every assistant turn's `usage.totalTokens`, pin the model. SUM (not last-turn) matches the project's token-usage heatmap convention — "total tokens processed". - The chip selector aggregates the in-memory child messages live, falling back to `thread.metadata.*` on cold-load. - `threadModel.queryByTopicId` computes the SAME projection in SQL (LEFT JOIN + GROUP BY, reusing the `usage->totalTokens` index, with a legacy `metadata.usage` fallback) and folds it onto `metadata`, so cold-load reads a server-derived value without hydrating the child messages. Both finalize paths drop the metadata rollup and now only flip thread status Active; `lastTurnTokens` / `subagentModel` run-state fields are gone. Each subagent turn still writes its `usage` + `model` onto the in-thread assistant — those rows are what the read-time aggregation sums over. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
32c293f8c0 |
✨ feat(claude-code): add per-question custom input to askUserQuestion (#15506)
* ✨ feat(claude-code): add per-question custom input to askUserQuestion Let users write their own answer as the trailing item in each question's option list, beside picking a numbered choice. Single-select treats the two as mutually exclusive; multi-select appends the custom text as an extra entry. Merged into the question's answer at submit, so the bridge formatter and completed Render need no changes. Draft round-trips via a __custom__: prefix on the existing askUserDraft map. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ♻️ refactor(claude-code): split askUserQuestion form & drop draft key prefix Break the single ~530-line AskUserQuestion.tsx into a folder: - draft.ts pure helpers (read/buildSubmitPayload/isQuestionAnswered) - useAskUserForm.ts all state + handlers + draft persistence - OptionCard.tsx / QuestionPanel.tsx presentational pieces - index.tsx thin view Also drop the `__custom__:<question>` draft-key prefix: persist the draft as a typed object { picks, custom, escapeText, escapeActive } instead of a flat string-keyed map. The picks/custom split now lives in named fields, so the only sentinel left is `__freeform__` — and only in the submit payload, which is the actual bridge contract. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(claude-code): make AskUserDraft assignable to setInterventionDraft `setInterventionDraft` takes `Record<string, unknown>`; an `interface` isn't assignable to it (open to declaration merging, so no implicit index signature). Switch `AskUserDraft` to a `type` alias, which is closed and satisfies the index signature. Fixes the tsgo TS2345 in CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
485d664589 | 💬 style: rebrand platform agent copy to Connect Agent (#15498) | ||
|
|
64b7ab2f17 |
💄 style(topic): one-click collapse/expand all topic groups (#15484)
* ✨ feat(topic): add one-click collapse/expand all groups in topic sidebar Add a toggle button in the topic sidebar header (next to Filter and the more-actions menu) that collapses or expands all topic groups at once. It reuses the existing `expandTopicGroupKeys` global status, so it stays in sync with manual per-group toggling, and hides itself when there are fewer than two groups (e.g. flat mode). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(topic): hide group toggle in flat mode In flat mode, groupedTopicsForSidebar falls through to time grouping so the computed group count can exceed one, but List renders FlatMode with no accordion for the toggle to affect. Hide the control explicitly when topicGroupMode === 'flat' instead of relying on the group count. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 💄 style(topic): use 2-corner minimize/maximize icons for group toggle Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
9c4dadda4c |
✨ feat(task-detail): replace inline comment input with ChatInput that triggers a new run (#14873)
* ✨ feat(task-detail): split task panel comment from topic-thread reply CommentInput in TaskActivities stays as-is on canary — avatar + EditorCanvas + attachment + send button, posting a plain task-level comment. TopicChatDrawer footer becomes a FeedbackInput that calls the in-scope ConversationProvider's sendMessage, continuing the existing topic conversation instead of attaching a comment + restarting the run. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ✨ feat(task-detail): keep FeedbackInput visible while topic is running Drop the canLeaveFeedback gate so the in-thread reply box renders even when the topic is pending/running. ConversationStore.sendMessage already queues messages during an in-flight stream, so this just exposes the queue affordance to the user — letting them steer the next step without waiting for the current run to terminate. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 💄 style(task-detail): collapse FeedbackInput behind a follow-up button + add attach action FeedbackInput now starts collapsed as a full-width "Send follow up message" button. Click expands a ChatInput shell with EditorCanvas inside and a footer that carries an AttachmentUploadButton on the left (+ icon) and the send button on the right. Files are inserted inline into the editor (same pattern as CommentInput) so they ride along on sendMessage's editorData. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 💄 style(task-detail): tighten CommentInput card & switch follow-up button to filled - CommentInput card: padding-block 8px → 4px, editor placeholder fontSize 14px - FeedbackInput collapsed button: default size + variant="filled" for a less obtrusive look that sits flush in the chat footer Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 💄 style(task-detail): drop top padding above FeedbackInput in topic drawer Use paddingBlock="0 12px" so the follow-up button hugs the last message instead of floating with a 12px gap above. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 🐛 fix(task-detail): clear FeedbackInput editor before awaiting sendMessage Previously the editor cleanup ran after the awaited sendMessage call, so the box kept the just-sent text on screen until the entire send + stream lifecycle resolved. Move clearContent / collapse before the await so the input feels responsive (sendMessage already snapshots markdown and editorData for its optimistic update). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 🐛 fix(task-detail): keep FeedbackInput expanded after sending Drop the setExpanded(false) call in handleSubmit so the ChatInput remains open once the user has opened it. Collapsing it back to the "Send follow up message" button right after every reply was disruptive mid-conversation; the button only makes sense as the initial resting state of the drawer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ✨ feat(chat): add forceRuntime override to SendMessageParams Plumb a new optional forceRuntime field through SendMessageParams → ConversationLifecycle.sendMessage → selectRuntimeType(parentRuntime). parentRuntime already wins over every other signal in the dispatcher, so callers can pin a send to 'gateway' / 'client' / 'hetero' regardless of the agent's local/cloud config. Also propagate forceRuntime through the message queue (QueuedMessage + MergedQueuedMessage + mergeQueuedMessages + both drain sites in the client and hetero executors) so a follow-up queued during an in-flight run keeps its runtime pin when it eventually fires. FeedbackInput in TopicChatDrawer passes forceRuntime: 'gateway' so task-topic follow-ups stay on the server-side path that runTask originally used, even if the user's global runtime preference is local. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
537c39f771 | 💄 style(chat-input): rework Plus menu with toggle switches and grouped submenus (#15433) | ||
|
|
2eb9e34fda |
✨ feat(stats): add daily token-usage mode to activity heatmap (#15417)
* ✨ feat(stats): add daily token-usage mode to activity heatmap Add a Messages/Tokens toggle to the stats activity heatmap. The token mode sums assistant messages' `metadata.usage.totalTokens` (the source of truth for usage) bucketed by the day each message was created, so tokens land on the day they were actually consumed rather than on a topic's creation date. Aggregation runs in SQL (SUM over the jsonb path, GROUP BY date) and levels are scaled relative to the busiest day. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 💄 feat(stats): format heatmap token counts and add token stat row - Format tooltip token counts compactly (e.g. 44.2K, 12.5M) via the chart's customTooltip; message counts get thousand separators. - Add a token-dimension summary row (cumulative / peak daily / current streak / longest streak) shown in token mode, derived client-side from the heatmap data over the past year. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ✨ feat(stats): add longest-task duration to token heatmap stats Add the "longest task" figure to the token-mode stats row, computed from the longest wall-clock agent operation (completedAt - startedAt) over the past year — MAX in SQL on the agent_operations table, scoped by user and using the (user_id, created_at) index. Rendered as a compact 1h 15m / 45s duration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 💄 feat(stats): default heatmap to token mode and move toggle beside title - Token is now the first/default segmented option (Messages second); the share card keeps Messages as its default. - Move the Messages/Tokens toggle next to the section title (left) via a new StatsFormGroup `afterTitle` slot; day tags stay on the right. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f9eb48feea | ✨ feat: add limited offer & original price locale keys for top-up (#15415) | ||
|
|
8dee729f9f | ✨ feat: add storage pay-as-you-go stubs and locale keys (#13501) | ||
|
|
857aaf4766 |
✨ feat(chat-input): show execution-device switcher for all agents (#15371)
✨ feat(chat-input): show execution-device switcher for all agents and add desktop download link - Remove `!isHeterogeneous` guard so the device switcher surfaces for every agent type (not just non-heterogeneous), controlled by the existing Lab toggle - Make the sandbox/runtime-env mode selector mutually exclusive with the device switcher: hide it when `enableExecutionDeviceSwitcher` is on - Add a "下载桌面端 / Get Desktop App" quick link in the execution-device popover header (right side) linking to https://lobehub.com/downloads Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |