Commit graph

198 commits

Author SHA1 Message Date
Jiayuan Zhang
7ac90a2ce7 feat(tools): add image resize wrapper for read tool
Wraps the read tool from pi-coding-agent to automatically downscale
oversized images (>1MB or >2000px) before they enter the session.
Uses macOS sips for resize with no extra dependencies, following the
same pattern as OpenClaw. Falls back gracefully on non-macOS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:12:37 +08:00
Jiayuan Zhang
278334474f feat(session): externalize base64 images from session JSONL
Session JSONL files were bloated because base64 image data was stored
inline (a real session had 6.7MB of images in a 9.8MB file). Images
are now extracted to per-session media/ directories as binary files,
with compact $ref references stored in the JSONL. Images are restored
transparently on read. Old sessions with inline base64 remain
backward compatible and auto-migrate on next compaction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:12:30 +08:00
Jiang Bohan
a490c737cc feat(providers): add gpt-5.3-codex and update OpenAI model lists
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:55:16 +08:00
Jiang Bohan
16c325c808 fix(oauth): don't expire OAuth credentials that have refresh_token
Codex and Claude Code OAuth tokens with refresh_token can auto-renew,
so they should not be considered expired based on last_refresh time or
file mtime. Previously, credentials were hardcoded to expire after 1
hour, causing valid Codex sessions to show as unconfigured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:42:24 +08:00
Naiyuan Qing
e87e39f13b docs: add monorepo development workflow documentation
- Update root dev script to build packages before watching
- Add --no-dts flag to package dev scripts to avoid DTS race conditions
- Document monorepo development workflow in README

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 09:21:47 +08:00
Naiyuan Qing
374ce68b84 fix(ui): remove math plugins and disable single-tilde strikethrough
- Remove remarkMath and rehypeKatex plugins that caused text wrapping
  issues by interpreting $ signs as LaTeX delimiters
- Configure remarkGfm with singleTilde: false to prevent single ~ from
  being parsed as strikethrough (e.g., ~1000 should not become <del>)
- Only double tilde ~~text~~ now renders as strikethrough

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 08:33:56 +08:00
Jiayuan Zhang
0c6cdb0d3a fix(hub): initialize channelManager before restoreAgents
Move channel plugin initialization (initChannels + ChannelManager
constructor) before restoreAgents() to prevent TypeError when
createAgent() calls channelManager.listChannelInfos() during restore.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:40:16 +08:00
Jiayuan Zhang
c64616512a feat(hub): wire send_file callback with dual-path routing
Create onChannelSendFile callback in Hub.createAgent() that tries the
channel plugin path first (local file), then falls back to the gateway
path (base64 over RoutedMessage). Also pass channel info to agent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:35 +08:00
Jiayuan Zhang
0ebd9d6b22 feat(agent): add connected channels section to system prompt
Add ChannelInfo type and buildChannelsSection() that informs the LLM
about connected messaging channels and their capabilities (e.g. send
files). Wire through SystemPromptOptions and runner.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:29 +08:00
Jiayuan Zhang
01b89ed488 feat(channels): add message source prefix, sendFile, and channel info
Prepend [ChannelName · private/group] prefix to debounced messages so
the LLM knows the message source. Add sendFile() for outbound media
routing and listChannelInfos() for system prompt channel awareness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:22 +08:00
Jiayuan Zhang
a29366d7cf feat(agent): add send_file tool for channel file sending
New send_file tool with TypeBox schema, auto-detect media type from
file extension, and file validation. Wired through AgentOptions and
resolveTools with conditional registration when callback is provided.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:15 +08:00
Jiayuan Zhang
6e96fd1306 feat(channels): add outbound media types and sendMedia to channel adapter
Add OutboundMedia interface and OutboundMediaType to the channel type
system. Implement sendMedia in the Telegram plugin using grammy's
InputFile API with HTML caption formatting and plain-text fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:08 +08:00
Jiayuan Zhang
ade7f2b056
feat(agent): add search-then-fetch guidance to web tools system prompt (#150)
Guide the LLM to evaluate snippet quality after web_search and
follow up with web_fetch on the most relevant URLs when deeper
content is needed for accurate answers.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:50:13 +08:00
Bohan Jiang
a986456e72
Merge pull request #148 from multica-ai/refactor/workspace-documents
refactor(agent): move workspace to ~/Documents/Multica
2026-02-12 23:08:57 +08:00
Bohan Jiang
d385915f95
Merge pull request #149 from multica-ai/feat/default-agent-name-multica
feat(profile): default new agent name to "Multica"
2026-02-12 23:08:33 +08:00
Jiang Bohan
02b480dc47 feat(profile): default new agent name to "Multica" instead of "Assistant"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:48:40 +08:00
Jiang Bohan
cb2dfd246f refactor(agent): move workspace to ~/Documents/Multica
Hidden directory ~/.super-multica is not user-friendly for a working
directory. Move default workspace base to ~/Documents/Multica so
users can easily find agent-created files in Finder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:04:20 +08:00
Naiyuan Qing
71433fc4ed
Merge pull request #146 from multica-ai/feat/message-source-tracking
feat(core): add message source tracking and persistence
2026-02-12 18:51:23 +08:00
Naiyuan Qing
8199dde1b6 feat(core): add message source tracking and persistence
- Add MessageSource type to track where user messages originate (local, gateway, channel)
- Broadcast inbound messages from all channels to local Desktop UI via Hub.onInboundMessage()
- Persist source field in JSONL session storage so it survives page refresh
- Display source icon (Monitor/Smartphone/Send) with tooltip for non-local user messages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 18:45:15 +08:00
Jiang Bohan
18ab2da8c4 test(agent): add workspace resolution and initialization tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:08:04 +08:00
Jiang Bohan
ca0b4624fd feat(agent): add default workspace directory per profile
Each agent profile now gets a dedicated workspace directory
(~/.super-multica/workspace/{profileId}) used as the default CWD
for tool operations. Supports override via MULTICA_WORKSPACE_DIR
env var or config.json workspaceDir field. The workspace path is
injected into system prompt and runtime info.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:07:59 +08:00
Jiang Bohan
5b0cbd4d7d feat(subagent): increase default timeout from 10 min to 30 min
A subagent that times out loses all its work, so a generous default
reduces wasted compute. Update the constant, tool description, system
prompt guidelines, and documentation to reflect the new 1800s default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:54:53 +08:00
Bohan Jiang
28c83af0d3
Merge pull request #141 from multica-ai/fix/writeinternal-retry
fix(agent): retry writeInternal once on transient LLM errors
2026-02-12 17:31:03 +08:00
LinYushen
8bc36a9cc9
Merge pull request #136 from multica-ai/fix/agent-compaction
fix(agent): prevent context window overflow with 3-layer compaction defense
2026-02-12 17:23:12 +08:00
Jiang Bohan
d627fb4ff4 fix(agent): retry writeInternal once on transient LLM errors
When writeInternal fails with a transient error (e.g. undici
"terminated", connection reset, 502/503), wait 5 seconds and retry
once. This prevents continuation tasks from silently failing when
the LLM streaming connection is interrupted mid-generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:19:52 +08:00
Jiang Bohan
6b9e5d5f40 refactor(subagent): improve system prompt with anti-hallucination and group guidance
Rewrite Sub-Agents section: add explicit anti-hallucination rules (never
fabricate completion status), make group/next the recommended pattern for
multi-agent tasks, remove sessions_list polling restrictions, add usage
examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:11:38 +08:00
Jiang Bohan
48185c3e77 feat(subagent): add groupId/next params to spawn and group display to list
sessions_spawn now accepts groupId and next parameters. First spawn with
next auto-creates a group; subsequent spawns join via groupId. sessions_list
groups runs by groupId with completion progress display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:11:31 +08:00
Jiang Bohan
f46c00e902 feat(subagent): update announce flow for group continuation
When all runs in a group complete, deliver combined findings plus the
`next` continuation prompt to the parent agent via writeInternal. The
parent can then act on the collected data (summarize, write files, etc).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:11:25 +08:00
Jiang Bohan
12fb12b895 feat(subagent): add SubagentGroup type and registry support
Add SubagentGroup for "collect all, then act" workflows where multiple
subagents complete before a continuation task runs. Groups are persisted
alongside run records and support a `next` continuation prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:11:20 +08:00
Naiyuan Qing
bad4d05c15
Merge pull request #138 from multica-ai/refactor/desktop-page-restructure
refactor(desktop): restructure pages and add dev reset scripts
2026-02-12 16:45:07 +08:00
yushen
8f4e894370 feat(ui): show in-chat system message when context compaction occurs
Add CompactionItem component that renders a subtle inline notification
in the chat stream when the agent compacts its context window. Extends
Message type with "system" role and handles compaction_end events in
useChat's handleStream.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:10:19 +08:00
Naiyuan Qing
bc9b7d6fc5 refactor(desktop): restructure pages and consolidate UI components
- Rename channels.tsx to clients.tsx
- Remove standalone skills.tsx and tools.tsx pages
- Add agent/ directory for agent-related pages
- Update layout and navigation structure
- Add tabs component to ui package
- Update fonts and global styles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:49:52 +08:00
yushen
9c52dc0124 fix(agent): 3-layer defense against context window overflow
Root cause: compaction only ran after successful assistant response,
never before calling the LLM API. Internal runs skipped it entirely,
and the fire-and-forget void swallowed errors with race conditions.

Layer 1 - Pre-flight compaction in transformContext:
  Runs before EVERY LLM call (including internal runs). Prunes tool
  results and drops oldest messages when utilization exceeds 80%.
  Pure in-memory, no disk writes.

Layer 2 - Fix post-hoc compaction:
  Store compaction promise instead of voiding it, await at _run() start
  to prevent race conditions. Emit compaction_start before the actual
  compaction. Remove useless catch-rethrow block.

Layer 3 - Context overflow recovery:
  Catch context overflow 400 errors → auto-compact → retry (up to 2
  attempts). Runs before classifyError/auth rotation so overflow errors
  are handled by compaction, not profile switching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:52:19 +08:00
Jiang Bohan
ece00cac2b merge: resolve conflict with main (lucide-react migration)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:47:00 +08:00
yushen
b13d40c6da fix(agent): increase token estimation safety margins
- ESTIMATION_SAFETY_MARGIN: 1.2 → 1.5 (50% buffer covers CJK text)
- estimateSystemPromptTokens: /3 → /2 (conservative for mixed content)

This makes the 80% compaction trigger fire earlier, reducing the gap
between estimated and actual token counts that caused overflow errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:43:43 +08:00
yushen
f8ca4ca95e feat(agent): add isContextOverflowError utility
Detects context overflow 400 errors from various LLM providers
(prompt too long, context length exceeded, request too large, etc.)
for use in auto-compaction recovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:43:33 +08:00
Jiang Bohan
a33df19bef feat(desktop): add chat abort support with partial content preservation
Add stop button to interrupt agent generation mid-stream. The send button
toggles to a stop icon during loading. Abort propagates from UI through
IPC to the Agent layer (PiAgentCore.abort()), preserving all partial
content in the agent's context so users can follow up immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:33:06 +08:00
Naiyuan Qing
b310b57ce9 merge: integrate origin/main into feat/onboarding-check
Resolved conflicts:
- Keep Lucide icons (replaced Hugeicons) in desktop and ui
- Keep new Sidebar layout design
- Merge new dependencies (electron-updater, lucide-react, katex)
- Add new 'data' tool with Lucide BarChart3 icon
- Keep UpdateNotification component (not integrated into UI yet)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 11:16:49 +08:00
Naiyuan Qing
eb4e1f57b1 feat(desktop): persist onboarding state to file system
- Add AppState module in core for managing app state persistence
- Add app-state IPC handlers for reading/writing onboarding state
- Hydrate onboarding state from file system on app startup
- Prevent flash by showing blank screen during hydration
- Update onboarding store to sync with file system
- Improve MulticaIcon with enhanced animation states
- Minor UI fixes in chat and device list components

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 10:53:04 +08:00
Naiyuan Qing
6037be2efa refactor: migrate from Hugeicons to Lucide icons
- Replace @hugeicons/react with lucide-react across all packages
- Update all components to use Lucide icon components
- Add silent option to store refresh methods to control toast display
- Simplify icon usage with direct component imports

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 10:12:56 +08:00
Naiyuan Qing
b718b95da7 fix(ui): improve chat input scroll behavior
- Scroll cursor into view on content changes (e.g., Shift+Enter)
- Add scroll threshold and margin for better edge handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 09:39:16 +08:00
Naiyuan Qing
d1d3cd0a9f feat(ui): add collapsible component
Add Radix-based collapsible component for accordion-style UI sections.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 09:38:56 +08:00
Jiayuan Zhang
953041efa0 feat(ui): add LaTeX math rendering support to chat markdown
Add remark-math + rehype-katex plugins to render inline ($...$) and
display ($$...$$) math expressions. Includes dark mode CSS overrides,
streaming block splitting for math fences, and math range exclusion
in link preprocessing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:57:52 +08:00
Jiayuan Zhang
b5f63f7f7c
Merge pull request #130 from multica-ai/forrestchang/finance-pr
feat(finance): add internal evidence decision engine
2026-02-11 20:39:29 +08:00
Jiayuan Zhang
24435cdba4 refactor(agent): remove hasWebTools conditional in data section
Web tools are always available, so the conditional branching was
unnecessary. Data section now always includes the dynamic evidence
decision guidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:31:40 +08:00
Jiayuan Zhang
0330b8b7ca refactor(agent): remove keyword-based finance decisioner
The finance-decisioner used hardcoded keyword matching and arbitrary
scoring weights to decide evidence plans — the LLM reading the
improved SKILL.md already makes this decision more intelligently.

Removes: finance-decisioner.ts, its tests, runner.ts integration
(applyFinanceResearchGuidance, saveFinanceDecisionMeta,
rebuildSystemPromptWithExtra shim), and researchDecision from
session meta.

Keeps: SKILL.md improvements, sections.ts dynamic data/web guidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:29:14 +08:00
Jiayuan Zhang
4c4f8989ca feat(agent): add internal finance evidence decisioner 2026-02-11 20:02:30 +08:00
Jiang Bohan
c49ab1fee4 fix(heartbeat): use internal run to hide heartbeat from chat history
The heartbeat runner used agent.write() (normal write), which persisted
both the heartbeat prompt and HEARTBEAT_OK response as regular messages
visible in the UI chat history.

Switch to runInternalForResult() — a new AsyncAgent method that runs
via runInternal() (messages marked internal: true, rolled back from
in-memory state). This hides both the heartbeat prompt and response
from the UI entirely, while still persisting to JSONL for diagnostics.

The previous commit's event-stream heartbeat ACK filter remains as a
defense-in-depth layer for edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 19:41:57 +08:00
Jiang Bohan
8d6a803739 fix(agent): filter heartbeat ACK messages from desktop event stream
The heartbeat runner uses agent.write() (normal write), so heartbeat
ACK responses like "HEARTBEAT_OK" were not suppressed by the internal
run filter and leaked into the desktop UI chat. The Gateway path was
already fixed (Hub has delayed-start + isHeartbeatAckEvent filtering),
but the local Desktop path through AsyncAgent had no such filtering.

Add createFilteredHandler() to AsyncAgent that buffers message_start
for assistant messages and checks subsequent events with
isHeartbeatAckEvent(). Pure heartbeat ACKs are suppressed end-to-end;
all other messages are forwarded normally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 19:34:23 +08:00
Bohan Jiang
16cd5d0aaf
Merge pull request #126 from multica-ai/feat/subagent-announce-delivery
feat(subagent): two-tier announce delivery, provider inheritance, error propagation
2026-02-11 19:04:39 +08:00