* ✨ feat: add Agent Runtime Hooks — external lifecycle hook system
Hooks are registered once and automatically adapt to runtime mode:
- Local: handler functions called directly (in-process)
- Production: webhook configs persisted to Redis, delivered via HTTP/QStash
- HookDispatcher: register, dispatch, serialize hooks per operationId
- AgentHook type: id, type (beforeStep/afterStep/onComplete/onError),
handler function, optional webhook config
- Integrated into AgentRuntimeService.createOperation + executeStep
- Hooks persisted in AgentState.metadata._hooks for cross-request survival
- Dispatched at both normal completion and error paths
- Non-fatal: hook errors never affect main execution flow
LOBE-6208
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✅ test: add HookDispatcher unit tests (19 tests)
Tests cover:
- register/unregister/hasHooks
- Local mode dispatch: matching types, multiple handlers, error isolation
- Production mode dispatch: webhook delivery, body merging, mode isolation
- Serialization: getSerializedHooks filters webhook-only hooks
- All hook types: beforeStep, afterStep, onComplete, onError
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: migrate SubAgent to hooks + add afterStep dispatch + finalState
- AgentHookEvent: added finalState field (local-mode only, stripped from webhooks)
- AgentRuntimeService: dispatch afterStep hooks alongside legacy callbacks
- AiAgentService: createThreadHooks() replaces createThreadMetadataCallbacks()
for SubAgent Thread execution — same behavior, using hooks API
- HookDispatcher: strip finalState from webhook payloads (too large)
LOBE-6208
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: add Vercel bypass header to QStash hook webhooks
Preserves x-vercel-protection-bypass header when delivering hook
webhooks via QStash, matching existing behavior in
AgentRuntimeService.deliverWebhook and libs/qstash.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat: migrate Eval Run to hooks + add finalState to AgentHookEvent
Eval Run now uses hooks API instead of raw completionWebhook:
- executeTrajectory: hook with local handler + webhook fallback
- executeThreadTrajectory: hook with local handler + webhook fallback
- Local mode now works for eval runs (previously production-only)
Also:
- AgentHookEvent: added finalState field (local-only, stripped from webhooks)
for consumers that need deep state access
LOBE-6208
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: dispatch beforeStep hooks + fix completion event payload fields
P1: Add hookDispatcher.dispatch('beforeStep') alongside legacy
onBeforeStep callback. All 4 hook types now dispatch correctly:
beforeStep, afterStep, onComplete, onError.
P2: Fix completion event payload to use actual AgentState fields
(state.cost.total, state.usage.llm.*, state.messages) instead of
non-existent state.session.* properties. Matches the field access
pattern in triggerCompletionWebhook.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: update eval test assertions for hooks migration + fix status type
- Test: update executeTrajectory assertion to expect hooks array
instead of completionWebhook object
- Fix: add fallback for event.status (string | undefined) when passing
to recordTrajectoryCompletion/recordThreadCompletion (status: string)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: update SubAgent test assertions for hooks migration
Update execGroupSubAgentTask tests to expect hooks array instead of
stepCallbacks object, matching the SubAgent → hooks migration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix(chat): strip forkedFromIdentifier before LLM API request
Fork & Chat stores forkedFromIdentifier in agent.params for DB lookup.
Spreading params into the chat payload forwarded it to Responses API,
causing strict providers (e.g. AiHubMix) to reject the request.
Remove the field in getChatCompletion alongside existing non-API keys.
Fixeslobehub/lobehub#13071
Made-with: Cursor
* ♻️ refactor: use incremental diff for snapshot messages to prevent OOM
Replace full messages/messagesAfter duplication per step with baseline + delta approach:
- Step 0 and compression resets store full messagesBaseline
- Other steps store only messagesDelta (new messages added)
- Strip llm_stream events from snapshot (not useful for post-analysis)
- Strip messages from done.finalState (reconstructible from delta chain)
- Strip duplicate toolResults from context.payload
- Reduce context_engine_result event size by removing messages and toolsConfig
- Add reconstructMessages() utility for rebuilding full state from delta chain
- AiAgentService constructor now accepts runtimeOptions for DI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ♻️ refactor: add incremental toolset delta for snapshot
- Store operationToolSet as toolsetBaseline in step 0 only (immutable)
- Track activatedStepTools changes via per-step activatedStepToolsDelta
- Strip operationToolSet/toolManifestMap/tools/toolSourceMap from done.finalState
- Add reconstructToolsetBaseline() and reconstructActivatedStepTools() utilities
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* 🐛 fix: correct snapshot delta recording and restore context-engine output
- P1: messagesDelta now always stores only appended messages (afterMessages.slice),
fixing duplication when isBaseline was true (step 0 / compression reset)
- P2: Restore context_engine_result.output (processedMessages) — needed by
inspect CLI for --env, --system-role, and -m commands
- Add P1 regression test for message deduplication
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ✨ feat(chat-input): add category-based mention menu with keyboard navigation
Replace flat mention list with a structured category menu (Agents, Members, Topics).
Supports home/category/search views, Fuse.js fuzzy search, floating-ui positioning,
and full keyboard navigation.
* 🔧 chore: update @lobehub/editor to version 4.3.0 and refactor type definition in useMentionCategories
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(MentionMenu): enhance icon rendering logic in MenuItem component
Updated the MenuItem component to improve how icons are rendered. Now, it checks if the icon is a valid React element or a function, ensuring better flexibility in icon usage. This change enhances the overall user experience in the mention menu.
Signed-off-by: Innei <tukon479@gmail.com>
* 🔧 chore: update @lobehub/editor to version 4.3.1 in package.json
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(version): display actual desktop app version with canary suffix
Add support for fetching and displaying the desktop application's actual version number in the About section. When running on desktop, the version now displays the desktop app's version (including canary suffix if applicable), falling back to the web version if unavailable.
- Add getAppVersion IPC method in SystemController
- Create versionDisplay utility module with comprehensive tests
- Integrate desktop version fetching in Version component
* ♻️ refactor(desktop): inject about version at build time
* ✨ feat: inject referenced topic context into last user message
When users @refer_topic in chat, inject the referenced topic's summary
or recent messages directly into the context, reducing unnecessary tool calls.
* 🐛 fix: include agentId and groupId in message retrieval for context engineering
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: skip topic reference resolution for messages with existing topic_reference_context
Added logic to prevent double injection of topic references when messages already contain the topic_reference_context. Updated tests to verify the behavior for both cases: when topic references should be resolved and when they should be skipped.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ♻️ refactor(nav): remove devOnly mode from nav layout and stabilize Footer during panel transitions
- Remove devOnly filtering from useNavLayout, treat all items as non-dev mode
- Move Pages to top nav position, remove video/image/settings/memory nav items
- Extract Footer from SideBarLayout into NavPanelDraggable outside animation layer
- Show settings ActionIcon in Footer when dev mode is enabled (hidden on settings page)
* 🔧 fix(footer): update settings icon in Footer component
- Replace Settings2 icon with Settings icon in the Footer when dev mode is enabled, ensuring consistency in the user interface.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
fix: add no-cache header to SPA HTML entry point
Prevent stale SPA HTML from being served after server upgrades.
JS/CSS assets still cache normally via hashed filenames.
* 🐛 fix(desktop): remove electron-liquid-glass to fix click event blocking
The electron-liquid-glass native addon was blocking all click events in the
Electron desktop app window. Remove the dependency and restore vibrancy-based
transparency with semi-transparent body background via `.desktop` CSS class.
* 🔨 chore(desktop): remove electron-liquid-glass from native modules config
* ♻️ refactor: replace per-message useNewScreen with centralized useConversationSpacer
Replace the old per-message min-height approach with a single spacer element appended to the virtual list, simplifying scroll-to-top UX when user sends a new message.
* 🔧 refactor: streamline handleSendButton logic and enhance editor focus behavior
Removed redundant editor null check and added double requestAnimationFrame calls to ensure the editor is focused after sending a message.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* 🐛 fix: clear input immediately on send to preserve drafts typed during streaming
Move inputMessage reset before the async streaming lifecycle so text
entered while the assistant is responding is not overwritten on completion.
Also normalize null/undefined in operation context matching so that
cancelOperations works correctly in null-topic sessions.
Fixes LOBE-2647
* 🐛 fix: resolve TS2322 null-vs-undefined type error in useOperationState test
* ✨ feat(desktop): Linux window specialization
- Add minimize/maximize/close buttons for Linux (WinControl)
- Linux: no tray, close main window quits app
- Linux: native window shadow and opaque background
- i18n for window control tooltips
Made-with: Cursor
* 🌐 i18n: add window control translations for all locales
Made-with: Cursor
* 🐛 fix(desktop): show WinControl in SimpleTitleBar only on Linux
Made-with: Cursor
* 🐛 fix(desktop): limit custom titlebar controls to Linux
Avoid rendering duplicate window controls on Windows and keep the Linux maximize button in sync with the current window state.
Made-with: Cursor
---------
Co-authored-by: LiJian <onlyyoulove3@gmail.com>
* style: update claude 4.6 series 1M contextWindow
* chore: cleanup bedrock search tag
chore: cleanup bedrock retired model
chore: cleanup bedrock retired model
chore: cleanup bedrock retired model
* fix: fix ci test