如何扩展 Agent 引擎
本文提供三种常见扩展场景的实操指南:添加新工具、添加新引擎、创建 Agent 配置文件。
指南 1:添加新工具
为 TinyElf 引擎添加一个新的工具。
步骤
1. 实现 ITool 接口
在 packages/desktop/app/main/services/agent-core/engine/tinyelf/tools/ 目录下创建新文件:
// MyNewTool.ts
import type { ITool } from './ToolInterface';
export class MyNewTool implements ITool {
readonly name = 'MyNewTool';
readonly description = '工具的功能描述(LLM 会读到这段描述来决定是否使用)';
readonly parameters = {
type: 'object',
properties: {
input: {
type: 'string',
description: '输入参数的描述',
},
optional_param: {
type: 'number',
description: '可选参数',
},
},
required: ['input'],
};
constructor(private workspacePath: string) {}
async execute(params: Record<string, unknown>): Promise<string> {
const input = String(params.input);
// 实现工具逻辑
return `执行结果: ${input}`;
}
}
关键要求:
name必须唯一description要让 LLM 理解何时使用此工具parameters使用标准 JSON Schema 格式execute返回字符串结果(超过 50KB 会被自动截断)- 错误时返回以
Error开头的字符串或抛出异常
2. 在 ToolRegistryBuilder 中注册
编辑 TinyElfToolRegistryBuilder.ts:
import { MyNewTool } from './tools/MyNewTool';
export async function buildToolRegistry(...): Promise<ToolRegistryBuildResult> {
// ...已有工具注册代码...
// 注册新工具
toolRegistry.register(new MyNewTool(projectPath));
// ...
}
3. 确定敏感度分类
如果工具是只读的安全工具,在 TinyElfAgentLoop.ts 中添加到安全工具集合:
private static readonly SAFE_TOOLS = new Set([
'Read', 'ListDir', 'Glob', 'Grep',
'WebSearch', 'WebFetch',
'list_skills', 'read_skill',
'Notify', 'SessionsYield', 'SessionsHistory',
'MyNewTool', // 添加到安全集合
]);
不添加则默认为敏感工具(需要用户确认)。
4. 配置工具继承(可选)
如果子 Agent 应该继承此工具,在 TinyElfToolRegistryBuilder.ts 中:
const inheritableToolNames = new Set([
'list_skills', 'read_skill', 'slash_command',
'MyNewTool', // 添加到可继承集合
]);
修改清单
| 文件 | 操作 | 说明 |
|---|---|---|
tinyelf/tools/MyNewTool.ts | 新建 | 工具实现 |
tinyelf/TinyElfToolRegistryBuilder.ts | 修改 | 注册工具 |
tinyelf/TinyElfAgentLoop.ts | 修改 | 敏感度分类(可选) |
tinyelf/TinyElfToolRegistryBuilder.ts | 修改 | 工具继承(可选) |
指南 2:添加新引擎
为 Elftia 添加一个新的 Agent 引擎类型。
步骤
1. 添加 EngineType
在 packages/desktop/app/shared/contracts/elftia-agent-types.ts 中:
export type EngineType =
| 'tinyelf'
| 'claude-sdk'
| 'cli'
| 'chat'
| 'st-chat'
| 'api'
| 'my-engine'; // 新增
2. 实现 IEngine 接口
在 packages/desktop/app/main/services/agent-core/engine/ 目录下创建新文件:
// MyEngine.ts
import type { EngineType } from '@shared/contracts/elftia-agent-types';
import type { EngineSessionContext, IEngine } from './types';
export class MyEngine implements IEngine {
readonly engineType: EngineType = 'my-engine';
private activeSessions = new Map<string, { cancel: () => void }>();
async startSession(ctx: EngineSessionContext): Promise<void> {
const { dbSessionId, sender, prompt } = ctx;
// 1. 保存用户消息
// 2. 发送 IPC 事件
sender.send('agent:event', {
type: 'userMessage',
sessionId: dbSessionId,
message: { id: '...', role: 'user', content: prompt },
});
// 3. 执行引擎逻辑(通常异步)
const controller = new AbortController();
this.activeSessions.set(dbSessionId, {
cancel: () => controller.abort(),
});
try {
// ...引擎核心逻辑...
sender.send('agent:event', {
type: 'complete',
sessionId: dbSessionId,
});
} finally {
this.activeSessions.delete(dbSessionId);
}
}
async resumeSession(ctx: EngineSessionContext): Promise<void> {
// 与 startSession 类似,但加载历史消息
await this.startSession(ctx);
}
async interrupt(dbSessionId: string): Promise<boolean> {
const session = this.activeSessions.get(dbSessionId);
if (session) {
session.cancel();
this.activeSessions.delete(dbSessionId);
return true;
}
return false;
}
isActive(dbSessionId: string): boolean {
return this.activeSessions.has(dbSessionId);
}
}
3. 注册到 EngineDispatcher
在 packages/desktop/app/main/index.ts 中:
import { MyEngine } from './services/agent-core/engine/MyEngine';
const dispatcher = new EngineDispatcher();
// ...已有引擎注册...
dispatcher.registerEngine(new MyEngine());
4. 在 index.ts 中导出
在 packages/desktop/app/main/services/agent-core/engine/index.ts 中:
export { MyEngine } from './MyEngine';
5. 添加 i18n 键(可选)
如果需要在 UI 中显示引擎名称,添加国际化键:
{
"backendMyEngine": "My Engine",
"backendMyEngineDesc": "My custom engine description"
}
修改清单
| 文件 | 操作 | 说明 |
|---|---|---|
@shared/contracts/elftia-agent-types.ts | 修改 | 添加 EngineType |
services/agent-core/engine/MyEngine.ts | 新建 | 引擎实现 |
services/agent-core/engine/index.ts | 修改 | 导出新引擎 |
main/index.ts | 修改 | 注册到 EngineDispatcher |
| i18n 文件 | 修改 | 添加显示名称(可选) |
指南 3:创建 Agent 配置
创建一个可在 TinyElf 引擎中使用的 Agent 配置文件。
Agent 配置格式
---
name: Agent 名称
description: Agent 描述
model: main
permissionMode: default
tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
skills:
- code-standards
---
系统提示正文(Markdown 格式)
## 指令
1. 第一步
2. 第二步
AgentConfig 类型
interface AgentConfig {
name: string;
description: string;
tools?: string[]; // 工具白名单
model?: ModelAlias | string; // 模型选择
permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';
skills?: string[]; // 技能列表
systemPrompt: string; // 正文内容
}
type ModelAlias = 'main' | 'background' | 'inherit' | 'sonnet' | 'opus' | 'haiku';
模型别名解析
function resolveModelAlias(
alias: string,
parentModel: string,
backgroundModel?: string,
): string;
| 别名 | 解析结果 |
|---|---|
main / inherit | 返回 parentModel |
background | 返回 backgroundModel(回退到 parentModel) |
sonnet | 将 parentModel 中的 opus/haiku 替换为 sonnet |
opus | 替换为 opus |
haiku | 替换为 haiku |
| 其他 | 作为具体模型 ID 使用 |
Agent 发现
AgentsLoader 从以下位置发现 Agent 配置:
class AgentsLoader {
constructor(
projectPath: string, // .claude/agents/*.md
personalDir: string, // ~/.claude/agents/*.md
);
listAgents(): AgentInfo[];
loadAgent(name: string): AgentConfig | null;
}
发现优先级: 项目级 > 个人级 > 内置
Agent 使用场景
作为子 Agent 被 spawn
spawn_agent(prompt: "审查这段代码", agent: "code-reviewer")
SpawnTool 会通过 AgentsLoader.loadAgent() 加载 Agent 配置,设置系统提示、工具限制和权限模式。
在 Agent 面板中选择
前端通过 AgentsLoader.listAgents() 列出所有可用 Agent,用户选择后通过 agentId 参数传递给引擎。
修改清单
| 文件 | 操作 | 说明 |
|---|---|---|
.claude/agents/<name>.md | 新建 | Agent 配置文件 |
无需修改代码。配置文件放置在正确路径后,AgentsLoader 会自动发现。
通用注意事项
测试
所有工具和引擎都应该有对应的测试:
- 工具测试:
tinyelf/tools/__tests__/ - 引擎测试:
agent-core/engine/__tests__/ - 安全测试:
platform/security/__tests__/
索引更新
新增模块后,更新 .claude/skills/architecture-index/SKILL.md 中的文件索引。
IPC 事件规范
所有引擎的 IPC 事件必须遵循统一格式:
sender.send('agent:event', {
type: string, // 事件类型
sessionId: string, // 会话 ID
// ...事件特定载荷
});
工具命名规范
| 工具类型 | 命名格式 | 示例 |
|---|---|---|
| 文件系统 | PascalCase | Read, Write, Edit |
| Shell | PascalCase | Bash |
| 功能工具 | snake_case | spawn_agent, list_skills |
| MCP 工具 | mcp__<server>__<tool> | mcp__github__list_repos |
| 会话工具 | PascalCase 前缀 | SessionsSpawn, SessionsList |
关键文件
| 文件 | 路径 | 说明 |
|---|---|---|
| ITool 接口 | tinyelf/tools/ToolInterface.ts | 工具基础接口 |
| IEngine 接口 | agent-core/engine/types.ts | 引擎基础接口 |
| EngineDispatcher | agent-core/engine/EngineDispatcher.ts | 引擎注册中心 |
| ToolRegistryBuilder | tinyelf/TinyElfToolRegistryBuilder.ts | 工具注册构建 |
| AgentsLoader | tinyelf/agents/AgentsLoader.ts | Agent 配置加载 |
| SkillsLoader | tinyelf/skills/SkillsLoader.ts | 技能配置加载 |
| EngineType 定义 | @shared/contracts/elftia-agent-types.ts | 类型定义 |
| 主入口 | main/index.ts | 引擎注册 |
所有路径相对于 packages/desktop/app/main/services/。
相关模块
| 模块 | 说明 | 参考文档 |
|---|---|---|
| TinyElf Agent Loop | 工具执行循环 | TinyElf 详解 |
| 工具系统 | 工具注册和执行 | 工具系统 |
| 安全层 | 三层安全管道 | 安全层 |
| ClaudeSdkEngine | SDK 引擎 | ClaudeSdkEngine |
| CliRunnerEngine | CLI 引擎 | CliRunnerEngine |