magic-agent
统一的 agent CLI 代理 —— 把 claude / codebuddy / trae / llm / codex / openclaw / dsh 七家 CLI 与 arkclaw(A2A JSON-RPC 网关)、codebuddy-gateway(CodeBuddy Code HTTP 网关)的非交互调用收成一条命令,提供一致的引擎/模型切换、超时与重试、固定输出格式与稳定退出码。适合脚本化编排与上层工具集成。
能做什么
| 能力 | 说明 |
|---|---|
| 多引擎统一调用 | 一条命令串起 claude / codebuddy / trae / llm / codex / openclaw / dsh / arkclaw / codebuddy-gateway 这十种后端,参数语义统一 |
| 引擎与模型清单 | --engines 给出当前可用的引擎、模型列表与积分倍率;install 字段给出一键装/升级命令 |
| 流式 + 追加需求 | --stream 走各引擎原生协议;--keep-alive / --append 支持常驻会话里中途补需求 |
| 统一 wire | 多模态附件、用户选择(AskUserQuestion)、四档权限模型都收成同一套协议,CLI 端与上层 UI 共用收口 |
| 客户端契约面 | --contract 给固定 schema(contractVersion + engines[].capabilities),桌面 / 移动端插件启动时按它做能力降级 |
安装
npm install -g magic-agent # 从 npmjs 全局安装(无需 Go)
npm install -g ./magic-agent-<version>.tgz # 从本地 tgz 安装(离线 / 内网)
npm run build:current # 从源码构建当前平台(core + client,Go 1.26+)
⚠️ 截至 2026-09-28,npmjs 上还查不到
magic-agent(首次正式发布尚未发生), 所以npm install -g magic-agent暂时装不上 —— 先用本地 tgz 或源码构建。
平台产物缺失时 postinstall 会用本机 Go 现场编译;两者都没有只告警,不阻断安装。同一个 postinstall 还会按需安装 llm CLI(-e llm 的依赖,隔离在 ~/.llm-venv)。
发布由 GitHub Actions 完成:推 v*.*.* tag 触发 5 平台交叉编译并 npm publish 到 npmjs;手动触发走 dry-run。流程细节、NPM_TOKEN 配置与本地打包见 docs/development.md。
引擎依赖
七个 CLI 按需安装,未安装的引擎自动探测失败但不影响其他引擎:
| 引擎 | CLI | 探测路径 / 环境变量 |
|---|---|---|
| claude | Claude Code | MAGIC_AGENT_CLAUDE_BIN → /opt/homebrew/bin/claude → PATH |
| codebuddy | CodeBuddy Code CLI(npm i -g @tencent-ai/codebuddy-code) | MAGIC_AGENT_CODEBUDDY_BIN → PATH → npm 全局前缀 |
| codebuddy-ai | 同上(同一个 CLI 的第二个账号) | MAGIC_AGENT_CODEBUDDY_AI_BIN → PATH → npm 全局前缀 |
| trae | TRAE CLI 2.0(traex) | MAGIC_AGENT_TRAE_BIN → %LOCALAPPDATA%\Programs\TraeCLI\bin\traex.exe / ~/.local/bin/traex → PATH |
| llm | simonw/LLM | MAGIC_AGENT_LLM_BIN → ~/.llm-venv/bin/llm → /opt/homebrew/bin/llm → PATH |
| codex | @openai/codex | MAGIC_AGENT_CODEX_BIN → /opt/homebrew/bin/codex → PATH |
| openclaw | OpenClaw | MAGIC_AGENT_OPENCLAW_BIN → /opt/homebrew/bin/openclaw → PATH |
| dsh | DeepSeek Harness | MAGIC_AGENT_DSH_BIN → ~/.local/bin/dsh → PATH → npm 全局前缀 |
| arkclaw | 无(远端 A2A 网关) | 配置文件的 arkclaw 节,或 MAGIC_AGENT_ARKCLAW_URL / _KEY / _CLAW_ID |
| codebuddy-gateway | 无(已在跑的 CodeBuddy Code HTTP 网关) | 配置文件的 codebuddyGateway 节,或 MAGIC_AGENT_CBGW_URL / _PASSWORD |
探测链最后一跳是 npm 全局前缀 <NPM_CONFIG_PREFIX>/bin,专治「CLI 装好了、探测却说 not found」(容器常把 npm i -g 的落点设成不在 PATH 里的私有前缀)。优先级不变:显式参数 > 环境变量 > 候选路径 > PATH > npm 前缀。
codebuddy 与 codebuddy-ai 是一个 CLI、两个账号:跑同一个二进制,靠
authentication.id 分开票据(sharedDataPath/auth/<id>.info),互不顶号。
各自登录一次即可,登录态落进自己的票据:
magic-agent --login codebuddy # 拉起交互式会话,在里面执行 /login
magic-agent --login codebuddy-ai # 同上;两个账号各自独立
不再使用 WorkBuddy / WorkBuddy AI 桌面 App 内置的那份 CLI —— 那份的凭据由 App 用受管密钥静态加密,独立进程解不开(
missing-key),只会拿到空输出。
引擎与模型清单(--engines)
magic-agent --engines # JSON 数组:引擎 + 可用性 + 模型 + 版本 + 一键安装命令
magic-agent --engines --no-models # 跳过模型与版本探测(不启动任何 CLI,快)
每行的字段:
| 字段 | 含义 |
|---|---|
engine | 引擎名 |
ok | 该引擎是否可用(CLI 存在 / 网关配置齐备) |
bin | 可用时给二进制路径;无本机 CLI 的引擎给端点 URL |
note | 不可用原因(ok:false 时) |
install | 一键安装 / 升级命令(shell 一行)。ok:false 时拿它安装,已装的引擎重跑就是升级到最新版。桌面端 GUI 应用与网关类引擎没有该字段 |
version | 引擎当前版本号(尽力而为,拿不到就不给)。是「升级有没有生效」的依据,不是可用性判据 |
models | 该引擎当前支持的模型(动态探测,来源见下) |
models_note | 拿不到 models 时的原因 |
model_credits | 积分倍率表(model → "0.34")。codebuddy / codebuddy-ai 给出;客户端按它给模型加「限免 / 夜间免费」角标与结算 |
workspace | 指定工作目录的落地方式(flag:-C / cwd / none) |
streaming | 是否支持 --stream |
attachments | 收附件的落地方式(原生图片 / 路径写进提示词) |
append | 是否支持常驻会话 + 追加消息 |
ask | 「需要用户选择」的落地方式 |
permission | 四档权限模型的落地方式 |
capabilities | 该引擎的静态能力 id 集合,回答「能做什么」;与 ok / models 那些回答「此刻如何」的字段严格分开。取值见 internal/agent/capability.go |
--json 为兼容旧调用保留(行为相同)。
一键安装 / 升级(install 字段)
| 引擎 | install |
|---|---|
| claude | npm install -g @anthropic-ai/claude-code |
| codex | npm install -g @openai/codex |
| openclaw | npm install -g openclaw@latest |
| dsh | npm i -g @deepseek-ai/dsh |
| trae | sh -c "$(curl -fsSL https://trae.cn/trae-cli/install_v2.sh)"(Windows: `irm https://trae.cn/trae-cli/install_v2.ps1 |
| llm | python3 -m venv ~/.llm-venv && ~/.llm-venv/bin/pip install llm |
| codebuddy / codebuddy-ai / arkclaw / codebuddy-gateway / 具名 A2A agent | 无该字段(桌面端 GUI 应用 / 网关,没有可执行的安装命令),怎么才能用见同行 note |
# 装齐本机缺的引擎
magic-agent --engines --no-models | jq -r '.[] | select(.ok|not) | "\(.engine)\t\(.install // .note)"'
# 升级:看版本号 → 跑命令 → 再看版本号(变了才算升上去)
magic-agent --engines --no-models | jq -r '.[] | select(.install) | "\(.engine)\t\(.version // "-")\t\(.install)"'
模型清单来源(不硬编码)
models 一律从各引擎自己的权威入口现取现算,代理侧不维护任何模型名常量:
| 引擎 | 动态来源 |
|---|---|
| claude | ~/.claude/settings.json(顶层 model + env 里 ANTHROPIC_*MODEL[*_NAME]) |
| codebuddy | 客户端模型选择器清单 ∩ 客户端合并配置缓存;回退 codebuddy --help 的 Currently supported |
| codebuddy-ai | 同上(独立配置目录 ~/.workbuddy-ai) |
| trae | traex models --json |
| llm | llm models |
| codex | codex debug models |
| openclaw | openclaw models list --json |
| dsh | $DSH_HOME/settings.yaml 里已配置的模型,输出 route/model |
| arkclaw / codebuddy-gateway | 无清单(模型由网关侧决定),改用 models_note 说明 |
探测只跑只读子命令(不发起推理、不消耗额度),但会真的启动进程,因此并发执行、单引擎上限 30s;任一引擎失败只写进该行 models_note。
客户端契约(--contract)
magic-agent --contract # {"contractVersion":2,"engines":[...]}
magic-agent --contract | jq -r '.contractVersion' # 启动时先校验这个
| 字段 | 含义 |
|---|---|
contractVersion | 契约面版本(当前 2)。客户端超出自己支持的范围就明确报错并提示升级,不要带着不匹配的能力继续跑 |
engines | 与 --engines 的行完全同构,每行另含 capabilities |
版本规则:只增字段不升版本;字段改名 / 语义变化 / 删除时必须升 contractVersion。--contract 默认不探测模型(模型探测要起真 CLI,30 秒级,客户端启动路径等不起),要连模型一起拿就写 --no-models=false。
用法
无子命令设计:所有功能都走根命令 + flags。
# 基本提问(默认 json 输出;位置参数等价于 -p)
magic-agent -p "用一句话解释什么是熵"
magic-agent -o text -p "用一句话解释什么是熵"
# 切引擎、切模型
magic-agent -e codebuddy "写一首俳句" # codebuddy 默认 hy3
magic-agent -e codebuddy -m glm-5.3 "写一首俳句"
magic-agent -e trae -m My-MiniMax-M3 "..." # 内部转 traex exec -m <model>
magic-agent -e llm -m minimax-m3 "问题" # llm 用自己注册的模型
# 工具与权限(--tools 默认 off = 纯 chat)
magic-agent -e claude --tools on -p "看看当前目录有什么"
magic-agent -e claude --tools Bash,Read -p "读一下 README"
magic-agent -e claude --tools on --permission auto -p "重构这个函数"
# 超时 + 重试 + 系统提示词
magic-agent -e claude -t 3m -r 2 --verbose -o text "复杂的分析任务"
magic-agent -e claude -s "你是严谨的翻译官,只输出译文" -o text "Hello, world"
# 管道输入 / 文件
cat doc.md | magic-agent -e claude -o text -f - "总结上文"
magic-agent -e claude -p ./prompt.md "补充一句" # 提示词给文件路径
# 附件(截图 + 提示词)
magic-agent -p "这张图什么颜色" -a shot.png
magic-agent -p "对比两张图" -a a.png -a b.png
# 流式输出
magic-agent --stream -e claude -o text "复杂问题"
magic-agent --stream --no-thinking -e claude "问题" # 只隐藏思考事件
magic-agent --disable-thinking -e claude "问题" # 请求模型真正关闭思考
# 会话
magic-agent --sessions # 会话登记表
magic-agent --session-log <id> # 读这段会话的事件历史({session, events})
magic-agent --session-log <id> --after 20 # 增量续读:只回 seq > 20 的部分
magic-agent --stop <session_id> # 停掉这条会话的引擎进程组
magic-agent --append <run_id> -p "追加:顺便把 lint 也跑了"
Flags
| Flag | 默认 | 说明 |
|---|---|---|
-e, --engine | codebuddy | 引擎:claude | codebuddy | codebuddy-ai | codebuddy-gateway | trae | llm | codex | openclaw | dsh | arkclaw,外加配置里 agents 声明的具名 agent |
-m, --model | 空 | 模型(空 = 引擎默认;codebuddy 默认 hy3) |
-s, --system | 空 | 系统提示词;空 = 用配置里的 systemPrompt。值可以是文件路径或 @文件 |
-p, --prompt | 空 | 提示词;值可以是文件路径或 @文件 |
-f, --file | 空 | 从文件读 prompt(- = stdin) |
-a, --attach | 空 | 附件(截图 / 图片),可重复或逗号分隔 |
--tools | off | off(纯 chat)| on(agent 模式)| 逗号分隔白名单 |
-t, --timeout | 1h | 单次尝试超时(如 90s / 3m) |
-r, --retries | 0 | 失败重试次数(总尝试 = 1 + retries) |
--backoff | 2s | 首次重试退避(指数翻倍,上限 30s,带抖动) |
-o, --output | json | 输出格式:json | text |
--stream | 关 | 流式输出(text 模式思考走 stderr) |
--no-thinking | 关 | 流式模式下不转发思考过程增量(只隐藏,不关闭模型思考) |
--disable-thinking / --no-think | 关 | 请求引擎真正关闭模型思考:claude --thinking disabled、codex effort=none、codebuddy alwaysThinkingEnabled=false、dsh reasoningEffort=off、llm 传 reasoning_effort=none(不自动换模型) |
--engines | 关 | 列出引擎、可用性、模型、版本与一键安装命令 |
--no-models | 关 | 配合 --engines:跳过模型与版本探测 |
--json | 关 | 兼容保留(行为同 --engines 的默认 JSON 输出) |
--stop | 空 | 停止指定会话 / 运行(传 session_id 或 run_id);只停得掉已存档的会话 |
--sessions | 关 | 列出会话登记表(只列已存档的会话) |
--save-registry | 关 | 把会话登记落盘(<run_id>.json),让 --sessions / --stop 事后能按 id 寻址。默认关:不留痕;不留档的会话停不掉 |
--session-log | 空 | 读一段会话的事件历史(传 session_id 或 run_id);输出 {session, events} |
--after | 0 | 配合 --session-log 增量续读:只回 seq > N 的事件(另附 count/after/lastSeq/snapshotRequired) |
--save-history | 关 | 把流式会话的事件落盘存档(<session_id>.jsonl),供 --session-log 回看。默认不存:一次性调用不留痕 |
--keep-alive | 开 | 常驻会话(仅 claude/codebuddy 的 --stream 调用生效) |
--append | 空 | 向常驻会话追加一条消息(传 session_id 或 run_id) |
--idle | 5m | 常驻会话空闲收工时长(0 = 本轮结束就收工) |
-v, --verbose | false | 重试过程打印到 stderr |
prompt 输入优先级:-p/--prompt > 位置参数 > --file > stdin 管道(stdin 非 TTY 且无其他输入时自动读)。
流式模式(--stream)
--stream 走各引擎的原生协议:claude / codebuddy / trae 走 CLI 的原生 stream-json NDJSON,llm 走纯文本流式,openclaw 走 ACP 桥,arkclaw 与 codebuddy-gateway 走 SSE。增量实时转发,无缓冲等待。
思考通道与正文分开:-o text 下正文进 stdout、思考进 stderr;-o json 下是 NDJSON 事件流(thinking / text / tool_use / tool_result / ask / turn_end),末尾一条 result 收尾行。
各引擎的流式成色不同(其中 openclaw 的 ACP 桥、arkclaw 的 A2A SSE、dsh 的 SDK 通道差异最大),细节见 docs/streaming.md。
常驻会话与追加需求(--keep-alive 默认开)
claude / codebuddy 的 --stream 调用默认即常驻:长任务跑着的时候,可以在另一个进程追加需求。
magic-agent -e claude --stream -p "先把仓库跑一遍测试" -o text # ① 起会话
magic-agent --append <run_id> -p "追加:顺便把 lint 也跑了" # ② 中途追加
magic-agent --stop <run_id> # ③ 收工(或空闲 --idle 自动退出)
magic-agent -e claude --stream --keep-alive=false -p "..." # 要「一轮结束就退出」的老行为
| 维度 | 行为 |
|---|---|
| 支持范围 | 只有 claude / codebuddy 的 --stream 调用;其它情况自动忽略(显式传 --keep-alive 却不满足条件 → exit 2 报错) |
| 追加语义 | 消息写进引擎 stdin 成为下一轮 user 消息:本轮跑完后接着处理,不打断当前轮 |
| 收工 | 最后一轮结束后 --idle(默认 5m)内无人追加则优雅收尾;--idle 0 = 本轮结束就收工 |
| 超时 | 常驻生效期间不套 -t 的默认 1h(长任务 + 追加不该被砍),显式给 -t 才生效 |
⚠️ 默认常驻带来的行为变化:进程会在最后一轮结束后继续存活
--idle等待追加。调用方若要「一轮完成」的信号,请读事件流里的turn_end事件(而不是等进程退出),或启动时传--keep-alive=false。
需求聚合(--requirements / --consolidate-requirements)
把会话里聊过的需求自动归纳成「模块 → 功能点」两级 markdown 文档,存储在
~/.magic-agent/requirements/(MAGIC_AGENT_REQUIREMENTS 可覆盖)。
magic-agent --requirements all # 列全部工作区(只读,不调模型)
magic-agent --requirements ~/work/proj # 只列这个目录(也认 ws id)
magic-agent --consolidate-requirements ~/work/proj # 手动整理:首次=按目录初始化,之后只处理新会话
magic-agent --consolidate-requirements . --requirement-all # 全量重放(回填/校正)
magic-agent --consolidate-requirements . --requirement-module 登录 # 只整理「登录」这个模块
- 第一次整理 = 初始化:工作区还没初始化过时,先有界扫描空间目录,用客户端配置的默认
引擎(
--requirement-engine;空 = 自动挑 claude / codebuddy / codex / dsh 等能读代码的) 反推一版用户视角的需求基线;此前旧会话记为已消费,之后只消费上次整理后的新会话。 默认引擎不能读目录(如llm)会明确报错并提示换引擎。目录为空不算失败,会回落到会话增量。 - 定时整理(每 5 分钟):插件起一个定时任务,每 5 分钟让 core 整理「上次整理后新结束、
且正常完成」的会话(判据是会话日志里 turn_end 正常收尾,不是「这一轮 HTTP 请求成功」——
PC / 手机 / 直接跑 CLI 的会话一视同仁)。
MAGIC_CLIENT_NO_REQ_AUTO=1关闭;它带--requirement-auto,绝不触发首次目录初始化;忙就顺延,一轮不会与下一轮叠加。 一轮只收「上次整理后新结束、正常完成」的会话,顺手不会把别的会话灌进记忆流;上一轮没整理完 的条目会在下一轮继续。 - 模块级整理:
--requirement-module <模块>只把这个模块的增量写回该模块, 不推进空间游标(别的模块的记忆仍留在待整理),可以重复点;它不触发首次目录初始化。 - 需求页每个空间组头有独立「整理」,只整理那个空间;点进某个模块后,二级页的「整理」
只整理当前模块;顶栏「全部整理」按空间串行跑一遍,一键触发全部(某个空间失败不影响后面的)。
没有新会话时返回
noop,不会空跑一次模型。
详细契约见 CLIENT-CONTRACT.md §3.4.1。
停止指定会话
magic-agent --sessions # 列出会话登记表(新→旧)
magic-agent --stop <session_id> # 按会话 id 停
magic-agent --stop <run_id> # 按运行 id 停(新会话还没拿到 session_id 时)
引擎 CLI 在独立进程组里跑,所以调用方对 magic-agent 发信号带不走它 —— 界面显示「已停止」而引擎还在后台跑。因此每次调用都落一条记录(~/.magic-agent/sessions/<run_id>.json,MAGIC_AGENT_SESSIONS 可改目录,永久保留),--stop 按记录里的 pid 杀整个进程组(先 SIGTERM,2s 内不退再 SIGKILL)。
| 情况 | 退出码 |
|---|---|
| 在跑 → 已停 / 进程已不在 / 会话已结束(幂等,重复点「停止」不算错) | 0 |
| id 不存在 | 1 |
--stop 后没给 id | 2 |
附件(文件+提示词)
提示词照旧,附件是并列的第二份输入:「截图 + 提示词」是主要用法。
magic-agent -p "这张图什么颜色" -a ~/Desktop/shot.png
magic-agent -p "对比这两张图的差异" -a a.png -a b.png # 可重复,也可逗号分隔
每个引擎尽量走自己的原生附件通道(--engines 的 attachments 字段给出机器可读答案):
| 引擎 | 落地方式 |
|---|---|
claude / codebuddy | 原生 stream-json:图片作为 image content block 经 stdin 传入 |
codex | 原生 -i/--image(只收图片) |
llm | 原生 -a(委托 llm CLI 时)/ OpenAI 兼容 content parts(直连配置模型时) |
arkclaw | A2A 原生 file part(base64 inline) |
trae / openclaw / dsh / codebuddy-gateway | 无原生通道 → 把绝对路径写进提示词清单,靠引擎自己的读文件工具 |
校验:路径必须存在、是普通文件、≤32MB;重复路径自动去重;类型按魔数嗅探(不信扩展名)。无原生通道的引擎会明确提示不静默;提示词在有原生通道时原样不改写。
能力上限取决于模型:链路只保证把附件按协议送到位,模型是否真能看图要看后端。实测同一张纯红 PNG,
-e llm直连 MiniMax-M3 答对,而走某网关的 claude CLI 把图片块吞掉了。
需要用户选择(AskUserQuestion)
模型发起 AskUserQuestion(或工具调用待授权)时,claude 是普通 tool_use 块、codebuddy 族是 control_request——wire 上两种完全不同的形状。magic-agent 把它们归一化成一份统一格式,--stream 输出里多一类 ask 事件(消息里带 questions / options),上层 UI 拿到后渲染给用户,再用 --append 把选择传回去。
magic-agent --engines --no-models | jq -r '.[] | "\(.engine)\t\(.ask)"'
# claude → "tool:AskUserQuestion";其余(含 codebuddy 族)→ "none"
⚠️ codebuddy / codebuddy-ai 报
none是实测结论(2026-09-28):官方文档把AskUserQuestion列为内置工具,但 CLI 只把它交给第一方宿主(官方 App / IDE)——第三方宿主驱动的通道下模型根本看不到该工具。七种配置实测全部拿不到(-p/--tools default/ 白名单 /--allowedTools/-y/auto/ SDK 声明capabilities.elicitation.form/CODEBUDDY_HOST_CAPABILITIES/--acp±elicitation.form),模型一律搜索不到、退化成文字提问。此前按"同族协议"推断成支持,会让上层 UI 承诺永远不出现的决策卡。需要决策卡请用claude引擎。 详见 docs/engines.md。
wire 形状、三条通道与接住回答的写法见 docs/notes.md。
提示词可以是文件路径
长提示词写在文件里,不必每次 -f 或 cat |:-p / 位置参数 / -s 的值命中一个已存在的普通文件时,直接按文件内容用。
magic-agent -p ./prompt.md # 按文件内容提问
magic-agent -p ./prompt.md "补充一句" # 文件内容在前、追加文本在后
magic-agent -p @notes/task.md # @ 强制按文件读(读不到 → exit 2)
magic-agent -s ./reviewer.md "审一下这段" # 系统提示词也能给文件
自动识别的判据刻意保守,避免把正常提示词误判成路径:必须是单行、≤4096 字节、stat 出来是普通文件。所以多行提示词、粘贴的长文都不受影响。~ 前缀会展开。
默认系统提示词与配置
不想每次调用都敲 -s,就把默认系统提示词写进配置文件 —— 对所有引擎生效:
mkdir -p ~/.config/magic-agent && cat > ~/.config/magic-agent/config.json <<'EOF'
{
"systemPrompt": "你是一个中文助手,始终用中文回答所有问题。",
"arkclaw": { "url": "…", "key": "…", "claw_id": "…" }
}
EOF
| 维度 | 行为 |
|---|---|
| 生效条件 | 调用时未给 -s → 注入配置里的 systemPrompt;给了 -s 则 -s 优先,不叠加 |
| 作用范围 | 全部引擎 |
| 键名兼容 | systemPrompt | system_prompt | system 任选其一 |
| 临时覆盖 | 环境变量 MAGIC_AGENT_SYSTEM_PROMPT 优先于文件值 |
| 配置文件路径 | 默认 ~/.config/magic-agent/config.json(MAGIC_AGENT_CONFIG 覆盖,XDG_CONFIG_HOME 优先于 ~/.config) |
| 配置写坏时 | 不阻断调用(本次不注入),-v 打印原因,不静默 |
完整配置项见 config.example.json。
输出格式
json(默认):stdout 单行 envelope。
{"engine":"claude","model":"claude-sonnet-4-6","session_id":"...","attempts":1,"latency_ms":534,"text":"..."}
text(-o text):stdout 只含模型正文 + 尾换行。
失败时:stdout 恒为空(不产生半截内容),错误打到 stderr,格式与 -o 联动。json 模式下 stderr 也是一行 envelope,可直接 jq -r .reason 取根因。
| 字段 | 说明 |
|---|---|
error | 完整错误链(含引擎 / 重试包装),面向人排查 |
reason | 最内层根因(stderr 摘要 / 超时 / 非零退出码),面向程序分支判断 |
attempts | 实际执行次数;0 = 参数校验阶段即失败 |
手机 / 平板连接(client 子命令)
npm 包同时装着 core(magic-agent)和客户端插件(magic-client),后者提供 Web UI
与 /desk/* 接口。手机要用它,就在装包的那台电脑上把插件跑成后台服务:
magic-agent client start # 后台常驻(关掉终端也还在),默认手机可连
magic-agent client status # 在不在、端口、手机地址、健康检查(--json 给脚本)
magic-agent client stop # 停掉(本来没跑也算成功)
magic-agent client start --local # 只给本机用(绑 127.0.0.1)
同一台设备的配置只放一个目录:
~/.magic-agent(MAGIC_AGENT_HOME可换根)。旧版的~/.magic-client/会在第一次启动magic-client时自动搬过来(令牌 / 状态 / 日志 / 默认数据目录), 手机里存的「地址 + 令牌」不受影响;旧目录只留一份备份,可以手工删。
start 默认绑 0.0.0.0:9100,会打印每个网卡一条 http://<局域网IP>:9100/?token=…,以及 /pair
配对二维码页 —— 那条在电脑上打开,手机扫屏幕上的码(或把地址整行复制到手机 App)。
| 事实 | 位置 / 说明 |
|---|---|
| 状态文件(pid / 端口 / 令牌) | ~/.magic-agent/client.json,0600;--state 或 MAGIC_CLIENT_STATE 可改 |
| 令牌(跨重启稳定、全机共用) | ~/.magic-agent/token,0600;删掉它才会换新的 |
| 日志 | ~/.magic-agent/logs/magic-client.log;--log 或 MAGIC_CLIENT_LOG 可改 |
| 设备配置(引擎 / 模型 / 团队 / 置顶 / 字体 / 主题 / 通知 / 收藏 / 环境列表) | ~/.magic-agent/mobile-prefs.json,桌面与手机共用一份(/desk/prefs);桌面 tab 没有桌面壳也能同步(同源 HTTP + URL 里的令牌),点开配置菜单 / 切回页面 / 每 20 秒会主动拉取,不用刷新 |
| 各客户端插件的数据目录 | ~/.magic-agent/apps/<app-id>/(作业队列 / 实例 id / 锁;按插件分开,锁才不打架) |
| 界面资源 | 自动取与二进制同包的 client-ui/ client-ui-mobile/(--ui-dir / --mobile-dir 可覆盖) |
| core 路径 | 自动用这一份 magic-agent(MAGIC_AGENT_BIN),不取 PATH 里可能更旧的 |
要点:
- 默认就绑
0.0.0.0:9100,手机在同一 Wi-Fi 下可直接连;只想本机访问加--local(绑127.0.0.1)。跨网不在本命令范围内。 - 局域网模式下令牌是唯一门锁,短于 24 字符会被直接拒绝启动;默认生成的 32 位十六进制远超这条线。
- 令牌跨重启稳定是刻意的:手机里存的是「地址 + 令牌」,每次
start换一个就等于配对作废。 status的判据是「pid 活着 且/desk/health答得上」,不是只看进程;不健康时退出码 3。- 默认端口固定
9100(--addr可覆盖),跨重启稳定;被占用时启动会明确报错,不会悄悄换端口。 - 排障要看前台日志就跑
magic-client serve(同一个二进制,serve不脱离终端)。 magic-agent client …只是转发层:core 不依赖插件(internal/boundary钉着这条), 所以参数集合由magic-client start --help定义。
退出码
| 码 | 含义 |
|---|---|
| 0 | 成功 |
| 1 | 调用失败(引擎错误 / 超时耗尽 / 重试耗尽) |
| 2 | 参数或输入错误(未知引擎、非法格式、空 prompt 等) |
| 3 | 仅 client status:服务未运行(或进程在但健康检查失败),便于脚本判活 |
重试语义
- 可重试:网络类(connection refused / reset、EOF、timeout、signal killed)、限流类(429、rate limit、503 overloaded)、单次尝试超时。
- 快速失败:参数错、鉴权错、空输出、CLI 明确报错等不可恢复错误 —— 不浪费重试。
- 退避:
backoff * 2^(n-1)+ 抖动,上限 30s;整体 context 取消会立即打断等待。
所有引擎都以独立进程组运行:超时 / 取消时 kill(-pgid) 杀掉整个进程树,CLI 内部 spawn 的 node worker 不会残留。
平台支持
三档平台覆盖 npm 包内自带的 5 个预编译产物,进程组隔离在各平台均生效:
| 平台 | 产物目录 |
|---|---|
| macOS arm64 / x64 | npm/dist/darwin-arm64 / darwin-x64 |
| Linux x64 / arm64 | npm/dist/linux-x64 / linux-arm64 |
| Windows x64 | npm/dist/win32-x64 |
每个目录下并排两个二进制:magic-agent(core)与 magic-client(客户端插件)。
magic-agent client start 按「与自己同目录」找后者,所以两个必须是同一次构建
(插件启动时会比对 core 契约版本,跨版本会明确拒绝启动)。
集成 H5 对话组件(其他工程)
npm 包自带可复用的前端组件,npm install magic-agent 后在 node_modules/magic-agent/ 下:
| 路径 | 内容 |
|---|---|
client-ui-mobile/index.html | 移动端 H5 宿主页(顶栏 + AA 安卓端配色,含暗/亮双主题) |
client-ui/index.html | PC 宿主页(oklch 配色);client-ui/pc/ 是带工作台的完整版 |
client-ui/shared/ | 公共对话组件:MagicConversation.create() + HTTP 传输参考件 |
CLIENT-CONTRACT.md | 契约说明(/desk/* 接口、事件流、控制命令、模块机制) |
核心设计:组件不连后端,宿主注入 transport;现成的 transport-http.js 打
magic-client 的 /desk/* 接口。三种集成姿势:
① 直接当静态页托管(最快):先把包里的两块拼成一个可服务目录(index.html
按同级 shared/ 相对路径引用,这个关系不能拆散)——
cp -r node_modules/magic-agent/client-ui-mobile magic-h5
cp -r node_modules/magic-agent/client-ui/shared magic-h5/shared
magic-client serve --ui-dir magic-h5
手机访问启动时打印的 http://<局域网IP>/?token=...。嵌进自己的服务同理:按上面的
布局静态托管,令牌走 ?token=。
(magic-client 随 npm 包安装,也可以只跑 magic-agent client start 把插件后台拉起来,
界面资源会自动按包布局找到。)
② 拷进自己的构建(App/工程内嵌):把 client-ui-mobile/ 内容与 client-ui/shared/
复制进 www/(Vite/Capacitor 同理,require.resolve('magic-agent/client-ui-mobile/index.html')
定位源路径),再注入 window.MAGIC_BASE / window.MAGIC_TOKEN 指向 magic-client 地址。
③ 自定义 transport(不走 magic-client):实现四个方法即可挂组件——
listEngines() / ask(payload, {onEvent, onEnd}) / control(payload) / readSession(sid, opts),
数据从 IPC→CLI 或自有后端来都行(参考 client-ui/shared/transport-http.js 与
CLIENT-CONTRACT.md 的事件流形状)。
输入框支持粘贴 / 拖入图片:组件与 + 菜单共用同一条管线,走可选的
transport.upload(file)→ magic-client 的POST /desk/upload落盘(返回 core 那台机器的 绝对路径),路径随后随payload.attachments下发给引擎。自定义 transport 想支持贴图, 补上upload(file)(返回{path, name, size, url})即可;没有这个方法时组件会如实提示 「当前传输层不支持上传附件」,不会假装贴上了。
更多文档
| 文档 | 内容 |
|---|---|
| docs/engines.md | arkclaw / codebuddy-gateway / llm / dsh / codex 五个引擎的配置、协议与行为细节 |
| docs/streaming.md | 各引擎流式的实现路径与实测差异(openclaw ACP 桥、arkclaw A2A SSE、dsh SDK 通道) |
| docs/tools-and-permissions.md | --tools 工具白名单与四档权限模型的落地细节 |
| docs/notes.md | 需要用户选择的统一格式、在 WorkBuddy / CodeBuddy 会话内使用时的注意事项 |
| docs/development.md | CI 发版(GitHub Actions → npmjs)、本地打包流程、改动落地四步曲、架构与真机验证记录 |
| CLIENT-CONTRACT.md | 客户端契约面(magic-client 插件对接用) |
License
MIT