Commit graph

517 commits

Author SHA1 Message Date
Naiyuan Qing
971d68b605 feat(channels): add ChannelManager and Telegram plugin
ChannelManager orchestrates channel lifecycles and routes messages to per-conversation Agents.
Telegram plugin uses grammy for long polling with group @mention detection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:47:41 +08:00
Naiyuan Qing
5d63727a04 feat(channels): add channel plugin system with types, registry, and config
Introduces the extensible channel plugin architecture for messaging platform integrations.
- ChannelPlugin interface with config, gateway, and outbound adapters
- Plugin registry with register/get/list operations
- Config loader for ~/.super-multica/channels.json5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:47:36 +08:00
LinYushen
3b09d8d44d
Merge pull request #99 from multica-ai/message-aggregation
feat(hub): add message aggregation module for third-party messaging integrations
2026-02-06 12:51:14 +08:00
yushen
f6fab68873 fix(hub): include message_end text in aggregator 2026-02-06 12:44:15 +08:00
yushen
1e71341997 Merge remote-tracking branch 'origin/main' into message-aggregation 2026-02-06 11:55:58 +08:00
LinYushen
24204794d1
Merge pull request #98 from multica-ai/copilothub-web-search
feat(tools): replace web search with Devv Search + HMAC signing
2026-02-06 11:54:56 +08:00
yushen
ec6dbff61c Merge remote-tracking branch 'origin/main' into copilothub-web-search 2026-02-06 11:43:40 +08:00
yushen
efb1495326 fix(hub): fence close must reject info strings per CommonMark spec
The closing fence regex was not checking for an empty info string,
allowing e.g. ```python to incorrectly close an open fence. Also
adds missing test for tool_execution_update passthrough.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 22:23:55 +08:00
yushen
fc0c1781c3 refactor(hub): remove Hub-level aggregation integration
Message aggregation should not be managed by the Hub. The aggregator
is a standalone utility for client adapters to use internally — the
Hub stays clean and only does event forwarding. Third-party messaging
integrations (Discord, Telegram) will use MessageAggregator in their
own adapter layer.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 20:24:25 +08:00
Naiyuan Qing
1e6da205df feat(ui): spin MulticaIcon on hover
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 20:22:29 +08:00
Naiyuan Qing
5e174b8fef fix(ui): responsive horizontal padding on message list
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 20:15:19 +08:00
Naiyuan Qing
21312abd01 feat: chat input padding 2026-02-05 19:02:38 +08:00
Naiyuan Qing
039a625dbd
Merge pull request #96 from multica-ai/feat/message-return
feat(chat): add message history pagination with scroll-up loading
2026-02-05 18:48:56 +08:00
Naiyuan Qing
02f3534f2e chore(chat): set DEFAULT_MESSAGES_LIMIT to 200 for production
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:45:15 +08:00
Naiyuan Qing
f7950066bc
Merge pull request #97 from multica-ai/cleanup/remove-old-chat-files
Remove unused Zustand stores from @multica/store
2026-02-05 18:44:48 +08:00
Naiyuan Qing
1fe27a59d0 chore(store): remove unused Zustand stores and slim down package
After the chat refactoring moved state management to @multica/hooks,
the Zustand stores (useConnectionStore, useMessagesStore, useAutoConnect)
are no longer imported by any application code. This removes them along
with their unused dependencies (zustand, uuid, react).

- Delete connection-store.ts, messages.ts, use-auto-connect.ts
- Extract Message/ToolStatus types into types.ts (preserves UI imports)
- Remove saveConnection/loadConnection/clearConnection from connection.ts
- Drop zustand, uuid, react deps from package.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:41:31 +08:00
Naiyuan Qing
65c2fea1b6 feat(chat): add message history pagination with scroll-up loading
Return latest messages by default instead of oldest. Support paginated
loading of older messages when scrolling up via IntersectionObserver,
with scrollHeight compensation to preserve scroll position.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:40:15 +08:00
yushen
c03a60753e feat(hub): integrate message aggregator into Hub event pipeline
Add enableAggregation/disableAggregation methods to Hub for per-agent
aggregation control. When enabled, streaming text deltas are buffered
and emitted as block-reply events instead of raw stream events. The
existing streaming mode remains the default for own clients.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:28:14 +08:00
yushen
1859e32a30 feat(hub): add message aggregation module for block-level reply chunking
BlockChunker splits streaming text at natural boundaries (paragraph,
newline, sentence, word) with configurable min/max chars and markdown
fence-safe splitting. MessageAggregator consumes AgentEvents, buffers
text deltas, and emits complete BlockReply objects via callbacks.

Enables future third-party messaging integrations (Discord, Telegram)
that cannot consume raw streaming deltas.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:28:08 +08:00
Naiyuan Qing
c2b5ada2ef
Merge pull request #86 from multica-ai/exec-approvals
feat(agent): add exec approval system for command execution
2026-02-05 17:59:43 +08:00
Naiyuan Qing
669cbc791b fix(desktop): resolve eslint exhaustive-deps warnings in useLocalChat
Use chatRef to hold stable reference to useChat return value, avoiding
stale closure issues and satisfying react-hooks/exhaustive-deps rule.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:56:54 +08:00
Naiyuan Qing
9bcb0993b1 Merge remote-tracking branch 'origin/main' into exec-approvals
# Conflicts:
#	apps/desktop/src/hooks/use-local-chat.ts
2026-02-05 17:54:19 +08:00
Naiyuan Qing
bece8f0545 refactor(web): adapt chat page for extracted shared hooks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:51:12 +08:00
yushen
3817e2d8a2 feat(tools): add HMAC-SHA256 request signing to web search
Sign each search request with HMAC-SHA256 using Hub ID, a per-request
nonce (UUIDv7), and unix timestamp. The signed reqId is sent in the
request body to prevent unauthorized API usage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:50:57 +08:00
Naiyuan Qing
607adeb667 feat(desktop): implement local chat with direct IPC and mode switching
Add LocalChat component using useLocalChat hook that communicates with
the Hub via IPC (no Gateway required). Fix streamId extraction to use
event.message.id matching Hub behavior. Fix history to return raw
AgentMessageItem[] instead of flattened strings. Add exec approval
forwarding over IPC. Use conditional rendering for LocalChat to prevent
event leaking from remote sessions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:50:55 +08:00
Naiyuan Qing
7a21686505 refactor(hooks,ui): extract useGatewayChat hook and update shared components
Move gateway-specific chat logic into dedicated useGatewayChat hook.
useChat remains a pure state hook with no IO. Update ChatView props,
remove legacy chat.tsx and connect-prompt.tsx.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:50:47 +08:00
Naiyuan Qing
874de766ec feat(hub): add local exec approval routing for desktop IPC chat
Add localApprovalHandlers map so exec approval requests can be routed
to the Electron renderer via IPC instead of requiring a Gateway
connection. Expose setLocalApprovalHandler/removeLocalApprovalHandler
and resolveExecApproval on Hub for the IPC layer to use.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:50:41 +08:00
yushen
51ba86a8eb refactor(tools): clean up web search naming and remove dead code
Rename CopilotHub references to Devv Search (constants, types, function
names, error message). Remove unused resolveTimeoutSeconds/resolveCacheTtlMs
imports and use constants directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:31:53 +08:00
yushen
630f06eddb chore(tools): update web_search descriptions to Devv Search
Remove "requires API key" wording and rebrand to Devv Search across
tool definition, desktop UI, system prompt, and README.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:21:39 +08:00
yushen
8ea2f2a1bf feat(tools): replace web search with CopilotHub API
Remove Brave and Perplexity providers in favor of a single CopilotHub
search endpoint (api-dev.copilothub.ai/web-search). Simplifies schema
to query-only, removes credential dependencies, retains caching.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:19:12 +08:00
Naiyuan Qing
056b9abff6 refactor(ui): deduplicate device-pairing with StatusWrapper and PairingHeader
Extract StatusWrapper to replace duplicated fullscreen/inline wrapper in
ConnectionStatus and RejectedStatus. Extract PairingHeader to replace
repeated title+description blocks in mobile and desktop views. Make
desktop container mb responsive (mb-14 sm:mb-28).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:07:45 +08:00
Bohan Jiang
363c65b392
Merge pull request #95 from multica-ai/Bohan-J/tool-result-pruning
feat(context): add tool result pruning for smarter context management
2026-02-05 16:28:41 +08:00
Jiang Bohan
6a21a51766 merge: resolve conflict with main branch
- Keep needsCompaction() method from compaction-feedback PR
- Keep tool result pruning from this branch
- Add "pruning" to CompactionEndEvent.reason type in events.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 16:26:11 +08:00
Jiang Bohan
d46d647cfb chore: trigger CI 2026-02-05 16:22:41 +08:00
Jiang Bohan
71e44bebc0 fix(session): add explicit return type to maybeCompact method
Adding explicit return type to help TypeScript resolve the type
correctly across different build configurations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 16:20:40 +08:00
Jiang Bohan
4e61155e5e chore(turbo): add src as global dependency for cache invalidation
The desktop app imports from the root src directory, but turbo wasn't
tracking those files for cache hash calculation. This caused CI builds
to use stale hashes when types changed in the root src directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 16:16:33 +08:00
Jiang Bohan
17fc77e44d chore: trigger CI rebuild 2026-02-05 16:11:35 +08:00
Jiang Bohan
d2827ae948 fix(session): add pruning to SessionEntry reason type
The CompactionResult type includes "pruning" as a reason but SessionEntry
did not, causing type errors when writing compaction entries.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 16:01:10 +08:00
Jiang Bohan
a7f1c56e09 fix(profile): resolve exactOptionalPropertyTypes type error in updateStyle 2026-02-05 15:55:30 +08:00
Jiang Bohan
3dd7ff52d6 feat(context): add tool result pruning for smarter context management
Two-phase pruning approach based on OpenClaw's microcompact-style:
- Soft Trim (30% utilization): Keep head 1500 + tail 1500 chars of large tool results
- Hard Clear (50% utilization): Replace old tool results with placeholder

Protections:
- Never prunes before first real user message (bootstrap protection)
- Protects last 3 assistant messages and their corresponding tool results
- Skips image-containing tool results
- Respects tool allow/deny lists

Enabled by default in tokens/summary compaction modes.
2026-02-05 15:50:58 +08:00
Naiyuan Qing
22bd392cb0 refactor(desktop): reuse shared ChatView, DevicePairing, and hooks in chat page
Replace Zustand-based message/connection stores with local state hooks.
useLocalChat now returns UseChatReturn shape with internal agentId discovery,
tool execution events, and error handling. Remote mode uses shared
useGatewayConnection + useChat + DevicePairing from packages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:43:39 +08:00
LinYushen
6ebd610ffe
Merge pull request #94 from multica-ai/compaction-feedback
feat: add compaction feedback events
2026-02-05 15:41:38 +08:00
yushen
d42cd8b2e1 docs: add client streaming protocol reference
Document how clients receive real-time events via WebSocket and IPC,
covering message lifecycle, tool execution, and compaction events with
full data structure definitions and routing pseudocode.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:39:21 +08:00
Naiyuan Qing
b896ac402a refactor(ui): self-contain Loading/Spinner styles and clarify usage semantics
Move all CSS out of globals.css into inline styles within each component.
Loading (Apple-style radiating lines) for passive waiting states;
Spinner (3x3 grid pulse) for active processing/execution states.
Switch device-pairing ConnectionStatus from Loading to Spinner.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:38:39 +08:00
yushen
0421efb824 fix(desktop): add compaction event types to LocalChatEvent
Widen the LocalChatEvent.event.type union to include compaction_start
and compaction_end, fixing TS2367 comparison errors in use-local-chat.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:35:51 +08:00
yushen
f0a359ba64 fix(agent): emit compaction events only when compacted 2026-02-05 15:32:41 +08:00
Naiyuan Qing
53c350ea33 refactor(ui,hooks): extract shared ChatView and DevicePairing to packages
- Extract ChatView from web chat-page into packages/ui as a prop-driven
  component (accepts UseChatReturn shape, no transport dependency)
- Move DevicePairing from apps/web to packages/ui with locally defined
  ConnectionIdentity type (no @multica/hooks dependency)
- Create @multica/hooks package with useGatewayConnection and useChat
  (moved from apps/web/hooks)
- Add isLoadingHistory state to useChat with skeleton loading in ChatView
- Add MulticaIcon (pure CSS asterisk via clip-path, adapts to theme)
- Slim web chat-page.tsx from 188 to 65 lines (just wires hooks to UI)

Desktop can now reuse ChatView and DevicePairing directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:28:44 +08:00
yushen
8f9dcbf7e5 fix(agent): address compaction feedback review findings
- Wrap maybeCompact() in try/catch to ensure compaction_end always fires
- Widen multicaListeners type to match subscribeAll() callback signature
- Import CompactionEndEvent from SDK instead of inline type casts
- Add doc comment explaining reason field type difference (agent vs SDK)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:27:08 +08:00
Jiang Bohan
0b69c8f160 docs: simplify README and add development section 2026-02-05 15:21:15 +08:00
Jiang Bohan
79e1dc0acd refactor(prompt): update profile and memory sections
- Profile: add usage hint for base path
- Memory Recall: clear step-by-step instructions for search and update

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:14:09 +08:00