整体架构概述

codeagent-wrapper 是 PinableAgents 的核心执行引擎,使用 Go 语言编写,负责将上层工作流的抽象任务描述转化为对底层 AI 后端的具体调用。它充当工作流编排层与 AI 后端之间的桥梁,提供统一的调用接口、会话持久化、错误恢复和输出格式化能力。

架构上,codeagent-wrapper 采用四层分层设计,数据从上到下依次经过:CLI 解析层(接收和验证命令行参数)、后端适配器层(将通用请求转化为后端特定的 API 调用)、会话管理层(维护任务执行状态和上下文)、输出格式化层(将后端响应转化为统一的结构化输出)。这种分层设计使得各层可以独立演进和测试。

                    +------------------+
                    |   CLI 解析层      |  ← 命令行参数输入
                    +--------+---------+
                             |
                    +--------v---------+
                    | 后端适配器层      |  ← Codex / Claude / Gemini
                    +--------+---------+
                             |
                    +--------v---------+
                    | 会话管理层        |  ← JSON 状态持久化
                    +--------+---------+
                             |
                    +--------v---------+
                    | 输出格式化层      |  ← 结构化输出
                    +------------------+

codeagent-wrapper 的设计原则是"薄包装,厚适配"。包装层尽可能轻量,而适配层承担了参数映射、响应规范化、错误转换等重要职责。这确保了新后端的接入成本最低。

CLI 解析层

CLI 解析层基于 Go 标准库的 flag 包构建,提供了丰富的命令行参数支持。以下是所有支持的 CLI 参数及其说明:

参数 类型 默认值 说明
--backend string codex 指定 AI 后端,可选值:codex、claude、gemini
--task string 必填 任务描述文本或指向任务描述文件的路径
--files string[] 需要关注的文件列表,逗号分隔
--session-id string 自动生成 会话标识符,用于恢复或继续之前的会话
--parallel int 1 并行执行的任务数量上限
--worktree bool false 是否使用 Git worktree 隔离执行环境
--timeout duration 10m 任务执行超时时间
--output string text 输出格式:text、json、markdown

CLI 解析层在接收到参数后会进行严格的验证。对于必填参数(如 --task),如果缺失会立即报错并输出用法帮助。对于枚举类型参数(如 --backend),会检查值是否在合法范围内。

# 基本用法
codeagent-wrapper --backend claude --task "实现用户注册接口"

# 指定文件范围和并行度
codeagent-wrapper --backend codex --task "为以下文件添加单元测试" \
  --files "src/user.go,src/order.go,src/payment.go" \
  --parallel 3

# 使用 worktree 隔离并指定超时
codeagent-wrapper --backend gemini --task "重构数据库连接池" \
  --worktree --timeout 20m

# 恢复之前的会话
codeagent-wrapper --session-id sess_abc123 --task "继续上次的实现"

后端适配器模式

后端适配器层是 codeagent-wrapper 的核心设计模式。它定义了一个通用的 Backend 接口,所有 AI 后端适配器都必须实现该接口。这使得新后端的接入只需实现一个接口,无需修改上层代码。

// backend.go - 后端适配器接口定义
package backend

// Backend 定义了所有 AI 后端必须实现的统一接口
type Backend interface {
    // Name 返回后端的标识名称
    Name() string

    // Execute 执行一个任务并返回结果
    Execute(ctx context.Context, req *Request) (*Response, error)

    // Stream 以流式方式执行任务,通过 channel 返回增量结果
    Stream(ctx context.Context, req *Request) (<-chan Chunk, error)

    // Validate 验证后端配置是否有效(API 密钥、模型可用性等)
    Validate() error

    // Capabilities 返回后端支持的能力集合
    Capabilities() CapabilitySet
}

// Request 统一请求结构
type Request struct {
    Task        string            `json:"task"`
    Files       []string          `json:"files,omitempty"`
    Context     string            `json:"context,omitempty"`
    Parameters  map[string]any    `json:"parameters,omitempty"`
    SessionID   string            `json:"session_id,omitempty"`
    MaxTokens   int               `json:"max_tokens,omitempty"`
}

// Response 统一响应结构
type Response struct {
    Content     string            `json:"content"`
    Files       []FileChange      `json:"files,omitempty"`
    TokensUsed  TokenUsage        `json:"tokens_used"`
    Duration    time.Duration     `json:"duration"`
    Metadata    map[string]any    `json:"metadata,omitempty"`
}

目前支持三种后端适配器的实现。Codex 适配器通过 OpenAI API 调用 Codex 系列模型,支持函数调用和代码生成的专门优化。Claude 适配器对接 Anthropic API,利用 Claude 的长上下文窗口处理大型代码库分析任务。Gemini 适配器使用 Google AI API,在多模态处理(如截图分析)方面有独特优势。

每个适配器在内部负责将通用的 Request 结构转化为后端特定的 API 请求格式,并将后端响应转化为通用的 Response 结构。这种转化过程包括参数映射(如 temperature、max_tokens 等参数在不同 API 中的名称差异)、系统提示注入、以及响应内容的规范化。

会话管理器

会话管理器负责维护任务执行的状态和上下文,使得长时间运行的任务可以在中断后恢复。每个会话由一个唯一的 SESSION_ID 标识,会话状态以 JSON 格式持久化到本地文件系统。

会话的生命周期包括四个状态:created(已创建,尚未开始执行)、running(执行中)、paused(已暂停或中断,可恢复)、completed(已完成)。状态转换是单向的,除了 paused 可以回到 running 外,其他转换不可逆。

// session.go - 会话状态结构
type Session struct {
    ID          string          `json:"id"`
    Status      SessionStatus   `json:"status"`
    Backend     string          `json:"backend"`
    Task        string          `json:"task"`
    TaskHash    string          `json:"task_hash"`
    CreatedAt   time.Time       `json:"created_at"`
    UpdatedAt   time.Time       `json:"updated_at"`
    Checkpoints []Checkpoint    `json:"checkpoints"`
    Context     SessionContext  `json:"context"`
    Metadata    map[string]any  `json:"metadata"`
}

// Checkpoint 记录执行过程中的检查点
type Checkpoint struct {
    Index       int             `json:"index"`
    Timestamp   time.Time       `json:"timestamp"`
    Phase       string          `json:"phase"`
    State       json.RawMessage `json:"state"`
    FilesChanged []string       `json:"files_changed"`
}

会话文件默认存储在 ~/.pinable-agents/sessions/ 目录下,文件名格式为 {session_id}.json。每次状态变更都会立即写入磁盘,确保崩溃恢复的数据完整性。

输出格式化器

输出格式化器将后端响应转化为用户友好的展示格式。支持三种输出模式:text(纯文本,适合终端直接查看)、json(结构化数据,适合程序化处理)、markdown(格式化文档,适合保存为报告)。

在 text 模式下,输出格式化器会对代码块进行语法高亮(通过 ANSI 转义码),对文件变更进行 diff 格式展示,并在输出末尾附加执行摘要(耗时、token 用量、文件变更列表)。在 json 模式下,输出完整的 Response 结构体。在 markdown 模式下,生成包含目录、代码块和表格的完整文档。

# text 输出示例
codeagent-wrapper --backend claude --task "添加输入验证" --output text

# json 输出示例(适合管道处理)
codeagent-wrapper --backend codex --task "生成 API 文档" --output json | jq '.files'

# markdown 输出(适合保存报告)
codeagent-wrapper --backend gemini --task "代码审查" --output markdown > review.md

错误处理与重试逻辑

codeagent-wrapper 实现了分层错误处理机制。错误被分为三个级别:可重试错误(网络超时、速率限制、临时服务不可用)、配置错误(API 密钥无效、模型不可用)、致命错误(磁盘空间不足、权限不足)。对于可重试错误,系统采用指数退避策略自动重试,最多重试三次。

// retry.go - 重试策略实现
func executeWithRetry(ctx context.Context, fn func() error, maxRetries int) error {
    var lastErr error
    for attempt := 0; attempt <= maxRetries; attempt++ {
        if err := fn(); err != nil {
            if !isRetryable(err) {
                return fmt.Errorf("non-retryable error: %w", err)
            }
            lastErr = err
            backoff := time.Duration(math.Pow(2, float64(attempt))) * time.Second
            log.Printf("attempt %d failed, retrying in %v: %v", attempt+1, backoff, err)
            select {
            case <-time.After(backoff):
                continue
            case <-ctx.Done():
                return ctx.Err()
            }
        }
        return nil
    }
    return fmt.Errorf("max retries exceeded: %w", lastErr)
}

当所有重试都失败后,codeagent-wrapper 会在会话状态中记录失败的检查点,使用户可以在问题解决后通过 --session-id 从失败点恢复执行,而不需要从头开始。

从源码构建

如果你需要定制 codeagent-wrapper 或参与开发,可以从源码构建。构建过程依赖 Go 1.21 及以上版本。

# 克隆仓库
git clone https://github.com/PinableLab/codeagent-wrapper.git
cd codeagent-wrapper

# 安装依赖
go mod download

# 构建二进制文件
go build -o bin/codeagent-wrapper ./cmd/wrapper

# 运行测试
go test ./... -v -race

# 交叉编译(例如 Linux AMD64)
GOOS=linux GOARCH=amd64 go build -o bin/codeagent-wrapper-linux ./cmd/wrapper

# 安装到 GOPATH
go install ./cmd/wrapper

构建产物是一个单一的静态链接二进制文件,没有外部运行时依赖。二进制文件大小约为 15-20 MB(视目标平台而定)。你可以将二进制文件直接复制到 $PATH 中的任意目录即可使用。

性能基准测试

以下是在 Apple M2 Pro 芯片、32 GB 内存的 MacBook Pro 上测量的性能基准数据。测试任务为"在一个包含 50 个文件的 Go 项目中为指定的 3 个文件添加单元测试"。

指标 Codex Claude Gemini
CLI 启动时间 45ms 45ms 45ms
请求构建时间 12ms 15ms 11ms
后端响应时间 8.2s 6.5s 9.1s
输出格式化时间 3ms 3ms 3ms
会话持久化时间 2ms 2ms 2ms
总端到端时间 8.3s 6.6s 9.2s
内存峰值 28MB 32MB 26MB

从数据中可以看出,codeagent-wrapper 本身的开销(CLI 启动 + 请求构建 + 输出格式化 + 会话持久化)不超过 70 毫秒,端到端延迟的绝大部分来自 AI 后端的响应时间。Go 语言的低内存占用和快速启动使得 wrapper 层几乎是"透明"的。

高级配置选项

除了 CLI 参数外,codeagent-wrapper 还支持通过配置文件进行更细粒度的控制。配置文件路径为 ~/.pinable-agents/wrapper-config.json

{
  "defaults": {
    "backend": "claude",
    "timeout": "15m",
    "output": "text",
    "max_retries": 3
  },
  "backends": {
    "claude": {
      "model": "claude-opus-4-6",
      "max_tokens": 16000,
      "temperature": 0.3,
      "system_prompt_append": "请使用中文注释代码"
    },
    "codex": {
      "model": "o3",
      "max_tokens": 8000,
      "temperature": 0.2
    }
  },
  "session": {
    "storage_dir": "~/.pinable-agents/sessions",
    "auto_cleanup_days": 30,
    "max_checkpoints": 50
  },
  "logging": {
    "level": "info",
    "file": "~/.pinable-agents/logs/wrapper.log"
  }
}

故障排查

问题:后端连接超时

首先检查网络连接和 API 密钥是否有效。如果确认网络正常,可以增加 --timeout 参数的值。对于大型任务,建议设置 20 分钟以上的超时时间。

问题:会话恢复失败

检查会话文件是否存在且格式正确。可以使用 pinable-agents session inspect <session-id> 命令查看会话状态。如果会话文件损坏,只能重新开始任务。

问题:输出截断

某些后端在长输出时可能截断响应。通过 --backend-max-tokens 参数增大 token 上限,或拆分任务为多个子任务分别执行。