| ✨ feat(platform-agent): openclaw/hermes agent creation UI, device guard, and remote dispatch backend (#15065)
* ♻️ refactor(agent-invocation): add AgentInvocationIntent + unified non-hetero dispatcher (LOBE-8927/8928)
Introduce a shared invocation contract and unified dispatcher for the
non-hetero, non-group agent call paths (callAgent speak mode and @agent
direct mentions). Removes the implicit client-only fallback that existed
in both entry points.
Changes:
- agentDispatcher.ts: add AgentInvocationIntent interface as the unified
intent type for callSubAgent / callAgent / @agent invocations
- nonHeteroSubAgentDispatcher.ts (new): dispatchNonHeteroSubAgent()
resolves child runtime via selectRuntimeType and routes to
executeClientAgent (client) or executeGatewayAgent (gateway);
throws for hetero (out of scope per LOBE-8926)
- conversationLifecycle.ts #executeDirectMentionRoute: replace hardcoded
executeClientAgent + TODO fallback with dispatchNonHeteroSubAgent call
- builtin-tool-agent-management executor.ts callAgent speak mode:
replace hardcoded executeClientAgent + TODO fallback with
dispatchNonHeteroSubAgent call
Fixes LOBE-8927
Fixes LOBE-8928
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ✨ feat(platform-agent): openclaw/hermes agent creation UI, device guard, and remote dispatch backend
- Add CreatePlatformAgent 3-step creation modal (type select → config → bind device)
- Add RemoteAgentConfigCard to agent profile editor for openclaw/hermes config
- Add device guard banner in HeterogeneousChatInput for offline/unavailable devices
- Add useRemoteAgentDeviceGuard hook for real-time device status polling
- Fix backend dispatch: openclaw/hermes now use executeToolCall(runHeteroTask) instead of dispatchAgentRun (lh connect only handles tool_call_request)
- Add agentNotify router for lh notify → DB write + gateway stream event
- Add device.checkCapability endpoint for platform availability probe
- Add notify_update event type to gateway stream and event handler
- Add sendDoneSignal in heteroTask.ts for clean openclaw exit signaling
- Unify non-hetero sub-agent dispatch via dispatchNonHeteroSubAgent (LOBE-8927)
- Route openclaw/hermes to gateway runtime; keep claude-code/codex on hetero/client paths
- Add i18n keys for platform agent UI and device guard banners
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* 🐛 fix(agentNotify): reuse execAgent placeholder message on first lh notify call
Instead of creating a second empty bubble, the first assistant notify
without a messageId now updates the placeholder assistantMessageId that
execAgent already seeded in runningOperation.assistantMessageId.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ✨ feat(agentNotify): cancel openclaw/hermes process on interruptTask
- Store deviceId + heteroType in topic.metadata.runningOperation at dispatch time
- interruptTask now dispatches cancelHeteroTask tool call to the bound device
when topicId reveals a remote hetero operation, sending SIGINT to the process
- Pass topicId from gateway cancel callback to interruptTask
- Add topicId to InterruptTaskSchema and InterruptTaskParams
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ♻️ refactor(hetero-agent): consolidate remote/local type classification into heterogeneous-agents package
- Add RemoteHeterogeneousAgentConfig, REMOTE_HETEROGENEOUS_AGENT_CONFIGS, isRemoteHeterogeneousType, and derived type aliases (HeterogeneousAgentType, LocalHeterogeneousAgentType, RemoteHeterogeneousAgentType) to packages/heterogeneous-agents/src/config.ts
- Extend HETEROGENEOUS_TYPE_LABELS to cover remote platform types (openclaw, hermes) via REMOTE_HETEROGENEOUS_AGENT_CONFIGS
- Replace all inline `=== 'openclaw' || === 'hermes'` checks and local Sets/type aliases across aiAgent service, ProfileEditor, HeterogeneousChatInput, useRemoteAgentDeviceGuard, CreatePlatformAgent, RemoteAgentConfigCard, and deviceProxy with the shared utility
- Show OpenClaw/Hermes display name in assistant message model tag (Usage component) by setting provider=heteroType on placeholder message and using HETEROGENEOUS_TYPE_LABELS for rendering
- Fix ReferenceError: move remoteDeviceId declaration before updateMetadata call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add the platform agents get profiles
* 🐛 fix(platform-agent): routing, security, and i18n issues from review
- Route openclaw/hermes to gateway on desktop (P1): add isRemoteHeterogeneousType
check in selectRuntimeType before desktop hetero branch — remote agents never
use local desktop IPC, no special-casing needed
- Fix race in heteroTask: sendAutoNotify → sendDoneSignal now sequential via
.finally() so error message is written before agent_runtime_end is published
- Security: validate messageId belongs to topicId in agentNotify before
MessageModel.update to prevent cross-conversation data corruption
- Clear capability/device/profile state on platform change in creation modal (P2)
- Derive PLATFORM_DEFS from REMOTE_HETEROGENEOUS_AGENT_CONFIGS — new platforms
automatically appear in the modal without code changes
- Use HETEROGENEOUS_TYPE_LABELS for platform names in HeterogeneousChatInput
and RemoteAgentConfigCard (remove hardcoded PLATFORM_NAMES map)
- i18n: platform card descs, 'online'/'offline' tags, 'Select a device'
placeholder, checkFailed error — all now use i18n keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ♻️ refactor(platform-agent): derive remote platform enum from config + fix test
- device.ts: replace hardcoded z.enum(['hermes','openclaw']) with a
zod enum derived from REMOTE_HETEROGENEOUS_AGENT_CONFIGS so new
platforms are automatically covered without touching this file
- heteroTask.ts / getAgentProfile.ts: use RemoteHeterogeneousAgentType
instead of literal 'hermes' | 'openclaw' union for the same reason
- gateway.test.ts: update cancel-handler assertion to include topicId
which was added to the interruptTask call in the previous commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ✨ feat(platform-agent): gate creation entry behind labs flag + expand dispatcher tests
- Add enablePlatformAgent lab preference (default false) — the
"Add Platform Agent" menu item is hidden until the user opts in
via Settings → Advanced → Labs
- Wire toggle in settings/advanced with labs i18n key (en/zh)
- createPlatformAgentMenuItem returns null when flag is off
- agentDispatcher.test: add remote hetero cases (openclaw/hermes →
gateway on both web and desktop) to cover the routing fix added earlier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* 🐛 fix(lint): merge duplicate import + sort interface props in nonHeteroSubAgentDispatcher
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* 💄 feat(platform-agent): disable Hermes option in creation modal (coming soon)
Hermes is not yet ready for production. Mark it as coming-soon in the
platform selection step: grayed-out card, not clickable, "Coming Soon"
tag next to the name.
To enable Hermes when ready: remove 'hermes' from COMING_SOON_PLATFORMS
in CreatePlatformAgent/index.tsx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ✅ fix(test): mock CreatePlatformAgentModal in ModalProvider.test
The modal always mounts (open=false) and calls lambdaQuery.useQuery
which requires a tRPC context not present in the test environment.
Mock it out the same way as ChatGroupWizard and EditingPopover.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ✅ fix(test): mock useUserStore + labPreferSelectors in useCreateMenuItems.test
Adding useUserStore to useCreateMenuItems triggered user store
initialization in tests, which pulled in @lobechat/const and failed
because the existing mock only exports isDesktop. Mock the store and
selectors directly instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* 🐛 fix(platform-agent): hide divider when platform agent entry is disabled
The divider before 'Add Platform Agent' was unconditional — it showed
even when the labs flag was off. Conditionally include both the divider
and the menu item together so no orphaned separator appears.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> | 1 天前 |
| ✨ feat: init lobehub-cli (#12735)
* init cli project
* Potential fix for code scanning alert no. 184: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* update
* Potential fix for code scanning alert no. 185: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> | 2 个月前 |
| ✨ feat: init lobehub-cli (#12735)
* init cli project
* Potential fix for code scanning alert no. 184: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* update
* Potential fix for code scanning alert no. 185: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> | 2 个月前 |
| ✨ feat: init lobehub-cli (#12735)
* init cli project
* Potential fix for code scanning alert no. 184: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* update
* Potential fix for code scanning alert no. 185: Uncontrolled command line
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> | 2 个月前 |