TheWaWaR/amp-local

★ 0Forks 0GitHub ↗Compare

README

amp-local

在本地跑一个 amp(ampcode.com)服务端 —— 让官方 amp CLI 完全在本机工作:LLM 调用走你自己的 端点(CLIProxyAPI / ollama / vllm / one-api / opencode Zen Go / OpenAI / Anthropic …),线程、 项目、附件全部落在本地磁盘,不依赖云端。

定位:CLI 是 executor(在本地执行工具),服务端是 agent 大脑(跑 LLM、编排回合)。amp-local 替代后者。协议细节来自对 amp bundle 与真实 ampcode.com 流量的逆向,见 notes/protocol.md。

快速开始

# 1. 准备配置(默认读取 ~/.amp-local/config.json,可用 AMP_LOCAL_CONFIG 指定)
cp config.example.json ~/.amp-local/config.json
$EDITOR ~/.amp-local/config.json

# 2. 启动(可选端口参数:./start.sh 9999)
./start.sh

# 3. 让 amp CLI 连到本地(API key 任意,服务端不校验)
AMP_URL=http://127.0.0.1:9876 AMP_API_KEY=local amp -x "你好"

依赖:Bun(启动脚本用 bun src/main.ts)。bun install 安装依赖后即可运行。

架构

amp CLI (executor)  ──REST + WebSocket──▶  amp-local (agent 大脑)
   本地执行工具                            · LLM 适配器(多 provider / 多协议方言)
   文件/Shell/工具注册                      · 回合编排、工具调度(tool_lease)
                                           · 线程/项目/附件/标签/技能存储

两条通道:

  • REST(/api/internal、/api/thread-actors、/actors/*、附件、线程搜索、远程线程等)
  • WebSocket
    • threadActor:文本帧 JSON-RPC 2.0(心跳 ping→pong);CLI 的 executor 连接、工具结果回传、 回合消息流(delta / message_added / agent_state / tool_lease…)都走这里
    • userActor / runner:二进制 rivet bare 帧(client-protocol v4);侧边栏摘要、pin、runner 注册、 远程线程意图等

支持 runner(Agents Anywhere) 闭环:CLI 注册为 runner 后,/api/remote-thread 创建的远程线程 通过 runnerIntentsUpdated 事件推给对应 runner 自动执行。

配置(声明式)

所有配置在 ~/.amp-local/config.json(可用 AMP_LOCAL_CONFIG 指定),无需环境变量。结构:

{
  "port": 9876,                                // 监听端口(默认 9876;AMP_LOCAL_PORT 覆盖)
  "dataDir": "/home/you/.amp-local",           // 数据目录(默认 ~/.amp-local;AMP_LOCAL_DATA_DIR 覆盖)
  "user": { "userId": "user_local", "username": "local" },
  "llm": {
    // 命名 provider,可多个;可互相引用(provider: "cliproxy" 之类)
    "providers": {
      "cliproxy": {
        "baseUrl": "http://127.0.0.1:8317/v1",
        "apiKey": "amp-local-dev"              // 明文密钥
      },
      "xai": {
        "baseUrl": "http://127.0.0.1:8000/v1",
        "apiKeyEnv": "XAI_API_KEY"             // 从环境变量读(推荐,密钥不落盘)
      },
      "opencode-go": {
        "baseUrl": "https://api.example-llm.com/v1",
        "apiKeyFile": "/home/you/.secrets/opencode.key",  // 从文件读
        "protocol": "chat"                     // 协议方言覆盖(见下)
      }
    },
    // 全局默认 provider(model 为默认模型)
    "default": { "provider": "cliproxy", "model": "gpt-4o-mini" },
    // mode → provider + model 绑定(low/medium/high/ultra,任意 key 均可)
    "modes": {
      "low":    { "provider": "cliproxy", "model": "gpt-4o-mini" },
      "medium": {
        "provider": "cliproxy",
        "model": "gpt-4o",
        "models": ["gpt-4o", "gpt-4o-mini"]    // fallback 链(见下)
      },
      "high":   { "provider": "cliproxy", "model": "claude-3-5-sonnet" },
      "ultra":  { "provider": "cliproxy", "model": "claude-3-5-sonnet" }
    },
    // 全局协议方言(可被 provider/mode 级覆盖)
    "protocol": "responses"
  }
}

字段说明

字段 说明
port / dataDir / user 监听端口、数据目录、本机用户标识(userId 同时用作项目 namespace 前缀)
provider baseUrl LLM 端点,不带尾斜杠(如 http://127.0.0.1:8317/v1)
provider apiKey / apiKeyEnv / apiKeyFile 明文 / 环境变量名 / 文件路径(文件内容 trim 后使用);三选一,优先级 apiKey > apiKeyEnv > apiKeyFile。路径不做 ~ 展开,请写绝对路径
provider provider 引用另一个 provider,继承其 baseUrl/apiKey/protocol 后再覆盖
llm.default 全局默认 provider;model 为默认模型
llm.modes.<mode> 每个 mode 独立绑定;缺 provider/baseUrl 时走全局默认;model 支持 models 数组
mode models fallback 模型链:数组按序尝试,上游模型间歇不可用时自动降级(如 ["gpt-4o", "gpt-4o-mini"])
protocol 协议方言,见下

协议方言(responses / chat / anthropic)

值 端点 适用
responses(默认) /responses(OpenAI Responses API) CLIProxyAPI 默认;直连 OpenAI 原生
chat /chat/completions ollama / vllm / one-api / opencode Zen Go 等 OpenAI 兼容网关
anthropic /messages 直连 Anthropic(适配器可用,部分特性尚待完善)

环境变量覆盖(优先级高于配置文件)

变量 作用
AMP_LOCAL_CONFIG 配置文件路径(默认 ~/.amp-local/config.json)
AMP_LOCAL_PORT 端口
AMP_LOCAL_DATA_DIR 数据目录
AMP_LOCAL_LLM_BASE_URL / AMP_LOCAL_LLM_API_KEY / AMP_LOCAL_LLM_MODEL 全局默认 provider 的旧式覆盖
AMP_LOCAL_MODELS JSON 对象 {mode: model} 兼容旧写法(配置文件 modes 优先)

功能

  • 多 provider + 多模式绑定:low / medium / high / ultra 各自映射到 provider + 模型; CLI 切换 mode 即换模型
  • 协议方言适配:同一套 amp 消息块(text/thinking/tool_use/tool_result)自动转换为 responses / chat / anthropic 格式,各上游怪癖(chat 要求 tool 消息紧跟 assistant、 responses 的 item_id 关联、reasoning 回传等)隔离在适配器内部
  • 模型 fallback 链:models 数组按序降级
  • 线程全生命周期:创建/恢复/导入(/request/import)、归档、pin、重命名、标签、全文搜索、 编辑消息、重试、truncate、turn 串行队列、草稿
  • 项目注册表:projects.json 持久化;listAccessibleProjects / getProject / createProject / updateProject / deleteProject / resolveProjectByRepositoryURLs 等,支持 git remote 匹配
  • 服务器实现工具(直接进 LLM 工具集,不走本地 executor): read_thread create_thread thread_interact wait_for_threads get_schedule set_schedule update_schedule clear_schedule Task finder view_media librarian list_agent_modes list_runners get_current_user_identity
  • Skills:loadSkills 从 ~/.agents/skills、~/.config/agents/skills、~/.claude/skills 及 工作区 .agents/skills、.claude/skills 读取 SKILL.md,CLI 落盘后 skill 工具直接可用
  • 附件:上传(/api/attachments)→ 哈希存盘 → 多级重定向下载(/attachments → /user-content/attachments → /raw-attachments,不同 origin 以适配 CLI 外部存储跟随逻辑)
  • Runner / 远程线程(Agents Anywhere):registerRunner / runnerHeartbeat / /api/remote-thread / createRemoteExecutorThread 完整闭环
  • 插件生命周期:回合发 session.start / agent.start / agent.end 插件消息
  • 标题自动生成:无标题线程取首条用户消息截取 48 字

数据存储(默认 ~/.amp-local/)

路径 内容
threads/<TID>.json 线程 + 全部消息(消息粒度持久化,中断/被杀不丢)
projects.json 项目注册表
attachments/ 附件(sha256 文件名 + .meta.json 元数据)

协议与端点速览

REST 端点(详见 notes/protocol.md):

端点 说明
POST /api/internal?<method> 核心方法网关:getUserInfo loadPlugins listAgentModes loadSkills archiveThread、项目/线程/标签/账单等(方法在 query 或 body.method)
POST /api/thread-actors 创建/复用线程,返回 {threadId, wsToken, ...}
POST /api/thread-actors/<id> 标记线程已导入
POST /api/user-actor-credentials userActor 凭据
POST /api/remote-thread 模拟 web 端远程创建线程(Agents Anywhere)
POST /api/attachments 附件上传
GET /api/threads/find?q= 线程全文搜索
GET /actors/metadata、GET /actors/actors rivet actor 解析/元数据
POST /gateway/…/request/import 线程数据导入
POST /gateway/…/action/<name> userActor HTTP action(rivet HTTP 通道)

WebSocket:

  • threadActor:JSON-RPC 2.0 文本帧;CLI→服务器 executor_connect executor_tools_register client_append_user_msg executor_tool_result 等;服务器→CLI 初始化序列 + delta / message_added / agent_state / tool_lease 等回合事件流
  • userActor:bare/cbor 二进制帧(Init / ActionRequest / Event);getRecentThreads、 setThreadPinned、registerRunner、runnerHeartbeat、订阅事件

认证:接受任意 key,不校验(Authorization: Bearer <key>;WS 用 Sec-WebSocket-Protocol 子协议携带 wsToken)。CLI 侧用 AMP_API_KEY=local 即可。

开发

bun install       # 安装依赖(@rivetkit/bare-ts、cbor-x、vbare)
bun run typecheck # tsc --noEmit
./start.sh        # 或 bun src/main.ts

目录结构:

src/
  main.ts          # 入口:Bun HTTP + WebSocket
  config.ts        # 声明式配置 + 环境变量覆盖
  rest-api.ts      # HTTP 端点(fetch handler)
  ws-handler.ts    # threadActor 的 JSON-RPC 消息分发
  agent-loop.ts    # agent 回合循环 + turn 队列 + 标题生成
  llm.ts           # LLM 适配器层(blocks ↔ 各协议方言 + SSE 解析)
  server-tools.ts  # 服务器实现工具
  server-state.ts  # 共享状态 + rivet bare 帧编解码
  store.ts         # 线程本地存储
  projects.ts      # 项目注册表
  thread-format.ts # CLI 线程格式转换
  types.ts         # 协议类型定义
notes/
  protocol.md      # 协议规格(逆向自真实流量)
  server-tools.md  # 服务器工具实测格式

已知局限

  • 不校验 API key / 无鉴权,仅适合本机或可信网络
  • anthropic 适配器可用但部分特性未完善;模型注册表(src/models.ts)为逆向数据,部分条目不完整
  • 单进程内存态会话(session),重启后线程从磁盘恢复

Contributors

0WD0

Issues