架构总览
相关源文件
本页面内容基于以下源文件生成:
- packages/ai/src/index.ts
- packages/agent/src/agent.ts
- packages/coding-agent/src/core/agent-session.ts
- packages/coding-agent/src/core/extensions/index.ts
- packages/tui/src/tui.ts
- packages/web-ui/src/index.ts
- packages/coding-agent/src/core/sdk.ts
- packages/coding-agent/src/core/exec.ts
- packages/coding-agent/src/core/index.ts
- packages/coding-agent/src/core/skills.ts
- packages/mom/src/main.ts
- packages/tui/src/index.ts
- packages/pods/src/index.ts
- packages/agent/src/index.ts
- packages/coding-agent/src/main.ts
- packages/coding-agent/src/index.ts
- packages/mom/src/tools/index.ts
- packages/web-ui/src/tools/index.ts
- packages/web-ui/example/src/main.ts
- packages/coding-agent/src/modes/index.ts
本项目是一个模块化的 AI Agent 开发框架,采用分层架构设计,支持多端 UI(终端与 Web),提供可扩展的工具与技能系统。核心设计理念是将 AI 能力、Agent 逻辑、会话管理、UI 渲染解耦,通过清晰的接口契约实现模块间协作。
核心架构层次
项目采用三层架构设计:AI 基础层、Agent 核心层、应用层。每层职责明确,依赖方向自上而下。
正在加载图表渲染器...
架构要点说明:
-
AI 基础层(packages/agent/src/agent.ts:1-50):提供模型抽象、流式传输、消息类型定义,是整个系统的底层依赖。
-
Agent 核心层(packages/coding-agent/src/core/index.ts:1-60):包含 Agent 类、会话管理、扩展系统、技能系统,是业务逻辑的核心载体。
-
应用层:TUI、Web UI、MOM 等具体应用场景,通过 SDK 与核心层交互(packages/coding-agent/src/core/sdk.ts:40-100)。
-
依赖方向:应用层依赖核心层,核心层依赖基础层,禁止反向依赖。
-
模块边界:每层通过 TypeScript 接口定义契约,内部实现可替换。
Agent 核心引擎
Agent 类是整个框架的核心,负责状态管理、消息处理、工具调用、流式响应。
状态管理与初始化
Agent 维护一个统一的 _state 对象,包含系统提示、模型配置、消息列表、工具定义、流式状态等(packages/agent/src/agent.ts:116-172):
typescript1// 核心状态结构 2private _state: AgentState = { 3 systemPrompt: "", 4 model: getModel("google", "gemini-2.5-flash-lite-preview-06-17"), 5 thinkingLevel: "off", 6 tools: [], 7 messages: [], 8 isStreaming: false, 9 streamMessage: null, 10 pendingToolCalls: new Set<string>(), 11 error: undefined, 12};
关键设计决策:
- 不可变更新:消息列表变更使用
[...this._state.messages, m]创建新数组,便于状态追踪与调试。 - 工具调用追踪:
pendingToolCalls使用 Set 存储进行中的工具调用 ID,支持并发控制。 - 流式状态隔离:
streamMessage单独存储当前流式消息,避免与历史消息混淆。
消息队列与控制流
Agent 实现了两种消息队列机制:steering(中断)和 followUp(后续),支持灵活的对话控制(packages/agent/src/agent.ts:256-337):
| 队列类型 | 触发时机 | 用途 | 模式 |
|---|---|---|---|
| steering | 工具执行后立即插入 | 中断当前流程,跳过剩余工具 | one-at-a-time / all |
| followUp | Agent 空闲时处理 | 追加后续任务 | one-at-a-time / all |
typescript1// 消息出队逻辑 2private dequeueSteeringMessages(): AgentMessage[] { 3 if (this.steeringMode === "one-at-a-time") { 4 if (this.steeringQueue.length > 0) { 5 const first = this.steeringQueue[0]; 6 this.steeringQueue = this.steeringQueue.slice(1); 7 return [first]; 8 } 9 return []; 10 } 11 // "all" 模式:一次性返回所有 12 const steering = this.steeringQueue.slice(); 13 this.steeringQueue = []; 14 return steering; 15}
会话层封装
AgentSession 在 Agent 基础上增加会话管理、自动压缩、重试机制、扩展集成等能力(packages/coding-agent/src/core/agent-session.ts:212-250):
typescript1export class AgentSession { 2 readonly agent: Agent; 3 readonly sessionManager: SessionManager; 4 readonly settingsManager: SettingsManager; 5 6 // 事件订阅与队列 7 private _unsubscribeAgent?: () => void; 8 private _eventListeners: AgentSessionEventListener[] = []; 9 private _agentEventQueue: Promise<void> = Promise.resolve(); 10 11 // 消息追踪 12 private _steeringMessages: string[] = []; 13 private _followUpMessages: string[] = []; 14 private _pendingNextTurnMessages: CustomMessage[] = []; 15 16 // 压缩与重试状态 17 private _compactionAbortController: AbortController | undefined; 18 private _retryAttempt = 0; 19 private _retryPromise: Promise<void> | undefined; 20}
会话事件类型(packages/coding-agent/src/core/agent-session.ts:110-150):
auto_compaction_start/end:自动上下文压缩auto_retry_start/end:自动重试机制- 继承自 Agent 的所有事件(消息、工具调用、流式更新等)
扩展与工具系统
扩展架构设计
扩展系统采用生命周期钩子模式,允许在 Agent 运行的关键节点注入自定义逻辑(packages/coding-agent/src/core/extensions/index.ts:1-56):
正在加载图表渲染器...
核心钩子类型:
| 钩子 | 触发时机 | 用途 |
|---|---|---|
BeforeAgentStartEvent | Agent 启动前 | 修改系统提示、注入上下文 |
AgentStartEvent/AgentEndEvent | Agent 轮次开始/结束 | 日志记录、性能监控 |
ToolCallEvent/ToolResultEvent | 工具调用前后 | 参数校验、结果后处理 |
SessionSwitchEvent/SessionForkEvent | 会话切换/分支 | 状态同步、清理 |
ContextEvent | 上下文变更 | 压缩、恢复通知 |
工具定义与执行
工具系统支持内置工具与自定义工具,通过 ToolDefinition 接口统一抽象(packages/coding-agent/src/core/exec.ts:10-50):
typescript1// 命令执行工具示例 2export interface ExecOptions { 3 signal?: AbortSignal; // 取消信号 4 timeout?: number; // 超时毫秒 5 cwd?: string; // 工作目录 6} 7 8export interface ExecResult { 9 stdout: string; 10 stderr: string; 11 code: number; 12 killed: boolean; 13} 14 15export async function execCommand( 16 command: string, 17 args: string[], 18 cwd: string, 19 options?: ExecOptions, 20): Promise<ExecResult> { 21 // 支持超时与取消 22 // SIGTERM 优雅终止,5秒后 SIGKILL 强制终止 23}
工具执行模式(packages/agent/src/agent.ts:106-107):
parallel:并行执行多个工具调用(默认)sequential:顺序执行
技能系统
技能是预定义的提示模板,支持 frontmatter 元数据配置(packages/coding-agent/src/core/skills.ts:66-84):
typescript1export interface Skill { 2 name: string; // 技能名称 3 description: string; // 描述 4 filePath: string; // 文件路径 5 baseDir: string; // 基础目录 6 source: string; // 原始内容 7 disableModelInvocation: boolean; // 禁用模型调用 8} 9 10export interface SkillFrontmatter { 11 name?: string; 12 description?: string; 13 "disable-model-invocation"?: boolean; 14 [key: string]: unknown; 15}
技能文件支持 .gitignore 风格的忽略规则,通过 IGNORE_FILE_NAMES 配置过滤不需要的文件。
多端 UI 架构
TUI 终端界面
TUI 采用组件化设计,通过差分渲染优化终端输出(packages/tui/src/tui.ts:173-212):
typescript1// 组件接口 2export interface Component { 3 render(width: number): string[]; 4 invalidate?(): void; 5} 6 7// 容器实现 8export class Container implements Component { 9 children: Component[] = []; 10 11 addChild(component: Component): void { 12 this.children.push(component); 13 } 14 15 removeChild(component: Component): void { 16 const index = this.children.indexOf(component); 17 if (index !== -1) { 18 this.children.splice(index, 1); 19 } 20 } 21 22 render(width: number): string[] { 23 const lines: string[] = []; 24 for (const child of this.children) { 25 lines.push(...child.render(width)); 26 } 27 return lines; 28 } 29} 30 31// TUI 主类 32export class TUI extends Container { 33 public terminal: Terminal; 34 private previousLines: string[] = []; 35 private previousWidth = 0; 36 // 差分渲染逻辑... 37}
关键设计:
- 光标标记:使用 APC 序列
\x1b_pi:c\x07标记光标位置,终端忽略该零宽序列 - Overlay 系统:支持锚点定位(center、top-left 等)、百分比尺寸、边距配置
- 差分渲染:对比前后帧,仅更新变化的行
Web UI 组件体系
Web UI 提供完整的 React 组件库,支持消息渲染、工具可视化、存储管理(packages/web-ui/src/index.ts:1-60):
typescript1// 核心组件导出 2export { ChatPanel } from "./ChatPanel.js"; 3export { AgentInterface } from "./components/AgentInterface.js"; 4export { MessageList } from "./components/MessageList.js"; 5export { Input } from "./components/Input.js"; 6 7// 消息组件 8export { 9 AbortedMessage, 10 AssistantMessage, 11 ToolMessage, 12 UserMessage, 13} from "./components/Messages.js"; 14 15// 工具渲染器 16export { BashRenderer } from "./tools/renderers/BashRenderer.js"; 17export { CalculateRenderer } from "./tools/renderers/CalculateRenderer.js"; 18export { DefaultRenderer } from "./tools/renderers/DefaultRenderer.js";
工具渲染系统(packages/web-ui/src/index.ts:92-119):
typescript1// 渲染器注册机制 2export { 3 getToolRenderer, 4 registerToolRenderer, 5 renderTool, 6 setShowJsonMode 7} from "./tools/index.js"; 8 9// Artifact 类型 10export { 11 ArtifactElement, 12 ArtifactPill, 13 ArtifactsPanel, 14 HtmlArtifact, 15 ImageArtifact, 16 MarkdownArtifact, 17 SvgArtifact, 18 TextArtifact, 19} from "./tools/artifacts/";
存储抽象:
IndexedDBStorageBackend:浏览器端持久化SessionsStore:会话元数据管理SettingsStore:用户配置ProviderKeysStore:API 密钥管理
会话与状态管理
会话创建流程
SDK 提供 createAgentSession 函数,封装会话创建的完整流程(packages/coding-agent/src/core/sdk.ts:165-204):
正在加载图表渲染器...
会话恢复逻辑:
typescript1// 检查历史会话数据 2const existingSession = sessionManager.buildSessionContext(); 3const hasExistingSession = existingSession.messages.length > 0; 4 5// 尝试恢复模型 6if (!model && hasExistingSession && existingSession.model) { 7 const restoredModel = modelRegistry.find( 8 existingSession.model.provider, 9 existingSession.model.modelId 10 ); 11 if (restoredModel && (await modelRegistry.getApiKey(restoredModel))) { 12 model = restoredModel; 13 } 14 if (!model) { 15 modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`; 16 } 17}
实际应用示例
MOM(Slack 集成)展示了会话状态管理的实际应用(packages/mom/src/main.ts:136-170):
typescript1// Slack 消息响应处理 2respond: async (text: string, shouldLog = true) => { 3 updatePromise = updatePromise.then(async () => { 4 try { 5 // 累积文本(支持流式更新) 6 accumulatedText = accumulatedText 7 ? `${accumulatedText}\n${text}` 8 : text; 9 10 // 截断处理(Slack 限制 40K,安全值 35K) 11 const MAX_MAIN_LENGTH = 35000; 12 const truncationNote = "\n\n_(message truncated, ask me to elaborate on specific parts)_"; 13 if (accumulatedText.length > MAX_MAIN_LENGTH) { 14 accumulatedText = 15 accumulatedText.substring(0, MAX_MAIN_LENGTH - truncationNote.length) 16 + truncationNote; 17 } 18 19 // 更新或创建消息 20 const displayText = isWorking 21 ? accumulatedText + workingIndicator 22 : accumulatedText; 23 24 if (messageTs) { 25 await slack.updateMessage(event.channel, messageTs, displayText); 26 } else { 27 messageTs = await slack.postMessage(event.channel, displayText); 28 } 29 } catch (err) { 30 log.logWarning("Slack respond error", err instanceof Error ? err.message : String(err)); 31 } 32 }); 33 await updatePromise; 34}
核心设计决策与取舍
| 决策 | 选择 | 理由 | 已知限制 |
|---|---|---|---|
| 状态管理 | 单一 _state 对象 | 简化状态追踪,便于调试 | 大规模状态可能影响性能 |
| 消息队列 | steering + followUp 双队列 | 支持中断与后续两种控制流 | 队列管理增加复杂度 |
| 工具执行 | 默认并行 | 提升执行效率 | 顺序依赖需显式配置 |
| 流式响应 | 事件订阅模式 | 解耦 UI 与 Agent 逻辑 | 事件顺序需仔细处理 |
| 扩展系统 | 生命周期钩子 | 灵活注入自定义逻辑 | 钩子过多影响性能 |
| UI 渲染 | 差分渲染 | 减少终端闪烁 | 实现复杂度高 |
| 存储抽象 | 接口 + 多后端 | 支持不同运行环境 | 需要适配层 |
| 会话恢复 | 模型 ID + API Key 校验 | 确保恢复后可用 | 模型不可用时需回退 |
技术选型
| 技术 | 用途 | 选型理由 | 替代方案 |
|---|---|---|---|
| TypeScript | 核心语言 | 类型安全、IDE 支持、生态成熟 | JavaScript(无类型)、Rust(学习曲线陡) |
| Mermaid | 架构图 | 文本定义、版本控制友好 | PlantUML、Draw.io |
| React | Web UI | 组件化、生态丰富、团队熟悉 | Vue、Svelte |
| IndexedDB | 浏览器存储 | 大容量、异步 API | localStorage(容量小)、SQLite WASM |
| AbortController | 取消机制 | 标准 API、统一取消模式 | 自定义取消令牌 |
| Event Queue | 事件处理 | 保证顺序、避免竞态 | 直接回调(可能乱序) |
| Set | 工具调用追踪 | O(1) 查找、自动去重 | 数组(O(n) 查找) |
| Promise 队列 | 异步串行化 | 确保操作顺序 | async-mutex 库 |
模块依赖关系
正在加载图表渲染器...
依赖要点:
- 单向依赖:UI → Session → Agent → AI,无循环依赖
- 接口隔离:模块间通过 TypeScript 接口通信,实现可替换
- 分层清晰:基础设施层无业务逻辑,核心层无 UI 代码
关键配置与启动流程
SDK 配置项
typescript1export interface CreateAgentSessionOptions { 2 // 路径配置 3 cwd?: string; // 工作目录,默认 process.cwd() 4 agentDir?: string; // 配置目录,默认 ~/.pi/agent 5 6 // 核心组件 7 authStorage?: AuthStorage; // 认证存储 8 modelRegistry?: ModelRegistry; // 模型注册表 9 sessionManager?: SessionManager; // 会话管理器 10 settingsManager?: SettingsManager; // 设置管理器 11 resourceLoader?: ResourceLoader; // 资源加载器 12 13 // 模型配置 14 model?: Model<any>; // 指定模型 15 thinkingLevel?: ThinkingLevel; // 思考级别 16 scopedModels?: Array<{ // 可切换模型列表 17 model: Model<any>; 18 thinkingLevel?: ThinkingLevel; 19 }>; 20 21 // 工具配置 22 tools?: Tool[]; // 内置工具 23 customTools?: ToolDefinition[]; // 自定义工具 24}
启动流程
- 初始化路径:确定
cwd和agentDir - 创建存储:初始化
AuthStorage、ModelRegistry、SettingsManager、SessionManager - 加载资源:通过
ResourceLoader加载技能、提示、主题、上下文文件 - 恢复或选择模型:尝试恢复历史模型,失败则使用默认模型
- 创建 AgentSession:组装所有组件,返回会话实例
- 加载扩展:发现并加载项目级扩展,注册钩子
错误处理策略
| 场景 | 处理方式 | 代码位置 |
|---|---|---|
| 模型不可用 | 回退到默认模型,返回 modelFallbackMessage | sdk.ts:194-202 |
| 命令超时 | SIGTERM 优雅终止,5秒后 SIGKILL | exec.ts:51-62 |
| 消息过长 | 截断并添加提示 | mom/main.ts:148-153 |
| Agent 重复调用 | 抛出错误,提示使用 steer/followUp | agent.ts:395-399 |
| 扩展错误 | 通过 ExtensionErrorListener 回调 | extensions/index.ts:13 |
