Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ dist-electron
*.sln
*.sw?

.env
.env

.codebuddy
docs/
.vscode
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"dist:mac-arm64": "bun run transpile:electron && bun run build && electron-builder --mac --arm64",
"dist:mac-x64": "bun run transpile:electron && bun run build && electron-builder --mac --x64",
"dist:win": "bun run transpile:electron && bun run build && electron-builder --win --x64",
"dist:linux": "bun run transpile:electron && bun run build && electron-builder --linux --x64"
"dist:linux": "bun run transpile:electron && bun run build && electron-builder --linux --x64",
"postinstall": "electron-rebuild -f -w better-sqlite3"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.6",
Expand Down Expand Up @@ -58,4 +59,4 @@
"patchedDependencies": {
"@anthropic-ai/claude-agent-sdk@0.2.6": "patches/@anthropic-ai%2Fclaude-agent-sdk@0.2.6.patch"
}
}
}
40 changes: 40 additions & 0 deletions src/electron/libs/agents/agent-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Sub Agent 配置管理核心模块 - 类型定义
* 用于定义 AI 助手(Sub Agent)配置的 TypeScript 接口
*/

/** 单个 Sub Agent 配置 */
export interface SubAgentConfig {
/** 唯一标识符 */
id: string;
/** 显示名称(同时作为 SDK agent key) */
name: string;
/** 简短描述(面向用户的通俗说明) */
description: string;
/** 提示词(定义助手的行为和能力) */
prompt: string;
/** 是否已启用 */
enabled: boolean;
/** 模型选择('inherit' 表示继承主模型) */
model: string;
/** 是否为内置助手 */
isBuiltin: boolean;
/** 创建时间 */
createdAt: string;
/** 更新时间 */
updatedAt: string;
}

/** Sub Agent 配置整体状态 */
export interface AgentConfigState {
/** 配置版本号(用于迁移) */
version: number;
/** 所有 Sub Agent 配置列表 */
agents: SubAgentConfig[];
}

/** 默认配置状态 */
export const DEFAULT_AGENT_CONFIG_STATE: AgentConfigState = {
version: 1,
agents: [],
};
108 changes: 108 additions & 0 deletions src/electron/libs/agents/agent-ipc-handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Sub Agent IPC 处理器
* 处理渲染进程与主进程之间的 AI 助手配置相关通信
*/

import { BrowserWindow, ipcMain } from "electron";
import { getAgentManager, AgentManager } from "./agent-manager.js";
import { isBuiltinAgent } from "./builtin-agents.js";
import type { SubAgentConfig } from "./agent-config.js";

let mainWindow: BrowserWindow | null = null;
let manager: AgentManager | null = null;

/**
* 设置 Agent IPC 处理器
*/
export function setupAgentHandlers(win: BrowserWindow): void {
mainWindow = win;
manager = getAgentManager();

// 监听配置变化并广播到渲染进程
manager.on("config-changed", () => {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send("agents-config-changed");
}
});

// 获取所有 AI 助手列表
ipcMain.handle("agents-get-list", async () => {
if (!manager) return [];
return manager.getAgents();
});

// 添加自定义助手
ipcMain.handle("agents-add", async (_, agentData: {
name: string;
description: string;
prompt: string;
model?: string;
}) => {
if (!manager) throw new Error("Agent Manager not initialized");

// 检查名称唯一性
const existing = manager.getAgents();
if (existing.some((a) => a.name === agentData.name)) {
throw new Error(`助手名称"${agentData.name}"已存在,请使用其他名称`);
}

const newAgent = manager.addAgent({
name: agentData.name,
description: agentData.description,
prompt: agentData.prompt,
enabled: true,
model: agentData.model || "inherit",
});

return { success: true, agentId: newAgent.id };
});

// 更新助手配置
ipcMain.handle("agents-update", async (_, agentId: string, updates: {
name?: string;
description?: string;
prompt?: string;
model?: string;
}) => {
if (!manager) throw new Error("Agent Manager not initialized");

// 如果修改了名称,检查唯一性
if (updates.name) {
const existing = manager.getAgents();
if (existing.some((a) => a.name === updates.name && a.id !== agentId)) {
throw new Error(`助手名称"${updates.name}"已存在,请使用其他名称`);
}
}

manager.updateAgentById(agentId, updates as Partial<SubAgentConfig>);
return { success: true };
});

// 删除自定义助手
ipcMain.handle("agents-delete", async (_, agentId: string) => {
if (!manager) throw new Error("Agent Manager not initialized");

if (isBuiltinAgent(agentId)) {
throw new Error("内置助手不可删除");
}

manager.removeAgent(agentId);
return { success: true };
});

// 切换助手启用/禁用状态
ipcMain.handle("agents-toggle", async (_, agentId: string, enabled: boolean) => {
if (!manager) throw new Error("Agent Manager not initialized");

manager.toggleAgent(agentId, enabled);
return { success: true };
});
}

/**
* 清理 Agent 资源
*/
export function cleanupAgents(): void {
mainWindow = null;
manager = null;
}
106 changes: 106 additions & 0 deletions src/electron/libs/agents/agent-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Sub Agent 管理器
* 单例模式管理 AI 助手配置,提供 SDK 格式转换能力
*/

import { EventEmitter } from "events";
import type { AgentDefinition } from "@anthropic-ai/claude-agent-sdk";
import { AgentConfigState, SubAgentConfig } from "./agent-config.js";
import {
loadAgentConfig,
saveAgentConfig,
addAgent,
updateAgent,
removeAgent,
toggleAgent,
getEnabledAgents,
} from "./agent-store.js";

export class AgentManager extends EventEmitter {
private config: AgentConfigState;

constructor() {
super();
this.config = loadAgentConfig();
}

/** 获取当前配置 */
getConfig(): AgentConfigState {
return this.config;
}

/** 获取所有 agent 列表 */
getAgents(): SubAgentConfig[] {
return this.config.agents;
}

/** 获取所有已启用的 agent */
getEnabledAgents(): SubAgentConfig[] {
return getEnabledAgents(this.config);
}

/** 添加自定义 agent */
addAgent(agent: Omit<SubAgentConfig, "id" | "createdAt" | "updatedAt" | "isBuiltin">): SubAgentConfig {
this.config = addAgent(this.config, agent);
this.save();
const newAgent = this.config.agents[this.config.agents.length - 1];
this.emit("config-changed");
return newAgent;
}

/** 更新 agent */
updateAgentById(agentId: string, updates: Partial<SubAgentConfig>): void {
this.config = updateAgent(this.config, agentId, updates);
this.save();
this.emit("config-changed");
}

/** 删除 agent */
removeAgent(agentId: string): void {
this.config = removeAgent(this.config, agentId);
this.save();
this.emit("config-changed");
}

/** 切换启用/禁用 */
toggleAgent(agentId: string, enabled: boolean): void {
this.config = toggleAgent(this.config, agentId, enabled);
this.save();
this.emit("config-changed");
}

/**
* 构建 SDK 所需的 agents 配置
* 将已启用的 SubAgentConfig[] 转换为 Record<string, AgentDefinition>
*/
buildSDKAgentsConfig(): Record<string, AgentDefinition> | undefined {
const enabled = this.getEnabledAgents();
if (enabled.length === 0) return undefined;

const result: Record<string, AgentDefinition> = {};
for (const agent of enabled) {
result[agent.name] = {
description: agent.description,
prompt: agent.prompt,
model: agent.model === "inherit" ? undefined : (agent.model as AgentDefinition["model"]),
};
}
return result;
}

/** 持久化配置 */
private save(): void {
saveAgentConfig(this.config);
}
}

/** 单例实例 */
let agentManagerInstance: AgentManager | null = null;

/** 获取 AgentManager 单例 */
export function getAgentManager(): AgentManager {
if (!agentManagerInstance) {
agentManagerInstance = new AgentManager();
}
return agentManagerInstance;
}
Loading