From a80c858ce59dd4fdaa216b1d6bd8a022fef3bc25 Mon Sep 17 00:00:00 2001 From: Jiang Bohan Date: Wed, 4 Feb 2026 03:12:12 +0800 Subject: [PATCH 1/7] 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 --- src/agent/async-agent.ts | 28 ++++++++++++++++++++++++++++ src/agent/profile/index.ts | 37 +++++++++++++++++++++++++++++++++++++ src/agent/profile/types.ts | 2 ++ src/agent/runner.ts | 28 ++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/src/agent/async-agent.ts b/src/agent/async-agent.ts index 86ae5d90..cee3b3e8 100644 --- a/src/agent/async-agent.ts +++ b/src/agent/async-agent.ts @@ -148,4 +148,32 @@ export class AsyncAgent { getProfileId(): string | undefined { return this.agent.getProfileId(); } + + /** + * Get agent display name from profile config. + */ + getAgentName(): string | undefined { + return this.agent.getAgentName(); + } + + /** + * Update agent display name in profile config. + */ + setAgentName(name: string): void { + this.agent.setAgentName(name); + } + + /** + * Get user.md content from profile. + */ + getUserContent(): string | undefined { + return this.agent.getUserContent(); + } + + /** + * Update user.md content in profile. + */ + setUserContent(content: string): void { + this.agent.setUserContent(content); + } } diff --git a/src/agent/profile/index.ts b/src/agent/profile/index.ts index bc41e046..556dead3 100644 --- a/src/agent/profile/index.ts +++ b/src/agent/profile/index.ts @@ -13,7 +13,10 @@ import { loadProfile, profileExists, saveProfile, + writeProfileConfig, + writeProfileFile, } from "./storage.js"; +import { PROFILE_FILES } from "./types.js"; export { type AgentProfile, type CreateProfileOptions, type ProfileConfig, type ProfileManagerOptions } from "./types.js"; export { DEFAULT_TEMPLATES } from "./templates.js"; @@ -215,4 +218,38 @@ export class ProfileManager { this.updateToolsConfig(newConfig); return newConfig; } + + /** 获取 Agent 名称 */ + getName(): string | undefined { + const profile = this.getProfile(); + return profile?.config?.name; + } + + /** 更新 Agent 名称 */ + updateName(name: string): void { + const profile = this.getOrCreateProfile(false); + const currentConfig = profile.config ?? {}; + const newConfig: ProfileConfig = { + ...currentConfig, + name, + }; + profile.config = newConfig; + this.profile = profile; + writeProfileConfig(this.profileId, newConfig, { baseDir: this.baseDir }); + } + + /** 获取 user.md 内容 */ + getUserContent(): string | undefined { + const profile = this.getProfile(); + return profile?.user; + } + + /** 更新 user.md 内容 */ + updateUserContent(content: string): void { + writeProfileFile(this.profileId, PROFILE_FILES.user, content, { baseDir: this.baseDir }); + // Update cached profile + if (this.profile) { + this.profile.user = content; + } + } } diff --git a/src/agent/profile/types.ts b/src/agent/profile/types.ts index 4565d7df..db313ceb 100644 --- a/src/agent/profile/types.ts +++ b/src/agent/profile/types.ts @@ -15,6 +15,8 @@ export const PROFILE_FILES = { /** Profile config.json structure */ export interface ProfileConfig { + /** Agent display name */ + name?: string; /** Tools policy configuration */ tools?: ToolsConfig; /** Default LLM provider */ diff --git a/src/agent/runner.ts b/src/agent/runner.ts index bdc9e203..9a013e93 100644 --- a/src/agent/runner.ts +++ b/src/agent/runner.ts @@ -532,4 +532,32 @@ export class Agent { getProfileId(): string | undefined { return this.profile?.getProfile()?.id; } + + /** + * Get agent display name from profile config. + */ + getAgentName(): string | undefined { + return this.profile?.getName(); + } + + /** + * Update agent display name in profile config. + */ + setAgentName(name: string): void { + this.profile?.updateName(name); + } + + /** + * Get user.md content from profile. + */ + getUserContent(): string | undefined { + return this.profile?.getUserContent(); + } + + /** + * Update user.md content in profile. + */ + setUserContent(content: string): void { + this.profile?.updateUserContent(content); + } } From a157c6546dc853b9193f69dc6202597dec0a72d9 Mon Sep 17 00:00:00 2001 From: Jiang Bohan Date: Wed, 4 Feb 2026 03:12:17 +0800 Subject: [PATCH 2/7] feat(desktop): add profile IPC handlers Add IPC handlers for profile management: - profile:get - Get profile name and user content - profile:updateName - Update agent display name - profile:updateUser - Update user.md content Co-Authored-By: Claude Opus 4.5 --- apps/desktop/electron/electron-env.d.ts | 11 ++++ apps/desktop/electron/ipc/index.ts | 3 + apps/desktop/electron/ipc/profile.ts | 80 +++++++++++++++++++++++++ apps/desktop/electron/preload.ts | 13 ++++ 4 files changed, 107 insertions(+) create mode 100644 apps/desktop/electron/ipc/profile.ts diff --git a/apps/desktop/electron/electron-env.d.ts b/apps/desktop/electron/electron-env.d.ts index 583a19b9..c92ef48a 100644 --- a/apps/desktop/electron/electron-env.d.ts +++ b/apps/desktop/electron/electron-env.d.ts @@ -65,6 +65,12 @@ interface SkillAddResult { skills?: string[] } +interface ProfileData { + profileId: string | undefined + name: string | undefined + userContent: string | undefined +} + interface ElectronAPI { hub: { init: () => Promise @@ -97,6 +103,11 @@ interface ElectronAPI { agent: { status: () => Promise } + profile: { + get: () => Promise + updateName: (name: string) => Promise + updateUser: (content: string) => Promise + } } // Used in Renderer process, expose in `preload.ts` diff --git a/apps/desktop/electron/ipc/index.ts b/apps/desktop/electron/ipc/index.ts index 71bbec88..762fe18f 100644 --- a/apps/desktop/electron/ipc/index.ts +++ b/apps/desktop/electron/ipc/index.ts @@ -4,10 +4,12 @@ export { registerAgentIpcHandlers, cleanupAgent } from './agent.js' export { registerSkillsIpcHandlers } from './skills.js' export { registerHubIpcHandlers, cleanupHub, initializeHub } from './hub.js' +export { registerProfileIpcHandlers } from './profile.js' import { registerAgentIpcHandlers, cleanupAgent } from './agent.js' import { registerSkillsIpcHandlers } from './skills.js' import { registerHubIpcHandlers, cleanupHub, initializeHub } from './hub.js' +import { registerProfileIpcHandlers } from './profile.js' /** * Register all IPC handlers. @@ -17,6 +19,7 @@ export function registerAllIpcHandlers(): void { registerHubIpcHandlers() registerAgentIpcHandlers() registerSkillsIpcHandlers() + registerProfileIpcHandlers() } /** diff --git a/apps/desktop/electron/ipc/profile.ts b/apps/desktop/electron/ipc/profile.ts new file mode 100644 index 00000000..bfb924da --- /dev/null +++ b/apps/desktop/electron/ipc/profile.ts @@ -0,0 +1,80 @@ +/** + * Profile IPC handlers for Electron main process. + * + * Manages agent profile settings like name and user.md content. + */ +import { ipcMain } from 'electron' +import { getCurrentHub } from './hub.js' + +/** + * Get the default agent from Hub. + */ +function getDefaultAgent() { + const hub = getCurrentHub() + if (!hub) return null + + const agentIds = hub.listAgents() + if (agentIds.length === 0) return null + + return hub.getAgent(agentIds[0]) ?? null +} + +/** + * Profile data returned to renderer. + */ +export interface ProfileData { + profileId: string | undefined + name: string | undefined + userContent: string | undefined +} + +/** + * Register all Profile-related IPC handlers. + */ +export function registerProfileIpcHandlers(): void { + /** + * Get profile data (name + user content). + */ + ipcMain.handle('profile:get', async (): Promise => { + const agent = getDefaultAgent() + if (!agent) { + return { + profileId: undefined, + name: undefined, + userContent: undefined, + } + } + + return { + profileId: agent.getProfileId(), + name: agent.getAgentName(), + userContent: agent.getUserContent(), + } + }) + + /** + * Update agent display name. + */ + ipcMain.handle('profile:updateName', async (_event, name: string) => { + const agent = getDefaultAgent() + if (!agent) { + return { error: 'No agent available' } + } + + agent.setAgentName(name) + return { ok: true, name } + }) + + /** + * Update user.md content. + */ + ipcMain.handle('profile:updateUser', async (_event, content: string) => { + const agent = getDefaultAgent() + if (!agent) { + return { error: 'No agent available' } + } + + agent.setUserContent(content) + return { ok: true } + }) +} diff --git a/apps/desktop/electron/preload.ts b/apps/desktop/electron/preload.ts index 8c898819..e0afbf9a 100644 --- a/apps/desktop/electron/preload.ts +++ b/apps/desktop/electron/preload.ts @@ -37,6 +37,12 @@ export interface SkillInfo { triggers: string[] } +export interface ProfileData { + profileId: string | undefined + name: string | undefined + userContent: string | undefined +} + // ============================================================================ // Expose typed API to Renderer process // ============================================================================ @@ -84,6 +90,13 @@ const electronAPI = { agent: { status: () => ipcRenderer.invoke('agent:status'), }, + + // Profile management + profile: { + get: (): Promise => ipcRenderer.invoke('profile:get'), + updateName: (name: string) => ipcRenderer.invoke('profile:updateName', name), + updateUser: (content: string) => ipcRenderer.invoke('profile:updateUser', content), + }, } // Expose to renderer From bdc2006e0ea026eaaefc0a2dff229776f35878db Mon Sep 17 00:00:00 2001 From: Jiang Bohan Date: Wed, 4 Feb 2026 03:12:22 +0800 Subject: [PATCH 3/7] feat(desktop): add agent settings dialog Add UI for editing agent name and user preferences: - AgentSettingsDialog component with name input and user.md textarea - Agent Settings section on Home page with Edit button - Auto-reload agent info when settings are saved Co-Authored-By: Claude Opus 4.5 --- .../src/components/agent-settings-dialog.tsx | 130 ++++++++++++++++++ apps/desktop/src/pages/home.tsx | 65 ++++++++- 2 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 apps/desktop/src/components/agent-settings-dialog.tsx diff --git a/apps/desktop/src/components/agent-settings-dialog.tsx b/apps/desktop/src/components/agent-settings-dialog.tsx new file mode 100644 index 00000000..3f44d548 --- /dev/null +++ b/apps/desktop/src/components/agent-settings-dialog.tsx @@ -0,0 +1,130 @@ +import { useState, useEffect } from 'react' +import { + Dialog, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} from '@multica/ui/components/ui/dialog' +import { Button } from '@multica/ui/components/ui/button' +import { Input } from '@multica/ui/components/ui/input' +import { Textarea } from '@multica/ui/components/ui/textarea' +import { Label } from '@multica/ui/components/ui/label' +import { HugeiconsIcon } from '@hugeicons/react' +import { Loading03Icon } from '@hugeicons/core-free-icons' + +interface AgentSettingsDialogProps { + open: boolean + onOpenChange: (open: boolean) => void +} + +export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogProps) { + const [loading, setLoading] = useState(false) + const [saving, setSaving] = useState(false) + const [name, setName] = useState('') + const [userContent, setUserContent] = useState('') + const [profileId, setProfileId] = useState() + + // Load profile data when dialog opens + useEffect(() => { + if (open) { + loadProfile() + } + }, [open]) + + const loadProfile = async () => { + setLoading(true) + try { + const data = await window.electronAPI.profile.get() + setProfileId(data.profileId) + setName(data.name ?? '') + setUserContent(data.userContent ?? '') + } catch (err) { + console.error('Failed to load profile:', err) + } finally { + setLoading(false) + } + } + + const handleSave = async () => { + setSaving(true) + try { + // Update name if changed + await window.electronAPI.profile.updateName(name) + // Update user content + await window.electronAPI.profile.updateUser(userContent) + onOpenChange(false) + } catch (err) { + console.error('Failed to save profile:', err) + } finally { + setSaving(false) + } + } + + return ( + + + + Edit Agent + + Customize your agent's name and personal settings. + + + + {loading ? ( +
+ +
+ ) : ( +
+ {/* Profile ID (read-only) */} + {profileId && ( +
+ Profile: {profileId} +
+ )} + + {/* Name */} +
+ + setName(e.target.value)} + placeholder="My Assistant" + /> +
+ + {/* User Content */} +
+ +

+ Help the agent understand you better. Share your preferences, role, or any context. +

+