From 22e225c6a8f20b67a70ea520c1ddd52229fac643 Mon Sep 17 00:00:00 2001 From: Jiang Bohan Date: Mon, 9 Feb 2026 14:24:07 +0800 Subject: [PATCH] refactor(profile): remove Communication Style UI and programmatic API Style is now solely managed by the agent editing soul.md directly, removing the need for UI controls, IPC handlers, and typed constants. Co-Authored-By: Claude Opus 4.6 --- apps/desktop/electron/electron-env.d.ts | 24 ++++---- apps/desktop/electron/ipc/profile.ts | 18 ------ apps/desktop/electron/preload.ts | 28 ++++------ .../src/components/agent-settings-dialog.tsx | 45 +-------------- src/agent/async-agent.test.ts | 4 -- src/agent/async-agent.ts | 14 ----- src/agent/profile/index.ts | 55 ------------------- src/agent/profile/types.ts | 12 ---- src/agent/runner.ts | 14 ----- 9 files changed, 24 insertions(+), 190 deletions(-) diff --git a/apps/desktop/electron/electron-env.d.ts b/apps/desktop/electron/electron-env.d.ts index 4baf763e..874eaa47 100644 --- a/apps/desktop/electron/electron-env.d.ts +++ b/apps/desktop/electron/electron-env.d.ts @@ -81,7 +81,6 @@ interface SkillAddResult { interface ProfileData { profileId: string | undefined name: string | undefined - style: string | undefined userContent: string | undefined } @@ -177,7 +176,6 @@ interface ElectronAPI { profile: { get: () => Promise updateName: (name: string) => Promise - updateStyle: (style: string) => Promise updateUser: (content: string) => Promise } provider: { @@ -190,17 +188,17 @@ interface ElectronAPI { saveApiKey: (providerId: string, apiKey: string) => Promise<{ ok: boolean; error?: string }> importOAuth: (providerId: string) => Promise<{ ok: boolean; expiresAt?: number; error?: string }> } - cron: { - list: () => Promise - toggle: (jobId: string) => Promise<{ ok: boolean }> - remove: (jobId: string) => Promise<{ ok: boolean }> - } - heartbeat: { - last: () => Promise - setEnabled: (enabled: boolean) => Promise<{ ok: boolean; enabled?: boolean; error?: string }> - wake: (reason?: string) => Promise<{ ok: boolean; result?: unknown; error?: string }> - } - localChat: { + cron: { + list: () => Promise + toggle: (jobId: string) => Promise<{ ok: boolean }> + remove: (jobId: string) => Promise<{ ok: boolean }> + } + heartbeat: { + last: () => Promise + setEnabled: (enabled: boolean) => Promise<{ ok: boolean; enabled?: boolean; error?: string }> + wake: (reason?: string) => Promise<{ ok: boolean; result?: unknown; error?: string }> + } + localChat: { subscribe: (agentId: string) => Promise<{ ok?: boolean; error?: string; alreadySubscribed?: boolean }> unsubscribe: (agentId: string) => Promise<{ ok: boolean }> getHistory: (agentId: string, options?: { offset?: number; limit?: number }) => Promise<{ messages: unknown[]; total: number; offset: number; limit: number }> diff --git a/apps/desktop/electron/ipc/profile.ts b/apps/desktop/electron/ipc/profile.ts index d6dd4dac..36ac1512 100644 --- a/apps/desktop/electron/ipc/profile.ts +++ b/apps/desktop/electron/ipc/profile.ts @@ -25,7 +25,6 @@ function getDefaultAgent() { export interface ProfileData { profileId: string | undefined name: string | undefined - style: string | undefined userContent: string | undefined } @@ -42,7 +41,6 @@ export function registerProfileIpcHandlers(): void { return { profileId: undefined, name: undefined, - style: undefined, userContent: undefined, } } @@ -50,7 +48,6 @@ export function registerProfileIpcHandlers(): void { return { profileId: agent.getProfileId(), name: agent.getAgentName(), - style: agent.getAgentStyle(), userContent: agent.getUserContent(), } }) @@ -92,19 +89,4 @@ export function registerProfileIpcHandlers(): void { return { ok: true } }) - /** - * Update agent communication style. - */ - ipcMain.handle('profile:updateStyle', async (_event, style: string) => { - const agent = getDefaultAgent() - if (!agent) { - return { error: 'No agent available' } - } - - agent.setAgentStyle(style) - // Reload system prompt to apply changes immediately - agent.reloadSystemPrompt() - - return { ok: true, style } - }) } diff --git a/apps/desktop/electron/preload.ts b/apps/desktop/electron/preload.ts index 05313545..e0295898 100644 --- a/apps/desktop/electron/preload.ts +++ b/apps/desktop/electron/preload.ts @@ -40,7 +40,6 @@ export interface SkillInfo { export interface ProfileData { profileId: string | undefined name: string | undefined - style: string | undefined userContent: string | undefined } @@ -93,10 +92,6 @@ export interface LocalChatApproval { expiresAtMs: number } -// Available style options -export const AGENT_STYLES = ['concise', 'warm', 'playful', 'professional'] as const -export type AgentStyle = (typeof AGENT_STYLES)[number] - // ============================================================================ // Expose typed API to Renderer process // ============================================================================ @@ -174,7 +169,6 @@ const electronAPI = { profile: { get: (): Promise => ipcRenderer.invoke('profile:get'), updateName: (name: string) => ipcRenderer.invoke('profile:updateName', name), - updateStyle: (style: string) => ipcRenderer.invoke('profile:updateStyle', style), updateUser: (content: string) => ipcRenderer.invoke('profile:updateUser', content), }, @@ -202,17 +196,17 @@ const electronAPI = { }, // Cron jobs management - cron: { - list: () => ipcRenderer.invoke('cron:list'), - toggle: (jobId: string) => ipcRenderer.invoke('cron:toggle', jobId), - remove: (jobId: string) => ipcRenderer.invoke('cron:remove', jobId), - }, - - heartbeat: { - last: () => ipcRenderer.invoke('heartbeat:last'), - setEnabled: (enabled: boolean) => ipcRenderer.invoke('heartbeat:setEnabled', enabled), - wake: (reason?: string) => ipcRenderer.invoke('heartbeat:wake', reason), - }, + cron: { + list: () => ipcRenderer.invoke('cron:list'), + toggle: (jobId: string) => ipcRenderer.invoke('cron:toggle', jobId), + remove: (jobId: string) => ipcRenderer.invoke('cron:remove', jobId), + }, + + heartbeat: { + last: () => ipcRenderer.invoke('heartbeat:last'), + setEnabled: (enabled: boolean) => ipcRenderer.invoke('heartbeat:setEnabled', enabled), + wake: (reason?: string) => ipcRenderer.invoke('heartbeat:wake', reason), + }, // Local chat (direct IPC, no Gateway required) localChat: { diff --git a/apps/desktop/src/components/agent-settings-dialog.tsx b/apps/desktop/src/components/agent-settings-dialog.tsx index 5414a7c2..bcd28a17 100644 --- a/apps/desktop/src/components/agent-settings-dialog.tsx +++ b/apps/desktop/src/components/agent-settings-dialog.tsx @@ -12,15 +12,7 @@ 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, Tick02Icon } from '@hugeicons/core-free-icons' - -// Style options with labels -const STYLE_OPTIONS = [ - { value: 'concise', label: 'Concise', description: 'Brief and to the point' }, - { value: 'warm', label: 'Warm', description: 'Friendly and approachable' }, - { value: 'playful', label: 'Playful', description: 'Fun and lighthearted' }, - { value: 'professional', label: 'Professional', description: 'Formal and business-like' }, -] as const +import { Loading03Icon } from '@hugeicons/core-free-icons' interface AgentSettingsDialogProps { open: boolean @@ -31,7 +23,6 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) const [name, setName] = useState('') - const [style, setStyle] = useState('concise') const [userContent, setUserContent] = useState('') // Load profile data when dialog opens @@ -46,7 +37,6 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP try { const data = await window.electronAPI.profile.get() setName(data.name ?? '') - setStyle(data.style ?? 'concise') setUserContent(data.userContent ?? '') } catch (err) { console.error('Failed to load profile:', err) @@ -60,8 +50,6 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP try { // Update name if changed await window.electronAPI.profile.updateName(name) - // Update style - await window.electronAPI.profile.updateStyle(style) // Update user content await window.electronAPI.profile.updateUser(userContent) onOpenChange(false) @@ -78,7 +66,7 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP Edit Agent - Customize your agent's name, style and personal settings. + Customize your agent's name and personal settings. @@ -99,35 +87,6 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP /> - {/* Style */} -
- -
- {STYLE_OPTIONS.map((option) => ( - - ))} -
-
- {/* User Content */}
diff --git a/src/agent/async-agent.test.ts b/src/agent/async-agent.test.ts index 3ebe01fd..8e29dd22 100644 --- a/src/agent/async-agent.test.ts +++ b/src/agent/async-agent.test.ts @@ -58,10 +58,6 @@ vi.mock("./runner.js", () => ({ return undefined; } setUserContent() {} - getAgentStyle() { - return undefined; - } - setAgentStyle() {} reloadSystemPrompt() {} getProviderInfo() { return { provider: "test", model: "test-model" }; diff --git a/src/agent/async-agent.ts b/src/agent/async-agent.ts index 9aed5913..524dba8c 100644 --- a/src/agent/async-agent.ts +++ b/src/agent/async-agent.ts @@ -296,20 +296,6 @@ export class AsyncAgent { this.agent.setUserContent(content); } - /** - * Get agent communication style from profile config. - */ - getAgentStyle(): string | undefined { - return this.agent.getAgentStyle(); - } - - /** - * Update agent communication style in profile config. - */ - setAgentStyle(style: string): void { - this.agent.setAgentStyle(style); - } - /** * Reload profile from disk and rebuild system prompt. * Call this after updating profile files to apply changes immediately. diff --git a/src/agent/profile/index.ts b/src/agent/profile/index.ts index 43a67d51..e78838d3 100644 --- a/src/agent/profile/index.ts +++ b/src/agent/profile/index.ts @@ -297,59 +297,4 @@ export class ProfileManager { } } - /** 获取 Agent 风格 */ - getStyle(): string | undefined { - const profile = this.getProfile(); - return profile?.config?.style; - } - - /** 更新 Agent 风格 */ - updateStyle(style: string): void { - const profile = this.getOrCreateProfile(false); - const currentConfig = profile.config ?? {}; - // Use Object.assign to avoid exactOptionalPropertyTypes issues with spread - const newConfig: ProfileConfig = Object.assign({}, currentConfig, { - style: style as ProfileConfig["style"], - }); - profile.config = newConfig; - this.profile = profile; - writeProfileConfig(this.profileId, newConfig, { baseDir: this.baseDir }); - - // Also update soul.md to include the style - this.updateSoulWithStyle(style); - } - - /** 更新 soul.md,确保包含 Agent 风格 */ - private updateSoulWithStyle(style: string): void { - const profile = this.getOrCreateProfile(true); - let soulContent = profile.soul ?? DEFAULT_TEMPLATES.soul; - - // 替换 soul.md 中的 Style 字段 - // 匹配 "- **Style:** xxx" 格式 - const stylePattern = /- \*\*Style:\*\* .*/; - const newStyleLine = `- **Style:** ${style}`; - - if (stylePattern.test(soulContent)) { - soulContent = soulContent.replace(stylePattern, newStyleLine); - } else { - // 如果没有找到 Style 字段,在 Identity 部分的 Role 后添加 - const rolePattern = /(- \*\*Role:\*\* .*)/; - if (rolePattern.test(soulContent)) { - soulContent = soulContent.replace(rolePattern, `$1\n${newStyleLine}`); - } else { - // 如果没有 Role,尝试在 Name 后添加 - const namePattern = /(- \*\*Name:\*\* .*)/; - if (namePattern.test(soulContent)) { - soulContent = soulContent.replace(namePattern, `$1\n${newStyleLine}`); - } - } - } - - // 保存更新后的 soul.md - writeProfileFile(this.profileId, PROFILE_FILES.soul, soulContent, { baseDir: this.baseDir }); - // 更新缓存 - if (this.profile) { - this.profile.soul = soulContent; - } - } } diff --git a/src/agent/profile/types.ts b/src/agent/profile/types.ts index a250cf91..228a0788 100644 --- a/src/agent/profile/types.ts +++ b/src/agent/profile/types.ts @@ -15,22 +15,10 @@ export const PROFILE_FILES = { config: "config.json", } as const; -/** Available style options for agent personality */ -export const AGENT_STYLES = [ - "concise", // 简洁直接 - "warm", // 温暖友好 - "playful", // 轻松活泼 - "professional", // 专业正式 -] as const; - -export type AgentStyle = (typeof AGENT_STYLES)[number]; - /** Profile config.json structure */ export interface ProfileConfig { /** Agent display name */ name?: string; - /** Agent communication style */ - style?: AgentStyle; /** Tools policy configuration */ tools?: ToolsConfig; /** Default LLM provider */ diff --git a/src/agent/runner.ts b/src/agent/runner.ts index 3deef81e..37666ed9 100644 --- a/src/agent/runner.ts +++ b/src/agent/runner.ts @@ -751,20 +751,6 @@ export class Agent { this.profile?.updateUserContent(content); } - /** - * Get agent communication style from profile config. - */ - getAgentStyle(): string | undefined { - return this.profile?.getStyle(); - } - - /** - * Update agent communication style in profile config. - */ - setAgentStyle(style: string): void { - this.profile?.updateStyle(style); - } - /** * Get current provider and model information. */