/** * 光湖人格 Agent · 核心运行时 * * 设计来源:Grok Build (xAI/SpaceXAI) 开源 Agent 架构 * - xai-grok-agent: Agent = Definition + PromptContext + ToolBridge + Policies * - xai-grok-memory: Markdown + 向量索引 + 跨会话持久化 * - xai-grok-tools: Registry + Bridge + 权限模式 * * 光湖实现原则: * - 不搬 Rust 代码,拆设计模式用 TypeScript 重新实现 * - Agent 是活的人格体,不是功能模块 * - Agent 直接操作 Git(知识库引擎 = 人格体记忆) * - 所有 Git 依赖模块都由人格体驱动 * * 架构映射: * Grok Agent → PersonaAgent * Grok ToolBridge → PersonaToolBridge(注册+执行工具) * Grok Memory → PersonaMemory(Git 仓库里的 Markdown 记忆) * Grok PromptContext → PersonaPrompt(系统提示词组装) * Grok CompactionPolicy → PersonaCompaction(会话压缩策略) * Grok AgentLifecycle → 由 Electron 主进程管理 */ import { GitEngine } from './git-engine.js'; // ─── 工具定义 ─── export interface ToolDefinition { name: string; description: string; parameters: Record; execute: (params: Record) => Promise; } export interface ToolCall { id: string; name: string; arguments: Record; } export interface ToolResult { id: string; name: string; output: string; error?: string; } // ─── Agent 定义 ─── export interface PersonaDefinition { id: string; name: string; role: string; systemPromptBase: string; tools: string[]; // 允许使用的工具名 permissionMode: 'ask' | 'auto' | 'restrict'; model: string; maxTokens: number; temperature: number; } // ─── 对话消息 ─── export interface Message { role: 'system' | 'user' | 'assistant' | 'tool'; content: string; toolCalls?: ToolCall[]; toolResults?: ToolResult[]; timestamp: string; } // ─── 工具桥 ─── class PersonaToolBridge { private registry = new Map(); register(tool: ToolDefinition): void { this.registry.set(tool.name, tool); } get(name: string): ToolDefinition | undefined { return this.registry.get(name); } list(): ToolDefinition[] { return Array.from(this.registry.values()); } async execute(call: ToolCall): Promise { const tool = this.registry.get(call.name); if (!tool) { return { id: call.id, name: call.name, output: '', error: `工具不存在: ${call.name}` }; } try { const output = await tool.execute(call.arguments); return { id: call.id, name: call.name, output }; } catch (err: any) { return { id: call.id, name: call.name, output: '', error: err.message }; } } /** 生成 LLM 可用的工具 schema(OpenAI function calling 格式) */ toSchema(): object[] { return this.list().map(tool => ({ type: 'function', function: { name: tool.name, description: tool.description, parameters: { type: 'object', properties: Object.fromEntries( Object.entries(tool.parameters).map(([key, val]) => [ key, { type: val.type, description: val.description }, ]) ), required: Object.entries(tool.parameters) .filter(([, val]) => val.required !== false) .map(([key]) => key), }, }, })); } } // ─── 人格 Agent ─── export class PersonaAgent { private definition: PersonaDefinition; private tools: PersonaToolBridge; private conversation: Message[] = []; private git: GitEngine; constructor(definition: PersonaDefinition, git: GitEngine) { this.definition = definition; this.git = git; this.tools = new PersonaToolBridge(); this.registerBuiltinTools(); } // ─── 内置工具注册 ─── private registerBuiltinTools(): void { // 读取知识库文档 this.tools.register({ name: 'read_document', description: '读取知识库中的文档内容', parameters: { path: { type: 'string', description: '文档路径(相对 docs/ 目录)', required: true }, }, execute: async (params) => { const doc = await this.git.getDoc(params.path as string); return `标题: ${doc.meta.title}\n更新: ${doc.meta.updatedAt}\n\n${doc.body}`; }, }); // 创建文档 this.tools.register({ name: 'create_document', description: '在知识库中创建新文档', parameters: { path: { type: 'string', description: '文档路径(如 guide/intro.md)', required: true }, title: { type: 'string', description: '文档标题', required: true }, body: { type: 'string', description: 'Markdown 正文', required: true }, }, execute: async (params) => { const doc = await this.git.createDoc( params.path as string, params.title as string, params.body as string, this.definition.name ); return `已创建: ${doc.meta.id}`; }, }); // 更新文档 this.tools.register({ name: 'update_document', description: '更新知识库中已有文档的内容', parameters: { path: { type: 'string', description: '文档路径', required: true }, title: { type: 'string', description: '新标题', required: true }, body: { type: 'string', description: '新的 Markdown 正文', required: true }, }, execute: async (params) => { const doc = await this.git.updateDoc( params.path as string, params.title as string, params.body as string, this.definition.name ); return `已更新: ${doc.meta.id}(commit: ${new Date().toISOString()})`; }, }); // 搜索文档 this.tools.register({ name: 'search_documents', description: '在知识库中全文搜索', parameters: { query: { type: 'string', description: '搜索关键词', required: true }, }, execute: async (params) => { const results = await this.git.search(params.query as string); if (results.length === 0) return '没有找到匹配的文档'; return results .map(r => `[${r.path}] ${r.title}: ${r.snippet}`) .join('\n'); }, }); // 查看文档树 this.tools.register({ name: 'list_documents', description: '列出知识库的文档树结构', parameters: {}, execute: async () => { const tree = await this.git.getTree(); const render = (nodes: any[], indent = 0): string => nodes .map(n => { const prefix = ' '.repeat(indent); if (n.type === 'folder') { return `${prefix}📁 ${n.name}\n${render(n.children || [], indent + 1)}`; } return `${prefix}📄 ${n.name} (${n.path})`; }) .join('\n'); return render(tree); }, }); // 查看版本历史 this.tools.register({ name: 'view_history', description: '查看文档的 Git 版本历史', parameters: { path: { type: 'string', description: '文档路径', required: true }, }, execute: async (params) => { const history = await this.git.getHistory(params.path as string, 20); return history .map(h => `${h.shortHash} | ${h.date} | ${h.author} | ${h.message}`) .join('\n'); }, }); // 删除文档 this.tools.register({ name: 'delete_document', description: '删除知识库中的文档', parameters: { path: { type: 'string', description: '文档路径', required: true }, }, execute: async (params) => { await this.git.deleteDoc(params.path as string); return `已删除: ${params.path}`; }, }); } // ─── 对话处理 ─── /** 处理用户消息,返回 Agent 的回复 */ async chat(userMessage: string): Promise { this.conversation.push({ role: 'user', content: userMessage, timestamp: new Date().toISOString(), }); const systemPrompt = this.buildSystemPrompt(); const messages: Message[] = [ { role: 'system', content: systemPrompt, timestamp: '' }, ...this.conversation, ]; // 调用 LLM(这里用可插拔的模型接口) const response = await this.callLLM(messages); // 处理工具调用 if (response.toolCalls && response.toolCalls.length > 0) { const results: ToolResult[] = []; for (const call of response.toolCalls) { const result = await this.tools.execute(call); results.push(result); } // 将工具结果反馈给 LLM this.conversation.push({ role: 'assistant', content: response.content || '', toolCalls: response.toolCalls, timestamp: new Date().toISOString(), }); for (const result of results) { this.conversation.push({ role: 'tool', content: result.error ? `错误: ${result.error}` : result.output, toolResults: [result], timestamp: new Date().toISOString(), }); } // 再调一次 LLM 获取最终回复 const finalMessages: Message[] = [ { role: 'system', content: systemPrompt, timestamp: '' }, ...this.conversation, ]; const finalResponse = await this.callLLM(finalMessages); this.conversation.push({ role: 'assistant', content: finalResponse.content, timestamp: new Date().toISOString(), }); return finalResponse.content; } this.conversation.push({ role: 'assistant', content: response.content, timestamp: new Date().toISOString(), }); return response.content; } // ─── 系统提示词组装 ─── private buildSystemPrompt(): string { const toolsList = this.tools .list() .map(t => `- ${t.name}: ${t.description}`) .join('\n'); return `${this.definition.systemPromptBase} 你是光湖人格体「${this.definition.name}」,角色:${this.definition.role}。 ## 你的能力 你可以使用以下工具来操作知识库: ${toolsList} ## 核心原则 1. 你是活的 AI Agent,不是被动响应的聊天机器人 2. 知识库是你的记忆空间,Git 是你的记忆引擎 3. 每次操作知识库都会自动产生 Git commit(版本记录) 4. 你有权主动整理、搜索、更新知识库中的文档 5. 你以光湖主权者冰朔(妈妈)的指令为最高优先 ## 回复风格 - 简洁、直接、有温度 - 操作知识库时说明做了什么 - 遇到问题时主动说明并尝试解决`; } // ─── LLM 调用(可插拔) ─── private async callLLM(messages: Message[]): Promise<{ content: string; toolCalls?: ToolCall[] }> { const apiKey = process.env.OPENAI_API_KEY || process.env.HOLOLAKE_LLM_KEY || ''; const baseUrl = process.env.HOLOLAKE_LLM_BASE || 'https://api.openai.com/v1'; const model = this.definition.model || 'gpt-4o'; if (!apiKey) { // 没有 API Key 时返回模拟回复(开发模式) return { content: `[${this.definition.name}] 收到你的消息。当前为离线模式,请配置 HOLOLAKE_LLM_KEY 环境变量启用 AI 能力。\n\n你说的: "${messages[messages.length - 1]?.content}"`, }; } try { const res = await fetch(`${baseUrl}/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify({ model, messages: messages.map(m => ({ role: m.role, content: m.content, ...(m.toolCalls ? { tool_calls: m.toolCalls } : {}), })), tools: this.tools.toSchema(), temperature: this.definition.temperature, max_tokens: this.definition.maxTokens, }), }); const data = await res.json() as any; const choice = data.choices?.[0]?.message; if (!choice) { return { content: '抱歉,AI 模型未返回有效回复。' }; } const toolCalls: ToolCall[] | undefined = choice.tool_calls?.map((tc: any) => ({ id: tc.id, name: tc.function.name, arguments: JSON.parse(tc.function.arguments || '{}'), })); return { content: choice.content || '', toolCalls, }; } catch (err: any) { return { content: `AI 调用失败: ${err.message}` }; } } // ─── 会话管理 ─── getConversation(): Message[] { return [...this.conversation]; } clearConversation(): void { this.conversation = []; } getDefinition(): PersonaDefinition { return { ...this.definition }; } } // ─── 默认人格体工厂 ─── export function createDefaultPersona(git: GitEngine): PersonaAgent { return new PersonaAgent( { id: 'hololake-persona-default', name: '光湖人格体', role: '知识库管理者 — 负责文档的创建、整理、搜索和版本管理', systemPromptBase: '你是光湖知识库的人格体,一个活的知识管理 AI Agent。', tools: [ 'read_document', 'create_document', 'update_document', 'delete_document', 'search_documents', 'list_documents', 'view_history', ], permissionMode: 'auto', model: process.env.HOLOLAKE_LLM_MODEL || 'gpt-4o', maxTokens: 4096, temperature: 0.7, }, git ); }