@armadra/agent 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/README.md +142 -49
- package/dist/agent/retry.d.ts +1 -1
- package/dist/agent/retry.js +2 -1
- package/dist/agent/session-cache.js +6 -3
- package/dist/agent/session-classifier.d.ts +18 -0
- package/dist/agent/session-classifier.js +103 -0
- package/dist/agent/session-core.d.ts +13 -0
- package/dist/agent/session-state.js +2 -1
- package/dist/agent/session-sync.js +9 -2
- package/dist/agent/session-tools.js +24 -3
- package/dist/agent/session.d.ts +3 -0
- package/dist/agent/session.js +20 -10
- package/dist/agent/tool-runner.js +15 -2
- package/dist/agent/types.d.ts +9 -1
- package/dist/ai/apis/anthropic-messages.js +3 -2
- package/dist/ai/apis/google-generative-ai.js +3 -2
- package/dist/ai/apis/openai-completions.js +3 -2
- package/dist/ai/apis/openai-responses.js +5 -3
- package/dist/ai/cache/fingerprint.d.ts +1 -1
- package/dist/ai/cache/fingerprint.js +1 -1
- package/dist/ai/cache/reporting.js +2 -1
- package/dist/ai/http.d.ts +28 -6
- package/dist/ai/http.js +41 -8
- package/dist/ai/providers/channels.d.ts +51 -0
- package/dist/ai/providers/channels.js +96 -0
- package/dist/ai/providers/enrich.d.ts +34 -0
- package/dist/ai/providers/enrich.js +86 -0
- package/dist/ai/providers/models-dev-cache.d.ts +53 -0
- package/dist/ai/providers/models-dev-cache.js +147 -0
- package/dist/ai/providers/models-dev.d.ts +99 -0
- package/dist/ai/providers/models-dev.js +315 -0
- package/dist/ai/providers/registry.d.ts +42 -4
- package/dist/ai/providers/registry.js +195 -34
- package/dist/ai/providers/suggest.d.ts +18 -0
- package/dist/ai/providers/suggest.js +72 -0
- package/dist/ai/sse.d.ts +6 -2
- package/dist/ai/sse.js +22 -2
- package/dist/ai/types.d.ts +30 -3
- package/dist/bundle/ama.cjs +17893 -10698
- package/dist/cli/args.d.ts +23 -5
- package/dist/cli/args.js +113 -13
- package/dist/cli/bootstrap.js +28 -3
- package/dist/cli/codemode-notice.d.ts +20 -0
- package/dist/cli/codemode-notice.js +55 -0
- package/dist/cli/compose-providers.js +3 -0
- package/dist/cli/compose-session.d.ts +8 -0
- package/dist/cli/compose-session.js +32 -1
- package/dist/cli/compose-store.d.ts +1 -1
- package/dist/cli/compose-store.js +3 -1
- package/dist/cli/compose.d.ts +17 -5
- package/dist/cli/compose.js +53 -19
- package/dist/cli/default-model.d.ts +38 -1
- package/dist/cli/default-model.js +96 -9
- package/dist/cli/deps.d.ts +38 -0
- package/dist/cli/exit-codes.d.ts +2 -0
- package/dist/cli/exit-codes.js +3 -0
- package/dist/cli/fake-visibility.d.ts +13 -0
- package/dist/cli/fake-visibility.js +26 -0
- package/dist/cli/from-prompt.d.ts +18 -0
- package/dist/cli/from-prompt.js +49 -0
- package/dist/cli/main.d.ts +10 -2
- package/dist/cli/main.js +88 -2
- package/dist/cli/proxy.d.ts +51 -0
- package/dist/cli/proxy.js +135 -0
- package/dist/cli/startup-screen.d.ts +29 -0
- package/dist/cli/startup-screen.js +47 -0
- package/dist/cli/startup-steps.d.ts +1 -1
- package/dist/cli/startup-steps.js +20 -13
- package/dist/cli/subcommands/config.d.ts +29 -4
- package/dist/cli/subcommands/config.js +188 -25
- package/dist/cli/subcommands/context.js +5 -1
- package/dist/cli/subcommands/doctor.js +12 -1
- package/dist/cli/subcommands/init.d.ts +6 -0
- package/dist/cli/subcommands/init.js +23 -0
- package/dist/cli/subcommands/model-meta.d.ts +16 -0
- package/dist/cli/subcommands/model-meta.js +54 -0
- package/dist/cli/subcommands/models-cache-probe.js +1 -1
- package/dist/cli/subcommands/models-discover.d.ts +18 -6
- package/dist/cli/subcommands/models-discover.js +87 -52
- package/dist/cli/subcommands/models.js +26 -18
- package/dist/cli/subcommands/probe-runner.d.ts +96 -0
- package/dist/cli/subcommands/probe-runner.js +264 -0
- package/dist/cli/subcommands/providers-list.d.ts +8 -0
- package/dist/cli/subcommands/providers-list.js +97 -0
- package/dist/cli/subcommands/providers-plan.d.ts +79 -0
- package/dist/cli/subcommands/providers-plan.js +215 -0
- package/dist/cli/subcommands/providers-probe.d.ts +34 -0
- package/dist/cli/subcommands/providers-probe.js +87 -0
- package/dist/cli/subcommands/providers.d.ts +28 -0
- package/dist/cli/subcommands/providers.js +436 -0
- package/dist/cli/subcommands/sessions-export.d.ts +10 -0
- package/dist/cli/subcommands/sessions-export.js +59 -0
- package/dist/cli/subcommands/sessions-search.d.ts +13 -0
- package/dist/cli/subcommands/sessions-search.js +103 -0
- package/dist/cli/subcommands/sessions.d.ts +3 -2
- package/dist/cli/subcommands/sessions.js +22 -1
- package/dist/cli/subcommands/stats.d.ts +17 -0
- package/dist/cli/subcommands/stats.js +198 -0
- package/dist/cli/system-prompt-arg.d.ts +11 -0
- package/dist/cli/system-prompt-arg.js +34 -0
- package/dist/codemode/modes.d.ts +4 -11
- package/dist/codemode/modes.js +5 -27
- package/dist/codemode/tool.d.ts +18 -14
- package/dist/codemode/tool.js +71 -28
- package/dist/config/init.d.ts +34 -0
- package/dist/config/init.js +99 -0
- package/dist/config/json-schema.d.ts +15 -0
- package/dist/config/json-schema.js +215 -0
- package/dist/config/key-docs.d.ts +22 -0
- package/dist/config/key-docs.js +105 -0
- package/dist/config/merge.d.ts +9 -8
- package/dist/config/merge.js +22 -7
- package/dist/config/schema.d.ts +1 -1
- package/dist/config/schema.js +97 -15
- package/dist/config/types.d.ts +57 -11
- package/dist/config/types.js +19 -1
- package/dist/modes/commands-core.js +6 -5
- package/dist/modes/image-input.d.ts +27 -0
- package/dist/modes/image-input.js +78 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -5
- package/dist/modes/interactive/approval-dialog.js +106 -27
- package/dist/modes/interactive/commands.d.ts +11 -2
- package/dist/modes/interactive/commands.js +58 -19
- package/dist/modes/interactive/interactive-mode.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode.js +70 -82
- package/dist/modes/interactive/key-dispatch.d.ts +3 -1
- package/dist/modes/interactive/key-dispatch.js +5 -6
- package/dist/modes/interactive/line/line-mode.d.ts +1 -0
- package/dist/modes/interactive/line/line-mode.js +9 -5
- package/dist/modes/interactive/line/line-render.d.ts +4 -0
- package/dist/modes/interactive/line/line-render.js +28 -6
- package/dist/modes/interactive/message-view.d.ts +48 -9
- package/dist/modes/interactive/message-view.js +238 -44
- package/dist/modes/interactive/panels.d.ts +18 -0
- package/dist/modes/interactive/panels.js +143 -0
- package/dist/modes/interactive/pickers.d.ts +23 -2
- package/dist/modes/interactive/pickers.js +48 -15
- package/dist/modes/interactive/run-indicator.d.ts +51 -0
- package/dist/modes/interactive/run-indicator.js +189 -0
- package/dist/modes/interactive/startup-header.d.ts +40 -0
- package/dist/modes/interactive/startup-header.js +169 -0
- package/dist/modes/interactive/startup-ui.d.ts +7 -2
- package/dist/modes/interactive/startup-ui.js +41 -11
- package/dist/modes/interactive/status-bar.d.ts +18 -15
- package/dist/modes/interactive/status-bar.js +98 -56
- package/dist/modes/interactive/tool-summary.d.ts +46 -0
- package/dist/modes/interactive/tool-summary.js +218 -0
- package/dist/modes/interactive/tool-view.d.ts +48 -15
- package/dist/modes/interactive/tool-view.js +203 -145
- package/dist/modes/print/print-mode.d.ts +33 -4
- package/dist/modes/print/print-mode.js +128 -8
- package/dist/modes/rpc/commands.js +12 -2
- package/dist/permissions/auto-safe.d.ts +60 -0
- package/dist/permissions/auto-safe.js +529 -0
- package/dist/permissions/classifier.d.ts +64 -0
- package/dist/permissions/classifier.js +184 -0
- package/dist/permissions/dangerous.d.ts +5 -0
- package/dist/permissions/dangerous.js +1 -1
- package/dist/permissions/modes.d.ts +30 -0
- package/dist/permissions/modes.js +78 -0
- package/dist/permissions/pipeline.d.ts +31 -4
- package/dist/permissions/pipeline.js +196 -6
- package/dist/permissions/protected.d.ts +19 -0
- package/dist/permissions/protected.js +74 -0
- package/dist/permissions/rules.js +3 -0
- package/dist/permissions/types.d.ts +50 -3
- package/dist/permissions/types.js +3 -0
- package/dist/rpc.d.ts +2 -0
- package/dist/sdk.d.ts +9 -3
- package/dist/sdk.js +10 -2
- package/dist/session/export.d.ts +32 -0
- package/dist/session/export.js +187 -0
- package/dist/session/projection.js +5 -1
- package/dist/session/redact.d.ts +15 -0
- package/dist/session/redact.js +55 -0
- package/dist/session/reuse.d.ts +33 -0
- package/dist/session/reuse.js +86 -0
- package/dist/session/scan.d.ts +34 -0
- package/dist/session/scan.js +140 -0
- package/dist/session/search.d.ts +52 -0
- package/dist/session/search.js +211 -0
- package/dist/session/stats-aggregate.d.ts +63 -0
- package/dist/session/stats-aggregate.js +163 -0
- package/dist/session/stats-index.d.ts +26 -0
- package/dist/session/stats-index.js +91 -0
- package/dist/session/stats-scan.d.ts +54 -0
- package/dist/session/stats-scan.js +236 -0
- package/dist/session/types.d.ts +2 -0
- package/dist/tools/image-file.d.ts +31 -0
- package/dist/tools/image-file.js +114 -0
- package/dist/tools/presets.d.ts +35 -8
- package/dist/tools/presets.js +56 -17
- package/dist/tools/read.d.ts +4 -8
- package/dist/tools/read.js +15 -64
- package/dist/tui/component.d.ts +8 -2
- package/dist/tui/component.js +3 -1
- package/dist/tui/components/box.d.ts +6 -1
- package/dist/tui/components/box.js +16 -6
- package/dist/tui/components/card.d.ts +23 -0
- package/dist/tui/components/card.js +37 -0
- package/dist/tui/components/editor-history.d.ts +6 -0
- package/dist/tui/components/editor-history.js +45 -0
- package/dist/tui/components/editor-paste.d.ts +1 -1
- package/dist/tui/components/editor-paste.js +4 -4
- package/dist/tui/components/editor.d.ts +11 -5
- package/dist/tui/components/editor.js +52 -58
- package/dist/tui/components/key-value.d.ts +3 -0
- package/dist/tui/components/key-value.js +16 -6
- package/dist/tui/components/loader.d.ts +37 -7
- package/dist/tui/components/loader.js +84 -21
- package/dist/tui/components/markdown.d.ts +5 -1
- package/dist/tui/components/markdown.js +45 -21
- package/dist/tui/components/meter.d.ts +3 -3
- package/dist/tui/components/meter.js +13 -11
- package/dist/tui/components/select-list.d.ts +23 -1
- package/dist/tui/components/select-list.js +76 -13
- package/dist/tui/glyphs.d.ts +68 -0
- package/dist/tui/glyphs.js +114 -0
- package/dist/tui/theme.d.ts +30 -6
- package/dist/tui/theme.js +103 -17
- package/dist/tui.d.ts +4 -2
- package/dist/tui.js +3 -1
- package/docs/codemode.md +23 -9
- package/docs/hooks.md +10 -10
- package/docs/permissions.md +148 -0
- package/docs/providers.md +241 -3
- package/docs/rpc.md +38 -38
- package/docs/session-format.md +3 -2
- package/docs/sessions.md +134 -0
- package/docs/tui.md +140 -61
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,104 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 未发布
|
|
4
|
+
|
|
5
|
+
## 0.4.0(2026-10-02)
|
|
6
|
+
|
|
7
|
+
- **终端界面重做**(视觉规格见 docs/tui-design.md):带框启动头(模型 / 目录 / 模式 / 已加载资源,窄屏去框);
|
|
8
|
+
工具调用改 `⏺ 工具名 摘要` + `⎿ 一行结果摘要` + 缩进正文三级层级,相邻调用不空行,运行中摘要行带 spinner 与秒数,
|
|
9
|
+
diff 带行号;思考块 `✻ 思考 · N token`,`Ctrl+O` 同时展开思考;运行中动词(思考中 / 回复中 · ↓≈N / 运行 bash /
|
|
10
|
+
等待确认 / 重试 / 压缩上下文);输入框 `›` 提示符与占位;状态栏两区(左模式 + `shift+tab 切换`,右用量,
|
|
11
|
+
模型名按宽度缩写);审批对话框编号选项(1–3 / ↑↓ Enter,危险命令缺省选中拒绝,边框随严重度着色);
|
|
12
|
+
`/session` `/cache` `/permissions` 改为左竖条面板;退出时留一行会话摘要与 `ama --resume <id>`。
|
|
13
|
+
新配置 `ui.theme: "auto"`、`ui.ascii`(`AMA_ASCII=1`)、`ui.compact`、`ui.animation`。
|
|
14
|
+
- **破坏性变更(`@armadra/agent/tui` 与界面文本)**:`SemanticColor` 增加 `muted` / `link` / `selection`,`Theme`
|
|
15
|
+
增加必填的 `glyphs`——自己实现 `Theme` 的宿主需补这 3 个颜色与字形表(可用 `UNICODE_GLYPHS`);`Loader` 渲染从
|
|
16
|
+
`⠋ 消息 (12s)` 改为 `⠋ 动词 · 12s · 附加项`;粘贴折叠标记从 `[paste #N +M lines]` 改为 `[粘贴 #N · M 行]`;
|
|
17
|
+
状态栏不再有 `mode:` / `think:` / `preset:` 前缀(模式移到最左,`preset` 只在非 default 时出现),按 `mode:` 解析
|
|
18
|
+
状态栏的脚本需改为取最左一项;排队消息标签 `↳ steer` / `↳ followUp` / `↳ host` 改为 `↳ 插话` / `↳ 之后` / `↳ 宿主`
|
|
19
|
+
(会话文件里的 `origin` 不变);`/permission` 选择器标题 `Mode` 改为「权限模式」。
|
|
20
|
+
- **codemode 缺省开放**:`codemode.mode` 不写时跟随预设——`default` 预设在沙箱网络隔离(Node ≥ 25)时带上
|
|
21
|
+
`codemode`(六个工具 + codemode),Node 22 / 24 缺省不开并在启动时提示一次(每个配置目录一次,记在数据目录
|
|
22
|
+
`notices.json`),`--codemode on` 或 config 显式开启;`minimal` / `coordinator` 不开。缺省配置不写这个键。
|
|
23
|
+
- **修复:coordinator 经 codemode 绕过**:`coordinator` 预设显式开了 codemode 时,脚本里只能调活动集里的工具
|
|
24
|
+
(read 与宿主工具),`tools.bash` / `tools.write` 不再可达。
|
|
25
|
+
- **on 模式去重**:`codemode` 描述不再内联已直接暴露的工具声明,其它工具描述也不再追加提示,只列「参数同直接
|
|
26
|
+
工具」与「仅脚本可调用」的名字;系统提示 + 工具表比 off 只多约 390 token(原约 1356)。`--codemode on` 的旧会话
|
|
27
|
+
续接时描述字节变化,会有一次缓存未命中。
|
|
28
|
+
- **预设改名**:`codemode` 预设更名 `codemode-only`;旧名作别名继续可用(配置、`--tools-preset`、RPC、SDK、schema),
|
|
29
|
+
`ama config show` 显示规范名并提示。
|
|
30
|
+
- **`ama init` 不写死缺省值**:新生成的 `config.json` 只有 `$schema`、`version` 与空 `providers`,以后缺省值调整对老
|
|
31
|
+
用户同样生效;init 结束打印下一步。已存在的文件不动(之前生成的文件里的 `thinkingLevel` / `permission.mode` /
|
|
32
|
+
`tools.preset` 仍会按 user 层生效,想跟随缺省可以删掉)。
|
|
33
|
+
- **`ama config show`**:补全 `cache`、`codemode` 等段与每项来源,codemode 写明生效模式与原因;接受
|
|
34
|
+
`--tools-preset` / `--codemode`;`ama doctor` 同样显示 codemode。`config.schema.json` 的每个键都带说明与缺省值。
|
|
35
|
+
- **不再展示 fake**:零配置的模型选择器、`doctor`、`models list`、`providers list`、`config show` 缺省不列测试供应商
|
|
36
|
+
`fake`(`AMA_SHOW_FAKE=1` 或 `AMA_FAKE_SCRIPT` 时照列,`--model fake/…` 照常可用);没有可用模型时提示 key 环境变量、
|
|
37
|
+
`ama auth set` 与 `ama providers add`。
|
|
38
|
+
- **缺省模型**:自定义供应商(中转站)不再取列表首条,而是在 models.dev 有价格、支持工具调用、上下文 ≥ 64k 的模型里
|
|
39
|
+
取输入价最低的;`ama providers add` 在还没有 `defaultModel` 时按同一规则写入并说明原因。内置供应商仍取目录首条。
|
|
40
|
+
|
|
41
|
+
- **auto 权限模式**:`--permission-mode auto`(界面显示名 Auto)由 ama 判断每一步——规则层不调模型,危险命令、
|
|
42
|
+
网络命令、删除类命令、机密文件与项目外写入一律询问;静态判定放行只读工具、项目内写入与安全名单里的命令
|
|
43
|
+
(`ls`、`grep`、`git status/diff/log`、`npm test`、`tsc --noEmit`、`cargo test` 等,`permission.autoSafeCommands` 追加);
|
|
44
|
+
其余交给一次独立的模型分类器(`permission.autoModel`,不影响主会话缓存,用量记 `permission_classify`)。
|
|
45
|
+
事件带 `autoDecision`,`/permissions` 显示最近判定。见 docs/permissions.md。
|
|
46
|
+
- **allowlist 模式**:只放行只读工具与 allow 规则命中的调用,其余直接拒绝、从不询问,适合 CI。
|
|
47
|
+
- **模式选择器**:`/permission` 打开 Mode 列表(显示名 + 说明、数字 1–6、当前打勾、Default / Recommended),
|
|
48
|
+
`Shift+Tab` 循环 Manual → Accept edits → Plan → Auto → Bypass permissions,状态栏显示显示名。
|
|
49
|
+
项目级配置不能设 `auto` / `full-auto`。
|
|
50
|
+
- **测试隔离**:组装测试不再把会话写进真实数据目录,测试结束检查真实 `~/.local/share/ama` / `~/.config/ama` 有无新增。
|
|
51
|
+
|
|
52
|
+
- **探测提速**:`ama providers add|refresh --probe` 与 `ama models discover --probe` 并发探测(`--concurrency`,缺省 6),
|
|
53
|
+
流里出现首个内容事件即判可用并断开,单次超时缩到 15 s(`--probe-timeout`);429 时降并发并重试一次,
|
|
54
|
+
连续 429 才停止。实测 22 个模型、60 次探测从预计 20–30 分钟降到约 85 s。
|
|
55
|
+
降并发之后连续 4 次没被限流就并发 +1,回到初始并发为止。
|
|
56
|
+
|
|
57
|
+
- **流空闲超时**:模型请求等响应头、以及流里两块数据之间缺省 300 s 没有任何字节即判卡住,按可重试错误重试;
|
|
58
|
+
`request.idleTimeoutMs`(用户级)或 `AMA_IDLE_TIMEOUT_MS` 调整,0 关闭。服务端发一块就停住不再让 `-p` 永久挂起。
|
|
59
|
+
- **`-p` 与 stdin**:`git diff | ama -p "审阅"` 照旧把管道内容拼在提示后面;有提示参数时只等管道首字节 2 秒
|
|
60
|
+
(`AMA_STDIN_WAIT_MS` 可调,0 = 不等),一个字节都没有就忽略 stdin 并在 stderr 提示,父进程留着不关的管道不再让
|
|
61
|
+
`-p` 挂起;收到首字节后读到 EOF。末尾加 `-` 一直等到 EOF(上游要先跑很久才输出时用),`< 文件` 照常读取;没有提示
|
|
62
|
+
参数时等 stdin 超过 3 s 提示一次;`--no-stdin` 完全不读。
|
|
63
|
+
- **`-p` 无人值守的拒绝可见**:被拒的工具调用在 stderr 汇总(工具、原因、放行办法),`json` 结果带 `deniedTools`,
|
|
64
|
+
`tool_execution_end` 带 `denied: true`,退出码 7(新增)。重试期间 stderr 每次一行 `↻`。
|
|
65
|
+
- **新参数**:`-p --max-turns N`(到上限仍在调工具时退出 1,`json` 带 `maxTurnsReached`)、
|
|
66
|
+
`--system-prompt <文本|@文件>` 与 `--system-prompt-mode append|replace`(缺省作为最后一条规则追加,缓存前缀不变)、
|
|
67
|
+
`--no-session`(会话不落盘)。
|
|
68
|
+
- **报错准确**:`provider/model@渠道` 渠道不存在时报「渠道不存在」并列出该模型的可用渠道(中转供应商不再把 `@后缀`
|
|
69
|
+
当成模型 id 发出去);供应商写错报「供应商不存在」并给编辑距离最近的候选;模型写错列出最接近的几个。
|
|
70
|
+
- **代理**:设了 `HTTPS_PROXY` / `HTTP_PROXY` 时启动即启用 Node 内置的环境变量代理(`NO_PROXY` 生效),Node 22.21 以前
|
|
71
|
+
提示一次并直连;`ama doctor` 新增「代理」一节。
|
|
72
|
+
- **行式管道模式**:模型错误只在运行结束时打印一次,有运行失败时退出码 1(以前 0)。
|
|
73
|
+
- **只读命令不写盘**:`config show` / `path`、`doctor`、`models list` 等不再创建配置目录,首次自动初始化只在进入对话的
|
|
74
|
+
命令与 `providers add` 里触发。
|
|
75
|
+
|
|
76
|
+
- **会话统计**:`ama stats` 只读扫描会话,汇总请求(对话、保温、权限分类、压缩分开计)、回合与平均耗时、
|
|
77
|
+
token、缓存命中率(只算报告缓存的端点)、费用(只加有价请求)、错误与重试、工具调用 Top N;
|
|
78
|
+
`--since` / `--until` / `--by day|week|month|provider|channel|model|project` / `--json`;
|
|
79
|
+
增量索引 `<数据目录>/stats-index.json`,1000 个会话冷扫描约 160 ms。
|
|
80
|
+
- **会话检索与导出**:`ama sessions search <关键词|/正则/>`(`--role`、`--since`、`--limit`,TTY 高亮);
|
|
81
|
+
`ama sessions export <id> --format md|json|jsonl [--branch leaf|all] [--output]`,导出前脱敏 key / token。
|
|
82
|
+
- **复用**:`ama sessions show` 列出用户消息编号;`--from <id>[#编号]` 用那条消息作新提示(`-p` 时连图片),
|
|
83
|
+
可配合 `--model` 换模型重问。见 docs/sessions.md。
|
|
84
|
+
- **发布**:release job 优先用 npm 可信发布(OIDC,npm ≥ 11.5.1),`NPM_TOKEN` 只作回退;需要在 npmjs.com
|
|
85
|
+
为 `@armadra/agent` 添加 Trusted Publisher(Owlbay / armadra-agent / ci.yml)。
|
|
86
|
+
|
|
87
|
+
## 0.3.0(2026-10-02)
|
|
88
|
+
|
|
89
|
+
自定义供应商与多渠道、models.dev 模型元数据、图像输入、默认配置目录。
|
|
90
|
+
|
|
91
|
+
- **一键接入**:`ama providers add <id> --base-url <url>` 只要 baseUrl 与 key——列出中转的模型、按提示或 `--probe` 逐渠道
|
|
92
|
+
探测、写进配置;`list` / `channels` / `remove` / `refresh`。
|
|
93
|
+
- **渠道**:一个供应商可挂多个渠道(协议 + 地址 + 可选 key / headers / compat),模型声明 `channels`,
|
|
94
|
+
`provider/model@channel` 指定渠道;旧配置按隐式 `default` 渠道处理,不用改。
|
|
95
|
+
- **models.dev 元数据**:上下文、输出上限、图像输入、推理、价格缺省从 models.dev 补(数据目录缓存,启动不联网),
|
|
96
|
+
`ama models refresh-catalog` 刷新;`models list` / `config show` 标出每个字段的来源。
|
|
97
|
+
- **图像输入**:`-p --image`、界面里 `@图片路径`;与 read 工具共用 MIME 检测与 5 MB 上限;模型不收图片时拒绝。
|
|
98
|
+
- **配置目录**:首次运行自动建 `~/.config/ama/` 与最小 `config.json`、`config.schema.json`;`ama init`、
|
|
99
|
+
`ama config path`、`ama config edit`。
|
|
100
|
+
- **修复**:Responses 的 `incomplete_details.reason: "length"` 按输出截断处理(中转转发 DeepSeek 时出现)。
|
|
101
|
+
|
|
3
102
|
## 0.2.1(2026-10-02)
|
|
4
103
|
|
|
5
104
|
npm 首发:`npm i -g @armadra/agent`。功能与 0.2.0 相同。
|
package/README.md
CHANGED
|
@@ -38,18 +38,20 @@ ama
|
|
|
38
38
|
|
|
39
39
|
## 特性一览
|
|
40
40
|
|
|
41
|
-
| 方面 | 内容
|
|
42
|
-
| -------------- |
|
|
43
|
-
| 多协议与供应商 | 4 条协议线、13 家内置供应商(Anthropic、OpenAI、Google、DeepSeek、Moonshot、智谱、通义、OpenRouter、Groq、xAI、Mistral、Ollama、LM Studio)、自定义供应商、模型级协议
|
|
44
|
-
| 零配置与中转站 | 有 key
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
41
|
+
| 方面 | 内容 |
|
|
42
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| 多协议与供应商 | 4 条协议线、13 家内置供应商(Anthropic、OpenAI、Google、DeepSeek、Moonshot、智谱、通义、OpenRouter、Groq、xAI、Mistral、Ollama、LM Studio)、自定义供应商、模型级协议 |
|
|
44
|
+
| 零配置与中转站 | 有 key 就选第一个可用的供应商(中转站按价格规则挑缺省模型);识别 `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL`;`ama providers add` 只给 baseUrl 与 key 一键接入:列模型、探测渠道、写回配置 |
|
|
45
|
+
| 模型元数据 | 上下文、输出上限、图像输入、推理、价格缺省从 models.dev 补(本地缓存,启动不联网);一个供应商可挂多个渠道(Chat / Responses / Messages),`provider/model@渠道` |
|
|
46
|
+
| 图像输入 | `-p --image`、界面里 `@图片路径`;四条协议都映射;模型不收图片时直接拒绝并提示换模型 |
|
|
47
|
+
| 工具与预设 | read / edit / write / bash / grep / glob,另有 ls、todo、task(子 Agent)、codemode;四个预设 `default` / `minimal` / `codemode-only` / `coordinator` |
|
|
48
|
+
| codemode | 模型写一段 JS,在受 Node 权限模型约束的子进程里编排多次工具调用,只有输出回到模型 |
|
|
49
|
+
| Skill | `SKILL.md` 目录,模型按索引自行读取,用户用 `/skill:<名字>` 调用;另有提示模板 |
|
|
50
|
+
| 两层 Hook | 命令式 Hook(`hooks.json`,9 个事件,用户策略)与进程内宿主适配器 HostApi(嵌入方) |
|
|
51
|
+
| 权限 | 四种模式、allow / deny 规则、危险命令识别(穿透 `sh -c` / `eval` / `xargs` / `find -exec`)、项目信任、审批时的执行前预览 |
|
|
52
|
+
| 缓存 | 前缀稳定、缓存字段与兼容开关、未命中归因、「报 / 不报缓存」三态、长工具运行时保温、压缩摘要按会话前缀续写 |
|
|
53
|
+
| 会话 | JSONL 条目树,分叉与 `/tree` 回溯;两档压缩(裁剪大工具结果 → 摘要)与熔断 |
|
|
54
|
+
| 入口 | 差分渲染终端界面、`--no-tui` 行式、`-p`(text / json / stream-json)、`--mode rpc`、SDK |
|
|
53
55
|
|
|
54
56
|
## 安装
|
|
55
57
|
|
|
@@ -85,16 +87,16 @@ node dist/bundle/ama.cjs --version
|
|
|
85
87
|
|
|
86
88
|
### Node 版本与 codemode
|
|
87
89
|
|
|
88
|
-
| Node | codemode 沙箱
|
|
89
|
-
| ------- |
|
|
90
|
-
| ≥ 25 | 文件系统与网络都隔离;`codemode` 按只读类工具处理,`default`
|
|
91
|
-
| 22 / 24 | 隔离文件系统,**不隔离网络**;`codemode` 按执行类处理,每次都要审批(状态栏显示红色 `net
|
|
90
|
+
| Node | codemode 沙箱 |
|
|
91
|
+
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| ≥ 25 | 文件系统与网络都隔离;`codemode` 按只读类工具处理,`default` 权限模式下免审批;`default` 预设**缺省开启** codemode |
|
|
93
|
+
| 22 / 24 | 隔离文件系统,**不隔离网络**;`codemode` 按执行类处理,每次都要审批(状态栏显示红色 `net!`);`default` 预设缺省**不开** codemode,启动时提示一次(每个配置目录一次) |
|
|
92
94
|
|
|
93
|
-
其余功能在 Node 22
|
|
95
|
+
其余功能在 Node 22 起都一样。Node 22 / 24 想用 codemode 就显式开:`--codemode on` 或 config 写 `"codemode": { "mode": "on" }`。`codemode.requireStrict: true` 可以在网络未隔离时直接禁用 codemode。
|
|
94
96
|
|
|
95
97
|
## 快速开始
|
|
96
98
|
|
|
97
|
-
**零配置**:设好任一家的标准环境变量就能用,ama 按内置顺序选第一个有 key
|
|
99
|
+
**零配置**:设好任一家的标准环境变量就能用,ama 按内置顺序选第一个有 key 的供应商和它的缺省模型(`ama config show` 说明选了谁、为什么)。没有任何 key 时启动会提示怎么配,不会落到测试用的 `fake` 供应商上。
|
|
98
100
|
|
|
99
101
|
```sh
|
|
100
102
|
export ANTHROPIC_API_KEY=sk-... # 或 OPENAI_API_KEY、GEMINI_API_KEY、DEEPSEEK_API_KEY、MOONSHOT_API_KEY ……
|
|
@@ -129,14 +131,19 @@ ama -p "列出 TODO" --model deepseek/deepseek-v4-pro --output-format json
|
|
|
129
131
|
| `--tools-preset <名>` | 工具预设(见下文) |
|
|
130
132
|
| `--allow <规则>` / `--deny <规则>` | 追加权限规则,可重复 |
|
|
131
133
|
|
|
132
|
-
本地 Ollama / LM Studio 不需要 key:`ama --model ollama/<模型名>`。`ama --help` 列出全部参数与子命令;测试或排查时可用不花钱的 `--model fake/echo
|
|
134
|
+
本地 Ollama / LM Studio 不需要 key:`ama --model ollama/<模型名>`。`ama --help` 列出全部参数与子命令;测试或排查时可用不花钱的 `--model fake/echo`(回显最后一条用户消息;模型选择器、`models list`、`doctor` 缺省不列这个测试供应商,`AMA_SHOW_FAKE=1` 时列出)。
|
|
133
135
|
|
|
134
136
|
## 配置
|
|
135
137
|
|
|
136
|
-
一个文件 `~/.config/ama/config.json
|
|
138
|
+
一个文件 `~/.config/ama/config.json`。第一次进入对话(交互、`-p`、RPC)或 `ama providers add` 时自动建好目录(0700)、
|
|
139
|
+
最小的 `config.json` 与给编辑器用的 `config.schema.json`;`config show`、`doctor`、`models list` 等只读命令不写配置目录。
|
|
140
|
+
也可以 `ama init` 手动建(已有文件不覆盖)。生成的 `config.json` 只有 `$schema`、`version` 与空 `providers`,不写死缺省值——以后
|
|
141
|
+
缺省值调整时老配置同样跟着变。`ama config path` 打印各文件位置,`ama config edit` 用 `$VISUAL` / `$EDITOR` 打开,
|
|
142
|
+
`config.schema.json` 给每个键带了说明与缺省值,编辑器悬停可见。常用的只有五个键:
|
|
137
143
|
|
|
138
144
|
```json
|
|
139
145
|
{
|
|
146
|
+
"$schema": "./config.schema.json",
|
|
140
147
|
"version": 1,
|
|
141
148
|
"defaultModel": "anthropic/<model-id>",
|
|
142
149
|
"thinkingLevel": "medium",
|
|
@@ -146,17 +153,25 @@ ama -p "列出 TODO" --model deepseek/deepseek-v4-pro --output-format json
|
|
|
146
153
|
}
|
|
147
154
|
```
|
|
148
155
|
|
|
149
|
-
其余(`compaction`、`retry`、`codemode`、`hooks`、`ui`、`skills`、`cache`)都有缺省,`ama config show`
|
|
156
|
+
其余(`compaction`、`retry`、`codemode`、`hooks`、`ui`、`skills`、`cache`、`request`)都有缺省,`ama config show` 列出每一项的生效值与来源(default / user / profile / project / cli),也接受 `--tools-preset` / `--codemode` 看覆盖后的效果。
|
|
157
|
+
|
|
158
|
+
**请求超时**:模型请求有空闲超时,缺省 300 s——等响应头、以及流里两块数据之间超过这个时间就判定卡住,按可重试错误
|
|
159
|
+
走 `retry` 的退避重试(收到任何字节即重新计时,长回答不受影响)。用 `request.idleTimeoutMs`(只认用户级)或环境变量
|
|
160
|
+
`AMA_IDLE_TIMEOUT_MS` 调整,0 关闭。
|
|
161
|
+
|
|
162
|
+
**代理**:设了 `HTTPS_PROXY` / `HTTP_PROXY`(`NO_PROXY` 排除)时,ama 启动时调用 Node 内置的环境变量代理(等价于
|
|
163
|
+
`NODE_USE_ENV_PROXY=1`,零依赖)。Node 24+ 直接可用;Node 22 只有 22.21+ 设 `NODE_USE_ENV_PROXY=1` 才行,更早的版本会提示一次
|
|
164
|
+
并直连。`ama doctor` 的「代理」一节显示当前状态(代理地址里的账号密码打码)。
|
|
150
165
|
|
|
151
166
|
### 文件位置与层级
|
|
152
167
|
|
|
153
|
-
| 位置 | 内容
|
|
154
|
-
| --------------------- |
|
|
155
|
-
| `~/.config/ama/` | 用户级:`config.json`、`auth.json
|
|
156
|
-
| `~/.local/share/ama/` | 数据:`sessions/`(会话 JSONL
|
|
157
|
-
| `<项目>/.ama/` | 项目级:`config.json`(只能收紧)、`hooks.json` / `skills/` / `prompts/`(需信任)
|
|
158
|
-
| `<项目>/AGENTS.md` | 项目约定,从 cwd 向上查找,自动进系统提示
|
|
159
|
-
| `--profile <文件>` | 宿主 profile(嵌入方用,见「嵌入 Armadra」)
|
|
168
|
+
| 位置 | 内容 |
|
|
169
|
+
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
170
|
+
| `~/.config/ama/` | 用户级:`config.json`、`config.schema.json`(ama 生成)、`auth.json`(0600)、`hooks.json`、`keybindings.json`、`trust.json`、`AGENTS.md`、`skills/` |
|
|
171
|
+
| `~/.local/share/ama/` | 数据:`sessions/`(会话 JSONL)、`models-dev.json`(模型元数据缓存)、输入历史 |
|
|
172
|
+
| `<项目>/.ama/` | 项目级:`config.json`(只能收紧)、`hooks.json` / `skills/` / `prompts/`(需信任) |
|
|
173
|
+
| `<项目>/AGENTS.md` | 项目约定,从 cwd 向上查找,自动进系统提示 |
|
|
174
|
+
| `--profile <文件>` | 宿主 profile(嵌入方用,见「嵌入 Armadra」) |
|
|
160
175
|
|
|
161
176
|
`AMA_CONFIG_DIR` / `AMA_DATA_DIR` 可改两个目录;也遵循 `XDG_CONFIG_HOME` / `XDG_DATA_HOME`,Windows 下是 `%APPDATA%\ama` 与 `%LOCALAPPDATA%\ama`。
|
|
162
177
|
|
|
@@ -172,6 +187,41 @@ ama doctor # 配置层级、项目信任、key 来源、Hook、终
|
|
|
172
187
|
|
|
173
188
|
## 接入中转站
|
|
174
189
|
|
|
190
|
+
**一键接入**:只给 baseUrl 与 key。
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
export PACKY_API_KEY=sk-...
|
|
194
|
+
ama providers add packy --base-url https://proxy.example/v1 --key-env PACKY_API_KEY --probe --limit 8 --yes
|
|
195
|
+
ama -p "hi" --model packy/kimi-k2.5 # 首选渠道
|
|
196
|
+
ama -p "hi" --model packy/kimi-k2.5@messages # 指定渠道(Anthropic Messages)
|
|
197
|
+
ama -p "图里有什么颜色" --image shot.png --model packy/kimi-k2.5
|
|
198
|
+
ama providers list # 供应商 → 渠道 → 模型数、key 来源
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`add` 列出 `GET {baseUrl}/models` 的模型,从 baseUrl 推出 chat / responses / messages 三个候选渠道,`--probe` 逐渠道发最小
|
|
202
|
+
请求,把能用的渠道写进每个模型的 `channels`;上下文、输出上限、图像、推理与价格不写进配置,运行时从 models.dev 缓存补
|
|
203
|
+
(`ama models list` 标出每个字段的来源)。不给 `--key-env` 时 key 从 stdin 读(不回显)存进 `auth.json`。写入后的配置:
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"providers": {
|
|
208
|
+
"packy": {
|
|
209
|
+
"apiKey": "$PACKY_API_KEY",
|
|
210
|
+
"channels": {
|
|
211
|
+
"chat": { "api": "openai-completions", "baseUrl": "https://proxy.example/v1" },
|
|
212
|
+
"responses": { "api": "openai-responses", "baseUrl": "https://proxy.example/v1" },
|
|
213
|
+
"messages": { "api": "anthropic-messages", "baseUrl": "https://proxy.example" }
|
|
214
|
+
},
|
|
215
|
+
"defaultChannel": "chat",
|
|
216
|
+
"models": [
|
|
217
|
+
{ "id": "kimi-k2.5", "channels": ["chat", "messages"] },
|
|
218
|
+
{ "id": "grok-4.7", "channels": ["responses"] }
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
175
225
|
**零配置**:内置的 `openai` / `anthropic` 识别 `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL`。baseUrl 不在官方主机时接受目录外的 model id,缓存相关字段按保守缺省。
|
|
176
226
|
|
|
177
227
|
```sh
|
|
@@ -200,7 +250,8 @@ OPENAI_BASE_URL=https://proxy.example/v1 OPENAI_API_KEY=$PACKY_API_KEY \
|
|
|
200
250
|
|
|
201
251
|
- `api` 缺省 `openai-completions`;可选 `openai-responses`、`anthropic-messages`、`google-generative-ai`。
|
|
202
252
|
- `apiKey` 支持 `$ENV` / `${ENV}`(读环境变量)与 `!command`(执行命令取值),不要把 key 明文写进配置。
|
|
203
|
-
-
|
|
253
|
+
- 自定义模型的元数据缺省从 models.dev 补(`ama models refresh-catalog` 刷新缓存);匹配不到时不猜 `contextWindow`,自动
|
|
254
|
+
压缩关闭,需要时在模型条目里补上或写 `"modelsDev": "provider/model"` 指定条目。
|
|
204
255
|
|
|
205
256
|
**不想手写模型表**:让 ama 去问中转站。
|
|
206
257
|
|
|
@@ -215,20 +266,20 @@ ama models cache-probe packy/grok-4.7 # 这个端点报不报
|
|
|
215
266
|
|
|
216
267
|
## 工具与预设
|
|
217
268
|
|
|
218
|
-
| 预设
|
|
219
|
-
|
|
|
220
|
-
| `default`
|
|
221
|
-
| `minimal`
|
|
222
|
-
| `codemode`
|
|
223
|
-
| `coordinator`
|
|
269
|
+
| 预设 | 模型直接看到的工具 | 适合 |
|
|
270
|
+
| --------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
271
|
+
| `default` | read、edit、write、bash、grep、glob;Node ≥ 25 时另加 `codemode` | 缺省 |
|
|
272
|
+
| `minimal` | read、edit、write、bash | 小模型、小上下文;`full-auto` |
|
|
273
|
+
| `codemode-only` | 只有 `codemode` | 长流程、工具调用密集的任务 |
|
|
274
|
+
| `coordinator` | read 与宿主注册的画布工具 | 嵌入 Armadra 的协调者:不写文件、不跑 bash;codemode 缺省关,显式开了脚本里也只能调这些工具 |
|
|
224
275
|
|
|
225
|
-
- `--tools-preset <名>` 或 `tools.preset`
|
|
276
|
+
- `--tools-preset <名>` 或 `tools.preset` 选预设。`codemode` 是 `codemode-only` 的旧名(0.3.0),配置、命令行、RPC、SDK 都还认,`ama config show` 显示规范名并提示。
|
|
226
277
|
- `tools.default` 在预设上微调:`["+todo", "+task", "-glob"]`;不带前缀的名字整组替换。
|
|
227
278
|
- 另有 `--tools a,b,c`(只启用这些)、`--exclude-tools a,b`、交互模式的 `/tools`。
|
|
228
279
|
|
|
229
|
-
**codemode** 让模型写一段 JavaScript,用 `tools.<name>(args)` 编排多次工具调用(可以 `Promise.all`
|
|
280
|
+
**codemode** 让模型写一段 JavaScript,用 `tools.<name>(args)` 编排多次工具调用(可以 `Promise.all` 并发),只有脚本输出回到模型。脚本跑在 `node --permission` 子进程的 vm 里:没有 `require` / `import` / `process` / `fetch`,每次内层调用仍逐个经过 Hook、权限与审批。
|
|
230
281
|
|
|
231
|
-
|
|
282
|
+
**缺省开放**:`codemode.mode` 不写时跟随预设——`default` → `on`(六个工具 + codemode,只在 Node ≥ 25 的网络隔离沙箱里;Node 22 / 24 → `off`),`codemode-only` → `only`,`minimal` / `coordinator` → `off`。显式的 `--codemode off|on|only` 或 `codemode.mode` 优先,项目级只能写 `off`。`on` 模式下 codemode 的描述只用一行列出可在脚本里调用的直接工具(参数相同)与仅脚本可调的工具名,不重复声明,前缀只多约 400 token([三预设基准](docs/benchmarks/presets-2026-10-02.md)测的是去重前的 codemode 预设:小任务输入多约 45%、轮数不减)。只读检索多、调用次数多的长流程可以用 `codemode-only`。
|
|
232
283
|
|
|
233
284
|
## 缓存
|
|
234
285
|
|
|
@@ -275,16 +326,21 @@ anthropic/<model-id> · think:medium · ↑412k ↓8.1k · cache 83% ♨ · $0.8
|
|
|
275
326
|
|
|
276
327
|
## 安全
|
|
277
328
|
|
|
278
|
-
**权限模式**(`--permission-mode`、`/permission
|
|
329
|
+
**权限模式**(`--permission-mode`、配置 `permission.mode`、`/permission` 选择器、交互模式 `Shift+Tab` 循环):
|
|
330
|
+
|
|
331
|
+
| 模式 | 显示名 | 读 | 写 | 执行(bash 等) |
|
|
332
|
+
| ----------- | ------------------ | --- | ------------------------------------------------------ | ------------------------------ |
|
|
333
|
+
| `default` | Manual | ✓ | 询问 | 询问 |
|
|
334
|
+
| `auto-edit` | Accept edits | ✓ | ✓ | 询问 |
|
|
335
|
+
| `plan` | Plan | ✓ | 拒绝 | 拒绝 |
|
|
336
|
+
| `auto` | Auto | ✓ | ✓ ¹ | 安全的自动放行,有风险的才问 ² |
|
|
337
|
+
| `full-auto` | Bypass permissions | ✓ | ✓ | ✓ |
|
|
338
|
+
| `allowlist` | Allowlist only | ✓ | 只放行 allow 规则命中的,其余拒绝,从不询问(适合 CI) | 同左 |
|
|
279
339
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
| `plan` | ✓ | 拒绝 | 拒绝 |
|
|
283
|
-
| `default` | ✓ | 询问 | 询问 |
|
|
284
|
-
| `auto-edit` | ✓ | ✓ | 询问 |
|
|
285
|
-
| `full-auto` | ✓ | ✓ | ✓ |
|
|
340
|
+
¹ 机密文件(`.env`、私钥、`.ssh/` 等)、`.git/` 与 `.ama/`、项目目录外的写入仍然询问。
|
|
341
|
+
² 三层判定:规则层(危险命令、网络、删除类、受保护路径 → 询问)→ 静态判定(安全名单:`ls`、`cat`、`grep`、`git status/diff/log`、`npm test`、`tsc --noEmit`、`cargo test` 等 → 放行)→ 都没决定时问一次模型分类器(独立请求,不影响主会话缓存;`permission.autoModel` 可指定便宜模型)。详见 [docs/permissions.md](docs/permissions.md)。
|
|
286
342
|
|
|
287
|
-
**判定顺序**:deny 规则(含 Hook deny)→ 危险命令
|
|
343
|
+
**判定顺序**:deny 规则(含 Hook deny)→ 危险命令 →(auto 的规则层)→ 模式 / 静态判定 → allow 规则把「询问」变「允许」→(auto 的分类器)。前面的结论后面不能放宽。无人值守(`-p`、RPC 未接审批)时「询问」一律按拒绝。项目级配置只能收紧模式,且不能设 `auto` / `full-auto`。
|
|
288
344
|
|
|
289
345
|
- **规则**:`bash(git push*)`、`write(src/**)`、`read(**)`、`canvas_*`;`--allow` / `--deny` 可重复。内置 deny:写 `.git/**`、读写 `.ssh/**`。
|
|
290
346
|
- **危险命令**:`rm -rf /`、`sudo`、`git push --force`、`git reset --hard`、`git clean -f`、`curl … | sh`、`chmod -R 777`、`npm publish`、`shutdown` 等,即使有 allow 规则也要询问。识别会穿透 `sh -c '…'`、`eval`、`xargs`、`find -exec` 与 git 全局选项。
|
|
@@ -310,7 +366,7 @@ anthropic/<model-id> · think:medium · ↑412k ↓8.1k · cache 83% ♨ · $0.8
|
|
|
310
366
|
| Ctrl+C | 清空输入;输入为空时 1.5 秒内再按一次退出 |
|
|
311
367
|
| Tab | 补全:`/` 命令、模板与 Skill,`@` 文件路径 |
|
|
312
368
|
|
|
313
|
-
常用命令:`/model`、`/thinking`、`/permission`、`/tools`、`/compact`、`/tree`(回到某条消息之前重新分支)、`/fork`、`/resume`、`/new`、`/session`、`/cache`、`/hooks`、`/skill:<名字>`、`/help`。按键可在 `~/.config/ama/keybindings.json` 覆盖。见 [docs/tui.md](docs/tui.md)。
|
|
369
|
+
常用命令:`/model`、`/thinking`、`/permission`、`/tools`、`/compact`、`/tree`(回到某条消息之前重新分支)、`/fork`、`/resume`、`/new`、`/session`、`/cache`、`/hooks`、`/skill:<名字>`、`/help`。输入里的 `@图片路径`(或粘贴 / 拖入的图片路径)作为图片附件发给模型;`/model` 按「供应商 · 渠道」分组,标出上下文与 `img`。按键可在 `~/.config/ama/keybindings.json` 覆盖。见 [docs/tui.md](docs/tui.md)。
|
|
314
370
|
|
|
315
371
|
`--no-tui`(或 stdin / stdout 不是 TTY、`TERM=dumb`)进入行式界面:readline + 括号粘贴,命令相同。
|
|
316
372
|
|
|
@@ -322,7 +378,42 @@ anthropic/<model-id> · think:medium · ↑412k ↓8.1k · cache 83% ♨ · $0.8
|
|
|
322
378
|
| `json` | 一个 `result` 对象:会话 id、模型、`stopReason`、`text`、用量、费用、缓存统计 |
|
|
323
379
|
| `stream-json` | 每行一个事件,与 RPC 事件同形状 |
|
|
324
380
|
|
|
325
|
-
|
|
381
|
+
**stdin**:管道内容拼在提示后面(`git diff | ama -p "审阅"`);没有提示参数时管道内容就是提示。有提示参数时只等管道的
|
|
382
|
+
首字节 2 秒(`AMA_STDIN_WAIT_MS` 可调,0 = 不等):一个字节都没收到就忽略 stdin、继续运行,并在 stderr 提示一行——父进程
|
|
383
|
+
留着不关的管道不会让 `-p` 挂起;收到首字节后读到 EOF。上游命令要先跑很久才输出时,在末尾加 `-` 一直等到 EOF
|
|
384
|
+
(`npm test 2>&1 | ama -p "找出失败原因" -`);`--no-stdin` 完全不读。`< 文件` 重定向总会读取。
|
|
385
|
+
|
|
386
|
+
`--image <文件>` 可重复,随提示发送图片(PNG / JPEG / GIF / WebP,单张 ≤ 5 MB);提示里的 `@图片路径` 同样作为附件。当前
|
|
387
|
+
模型不收图片时直接退出 2,不发请求。
|
|
388
|
+
|
|
389
|
+
`--max-turns N` 限制一次运行最多 N 轮(一次模型请求加它的工具执行算一轮),到上限仍在调用工具时提前结束,退出码 1,
|
|
390
|
+
`json` 结果带 `maxTurnsReached: true`。
|
|
391
|
+
|
|
392
|
+
`--system-prompt <文本|@文件>` 补充系统提示(任何模式都可用):缺省作为最后一条规则追加,preamble 与工具表这段最长的
|
|
393
|
+
缓存前缀不变;`--system-prompt-mode replace` 改为替换开头的角色说明,工具表、规则与 AGENTS.md 仍然保留。
|
|
394
|
+
|
|
395
|
+
`--no-session` 让会话只留在内存里、不写会话文件(适合 CI 与一次性调用;之后无法 `--resume`),交互模式里 `/new` 切出的
|
|
396
|
+
新会话同样不落盘。
|
|
397
|
+
|
|
398
|
+
**无人值守**:`-p` 没有人审批,缺省权限模式下需要询问的调用(写文件、跑命令)一律拒绝。被拒时 stderr 一行汇总被拒的
|
|
399
|
+
工具与原因,`json` 结果带 `deniedTools`,`stream-json` 的 `tool_execution_end` 带 `denied: true`,退出码 7。需要放行时用
|
|
400
|
+
`--permission-mode auto-edit`(放行写入)/ `auto`(ama 判断每一步),或 `--allow "bash(npm test*)"` 按规则放行。
|
|
401
|
+
|
|
402
|
+
退出码:0 正常 · 1 运行期错误 · 2 用法错误 · 3 配置错误 · 4 无可用模型或 key · 5 会话错误 · 6 宿主 / Hook 启动失败 · 7 `-p` 有工具调用被拒 · 78 宿主 API 版本不匹配 · 130 / 143 信号。
|
|
403
|
+
|
|
404
|
+
### 会话统计、检索与复用
|
|
405
|
+
|
|
406
|
+
会话是 `<数据目录>/sessions` 下的 JSONL,下面这些命令只读不写(缺省看当前目录的会话,`--all` 看全部):
|
|
407
|
+
|
|
408
|
+
```sh
|
|
409
|
+
ama stats --since 7d --by model # 请求、token、缓存命中率、费用、工具调用 Top N(--json 可用)
|
|
410
|
+
ama sessions search "parser" --role user # 跨会话全文检索,/正则/ 也行
|
|
411
|
+
ama sessions show 3f9a1c2e # 末尾列出用户消息编号
|
|
412
|
+
ama -p --from 3f9a1c2e#2 --model packy/kimi-k2.5 # 用那条消息(含图片)换个模型再问
|
|
413
|
+
ama sessions export 3f9a1c2e --format md --output s.md # md / json / jsonl,导出前脱敏
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
统计口径(命中率只算报告缓存的端点、费用只加有价请求等)与导出格式见 [docs/sessions.md](docs/sessions.md)。
|
|
326
417
|
|
|
327
418
|
### RPC
|
|
328
419
|
|
|
@@ -383,10 +474,12 @@ Armadra 以 `ama --profile <path>` 启动 ama。profile 是一个 JSON 文件,
|
|
|
383
474
|
| [docs/providers.md](docs/providers.md) | 内置供应商、API Key、自定义供应商与中转站、compat、缓存 |
|
|
384
475
|
| [docs/tui.md](docs/tui.md) | 终端界面:布局、按键、命令、审批预览、缓存显示、组件库 |
|
|
385
476
|
| [docs/codemode.md](docs/codemode.md) | codemode 脚本、沙箱与权限 |
|
|
477
|
+
| [docs/permissions.md](docs/permissions.md) | 权限模式、auto 三层判定、安全名单、allowlist |
|
|
386
478
|
| [docs/hooks.md](docs/hooks.md) | 命令式 Hook(hooks.json) |
|
|
387
479
|
| [docs/host-api.md](docs/host-api.md) | 宿主适配器 API |
|
|
388
480
|
| [docs/rpc.md](docs/rpc.md) | RPC 协议(stdio JSONL) |
|
|
389
481
|
| [docs/session-format.md](docs/session-format.md) | 会话文件格式 |
|
|
482
|
+
| [docs/sessions.md](docs/sessions.md) | 会话统计、检索、`--from` 复用与导出 |
|
|
390
483
|
| [docs/extensions.md](docs/extensions.md) | 本地扩展(设计草案,未实现) |
|
|
391
484
|
| [docs/design.md](docs/design.md) | 总体设计与决策记录 |
|
|
392
485
|
| [docs/benchmarks/](docs/benchmarks/) | 三预设基准与缓存验收实验(报告与原始数据) |
|
|
@@ -416,7 +509,7 @@ pnpm 10 起 `pnpm ci` 是内置的「清理后安装」,跑检查要写 `pnpm
|
|
|
416
509
|
|
|
417
510
|
**约束**:运行时依赖必须为零,`src/` 只允许 `node:` 内置模块与相对路径(`pnpm check:deps` 守住)。`src/` 按层分目录(`ai` 模型接入、`agent` 循环、`session` 会话树、`tools`、`codemode`、`permissions`、`hooks`、`host` 宿主契约、`tui` 组件库、`modes` 各入口、`cli` 启动),各目录的 `types.ts` 是模块之间的契约。
|
|
418
511
|
|
|
419
|
-
**发布**:改 `package.json` 版本与 [CHANGELOG.md](CHANGELOG.md),合入 main 后打 `v<版本>` tag。CI 全绿后 release job 生成 GitHub Release(`ama.cjs`、`ama-sandbox.cjs`、`package.tgz`、`SHA256SUMS`),再以 provenance 发布到 npm
|
|
512
|
+
**发布**:改 `package.json` 版本与 [CHANGELOG.md](CHANGELOG.md),合入 main 后打 `v<版本>` tag。CI 全绿后 release job 生成 GitHub Release(`ama.cjs`、`ama-sandbox.cjs`、`package.tgz`、`SHA256SUMS`),再以 provenance 发布到 npm:优先用 OIDC 可信发布(trusted publishing,npm ≥ 11.5.1,job 内自动升级),在 npmjs.com 的 `@armadra/agent` 包设置 → Trusted Publisher 添加 GitHub Actions(组织 `Owlbay`、仓库 `armadra-agent`、工作流 `ci.yml`、环境留空)即可,不需要长期 token;仓库 secret `NPM_TOKEN` 保留为回退,两者都没有时 job 失败并提示。`pnpm release:check` 检查 tag 与版本一致,协议常量变化要求破坏性版本升级。
|
|
420
513
|
|
|
421
514
|
## 更新记录
|
|
422
515
|
|
package/dist/agent/retry.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 会话层重试(设计 §3.6「重试」「溢出」)。[B2]
|
|
3
3
|
*
|
|
4
4
|
* 判定顺序:上下文溢出(不重试,走压缩)→ 不可重试(配额 / 计费 / key / 401 / 403,快速失败)→
|
|
5
|
-
* 可重试(429、5xx、overloaded
|
|
5
|
+
* 可重试(429、5xx、overloaded、网络错误、断流、空闲超时)→ 其它(不重试)。
|
|
6
6
|
* 延迟 `baseDelayMs × 2^(attempt−1)`,上限 `maxDelayMs`;`sleep` 可被 abort 打断。
|
|
7
7
|
* 协议层自身不重试。溢出文案识别只有一份:ai/overflow.ts 的 `isOverflowErrorText`(缺省),可注入替换。
|
|
8
8
|
*/
|
package/dist/agent/retry.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 会话层重试(设计 §3.6「重试」「溢出」)。[B2]
|
|
3
3
|
*
|
|
4
4
|
* 判定顺序:上下文溢出(不重试,走压缩)→ 不可重试(配额 / 计费 / key / 401 / 403,快速失败)→
|
|
5
|
-
* 可重试(429、5xx、overloaded
|
|
5
|
+
* 可重试(429、5xx、overloaded、网络错误、断流、空闲超时)→ 其它(不重试)。
|
|
6
6
|
* 延迟 `baseDelayMs × 2^(attempt−1)`,上限 `maxDelayMs`;`sleep` 可被 abort 打断。
|
|
7
7
|
* 协议层自身不重试。溢出文案识别只有一份:ai/overflow.ts 的 `isOverflowErrorText`(缺省),可注入替换。
|
|
8
8
|
*/
|
|
@@ -38,6 +38,7 @@ const RETRYABLE_PATTERNS = [
|
|
|
38
38
|
/bad gateway/i,
|
|
39
39
|
/gateway timeout/i,
|
|
40
40
|
/timed? ?out/i,
|
|
41
|
+
/idle timeout/i,
|
|
41
42
|
/network/i,
|
|
42
43
|
/fetch failed/i,
|
|
43
44
|
/ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|EPIPE/,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 之后的首个请求是重置点。子会话(depth > 0)有自己的控制器,`warmSubagents` 为 false 时不保温。
|
|
8
8
|
* fork 出的会话沿用根会话 id 作 `prompt_cache_key`(只是路由提示);task 子会话不沿用。
|
|
9
9
|
*/
|
|
10
|
+
import { modelRefOf } from "../ai/providers/channels.js";
|
|
10
11
|
import { readFileSync } from "node:fs";
|
|
11
12
|
import { evaluateWarm } from "../ai/cache/economics.js";
|
|
12
13
|
import { fingerprintContext } from "../ai/cache/fingerprint.js";
|
|
@@ -140,7 +141,7 @@ export class SessionCacheController {
|
|
|
140
141
|
this.inner = inner;
|
|
141
142
|
return (model, context, options) => {
|
|
142
143
|
const purpose = options.purpose ?? "turn";
|
|
143
|
-
if (this.disposed || purpose === "warm" || purpose === "probe") {
|
|
144
|
+
if (this.disposed || purpose === "warm" || purpose === "probe" || purpose === "classify") {
|
|
144
145
|
return inner(model, context, options);
|
|
145
146
|
}
|
|
146
147
|
const sent = { ...options };
|
|
@@ -183,7 +184,7 @@ export class SessionCacheController {
|
|
|
183
184
|
const record = {
|
|
184
185
|
at,
|
|
185
186
|
purpose,
|
|
186
|
-
model:
|
|
187
|
+
model: modelRefOf(model),
|
|
187
188
|
api: model.api,
|
|
188
189
|
baseUrl: model.baseUrl ?? "",
|
|
189
190
|
fingerprint: fingerprintContext(context, model),
|
|
@@ -305,7 +306,9 @@ export class SessionCacheController {
|
|
|
305
306
|
const model = this.core.model();
|
|
306
307
|
if (record === undefined || this.disposed)
|
|
307
308
|
return undefined;
|
|
308
|
-
if (model.provider !== record.model.provider ||
|
|
309
|
+
if (model.provider !== record.model.provider ||
|
|
310
|
+
model.id !== record.model.id ||
|
|
311
|
+
model.channel !== record.model.channel)
|
|
309
312
|
return undefined;
|
|
310
313
|
const messages = convertToLlm(this.core.agent.messages, {
|
|
311
314
|
provider: model.provider,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auto 权限模式的分类请求(§7.4 第 3 层):把 permissions/classifier.ts 的 `complete` 接到会话上。
|
|
3
|
+
*
|
|
4
|
+
* - 模型:`options.permissionClassifier.model`(config `permission.autoModel`)解析成功就用它,
|
|
5
|
+
* 否则(未配置、找不到)用当前会话模型;找不到时记一次 warning。
|
|
6
|
+
* - 请求是**独立**的:只有分类系统提示与一条用户消息,不带会话转录与工具表;`purpose: "classify"`
|
|
7
|
+
* 让会话层缓存包装直接透传(不观测、不暂停 / 触发保温、不成为下一次请求的前缀依据);
|
|
8
|
+
* `cacheRetention: "none"`,关闭思考,`maxTokens` 256。
|
|
9
|
+
* - 用量记一条 `usage{kind:"permission_classify"}` 条目:计入 `/session` 费用,不进上下文。
|
|
10
|
+
*/
|
|
11
|
+
import { PermissionClassifier, type ClassifierRequest } from "../permissions/classifier.js";
|
|
12
|
+
import type { SessionCore } from "./session-core.js";
|
|
13
|
+
export declare const CLASSIFY_USAGE_KIND = "permission_classify";
|
|
14
|
+
/** 最近一条用户消息的文本(分类器输入的摘要来源)。 */
|
|
15
|
+
export declare function latestUserText(core: SessionCore): string | undefined;
|
|
16
|
+
export declare function createSessionClassifier(core: SessionCore): PermissionClassifier;
|
|
17
|
+
/** gateToolCall 用:组装分类请求。 */
|
|
18
|
+
export declare function classifierRequest(core: SessionCore, toolName: string, input: unknown, projectRoot: string | undefined): ClassifierRequest;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auto 权限模式的分类请求(§7.4 第 3 层):把 permissions/classifier.ts 的 `complete` 接到会话上。
|
|
3
|
+
*
|
|
4
|
+
* - 模型:`options.permissionClassifier.model`(config `permission.autoModel`)解析成功就用它,
|
|
5
|
+
* 否则(未配置、找不到)用当前会话模型;找不到时记一次 warning。
|
|
6
|
+
* - 请求是**独立**的:只有分类系统提示与一条用户消息,不带会话转录与工具表;`purpose: "classify"`
|
|
7
|
+
* 让会话层缓存包装直接透传(不观测、不暂停 / 触发保温、不成为下一次请求的前缀依据);
|
|
8
|
+
* `cacheRetention: "none"`,关闭思考,`maxTokens` 256。
|
|
9
|
+
* - 用量记一条 `usage{kind:"permission_classify"}` 条目:计入 `/session` 费用,不进上下文。
|
|
10
|
+
*/
|
|
11
|
+
import { CLASSIFIER_MAX_TOKENS, PermissionClassifier, } from "../permissions/classifier.js";
|
|
12
|
+
export const CLASSIFY_USAGE_KIND = "permission_classify";
|
|
13
|
+
function textOf(message) {
|
|
14
|
+
return message.content
|
|
15
|
+
.filter((block) => block.type === "text")
|
|
16
|
+
.map((block) => (block.type === "text" ? block.text : ""))
|
|
17
|
+
.join("")
|
|
18
|
+
.trim();
|
|
19
|
+
}
|
|
20
|
+
function classifierModel(core, warned) {
|
|
21
|
+
const ref = core.options.permissionClassifier?.model;
|
|
22
|
+
if (ref !== undefined && ref.trim() !== "") {
|
|
23
|
+
const lookup = core.options.providers.findModel(ref);
|
|
24
|
+
if (lookup.ok)
|
|
25
|
+
return lookup.model;
|
|
26
|
+
if (!warned.done) {
|
|
27
|
+
warned.done = true;
|
|
28
|
+
core.log("warn", `permission.autoModel ${ref} not found; using the session model`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return core.model();
|
|
32
|
+
}
|
|
33
|
+
/** 最近一条用户消息的文本(分类器输入的摘要来源)。 */
|
|
34
|
+
export function latestUserText(core) {
|
|
35
|
+
const message = core.agent.messages.findLast((m) => m.role === "user");
|
|
36
|
+
if (message === undefined || message.role !== "user")
|
|
37
|
+
return undefined;
|
|
38
|
+
const content = message.content;
|
|
39
|
+
if (typeof content === "string")
|
|
40
|
+
return content;
|
|
41
|
+
return content.map((block) => (block.type === "text" ? block.text : "")).join(" ");
|
|
42
|
+
}
|
|
43
|
+
export function createSessionClassifier(core) {
|
|
44
|
+
const warned = { done: false };
|
|
45
|
+
const options = core.options.permissionClassifier;
|
|
46
|
+
return new PermissionClassifier(async (prompt, signal) => {
|
|
47
|
+
const model = classifierModel(core, warned);
|
|
48
|
+
const context = {
|
|
49
|
+
messages: [
|
|
50
|
+
{ role: "system", sections: { preamble: prompt.system }, timestamp: Date.now() },
|
|
51
|
+
{ role: "user", content: prompt.user, timestamp: Date.now() },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
const streamOptions = {
|
|
55
|
+
signal,
|
|
56
|
+
maxTokens: Math.min(CLASSIFIER_MAX_TOKENS, model.maxTokens || CLASSIFIER_MAX_TOKENS),
|
|
57
|
+
cacheRetention: "none",
|
|
58
|
+
thinkingLevel: "off",
|
|
59
|
+
purpose: "classify",
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
const { apiKey } = await core.options.providers.resolveApiKey(model.provider, model.channel);
|
|
63
|
+
if (apiKey !== undefined)
|
|
64
|
+
streamOptions.apiKey = apiKey;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// 本地供应商无 key 也能用;真正缺 key 时请求会报错并按 ask 处理
|
|
68
|
+
}
|
|
69
|
+
const message = await core.stream(model, context, streamOptions).result();
|
|
70
|
+
try {
|
|
71
|
+
core.appendEntry({
|
|
72
|
+
type: "usage",
|
|
73
|
+
kind: CLASSIFY_USAGE_KIND,
|
|
74
|
+
provider: model.provider,
|
|
75
|
+
model: model.id,
|
|
76
|
+
usage: message.usage,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
core.log("debug", `classifier usage not recorded: ${String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
83
|
+
throw new Error(message.errorMessage ?? `classifier request ${message.stopReason}`);
|
|
84
|
+
}
|
|
85
|
+
return textOf(message);
|
|
86
|
+
}, {
|
|
87
|
+
...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
88
|
+
log: (level, message) => core.log(level, message),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** gateToolCall 用:组装分类请求。 */
|
|
92
|
+
export function classifierRequest(core, toolName, input, projectRoot) {
|
|
93
|
+
const request = {
|
|
94
|
+
toolName,
|
|
95
|
+
input,
|
|
96
|
+
cwd: core.cwd,
|
|
97
|
+
projectRoot: projectRoot ?? core.cwd,
|
|
98
|
+
};
|
|
99
|
+
const user = latestUserText(core);
|
|
100
|
+
if (user !== undefined)
|
|
101
|
+
request.userMessage = user;
|
|
102
|
+
return request;
|
|
103
|
+
}
|