Commit graph

189 commits

Author SHA1 Message Date
yushen
f733f0bcc3 fix(agent): fix system prompt reload and tool casing issues
- reloadSystemPrompt() now updates both agent and session prompt
- reloadSystemPrompt() uses buildSkillsPrompt() consistently (not buildModelSkillsPrompt)
- Extract rebuildSystemPrompt() to eliminate duplicated builder logic
- Preserve original tool name casing in tooling summary (matching OpenClaw)
- Fix report line count to use actual newline count

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 15:46:18 +08:00
yushen
8333615fb4 refactor(agent): integrate system prompt builder into profile, runner, and subagent
ProfileManager.buildSystemPrompt() now delegates to the structured builder.
Runner assembles prompt after tool resolution with safety, tooling summary,
and runtime info. Subagent prompts use minimal mode with safety constitution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 15:41:22 +08:00
yushen
5a06bed549 feat(agent): add system prompt engineering module
Structured, mode-aware system prompt builder inspired by OpenClaw.
Supports three modes (full/minimal/none), safety constitution,
conditional tool sections, runtime info, and prompt telemetry.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 15:41:16 +08:00
Bohan Jiang
5760b86e80
Merge pull request #79 from multica-ai/feat/agent-style-setting
feat(desktop): add agent communication style setting
2026-02-04 14:48:29 +08:00
Jiang Bohan
4df39448be feat(agent): add communication style setting to profile
- Add AgentStyle type with 6 preset options (professional, friendly, etc.)
- Add getStyle/setStyle methods to ProfileManager
- Update soul.md template to include style section
- Add reloadSystemPrompt support for style changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:42:23 +08:00
yushen
f63a67e341 refactor(hub): improve device whitelist persistence format
- Rename storage path from ~/.super-multica/devices/ to
  ~/.super-multica/client-devices/ for clarity
- Change JSON format from bare array to { version, devices[] }
  dict for future extensibility
- Auto-migrate legacy array format on load

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:16:59 +08:00
yushen
c3ded8da41 merge: resolve conflicts with origin/main
Merge remote main branch, keeping both device verification (ws-auth-handshake)
and agent settings/profile features from main.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:04:47 +08:00
yushen
c604085065 fix(desktop): address review issues in device verification flow
- Add 60s timeout to pending device confirms to prevent Promise leaks
  when client disconnects before user responds
- Add offDeviceConfirmRequest to preload and clean up IPC listener on
  component unmount to prevent duplicate listener accumulation
- Extract duplicated parseUserAgent into shared lib/parse-user-agent.ts
- Clean up expired tokens in DeviceStore.registerToken to prevent
  memory accumulation from unscanned QR codes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:54:09 +08:00
yushen
ef9b5af221 fix(hub): send error response to unverified device instead of silent drop
When an unverified device sends a non-RPC message, reply with an
"error" action containing UNAUTHORIZED code so the client knows
verification is required.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:46:29 +08:00
yushen
c581183839 feat(hub): store device metadata in whitelist and pass to confirm handler
Extend DeviceEntry with optional DeviceMeta field. Verify handler
extracts meta from params and passes it through to onConfirmDevice
callback and deviceStore.allowDevice for persistence.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:43:48 +08:00
yushen
b2c0711676 feat(hub): add device verification with token + whitelist + user confirmation
Add DeviceStore for managing one-time tokens and persistent device
whitelist. Create async verify RPC handler that validates tokens and
awaits Desktop user confirmation for first-time connections. Whitelisted
devices (reconnections) pass through instantly. Add message guard to
reject unverified device traffic.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:27:29 +08:00
Jiang Bohan
fa03ae6e62 feat(agent): add soul.md support for agent identity
- Add getSoulContent/updateSoulContent to ProfileManager
- Create soul.md with agent name when updating profile name
- Add reloadSystemPrompt() method to Agent and AsyncAgent
- Include soul.md content in system prompt build

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:26:40 +08:00
Jiang Bohan
a80c858ce5 feat(agent): add profile name and user content management
Add methods to ProfileManager, Agent, and AsyncAgent for:
- Getting/setting agent display name (stored in config.json)
- Getting/setting user.md content

This enables the desktop app to manage agent settings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:26:40 +08:00
Jiang Bohan
f5a0d986a2 fix(desktop): resolve TypeScript build errors
- Disable noUnusedLocals/noUnusedParameters in desktop tsconfig
  (external src/ files have unused imports that fail strict checking)
- Add TSchema constraint to wrapTool generic to satisfy AgentTool type

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 19:26:25 +08:00
Jiang Bohan
4112d4511e fix(agent): resolve TypeScript errors with exactOptionalPropertyTypes
- Fix originalToolsConfig assignment to handle undefined properly
- Fix devNull type cast for WritableStream compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:58:45 +08:00
Jiang Bohan
dafbf856ac merge: resolve conflicts with main branch
- Merge auth-profiles feature from main into runner.ts
- Merge closeCallbacks feature from main into async-agent.ts
- Regenerate pnpm-lock.yaml with new dependencies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:57:05 +08:00
yushen
a065d5f64c fix(auth-profiles): add jittered cooldowns 2026-02-03 18:27:21 +08:00
Jiang Bohan
864d9166fc feat(hub): support profileId in createAgent
- Add profileId option to createAgent() method
- Default to "default" profile for all agents
- Ensures every agent has an associated profile for memory and config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:25:48 +08:00
Jiang Bohan
6f6a4f82e4 feat(agent): add tools and skills management methods
- Add setToolStatus() to persist tool enable/disable to profile config
- Add getActiveTools() and reloadTools() methods
- Add getSkillsWithStatus(), getEligibleSkills(), reloadSkills() methods
- Add updateToolsConfig() and setToolEnabled() to ProfileManager
- Ensure profile directory is created on Agent initialization
- Fix reloadTools() to re-read profile config for latest changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:25:43 +08:00
yushen
9ed4cdf2b0 fix(agent): handle auth profile failures and provider mismatch 2026-02-03 18:23:18 +08:00
yushen
617ddfbfea refactor(auth-profiles): replace proper-lockfile with custom file lock
Unify locking strategy across the project by using a custom synchronous
file lock (exclusive-create based, with PID stale detection) instead of
the proper-lockfile dependency, matching the pattern in session-write-lock.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:05:00 +08:00
yushen
4b10420324 Merge remote-tracking branch 'origin/main' into auth-profile-rotation
# Conflicts:
#	pnpm-lock.yaml
#	src/agent/runner.ts
2026-02-03 17:58:50 +08:00
yushen
0fee16f735 test(session): reset lock mock 2026-02-03 17:49:26 +08:00
yushen
f2ca86aa1f fix(session): harden write lock and repair 2026-02-03 17:47:41 +08:00
yushen
f1334349ca Merge remote-tracking branch 'origin/main' into session-writelock-repair 2026-02-03 17:45:56 +08:00
yushen
e8815dbb97 fix(agent): loop-based rotation, timeout rotatable, error classification tests
- Replace single-retry with while loop that exhausts all candidate profiles
- Add "format" detection to classifyError (400, malformed, bad request, schema)
- Make timeout errors rotatable (some providers hang on rate limit)
- Export classifyError and isRotatableError for testing
- Add error-classification.test.ts with coverage for all failure reasons

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:26:16 +08:00
yushen
a8c5042554 fix(auth-profiles): add file locking, type priority sort, credential filtering
- Add proper-lockfile for concurrent-safe store updates with fallback
- Add "format" to AuthProfileFailureReason
- Two-level round-robin sort: credential type priority (OAuth > API key), then lastUsed
- Filter out profiles with missing/invalid credentials from candidates
- Add preferredProfile option to resolveAuthProfileOrder
- Export coerceStore and ensureAuthStoreFile for testing
- Add store.test.ts with coerceStore, load/save round-trip, corruption handling
- Update order.test.ts mocks for resolver and registry dependencies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:26:09 +08:00
yushen
30f23459ce fix(agent): align subagent lifecycle with openclaw 2026-02-03 17:22:41 +08:00
yushen
0c549f76e6 feat(session): integrate write lock and auto-repair into session flow
- storage.ts: acquire/release write lock in appendEntry and writeEntries
- session-manager.ts: add repairIfNeeded() method, apply transcript
  sanitization in loadMessages()
- runner.ts: move message loading to lazy async init in run(), call
  repair before loading messages (following OpenClaw's pattern)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:21:26 +08:00
yushen
37e5b2ce7f feat(session): add write lock, file repair, and transcript repair modules
Port from OpenClaw:
- session-write-lock: file-level write lock with atomic creation, reference
  counting, stale lock detection, and process cleanup handlers
- session-file-repair: auto-detect and repair malformed JSONL lines with
  backup and atomic rename
- session-transcript-repair: fix tool call/result pairing issues including
  displaced results, duplicates, orphans, and missing inputs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:21:15 +08:00
yushen
1cd778b845 fix(agent): add task minLength validation, remove unused parentSessionId
Add minLength:1 to sessions_spawn task parameter to prevent empty
task strings. Remove parentSessionId from AgentOptions as the
subagent registry tracks lineage via requesterSessionId.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:02:03 +08:00
yushen
6bd068a97f fix(hub): init subagent registry on startup and cleanup on shutdown
Call initSubagentRegistry() after setHub() in Hub constructor to
restore persisted runs. Call shutdownSubagentRegistry() before
closing agents in shutdown() to mark active runs as ended.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:01:56 +08:00
yushen
918b5d294d fix(agent): resolve stream race condition and add lifecycle tests
Replace for-await stream consumption in watchChildAgent with
waitForIdle() + onClose() callbacks on AsyncAgent. This prevents
conflict with Hub.consumeAgent() which also reads the Channel.

Add shutdownSubagentRegistry() for clean Hub shutdown, guard
Hub access with isHubInitialized(), and clean resumedRuns in sweep.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:01:49 +08:00
yushen
dcc336f2d0 feat(agent): integrate auth profile rotation into runner and resolver
Extend credentials.ts with llm.order and listProfileIdsForProvider.
Add resolveApiKeyForProfile and resolveApiKeyForProvider to resolver.
Modify runner to support dynamic API key swapping and automatic
rotation on auth/rate_limit/billing errors with retry.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 16:56:04 +08:00
yushen
d89b409add feat(agent): add auth profile rotation and cooldown module
Implement multi-profile auth system with exponential-backoff cooldowns,
modeled after OpenClaw's auth-profiles system. Includes types, constants,
persistent store (auth-profiles.json), usage tracking with cooldown
calculation, and profile ordering with round-robin and explicit modes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 16:55:42 +08:00
yushen
83b557a6fc feat(agent): add sessions_spawn tool for subagent orchestration
Register sessions_spawn tool in the tool system with TypeBox schema.
Subagents are blocked from spawning nested subagents via both tool
policy (DEFAULT_SUBAGENT_TOOL_DENY) and runtime guard. Add group:subagent
tool group and parentSessionId to AgentOptions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 16:49:27 +08:00
yushen
5b6a1c6953 feat(hub): add singleton pattern and subagent spawning
Add global Hub singleton for cross-module access by subagent tools.
Add createSubagent() method to Hub for spawning ephemeral child agents
with isSubagent flag and custom system prompts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 16:49:05 +08:00
yushen
85f71e0084 feat(agent): add subagent orchestration core
Implement subagent registry, persistence store, and announcement flow
for child agent lifecycle management. Includes types, registry with
auto-archive sweeper, session JSONL reading for result extraction,
and formatted announcement message delivery.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 16:48:49 +08:00
yushen
203d760034 feat(hub): filter forwarded events to 5 types useful for frontend
Only forward message_start/update/end (assistant role) and
tool_execution_start/end to clients. Drop agent_start, agent_end,
turn_start, turn_end, and tool_execution_update at the Hub layer.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 15:08:46 +08:00
yushen
37ec8ff5e0 fix(streaming): use per-message stream ids and oauth resolver 2026-02-03 14:51:19 +08:00
yushen
273e49f678 feat(agent): stream raw AgentEvent from engine to Hub via Gateway
Expose PiAgentCore events through the full backend pipeline:
- Agent.subscribe() transparently forwards engine events
- AsyncAgent pushes all AgentEvent into Channel alongside error Messages
- Hub discriminates ChannelItem and forwards events via StreamAction

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 14:22:49 +08:00
Jiayuan Zhang
03347d99fd
Merge pull request #62 from multica-ai/forrestchang/agent-error-handling
Fix tool error handling
2026-02-03 02:59:51 +08:00
Jiayuan
0385b0e025 test(agent): convert tool policy test 2026-02-03 02:30:47 +08:00
Naiyuan Qing
7122b12ad5
Merge pull request #61 from multica-ai/feat/text-stream
feat: streaming AI message rendering
2026-02-02 17:45:30 +08:00
Jiang Bohan
c55bb5a864 feat(cli): add /model command for switching models within provider
Add /model command to interactively switch models:
- /model: Show current model and list available models for provider
- /model <name>: Switch to specified model (preserves session)

Example usage:
  /model                    # Shows claude-opus-4-5, claude-sonnet-4-5, etc.
  /model claude-sonnet-4-5  # Switch to sonnet model

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:35:40 +08:00
Jiang Bohan
932ecb5dbb refactor(providers): move oauth/ to providers/oauth/ and simplify model names
- Move src/agent/oauth/ to src/agent/providers/oauth/ (parent-child structure)
- Delete deprecated oauth/providers.ts re-export file
- Simplify Claude model names: claude-opus-4-5 (without date suffix)
- Update Codex models to current lineup (gpt-5.2, gpt-5.1-codex, etc.)
- Set claude-opus-4-5 as default model for claude-code provider

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:35:35 +08:00
Jiang Bohan
1592e0c211 fix(types): add undefined to optional properties for exactOptionalPropertyTypes
- MemoryStorageOptions.baseDir: add | undefined
- FilterToolsOptions: add | undefined to all optional properties
- CreateToolsOptions: add | undefined to optional properties
2026-02-02 17:20:10 +08:00
Jiang Bohan
6723aa8561 refactor(providers): extract provider management to dedicated module
- Create src/agent/providers/ with registry.ts and resolver.ts
- registry.ts: Provider metadata, status checking, login instructions
- resolver.ts: API key resolution, model resolution
- oauth/providers.ts now re-exports from providers/ (deprecated)
- tools.ts: Remove PROVIDER_ALIAS and DEFAULT_MODELS (moved to providers/)
- Update imports in runner.ts and chat.ts

This separates concerns:
- oauth/ only handles OAuth credential reading
- providers/ manages all provider metadata and resolution
2026-02-02 17:20:02 +08:00
Naiyuan Qing
d04bed8175 feat(agent): add streaming support for AI message generation
AsyncAgent now subscribes to pi-agent-core events (message_start,
message_update, message_end) and forwards incremental text deltas
through a stream callback. Hub registers the callback and sends
stream payloads to the requesting client via Gateway.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:18:10 +08:00
Jiang Bohan
35b13f976d feat(runner): validate provider credentials on startup
- Add isOAuthProvider() and isProviderAvailable() helpers
- Show login instructions for OAuth providers without credentials
- Show configuration example for API Key providers without keys
- Fail early with helpful error message instead of cryptic API errors
2026-02-02 17:10:10 +08:00