价格

架构总览

相关源文件

本页面内容基于以下源文件生成:

本项目是一个模块化的 AI Agent 开发框架,采用分层架构设计,支持多端 UI(终端与 Web),提供可扩展的工具与技能系统。核心设计理念是将 AI 能力、Agent 逻辑、会话管理、UI 渲染解耦,通过清晰的接口契约实现模块间协作。

核心架构层次

项目采用三层架构设计:AI 基础层、Agent 核心层、应用层。每层职责明确,依赖方向自上而下。

正在加载图表渲染器...

架构要点说明

  1. AI 基础层packages/agent/src/agent.ts:1-50):提供模型抽象、流式传输、消息类型定义,是整个系统的底层依赖。

  2. Agent 核心层packages/coding-agent/src/core/index.ts:1-60):包含 Agent 类、会话管理、扩展系统、技能系统,是业务逻辑的核心载体。

  3. 应用层:TUI、Web UI、MOM 等具体应用场景,通过 SDK 与核心层交互(packages/coding-agent/src/core/sdk.ts:40-100)。

  4. 依赖方向:应用层依赖核心层,核心层依赖基础层,禁止反向依赖。

  5. 模块边界:每层通过 TypeScript 接口定义契约,内部实现可替换。

Agent 核心引擎

Agent 类是整个框架的核心,负责状态管理、消息处理、工具调用、流式响应。

状态管理与初始化

Agent 维护一个统一的 _state 对象,包含系统提示、模型配置、消息列表、工具定义、流式状态等(packages/agent/src/agent.ts:116-172):

typescript
1// 核心状态结构
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
followUpAgent 空闲时处理追加后续任务one-at-a-time / all
typescript
1// 消息出队逻辑
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):

typescript
1export 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):

正在加载图表渲染器...

核心钩子类型

钩子触发时机用途
BeforeAgentStartEventAgent 启动前修改系统提示、注入上下文
AgentStartEvent/AgentEndEventAgent 轮次开始/结束日志记录、性能监控
ToolCallEvent/ToolResultEvent工具调用前后参数校验、结果后处理
SessionSwitchEvent/SessionForkEvent会话切换/分支状态同步、清理
ContextEvent上下文变更压缩、恢复通知

工具定义与执行

工具系统支持内置工具与自定义工具,通过 ToolDefinition 接口统一抽象(packages/coding-agent/src/core/exec.ts:10-50):

typescript
1// 命令执行工具示例
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):

typescript
1export 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):

typescript
1// 组件接口
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):

typescript
1// 核心组件导出
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):

typescript
1// 渲染器注册机制
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):

正在加载图表渲染器...

会话恢复逻辑

typescript
1// 检查历史会话数据
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):

typescript
1// 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
ReactWeb UI组件化、生态丰富、团队熟悉Vue、Svelte
IndexedDB浏览器存储大容量、异步 APIlocalStorage(容量小)、SQLite WASM
AbortController取消机制标准 API、统一取消模式自定义取消令牌
Event Queue事件处理保证顺序、避免竞态直接回调(可能乱序)
Set工具调用追踪O(1) 查找、自动去重数组(O(n) 查找)
Promise 队列异步串行化确保操作顺序async-mutex 库

模块依赖关系

正在加载图表渲染器...

依赖要点

  1. 单向依赖:UI → Session → Agent → AI,无循环依赖
  2. 接口隔离:模块间通过 TypeScript 接口通信,实现可替换
  3. 分层清晰:基础设施层无业务逻辑,核心层无 UI 代码

关键配置与启动流程

SDK 配置项

typescript
1export 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&lt;any&gt;;                  // 指定模型
15    thinkingLevel?: ThinkingLevel;       // 思考级别
16    scopedModels?: Array<{               // 可切换模型列表
17        model: Model&lt;any&gt;; 
18        thinkingLevel?: ThinkingLevel;
19    }>;
20    
21    // 工具配置
22    tools?: Tool[];                      // 内置工具
23    customTools?: ToolDefinition[];      // 自定义工具
24}

启动流程

  1. 初始化路径:确定 cwdagentDir
  2. 创建存储:初始化 AuthStorageModelRegistrySettingsManagerSessionManager
  3. 加载资源:通过 ResourceLoader 加载技能、提示、主题、上下文文件
  4. 恢复或选择模型:尝试恢复历史模型,失败则使用默认模型
  5. 创建 AgentSession:组装所有组件,返回会话实例
  6. 加载扩展:发现并加载项目级扩展,注册钩子

错误处理策略

场景处理方式代码位置
模型不可用回退到默认模型,返回 modelFallbackMessagesdk.ts:194-202
命令超时SIGTERM 优雅终止,5秒后 SIGKILLexec.ts:51-62
消息过长截断并添加提示mom/main.ts:148-153
Agent 重复调用抛出错误,提示使用 steer/followUpagent.ts:395-399
扩展错误通过 ExtensionErrorListener 回调extensions/index.ts:13