@armadra/agent 0.2.1 → 0.3.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 +15 -0
- package/README.md +55 -11
- package/dist/agent/session-cache.js +5 -2
- package/dist/agent/session-state.js +2 -1
- package/dist/agent/session-sync.js +9 -2
- package/dist/agent/session.js +8 -7
- package/dist/ai/apis/openai-responses.js +2 -1
- 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/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 +35 -4
- package/dist/ai/providers/registry.js +177 -24
- package/dist/ai/types.d.ts +21 -1
- package/dist/bundle/ama.cjs +4075 -2008
- package/dist/cli/args.d.ts +6 -3
- package/dist/cli/args.js +30 -3
- package/dist/cli/bootstrap.js +1 -0
- package/dist/cli/compose-providers.js +3 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose.d.ts +3 -1
- package/dist/cli/compose.js +24 -9
- package/dist/cli/deps.d.ts +2 -0
- package/dist/cli/main.d.ts +2 -1
- package/dist/cli/main.js +13 -1
- package/dist/cli/startup-steps.js +6 -1
- package/dist/cli/subcommands/config.d.ts +11 -2
- package/dist/cli/subcommands/config.js +80 -4
- package/dist/cli/subcommands/context.js +1 -0
- package/dist/cli/subcommands/init.d.ts +6 -0
- package/dist/cli/subcommands/init.js +22 -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 +6 -0
- package/dist/cli/subcommands/models-discover.js +37 -9
- package/dist/cli/subcommands/models.js +26 -18
- 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.d.ts +27 -0
- package/dist/cli/subcommands/providers.js +433 -0
- package/dist/config/init.d.ts +30 -0
- package/dist/config/init.js +92 -0
- package/dist/config/json-schema.d.ts +14 -0
- package/dist/config/json-schema.js +182 -0
- package/dist/config/schema.d.ts +1 -1
- package/dist/config/schema.js +74 -11
- package/dist/config/types.d.ts +23 -5
- package/dist/config/types.js +2 -0
- package/dist/modes/image-input.d.ts +27 -0
- package/dist/modes/image-input.js +78 -0
- package/dist/modes/interactive/commands.js +2 -3
- package/dist/modes/interactive/interactive-mode.js +5 -1
- package/dist/modes/interactive/line/line-mode.js +3 -1
- package/dist/modes/interactive/startup-ui.d.ts +7 -2
- package/dist/modes/interactive/startup-ui.js +41 -11
- package/dist/modes/print/print-mode.d.ts +2 -0
- package/dist/modes/print/print-mode.js +12 -1
- package/dist/modes/rpc/commands.js +7 -2
- package/dist/rpc.d.ts +2 -0
- package/dist/session/projection.js +5 -1
- 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/read.d.ts +4 -8
- package/dist/tools/read.js +15 -64
- package/docs/providers.md +216 -1
- package/docs/rpc.md +3 -3
- package/docs/session-format.md +1 -1
- package/docs/tui.md +2 -0
- package/package.json +1 -1
package/dist/cli/args.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* 手写参数解析(设计 §11.1 第 2 步、§12.10、§13)。[B5]
|
|
3
3
|
*
|
|
4
4
|
* - 支持 `--opt value` 与 `--opt=value`;`--` 之后全部作为提示文本;可重复的参数累加。
|
|
5
|
-
* - 子命令只在第一个参数是 `auth / sessions / models / doctor / config`
|
|
5
|
+
* - 子命令只在第一个参数是 `auth / sessions / models / providers / doctor / config / init` 时识别,
|
|
6
|
+
* 其余参数原样交给子命令。
|
|
6
7
|
* - 互斥:`-p` 与 `--mode rpc`;`--continue` / `--resume` / `--session-id` / `--fork` 两两互斥;
|
|
7
8
|
* `--trust` 与 `--no-trust`;`--api-key` 需要 `--model`;`--output-format` 需要 `-p`。
|
|
8
9
|
* - `--resume [id]`:下一个参数形如会话 id(无空白、不以 `-` 开头)才被当作 id;
|
|
@@ -13,7 +14,7 @@ import { AmaError } from "../errors.js";
|
|
|
13
14
|
import type { ModelThinkingLevel } from "../ai/types.js";
|
|
14
15
|
import type { PermissionMode } from "../permissions/types.js";
|
|
15
16
|
import type { CodemodeMode, ToolsPreset } from "../config/types.js";
|
|
16
|
-
export declare const SUBCOMMANDS: readonly ["auth", "sessions", "models", "doctor", "config"];
|
|
17
|
+
export declare const SUBCOMMANDS: readonly ["auth", "sessions", "models", "providers", "doctor", "config", "init"];
|
|
17
18
|
export type SubcommandName = (typeof SUBCOMMANDS)[number];
|
|
18
19
|
export type OutputFormat = "text" | "json" | "stream-json";
|
|
19
20
|
export type QuietStartup = "normal" | "header" | "silent";
|
|
@@ -54,6 +55,8 @@ export interface ParsedArgs {
|
|
|
54
55
|
toolsPreset?: ToolsPreset;
|
|
55
56
|
/** `--codemode`:覆盖 config `codemode.mode`。 */
|
|
56
57
|
codemode?: CodemodeMode;
|
|
58
|
+
/** `--image <文件>`(可重复,只用于 -p):随首条提示发送的图片。 */
|
|
59
|
+
images: string[];
|
|
57
60
|
/** 位置参数拼成的提示(空格连接)。 */
|
|
58
61
|
prompt?: string;
|
|
59
62
|
/** 原始位置参数。 */
|
|
@@ -70,7 +73,7 @@ export type ParseResult = {
|
|
|
70
73
|
export declare class UsageError extends AmaError {
|
|
71
74
|
constructor(message: string);
|
|
72
75
|
}
|
|
73
|
-
export declare const HELP_TEXT = "\u7528\u6CD5\uFF1Aama [\u9009\u9879] [\u63D0\u793A]\n ama <\u5B50\u547D\u4EE4> \u2026\n\n\u6A21\u5F0F\n \uFF08\u7F3A\u7701\uFF09 \u7EC8\u7AEF\u754C\u9762\uFF1Bstdin / stdout \u975E TTY \u6216 TERM=dumb \u65F6\u81EA\u52A8\u964D\u7EA7\u4E3A\u884C\u5F0F\n --no-tui \u884C\u5F0F\u754C\u9762\uFF08readline + \u62EC\u53F7\u7C98\u8D34\uFF09\n -p, --print \u975E\u4EA4\u4E92\uFF1A\u6267\u884C\u63D0\u793A\u540E\u9000\u51FA\uFF08\u63D0\u793A\u53EF\u6765\u81EA\u53C2\u6570\u4E0E stdin \u7BA1\u9053\uFF09\n --output-format <\u683C\u5F0F> -p \u7684\u8F93\u51FA\uFF1Atext\uFF08\u7F3A\u7701\uFF09| json | stream-json\n --mode rpc stdio JSONL \u534F\u8BAE\uFF08\u4F9B\u5D4C\u5165\uFF09\n --tui-mode <\u6A21\u5F0F> \u663E\u793A\u6A21\u5F0F\uFF0C\u7B2C\u4E00\u671F\u53EA\u6709 regular\uFF08\u4E3B\u5C4F\uFF09\n --quiet-startup <\u6863> \u542F\u52A8\u753B\u9762\uFF1Anormal | header | silent\n\n\u6A21\u578B\n --model <provider/id> \u6A21\u578B\uFF08\u53EF\u914D\u5408 --provider \u53EA\u5199 id\uFF09\n --provider <id> \u4F9B\u5E94\u5546\uFF08\u5FC5\u987B\u540C\u65F6\u7ED9 --model\uFF09\n --api-key <key> \u53EA\u7528\u4E8E\u672C\u6B21\u542F\u52A8\u7684 key\uFF08\u9700\u8981 --model\uFF1B\u4F18\u5148\u7528 ama auth set\uFF09\n --thinking <\u7EA7\u522B> off | minimal | low | medium | high | xhigh\n\n\u4F1A\u8BDD\n -c, --continue \u7EE7\u7EED\u672C\u76EE\u5F55\u6700\u8FD1\u7684\u4F1A\u8BDD\n -r, --resume [id] \u6062\u590D\u4F1A\u8BDD\uFF08\u4EA4\u4E92\u6A21\u5F0F\u65E0 id \u65F6\u5F39\u9009\u62E9\u5668\uFF09\n --session-id <id> \u4F7F\u7528\u6307\u5B9A id \u7684\u4F1A\u8BDD\uFF08\u4E0D\u5B58\u5728\u5219\u65B0\u5EFA\uFF09\n --fork <id> \u4ECE\u6307\u5B9A\u4F1A\u8BDD\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD\n --session-dir <\u76EE\u5F55> \u4F1A\u8BDD\u76EE\u5F55\uFF08\u7F3A\u7701 ~/.local/share/ama/sessions\uFF09\n\n\u6743\u9650\u4E0E\u4FE1\u4EFB\n --permission-mode <\u6A21\u5F0F> plan | default | auto-edit | full-auto\n --allow <\u89C4\u5219> \u8FFD\u52A0\u5141\u8BB8\u89C4\u5219\uFF0C\u53EF\u91CD\u590D\uFF08\u5982 \"bash(git status*)\"\uFF09\n --deny <\u89C4\u5219> \u8FFD\u52A0\u62D2\u7EDD\u89C4\u5219\uFF0C\u53EF\u91CD\u590D\uFF08\u5982 \"write(**/.env*)\"\uFF09\n --trust / --no-trust \u4FE1\u4EFB / \u4E0D\u4FE1\u4EFB\u5F53\u524D\u9879\u76EE\uFF08\u9879\u76EE\u7EA7 Hook\u3001Skill\u3001\u63D0\u793A\u6A21\u677F\uFF09\n\n\u8D44\u6E90\n --profile <\u6587\u4EF6> \u5BBF\u4E3B profile.json\uFF08\u5B57\u6BB5\u7B49\u4EF7\u4E8E\u5BF9\u5E94\u53C2\u6570\uFF0C\u547D\u4EE4\u884C\u4F18\u5148\uFF09\n --host <\u6A21\u5757> \u5BBF\u4E3B\u9002\u914D\u5668\u6A21\u5757\uFF08CJS / ESM\uFF09\n --instructions <\u6587\u4EF6> \u8FFD\u52A0\u6307\u4EE4\u6587\u4EF6\uFF0C\u53EF\u91CD\u590D\n --skill-dir <\u76EE\u5F55> \u8FFD\u52A0 Skill \u76EE\u5F55\uFF0C\u53EF\u91CD\u590D\n --auth-file <\u6587\u4EF6> auth.json \u4F4D\u7F6E\uFF08\u7F3A\u7701 ~/.config/ama/auth.json\uFF09\n --tools <a,b,\u2026> \u53EA\u542F\u7528\u8FD9\u4E9B\u5DE5\u5177\n --exclude-tools <a,b,\u2026> \u7981\u7528\u8FD9\u4E9B\u5DE5\u5177\n --tools-preset <\u540D> \u5DE5\u5177\u9884\u8BBE\uFF1Adefault\uFF08\u7F3A\u7701\uFF09| minimal | codemode | coordinator\n --codemode <\u6A21\u5F0F> codemode \u8C03\u7528\u65B9\u5F0F\uFF1Aoff | on | only\n\n\u5B50\u547D\u4EE4\n ama auth set <provider> \u4ECE stdin \u8BFB\u53D6 key \u5199\u5165 auth.json\uFF080600\uFF09\n ama auth list \u5217\u51FA\u5DF2\u4FDD\u5B58 key \u7684\u4F9B\u5E94\u5546\uFF08\u4E0D\u663E\u793A key\uFF09\n ama auth remove <provider> \u5220\u9664\u5DF2\u4FDD\u5B58\u7684 key\n ama sessions list|show|prune \u4F1A\u8BDD\u7BA1\u7406\n ama models list [--provider <id>] \u5217\u51FA\u6A21\u578B\uFF08\u542B\u6765\u6E90\u4E0E key \u72B6\u6001\uFF09\n ama models check <provider/id> \u53D1\u4E00\u6B21\u6700\u5C0F\u8BF7\u6C42\u68C0\u67E5\u53EF\u7528\u6027\n ama models discover <provider> [--probe] [--write] [--limit N]\n \u4ECE\u4E2D\u8F6C /v1/models \u5217\u51FA\u6A21\u578B\uFF0C\u63A2\u6D4B\u534F\u8BAE\u5E76\u5199\u5165\u914D\u7F6E\n ama models cache-probe <provider/id> [--tokens N] [--gap-ms MS] [--yes] [--json]\n \u5224\u65AD\u7AEF\u70B9\u662F\u5426\u62A5\u544A\u7F13\u5B58\u547D\u4E2D\n ama doctor \u914D\u7F6E\u5C42\u7EA7\u3001\u4FE1\u4EFB\u3001key \u6765\u6E90\u3001Hook\u3001\u7EC8\u7AEF\u80FD\u529B\n ama config show [--json] \u751F\u6548\u914D\u7F6E\u4E0E\u6BCF\u9879\u6765\u6E90\u3001\u5C06\u4F7F\u7528\u7684\u6A21\u578B\n\n\u5176\u5B83\n -h, --help \u8F93\u51FA\u672C\u5E2E\u52A9\n -v, --version \u8F93\u51FA\u7248\u672C\n\n\u9000\u51FA\u7801\uFF1A0 \u6B63\u5E38 \u00B7 1 \u8FD0\u884C\u671F\u9519\u8BEF \u00B7 2 \u7528\u6CD5\u9519\u8BEF \u00B7 3 \u914D\u7F6E\u9519\u8BEF \u00B7 4 \u65E0\u53EF\u7528\u6A21\u578B\u6216 key \u00B7\n 5 \u4F1A\u8BDD\u9519\u8BEF \u00B7 6 \u5BBF\u4E3B / Hook \u542F\u52A8\u5931\u8D25 \u00B7 78 \u5BBF\u4E3B API \u7248\u672C\u4E0D\u5339\u914D \u00B7 130 SIGINT \u00B7 143 SIGTERM\n";
|
|
76
|
+
export declare const HELP_TEXT = "\u7528\u6CD5\uFF1Aama [\u9009\u9879] [\u63D0\u793A]\n ama <\u5B50\u547D\u4EE4> \u2026\n\n\u6A21\u5F0F\n \uFF08\u7F3A\u7701\uFF09 \u7EC8\u7AEF\u754C\u9762\uFF1Bstdin / stdout \u975E TTY \u6216 TERM=dumb \u65F6\u81EA\u52A8\u964D\u7EA7\u4E3A\u884C\u5F0F\n --no-tui \u884C\u5F0F\u754C\u9762\uFF08readline + \u62EC\u53F7\u7C98\u8D34\uFF09\n -p, --print \u975E\u4EA4\u4E92\uFF1A\u6267\u884C\u63D0\u793A\u540E\u9000\u51FA\uFF08\u63D0\u793A\u53EF\u6765\u81EA\u53C2\u6570\u4E0E stdin \u7BA1\u9053\uFF09\n --output-format <\u683C\u5F0F> -p \u7684\u8F93\u51FA\uFF1Atext\uFF08\u7F3A\u7701\uFF09| json | stream-json\n --image <\u6587\u4EF6> -p \u968F\u63D0\u793A\u53D1\u9001\u56FE\u7247\uFF08\u53EF\u91CD\u590D\uFF1Bpng / jpg / gif / webp\uFF0C\u5355\u5F20 \u2264 5 MB\uFF09\uFF1B\n \u4EA4\u4E92\u754C\u9762\u91CC\u5199 @\u56FE\u7247\u8DEF\u5F84 \u6216\u7C98\u8D34\u56FE\u7247\u8DEF\u5F84\n --mode rpc stdio JSONL \u534F\u8BAE\uFF08\u4F9B\u5D4C\u5165\uFF09\n --tui-mode <\u6A21\u5F0F> \u663E\u793A\u6A21\u5F0F\uFF0C\u7B2C\u4E00\u671F\u53EA\u6709 regular\uFF08\u4E3B\u5C4F\uFF09\n --quiet-startup <\u6863> \u542F\u52A8\u753B\u9762\uFF1Anormal | header | silent\n\n\u6A21\u578B\n --model <provider/id> \u6A21\u578B\uFF08\u53EF\u914D\u5408 --provider \u53EA\u5199 id\uFF1B@\u6E20\u9053 \u6307\u5B9A\u6E20\u9053\uFF0C\u5982 packy/kimi-k2.5@messages\uFF09\n --provider <id> \u4F9B\u5E94\u5546\uFF08\u5FC5\u987B\u540C\u65F6\u7ED9 --model\uFF09\n --api-key <key> \u53EA\u7528\u4E8E\u672C\u6B21\u542F\u52A8\u7684 key\uFF08\u9700\u8981 --model\uFF1B\u4F18\u5148\u7528 ama auth set\uFF09\n --thinking <\u7EA7\u522B> off | minimal | low | medium | high | xhigh\n\n\u4F1A\u8BDD\n -c, --continue \u7EE7\u7EED\u672C\u76EE\u5F55\u6700\u8FD1\u7684\u4F1A\u8BDD\n -r, --resume [id] \u6062\u590D\u4F1A\u8BDD\uFF08\u4EA4\u4E92\u6A21\u5F0F\u65E0 id \u65F6\u5F39\u9009\u62E9\u5668\uFF09\n --session-id <id> \u4F7F\u7528\u6307\u5B9A id \u7684\u4F1A\u8BDD\uFF08\u4E0D\u5B58\u5728\u5219\u65B0\u5EFA\uFF09\n --fork <id> \u4ECE\u6307\u5B9A\u4F1A\u8BDD\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD\n --session-dir <\u76EE\u5F55> \u4F1A\u8BDD\u76EE\u5F55\uFF08\u7F3A\u7701 ~/.local/share/ama/sessions\uFF09\n\n\u6743\u9650\u4E0E\u4FE1\u4EFB\n --permission-mode <\u6A21\u5F0F> plan | default | auto-edit | full-auto\n --allow <\u89C4\u5219> \u8FFD\u52A0\u5141\u8BB8\u89C4\u5219\uFF0C\u53EF\u91CD\u590D\uFF08\u5982 \"bash(git status*)\"\uFF09\n --deny <\u89C4\u5219> \u8FFD\u52A0\u62D2\u7EDD\u89C4\u5219\uFF0C\u53EF\u91CD\u590D\uFF08\u5982 \"write(**/.env*)\"\uFF09\n --trust / --no-trust \u4FE1\u4EFB / \u4E0D\u4FE1\u4EFB\u5F53\u524D\u9879\u76EE\uFF08\u9879\u76EE\u7EA7 Hook\u3001Skill\u3001\u63D0\u793A\u6A21\u677F\uFF09\n\n\u8D44\u6E90\n --profile <\u6587\u4EF6> \u5BBF\u4E3B profile.json\uFF08\u5B57\u6BB5\u7B49\u4EF7\u4E8E\u5BF9\u5E94\u53C2\u6570\uFF0C\u547D\u4EE4\u884C\u4F18\u5148\uFF09\n --host <\u6A21\u5757> \u5BBF\u4E3B\u9002\u914D\u5668\u6A21\u5757\uFF08CJS / ESM\uFF09\n --instructions <\u6587\u4EF6> \u8FFD\u52A0\u6307\u4EE4\u6587\u4EF6\uFF0C\u53EF\u91CD\u590D\n --skill-dir <\u76EE\u5F55> \u8FFD\u52A0 Skill \u76EE\u5F55\uFF0C\u53EF\u91CD\u590D\n --auth-file <\u6587\u4EF6> auth.json \u4F4D\u7F6E\uFF08\u7F3A\u7701 ~/.config/ama/auth.json\uFF09\n --tools <a,b,\u2026> \u53EA\u542F\u7528\u8FD9\u4E9B\u5DE5\u5177\n --exclude-tools <a,b,\u2026> \u7981\u7528\u8FD9\u4E9B\u5DE5\u5177\n --tools-preset <\u540D> \u5DE5\u5177\u9884\u8BBE\uFF1Adefault\uFF08\u7F3A\u7701\uFF09| minimal | codemode | coordinator\n --codemode <\u6A21\u5F0F> codemode \u8C03\u7528\u65B9\u5F0F\uFF1Aoff | on | only\n\n\u5B50\u547D\u4EE4\n ama auth set <provider> \u4ECE stdin \u8BFB\u53D6 key \u5199\u5165 auth.json\uFF080600\uFF09\n ama auth list \u5217\u51FA\u5DF2\u4FDD\u5B58 key \u7684\u4F9B\u5E94\u5546\uFF08\u4E0D\u663E\u793A key\uFF09\n ama auth remove <provider> \u5220\u9664\u5DF2\u4FDD\u5B58\u7684 key\n ama sessions list|show|prune \u4F1A\u8BDD\u7BA1\u7406\n ama models list [--provider <id>] \u5217\u51FA\u6A21\u578B\uFF08\u542B\u6765\u6E90\u4E0E key \u72B6\u6001\uFF09\n ama models check <provider/id> \u53D1\u4E00\u6B21\u6700\u5C0F\u8BF7\u6C42\u68C0\u67E5\u53EF\u7528\u6027\n ama models discover <provider> [--probe] [--write] [--limit N]\n \u4ECE\u4E2D\u8F6C /v1/models \u5217\u51FA\u6A21\u578B\uFF0C\u63A2\u6D4B\u534F\u8BAE\u5E76\u5199\u5165\u914D\u7F6E\n ama models refresh-catalog \u5F3A\u5236\u5237\u65B0 models.dev \u6A21\u578B\u5143\u6570\u636E\u7F13\u5B58\n ama providers add <id> --base-url <url> [--key-env VAR] [--probe] [--channel n=api@url] [--yes]\n \u4E00\u952E\u63A5\u5165\uFF1A\u5217\u6A21\u578B\u3001\u8865 models.dev \u5143\u6570\u636E\u3001\u63A2\u6D4B\u6E20\u9053\u3001\u5199\u5165\u914D\u7F6E\n ama providers list|channels <id>|remove <id>|refresh <id>\n \u4F9B\u5E94\u5546 \u2192 \u6E20\u9053 \u2192 \u6A21\u578B\uFF1B\u5220\u9664\uFF1B\u91CD\u62C9\u6A21\u578B\u5217\u8868\n ama models cache-probe <provider/id> [--tokens N] [--gap-ms MS] [--yes] [--json]\n \u5224\u65AD\u7AEF\u70B9\u662F\u5426\u62A5\u544A\u7F13\u5B58\u547D\u4E2D\n ama doctor \u914D\u7F6E\u5C42\u7EA7\u3001\u4FE1\u4EFB\u3001key \u6765\u6E90\u3001Hook\u3001\u7EC8\u7AEF\u80FD\u529B\n ama config show [--json] \u751F\u6548\u914D\u7F6E\u4E0E\u6BCF\u9879\u6765\u6E90\u3001\u5C06\u4F7F\u7528\u7684\u6A21\u578B\n ama config path \u914D\u7F6E\u76EE\u5F55\u3001\u6570\u636E\u76EE\u5F55\u4E0E\u5404\u6587\u4EF6\u8DEF\u5F84\n ama config edit \u7528 $VISUAL / $EDITOR \u6253\u5F00 config.json\n ama init [--force] \u5EFA\u914D\u7F6E\u76EE\u5F55\uFF080700\uFF09\u4E0E config.json\u3001config.schema.json\uFF1B\u5DF2\u6709\u7684\u4E0D\u8986\u76D6\n\n\u5176\u5B83\n -h, --help \u8F93\u51FA\u672C\u5E2E\u52A9\n -v, --version \u8F93\u51FA\u7248\u672C\n\n\u9000\u51FA\u7801\uFF1A0 \u6B63\u5E38 \u00B7 1 \u8FD0\u884C\u671F\u9519\u8BEF \u00B7 2 \u7528\u6CD5\u9519\u8BEF \u00B7 3 \u914D\u7F6E\u9519\u8BEF \u00B7 4 \u65E0\u53EF\u7528\u6A21\u578B\u6216 key \u00B7\n 5 \u4F1A\u8BDD\u9519\u8BEF \u00B7 6 \u5BBF\u4E3B / Hook \u542F\u52A8\u5931\u8D25 \u00B7 78 \u5BBF\u4E3B API \u7248\u672C\u4E0D\u5339\u914D \u00B7 130 SIGINT \u00B7 143 SIGTERM\n";
|
|
74
77
|
export declare function emptyArgs(): ParsedArgs;
|
|
75
78
|
/** 解析 argv(不含 node 与脚本路径);用法错误抛 UsageError(退出码 2)。 */
|
|
76
79
|
export declare function parseArgs(argv: readonly string[]): ParseResult;
|
package/dist/cli/args.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* 手写参数解析(设计 §11.1 第 2 步、§12.10、§13)。[B5]
|
|
3
3
|
*
|
|
4
4
|
* - 支持 `--opt value` 与 `--opt=value`;`--` 之后全部作为提示文本;可重复的参数累加。
|
|
5
|
-
* - 子命令只在第一个参数是 `auth / sessions / models / doctor / config`
|
|
5
|
+
* - 子命令只在第一个参数是 `auth / sessions / models / providers / doctor / config / init` 时识别,
|
|
6
|
+
* 其余参数原样交给子命令。
|
|
6
7
|
* - 互斥:`-p` 与 `--mode rpc`;`--continue` / `--resume` / `--session-id` / `--fork` 两两互斥;
|
|
7
8
|
* `--trust` 与 `--no-trust`;`--api-key` 需要 `--model`;`--output-format` 需要 `-p`。
|
|
8
9
|
* - `--resume [id]`:下一个参数形如会话 id(无空白、不以 `-` 开头)才被当作 id;
|
|
@@ -11,7 +12,15 @@
|
|
|
11
12
|
*/
|
|
12
13
|
import { AmaError } from "../errors.js";
|
|
13
14
|
import { CODEMODE_MODES } from "../config/types.js";
|
|
14
|
-
export const SUBCOMMANDS = [
|
|
15
|
+
export const SUBCOMMANDS = [
|
|
16
|
+
"auth",
|
|
17
|
+
"sessions",
|
|
18
|
+
"models",
|
|
19
|
+
"providers",
|
|
20
|
+
"doctor",
|
|
21
|
+
"config",
|
|
22
|
+
"init",
|
|
23
|
+
];
|
|
15
24
|
export class UsageError extends AmaError {
|
|
16
25
|
constructor(message) {
|
|
17
26
|
super("invalid_arguments", message, { exitCode: 2 });
|
|
@@ -40,12 +49,14 @@ export const HELP_TEXT = `用法:ama [选项] [提示]
|
|
|
40
49
|
--no-tui 行式界面(readline + 括号粘贴)
|
|
41
50
|
-p, --print 非交互:执行提示后退出(提示可来自参数与 stdin 管道)
|
|
42
51
|
--output-format <格式> -p 的输出:text(缺省)| json | stream-json
|
|
52
|
+
--image <文件> -p 随提示发送图片(可重复;png / jpg / gif / webp,单张 ≤ 5 MB);
|
|
53
|
+
交互界面里写 @图片路径 或粘贴图片路径
|
|
43
54
|
--mode rpc stdio JSONL 协议(供嵌入)
|
|
44
55
|
--tui-mode <模式> 显示模式,第一期只有 regular(主屏)
|
|
45
56
|
--quiet-startup <档> 启动画面:normal | header | silent
|
|
46
57
|
|
|
47
58
|
模型
|
|
48
|
-
--model <provider/id> 模型(可配合 --provider 只写 id)
|
|
59
|
+
--model <provider/id> 模型(可配合 --provider 只写 id;@渠道 指定渠道,如 packy/kimi-k2.5@messages)
|
|
49
60
|
--provider <id> 供应商(必须同时给 --model)
|
|
50
61
|
--api-key <key> 只用于本次启动的 key(需要 --model;优先用 ama auth set)
|
|
51
62
|
--thinking <级别> off | minimal | low | medium | high | xhigh
|
|
@@ -83,10 +94,18 @@ export const HELP_TEXT = `用法:ama [选项] [提示]
|
|
|
83
94
|
ama models check <provider/id> 发一次最小请求检查可用性
|
|
84
95
|
ama models discover <provider> [--probe] [--write] [--limit N]
|
|
85
96
|
从中转 /v1/models 列出模型,探测协议并写入配置
|
|
97
|
+
ama models refresh-catalog 强制刷新 models.dev 模型元数据缓存
|
|
98
|
+
ama providers add <id> --base-url <url> [--key-env VAR] [--probe] [--channel n=api@url] [--yes]
|
|
99
|
+
一键接入:列模型、补 models.dev 元数据、探测渠道、写入配置
|
|
100
|
+
ama providers list|channels <id>|remove <id>|refresh <id>
|
|
101
|
+
供应商 → 渠道 → 模型;删除;重拉模型列表
|
|
86
102
|
ama models cache-probe <provider/id> [--tokens N] [--gap-ms MS] [--yes] [--json]
|
|
87
103
|
判断端点是否报告缓存命中
|
|
88
104
|
ama doctor 配置层级、信任、key 来源、Hook、终端能力
|
|
89
105
|
ama config show [--json] 生效配置与每项来源、将使用的模型
|
|
106
|
+
ama config path 配置目录、数据目录与各文件路径
|
|
107
|
+
ama config edit 用 $VISUAL / $EDITOR 打开 config.json
|
|
108
|
+
ama init [--force] 建配置目录(0700)与 config.json、config.schema.json;已有的不覆盖
|
|
90
109
|
|
|
91
110
|
其它
|
|
92
111
|
-h, --help 输出本帮助
|
|
@@ -119,6 +138,7 @@ const VALUE_OPTIONS = new Set([
|
|
|
119
138
|
"exclude-tools",
|
|
120
139
|
"tools-preset",
|
|
121
140
|
"codemode",
|
|
141
|
+
"image",
|
|
122
142
|
]);
|
|
123
143
|
const FLAG_ALIASES = {
|
|
124
144
|
"-h": "help",
|
|
@@ -146,6 +166,7 @@ export function emptyArgs() {
|
|
|
146
166
|
skillDirs: [],
|
|
147
167
|
allow: [],
|
|
148
168
|
deny: [],
|
|
169
|
+
images: [],
|
|
149
170
|
continue: false,
|
|
150
171
|
resume: false,
|
|
151
172
|
print: false,
|
|
@@ -228,6 +249,9 @@ function applyValue(args, option, value) {
|
|
|
228
249
|
case "codemode":
|
|
229
250
|
args.codemode = choice(option, value, CODEMODE_MODES);
|
|
230
251
|
break;
|
|
252
|
+
case "image":
|
|
253
|
+
args.images.push(value);
|
|
254
|
+
break;
|
|
231
255
|
}
|
|
232
256
|
}
|
|
233
257
|
function applyFlag(args, name) {
|
|
@@ -277,6 +301,9 @@ function validate(args) {
|
|
|
277
301
|
if (args.outputFormat !== undefined && !args.print) {
|
|
278
302
|
throw new UsageError("--output-format 只用于 -p / --print");
|
|
279
303
|
}
|
|
304
|
+
if (args.images.length > 0 && !args.print) {
|
|
305
|
+
throw new UsageError("--image 只用于 -p / --print(交互界面里写 @图片路径)");
|
|
306
|
+
}
|
|
280
307
|
}
|
|
281
308
|
/** 解析 argv(不含 node 与脚本路径);用法错误抛 UsageError(退出码 2)。 */
|
|
282
309
|
export function parseArgs(argv) {
|
package/dist/cli/bootstrap.js
CHANGED
|
@@ -143,6 +143,7 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
143
143
|
? resolve(io.cwd, args.authFile)
|
|
144
144
|
: defaultAuthFilePath(paths.configDir),
|
|
145
145
|
authEnv: profile?.authEnv ?? true,
|
|
146
|
+
dataDir: paths.dataDir,
|
|
146
147
|
...(args.apiKey !== undefined && args.model !== undefined
|
|
147
148
|
? {
|
|
148
149
|
cliApiKey: {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* - 零配置(设计 §10.0):没有 `defaultModel`、也没有任何需要 key 的供应商配了 key 时,探测本地
|
|
11
11
|
* ollama / lmstudio(短超时),把枚举到的模型加进注册表,供 `pickDefaultModel` 选用。
|
|
12
12
|
*/
|
|
13
|
+
import { loadModelsDevIndex } from "../ai/providers/models-dev-cache.js";
|
|
13
14
|
import { ProviderRegistry, discoverLocalModels } from "../ai/providers/registry.js";
|
|
14
15
|
export const LOCAL_PROBE_TIMEOUT_MS = 300;
|
|
15
16
|
export const NO_LOCAL_PROBE_ENV = "AMA_NO_LOCAL_PROBE";
|
|
@@ -45,6 +46,7 @@ export function withExtraProviders(config, providers) {
|
|
|
45
46
|
}
|
|
46
47
|
export async function buildProviderRegistry(input, options = {}) {
|
|
47
48
|
const config = withExtraProviders(input.config, options.providers);
|
|
49
|
+
const dataDir = input.dataDir;
|
|
48
50
|
const make = (cliApiKey) => new ProviderRegistry({
|
|
49
51
|
config,
|
|
50
52
|
apis: options.apis,
|
|
@@ -57,6 +59,7 @@ export async function buildProviderRegistry(input, options = {}) {
|
|
|
57
59
|
env: options.env,
|
|
58
60
|
},
|
|
59
61
|
onWarning: options.warn,
|
|
62
|
+
...(dataDir !== undefined ? { modelsDev: () => loadModelsDevIndex(dataDir) } : {}),
|
|
60
63
|
});
|
|
61
64
|
let registry = make();
|
|
62
65
|
const cli = input.cliApiKey;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* - 会话切换:`switchSession()` 复用同一份装配材料建新会话,`assembly.onSessionReplaced(next)`
|
|
16
16
|
* 让宿主访问、Hook 公共字段与退出 dispose 跟随新会话。
|
|
17
17
|
*/
|
|
18
|
+
import type { ProviderRegistryApi } from "../ai/types.js";
|
|
18
19
|
import { AgentSessionImpl } from "../agent/session.js";
|
|
19
20
|
import type { AgentSession, CacheSettings, SessionEvent } from "../agent/types.js";
|
|
20
21
|
import { type AmaConfig } from "../config/types.js";
|
|
@@ -32,6 +33,8 @@ export interface ComposeState {
|
|
|
32
33
|
warnings: string[];
|
|
33
34
|
/** 当前会话(工具工厂的 `session()`)。 */
|
|
34
35
|
session: AgentSession | undefined;
|
|
36
|
+
/** 第 11 步建好的供应商注册表(read 工具判断当前模型收不收图片)。 */
|
|
37
|
+
providers?: ProviderRegistryApi;
|
|
35
38
|
}
|
|
36
39
|
export declare function emptyComposeState(): ComposeState;
|
|
37
40
|
export type LogFn = (level: "debug" | "info" | "warn" | "error", message: string) => void;
|
package/dist/cli/compose.d.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* 需要会话时用 `ctx.session()`,嵌套调用其它工具用 `ToolContext.tools.executeTool`(走完整门禁)。
|
|
24
24
|
*/
|
|
25
25
|
import type { ApiRegistry } from "../ai/apis/api.js";
|
|
26
|
-
import type { ProviderData } from "../ai/types.js";
|
|
26
|
+
import type { ModelRef, ProviderData } from "../ai/types.js";
|
|
27
27
|
import type { AgentSession } from "../agent/types.js";
|
|
28
28
|
import type { AmaConfig } from "../config/types.js";
|
|
29
29
|
import type { Rule } from "../permissions/types.js";
|
|
@@ -82,6 +82,8 @@ export declare function createTools(input: {
|
|
|
82
82
|
cwd: string;
|
|
83
83
|
mode: RuntimeMode;
|
|
84
84
|
}, options: ComposeOptions, state: ComposeState): PresetToolRegistry;
|
|
85
|
+
/** 当前模型是否收图片(read 工具用);查不到模型时按收(交给协议层过滤)。 */
|
|
86
|
+
export declare function modelAcceptsImages(state: ComposeState, model: ModelRef | undefined): boolean;
|
|
85
87
|
/** 第 14 步前:内置 deny(builtinDeny 过滤)+ 用户规则;非法规则 warning 后跳过。 */
|
|
86
88
|
export declare function buildRules(specs: readonly {
|
|
87
89
|
effect: "allow" | "deny";
|
package/dist/cli/compose.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* 第 12 步建注册表时调用,产物以 `builtin` 来源注册(受预设管理);工厂拿不到会话对象本身,执行期
|
|
23
23
|
* 需要会话时用 `ctx.session()`,嵌套调用其它工具用 `ToolContext.tools.executeTool`(走完整门禁)。
|
|
24
24
|
*/
|
|
25
|
+
import { formatModelRef } from "../ai/providers/channels.js";
|
|
25
26
|
import { PermissionPipeline } from "../permissions/pipeline.js";
|
|
26
27
|
import { BUILTIN_DENY_RULES, parseRule } from "../permissions/rules.js";
|
|
27
28
|
import { discoverSkills, skillSources } from "../skills/discover.js";
|
|
@@ -58,7 +59,10 @@ export function createTools(input, options, state) {
|
|
|
58
59
|
const bash = input.config.tools?.bashTimeoutMs !== undefined
|
|
59
60
|
? { defaultTimeoutMs: input.config.tools.bashTimeoutMs }
|
|
60
61
|
: {};
|
|
61
|
-
const builtins = builtinTools({
|
|
62
|
+
const builtins = builtinTools({
|
|
63
|
+
bash,
|
|
64
|
+
read: { supportsImages: (ctx) => modelAcceptsImages(state, ctx.model) },
|
|
65
|
+
});
|
|
62
66
|
const ctx = {
|
|
63
67
|
...input,
|
|
64
68
|
registry,
|
|
@@ -94,6 +98,13 @@ export function createTools(input, options, state) {
|
|
|
94
98
|
state.warnings.push(...preset.warnings);
|
|
95
99
|
return registry;
|
|
96
100
|
}
|
|
101
|
+
/** 当前模型是否收图片(read 工具用);查不到模型时按收(交给协议层过滤)。 */
|
|
102
|
+
export function modelAcceptsImages(state, model) {
|
|
103
|
+
if (model === undefined || state.providers === undefined)
|
|
104
|
+
return true;
|
|
105
|
+
const found = state.providers.findModel(formatModelRef(model));
|
|
106
|
+
return found.ok ? found.model.input.includes("image") : true;
|
|
107
|
+
}
|
|
97
108
|
/** 第 14 步前:内置 deny(builtinDeny 过滤)+ 用户规则;非法规则 warning 后跳过。 */
|
|
98
109
|
export function buildRules(specs, builtinDeny, warn) {
|
|
99
110
|
const rules = [];
|
|
@@ -142,14 +153,18 @@ export function createRuntimeDeps(options = {}) {
|
|
|
142
153
|
const state = emptyComposeState();
|
|
143
154
|
const deps = {
|
|
144
155
|
providers: {
|
|
145
|
-
create: (input) =>
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
create: async (input) => {
|
|
157
|
+
const registry = await buildProviderRegistry(input, {
|
|
158
|
+
providers: options.providers,
|
|
159
|
+
apis: options.apis,
|
|
160
|
+
env: options.env,
|
|
161
|
+
includeFake: options.includeFake,
|
|
162
|
+
probeLocal: options.probeLocal,
|
|
163
|
+
warn: (message) => state.warnings.push(message),
|
|
164
|
+
});
|
|
165
|
+
state.providers = registry;
|
|
166
|
+
return registry;
|
|
167
|
+
},
|
|
153
168
|
},
|
|
154
169
|
sessions: createSessionStore(),
|
|
155
170
|
tools: { create: (input) => createTools(input, options, state) },
|
package/dist/cli/deps.d.ts
CHANGED
package/dist/cli/main.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* - 设 `AMA=1`、`AI_AGENT=ama`;直接执行时装 `uncaughtException` / `unhandledRejection` →
|
|
6
6
|
* stderr 一行 + 退出码 1;SIGINT / SIGTERM 交给当前模式。
|
|
7
|
-
* - `--version` / `--help` 短路;子命令 `auth / sessions / models / doctor / config
|
|
7
|
+
* - `--version` / `--help` 短路;子命令 `auth / sessions / models / providers / doctor / config /
|
|
8
|
+
* init` 分派后返回;其余命令启动前若配置目录不存在则静默初始化(`AMA_NO_INIT=1` 关闭);
|
|
8
9
|
* 其余交给 `runCli()`(bootstrap → 模式)。
|
|
9
10
|
* - 运行时实现(RuntimeDeps):`MainOptions.deps` > `registerRuntimeDeps()` > 组装根
|
|
10
11
|
* `createRuntimeDeps()`(cli/compose.ts,动态 import)。
|
package/dist/cli/main.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* - 设 `AMA=1`、`AI_AGENT=ama`;直接执行时装 `uncaughtException` / `unhandledRejection` →
|
|
6
6
|
* stderr 一行 + 退出码 1;SIGINT / SIGTERM 交给当前模式。
|
|
7
|
-
* - `--version` / `--help` 短路;子命令 `auth / sessions / models / doctor / config
|
|
7
|
+
* - `--version` / `--help` 短路;子命令 `auth / sessions / models / providers / doctor / config /
|
|
8
|
+
* init` 分派后返回;其余命令启动前若配置目录不存在则静默初始化(`AMA_NO_INIT=1` 关闭);
|
|
8
9
|
* 其余交给 `runCli()`(bootstrap → 模式)。
|
|
9
10
|
* - 运行时实现(RuntimeDeps):`MainOptions.deps` > `registerRuntimeDeps()` > 组装根
|
|
10
11
|
* `createRuntimeDeps()`(cli/compose.ts,动态 import)。
|
|
@@ -21,6 +22,10 @@ import { runAuth } from "./subcommands/auth.js";
|
|
|
21
22
|
import { runConfig } from "./subcommands/config.js";
|
|
22
23
|
import { runDoctor } from "./subcommands/doctor.js";
|
|
23
24
|
import { runModels } from "./subcommands/models.js";
|
|
25
|
+
import { runProviders } from "./subcommands/providers.js";
|
|
26
|
+
import { runInit } from "./subcommands/init.js";
|
|
27
|
+
import { autoInitConfigDir } from "../config/init.js";
|
|
28
|
+
import { resolveConfigDir } from "../config/paths.js";
|
|
24
29
|
import { runSessions } from "./subcommands/sessions.js";
|
|
25
30
|
let registeredDeps;
|
|
26
31
|
/** 集成批次注入运行时实现(B1 / B2 / B3 / B6 / B7)。 */
|
|
@@ -116,6 +121,9 @@ export async function main(argv, options = {}) {
|
|
|
116
121
|
const parsed = parseArgs(argv);
|
|
117
122
|
if (parsed.kind !== "subcommand")
|
|
118
123
|
noTui = parsed.args.noTui;
|
|
124
|
+
const informational = parsed.kind === "run" ? parsed.args.help || parsed.args.version : parsed.name === "init";
|
|
125
|
+
if (!informational)
|
|
126
|
+
autoInitConfigDir(resolveConfigDir({ env: io.env }), io.env);
|
|
119
127
|
if (parsed.kind === "subcommand") {
|
|
120
128
|
switch (parsed.name) {
|
|
121
129
|
case "auth":
|
|
@@ -124,10 +132,14 @@ export async function main(argv, options = {}) {
|
|
|
124
132
|
return await runSessions(parsed.argv, io, await resolveDeps());
|
|
125
133
|
case "models":
|
|
126
134
|
return await runModels(parsed.argv, io, await resolveDeps());
|
|
135
|
+
case "providers":
|
|
136
|
+
return await runProviders(parsed.argv, io, await resolveDeps());
|
|
127
137
|
case "doctor":
|
|
128
138
|
return await runDoctor(parsed.argv, io, await resolveDeps());
|
|
129
139
|
case "config":
|
|
130
140
|
return await runConfig(parsed.argv, io, await resolveDeps());
|
|
141
|
+
case "init":
|
|
142
|
+
return runInit(parsed.argv, io);
|
|
131
143
|
}
|
|
132
144
|
}
|
|
133
145
|
if (parsed.args.version) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* 启动序列的单步辅助(设计 §11.1):错误映射、模式判定、profile 合并、会话请求、
|
|
3
3
|
* 模型与思考级别解析、工具过滤、指令文件。[B5] 由 cli/bootstrap.ts 编排。
|
|
4
4
|
*/
|
|
5
|
+
import { formatModelRef } from "../ai/providers/channels.js";
|
|
5
6
|
import { statSync } from "node:fs";
|
|
6
7
|
import { isAbsolute, resolve } from "node:path";
|
|
7
8
|
import { AmaError, StartupError, isAmaError } from "../errors.js";
|
|
@@ -119,7 +120,11 @@ export async function resolveModel(args, registry, manager, defaultModel, deps,
|
|
|
119
120
|
else {
|
|
120
121
|
const change = lastEntry(manager, (e) => e.type === "model_change");
|
|
121
122
|
if (change?.type === "model_change") {
|
|
122
|
-
const found = registry.findModel(
|
|
123
|
+
const found = registry.findModel(formatModelRef({
|
|
124
|
+
provider: change.provider,
|
|
125
|
+
id: change.modelId,
|
|
126
|
+
...(change.channel !== undefined ? { channel: change.channel } : {}),
|
|
127
|
+
}));
|
|
123
128
|
if (found.ok)
|
|
124
129
|
choice = { model: found.model, provider: found.provider };
|
|
125
130
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { AmaConfig } from "../../config/types.js";
|
|
11
11
|
import type { Api, ProviderRegistryApi } from "../../ai/types.js";
|
|
12
12
|
import type { CliIo, RuntimeDeps } from "../deps.js";
|
|
13
|
-
export declare const CONFIG_USAGE = "\u7528\u6CD5\uFF1Aama config show [--json] [--profile <\u6587\u4EF6>] [--auth-file <\u6587\u4EF6>]\n";
|
|
13
|
+
export declare const CONFIG_USAGE = "\u7528\u6CD5\uFF1Aama config show [--json] [--profile <\u6587\u4EF6>] [--auth-file <\u6587\u4EF6>]\n ama config path \u914D\u7F6E\u76EE\u5F55\u3001\u6570\u636E\u76EE\u5F55\u4E0E\u5404\u6587\u4EF6\u8DEF\u5F84\n ama config edit \u7528 $VISUAL / $EDITOR \u6253\u5F00 config.json\uFF08\u6CA1\u6709\u7F16\u8F91\u5668\u65F6\u6253\u5370\u8DEF\u5F84\uFF09\n";
|
|
14
14
|
type Layer = {
|
|
15
15
|
name: "default" | "user" | "profile" | "project";
|
|
16
16
|
label: string;
|
|
@@ -30,10 +30,19 @@ export interface ProviderDescription {
|
|
|
30
30
|
baseUrl: string;
|
|
31
31
|
/** baseUrl 来自的环境变量。 */
|
|
32
32
|
baseUrlEnv?: string;
|
|
33
|
-
/**
|
|
33
|
+
/** 渠道(多渠道供应商)。 */
|
|
34
|
+
channels?: {
|
|
35
|
+
name: string;
|
|
36
|
+
api: Api;
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
}[];
|
|
39
|
+
/** config 里列出的模型及其生效协议、渠道与元数据来源。 */
|
|
34
40
|
models: {
|
|
35
41
|
id: string;
|
|
36
42
|
api: Api;
|
|
43
|
+
channels?: string[];
|
|
44
|
+
flags: string;
|
|
45
|
+
sources?: string;
|
|
37
46
|
}[];
|
|
38
47
|
}
|
|
39
48
|
/** config 里出现的供应商 + baseUrl 来自环境变量的内置供应商。 */
|
|
@@ -7,9 +7,16 @@
|
|
|
7
7
|
* `ANTHROPIC_BASE_URL`)的内置供应商,列出协议、生效 baseUrl 与来源、config 里每个模型的协议
|
|
8
8
|
* (模型级 `api` 生效后的值)。
|
|
9
9
|
*/
|
|
10
|
+
import { metadataOf, modelFlags, sourcesLine } from "./model-meta.js";
|
|
10
11
|
import { loadConfigFile } from "../../config/load.js";
|
|
11
12
|
import { DEFAULT_CONFIG, PROFILE_DEFAULTS, mergeProjectAndCli } from "../../config/merge.js";
|
|
12
|
-
import { CONFIG_FILE, projectFile } from "../../config/paths.js";
|
|
13
|
+
import { AUTH_FILE, CONFIG_FILE, HOOKS_FILE, projectFile, resolveConfigDir, resolveDataDir, } from "../../config/paths.js";
|
|
14
|
+
import { spawnSync } from "node:child_process";
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { modelsDevCachePath } from "../../ai/providers/models-dev-cache.js";
|
|
18
|
+
import { initConfigDir } from "../../config/init.js";
|
|
19
|
+
import { CONFIG_SCHEMA_FILE } from "../../config/json-schema.js";
|
|
13
20
|
import { baseUrlEnvOf } from "../../ai/providers/registry.js";
|
|
14
21
|
import { classifyKeyValue } from "../../config/auth-file.js";
|
|
15
22
|
import { effectiveCodemodeMode, resolvePreset } from "../../tools/presets.js";
|
|
@@ -19,7 +26,47 @@ import { pickDefaultModel } from "../default-model.js";
|
|
|
19
26
|
import { ExitCode } from "../exit-codes.js";
|
|
20
27
|
import { buildRegistry, loadUserLevel } from "./context.js";
|
|
21
28
|
export const CONFIG_USAGE = `用法:ama config show [--json] [--profile <文件>] [--auth-file <文件>]
|
|
29
|
+
ama config path 配置目录、数据目录与各文件路径
|
|
30
|
+
ama config edit 用 $VISUAL / $EDITOR 打开 config.json(没有编辑器时打印路径)
|
|
22
31
|
`;
|
|
32
|
+
/** `ama config path`:目录与文件路径,标出是否存在。 */
|
|
33
|
+
function showPaths(io) {
|
|
34
|
+
const configDir = resolveConfigDir({ env: io.env });
|
|
35
|
+
const dataDir = resolveDataDir({ env: io.env });
|
|
36
|
+
const mark = (path) => `${path}${existsSync(path) ? "" : " (不存在)"}`;
|
|
37
|
+
const lines = [
|
|
38
|
+
`配置目录 ${mark(configDir)}`,
|
|
39
|
+
` config.json ${mark(join(configDir, CONFIG_FILE))}`,
|
|
40
|
+
` config.schema.json ${mark(join(configDir, CONFIG_SCHEMA_FILE))}`,
|
|
41
|
+
` auth.json ${mark(join(configDir, AUTH_FILE))}`,
|
|
42
|
+
` hooks.json ${mark(join(configDir, HOOKS_FILE))}`,
|
|
43
|
+
`数据目录 ${mark(dataDir)}`,
|
|
44
|
+
` sessions/ ${mark(join(dataDir, "sessions"))}`,
|
|
45
|
+
` models-dev.json ${mark(modelsDevCachePath(dataDir))}`,
|
|
46
|
+
`项目级 ${mark(projectFile(io.cwd, CONFIG_FILE))}`,
|
|
47
|
+
];
|
|
48
|
+
io.stdout(`${lines.join("\n")}\n`);
|
|
49
|
+
return ExitCode.Ok;
|
|
50
|
+
}
|
|
51
|
+
/** `ama config edit`:不存在先 init;`$VISUAL` / `$EDITOR`(可带参数)打开,没有就打印路径。 */
|
|
52
|
+
function editConfig(io) {
|
|
53
|
+
const configDir = resolveConfigDir({ env: io.env });
|
|
54
|
+
const path = join(configDir, CONFIG_FILE);
|
|
55
|
+
if (!existsSync(path))
|
|
56
|
+
initConfigDir(configDir);
|
|
57
|
+
const editor = (io.env["VISUAL"] ?? io.env["EDITOR"] ?? "").trim();
|
|
58
|
+
if (editor === "") {
|
|
59
|
+
io.stdout(`${path}\n(没有设置 $VISUAL / $EDITOR,请用编辑器打开上面的文件)\n`);
|
|
60
|
+
return ExitCode.Ok;
|
|
61
|
+
}
|
|
62
|
+
const quoted = process.platform === "win32" ? `"${path}"` : `'${path.replace(/'/g, `'\\''`)}'`;
|
|
63
|
+
const result = spawnSync(`${editor} ${quoted}`, { stdio: "inherit", shell: true });
|
|
64
|
+
if (result.error !== undefined || result.status !== 0) {
|
|
65
|
+
io.stderr(`ama: 编辑器退出异常(${editor});文件在 ${path}\n`);
|
|
66
|
+
return ExitCode.RuntimeError;
|
|
67
|
+
}
|
|
68
|
+
return ExitCode.Ok;
|
|
69
|
+
}
|
|
23
70
|
function isObject(value) {
|
|
24
71
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
72
|
}
|
|
@@ -82,7 +129,27 @@ export function describeProviders(config, registry) {
|
|
|
82
129
|
api: provider.api,
|
|
83
130
|
baseUrl: provider.baseUrl,
|
|
84
131
|
...(env !== undefined ? { baseUrlEnv: env } : {}),
|
|
85
|
-
|
|
132
|
+
...(provider.channels !== undefined
|
|
133
|
+
? {
|
|
134
|
+
channels: provider.channels.map((c) => ({
|
|
135
|
+
name: c.name,
|
|
136
|
+
api: c.api,
|
|
137
|
+
baseUrl: c.baseUrl,
|
|
138
|
+
})),
|
|
139
|
+
}
|
|
140
|
+
: {}),
|
|
141
|
+
models: provider.models
|
|
142
|
+
.filter((m) => ids.has(m.id))
|
|
143
|
+
.map((m) => {
|
|
144
|
+
const sources = sourcesLine(metadataOf(registry, provider.id, m.id));
|
|
145
|
+
return {
|
|
146
|
+
id: m.id,
|
|
147
|
+
api: m.api,
|
|
148
|
+
...(m.channels !== undefined ? { channels: [...m.channels] } : {}),
|
|
149
|
+
flags: modelFlags(m),
|
|
150
|
+
...(sources !== undefined ? { sources } : {}),
|
|
151
|
+
};
|
|
152
|
+
}),
|
|
86
153
|
});
|
|
87
154
|
}
|
|
88
155
|
return out;
|
|
@@ -94,8 +161,13 @@ function providerLines(providers) {
|
|
|
94
161
|
for (const p of providers) {
|
|
95
162
|
const env = p.baseUrlEnv !== undefined ? `(baseUrl 来自环境变量 ${p.baseUrlEnv})` : "";
|
|
96
163
|
lines.push(` ${p.id} ${p.api} ${p.baseUrl}${env}`);
|
|
97
|
-
for (const
|
|
98
|
-
lines.push(`
|
|
164
|
+
for (const c of p.channels ?? [])
|
|
165
|
+
lines.push(` @${c.name} ${c.api} ${c.baseUrl}`);
|
|
166
|
+
for (const m of p.models) {
|
|
167
|
+
lines.push(` ${p.id}/${m.id} ${m.api} ${m.flags}`);
|
|
168
|
+
if (m.sources !== undefined)
|
|
169
|
+
lines.push(` ${m.sources}`);
|
|
170
|
+
}
|
|
99
171
|
}
|
|
100
172
|
return lines;
|
|
101
173
|
}
|
|
@@ -156,6 +228,10 @@ export async function runConfig(argv, io, deps) {
|
|
|
156
228
|
io.stdout(CONFIG_USAGE);
|
|
157
229
|
return ExitCode.Ok;
|
|
158
230
|
}
|
|
231
|
+
if (action === "path")
|
|
232
|
+
return showPaths(io);
|
|
233
|
+
if (action === "edit")
|
|
234
|
+
return editConfig(io);
|
|
159
235
|
if (action !== "show")
|
|
160
236
|
throw new UsageError(`未知的 config 子命令:${action}`);
|
|
161
237
|
const level = loadUserLevel(io, {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama init [--force]`(docs/providers.md「配置目录」):建配置目录与缺省文件,逐个报告状态。
|
|
3
|
+
*/
|
|
4
|
+
import type { CliIo } from "../deps.js";
|
|
5
|
+
export declare const INIT_USAGE = "\u7528\u6CD5\uFF1Aama init [--force] \u5EFA\u914D\u7F6E\u76EE\u5F55\uFF080700\uFF09\u4E0E config.json\u3001config.schema.json\n \u5DF2\u6709\u7684 config.json \u4E0D\u8986\u76D6\uFF08--force \u5148\u5907\u4EFD\u4E3A .bak \u518D\u91CD\u5199\uFF09\uFF1B\u4E0D\u521B\u5EFA auth.json\n";
|
|
6
|
+
export declare function runInit(argv: readonly string[], io: CliIo): number;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama init [--force]`(docs/providers.md「配置目录」):建配置目录与缺省文件,逐个报告状态。
|
|
3
|
+
*/
|
|
4
|
+
import { describeInit, initConfigDir } from "../../config/init.js";
|
|
5
|
+
import { resolveConfigDir } from "../../config/paths.js";
|
|
6
|
+
import { parseSubArgs, UsageError } from "../args.js";
|
|
7
|
+
import { ExitCode } from "../exit-codes.js";
|
|
8
|
+
export const INIT_USAGE = `用法:ama init [--force] 建配置目录(0700)与 config.json、config.schema.json
|
|
9
|
+
已有的 config.json 不覆盖(--force 先备份为 .bak 再重写);不创建 auth.json
|
|
10
|
+
`;
|
|
11
|
+
export function runInit(argv, io) {
|
|
12
|
+
const { positionals, flags } = parseSubArgs(argv, [], ["force"]);
|
|
13
|
+
if (flags.has("help")) {
|
|
14
|
+
io.stdout(INIT_USAGE);
|
|
15
|
+
return ExitCode.Ok;
|
|
16
|
+
}
|
|
17
|
+
if (positionals.length > 0)
|
|
18
|
+
throw new UsageError(`多余的参数:${positionals.join(" ")}`);
|
|
19
|
+
const result = initConfigDir(resolveConfigDir({ env: io.env }), { force: flags.has("force") });
|
|
20
|
+
io.stdout(describeInit(result));
|
|
21
|
+
return ExitCode.Ok;
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型元数据的一行描述(`ama models list`、`ama config show`、`ama providers`):上下文、输出、思考、
|
|
3
|
+
* 图片、渠道,以及每个字段来自哪里(config / 目录 / models.dev / 缺省)与 models.dev 匹配。
|
|
4
|
+
*/
|
|
5
|
+
import { type ModelMetadata } from "../../ai/providers/enrich.js";
|
|
6
|
+
import type { Model, ProviderRegistryApi } from "../../ai/types.js";
|
|
7
|
+
export declare function compactTokens(n: number | undefined): string;
|
|
8
|
+
/** 注册表若是 ProviderRegistry(或同形状),取模型元数据来源;否则 undefined。 */
|
|
9
|
+
export declare function metadataOf(registry: ProviderRegistryApi, providerId: string, modelId: string): ModelMetadata | undefined;
|
|
10
|
+
/** `ctx 262k · out 64k · 思考 · 图片 · 渠道 chat,messages`。 */
|
|
11
|
+
export declare function modelFlags(model: Model): string;
|
|
12
|
+
/**
|
|
13
|
+
* 来源说明:全部来自内置目录时返回 undefined(不刷屏);否则
|
|
14
|
+
* `来源 ctx models.dev · out config · 图片 models.dev · …;models.dev 原厂 moonshotai/kimi-k2.5`。
|
|
15
|
+
*/
|
|
16
|
+
export declare function sourcesLine(metadata: ModelMetadata | undefined): string | undefined;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型元数据的一行描述(`ama models list`、`ama config show`、`ama providers`):上下文、输出、思考、
|
|
3
|
+
* 图片、渠道,以及每个字段来自哪里(config / 目录 / models.dev / 缺省)与 models.dev 匹配。
|
|
4
|
+
*/
|
|
5
|
+
import { sourceText } from "../../ai/providers/enrich.js";
|
|
6
|
+
import { matchLabel } from "../../ai/providers/models-dev.js";
|
|
7
|
+
export function compactTokens(n) {
|
|
8
|
+
if (n === undefined)
|
|
9
|
+
return "?";
|
|
10
|
+
if (n >= 1_000_000)
|
|
11
|
+
return `${Math.round(n / 100_000) / 10}M`;
|
|
12
|
+
if (n >= 1000)
|
|
13
|
+
return `${Math.round(n / 1000)}k`;
|
|
14
|
+
return String(n);
|
|
15
|
+
}
|
|
16
|
+
/** 注册表若是 ProviderRegistry(或同形状),取模型元数据来源;否则 undefined。 */
|
|
17
|
+
export function metadataOf(registry, providerId, modelId) {
|
|
18
|
+
const r = registry;
|
|
19
|
+
return typeof r.modelMetadata === "function" ? r.modelMetadata(providerId, modelId) : undefined;
|
|
20
|
+
}
|
|
21
|
+
/** `ctx 262k · out 64k · 思考 · 图片 · 渠道 chat,messages`。 */
|
|
22
|
+
export function modelFlags(model) {
|
|
23
|
+
return [
|
|
24
|
+
`ctx ${compactTokens(model.contextWindow)}`,
|
|
25
|
+
`out ${compactTokens(model.maxTokens)}`,
|
|
26
|
+
model.reasoning ? "思考" : undefined,
|
|
27
|
+
model.input.includes("image") ? "图片" : undefined,
|
|
28
|
+
model.channels !== undefined ? `渠道 ${model.channels.join(",")}` : undefined,
|
|
29
|
+
]
|
|
30
|
+
.filter((x) => x !== undefined)
|
|
31
|
+
.join(" · ");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 来源说明:全部来自内置目录时返回 undefined(不刷屏);否则
|
|
35
|
+
* `来源 ctx models.dev · out config · 图片 models.dev · …;models.dev 原厂 moonshotai/kimi-k2.5`。
|
|
36
|
+
*/
|
|
37
|
+
export function sourcesLine(metadata) {
|
|
38
|
+
if (metadata === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
const values = Object.values(metadata.sources);
|
|
41
|
+
if (values.every((s) => s === "catalog" || s === "default") && !metadata.looked)
|
|
42
|
+
return undefined;
|
|
43
|
+
const label = {
|
|
44
|
+
contextWindow: "ctx",
|
|
45
|
+
maxTokens: "out",
|
|
46
|
+
input: "图片",
|
|
47
|
+
reasoning: "思考",
|
|
48
|
+
cost: "价格",
|
|
49
|
+
};
|
|
50
|
+
const parts = Object.keys(label).map((field) => `${label[field]} ${sourceText(metadata.sources[field])}`);
|
|
51
|
+
const match = metadata.looked ? `;models.dev ${matchLabel(metadata.match)}` : "";
|
|
52
|
+
const tools = metadata.toolCall === false ? ";不支持工具调用" : "";
|
|
53
|
+
return `来源 ${parts.join(" · ")}${match}${tools}`;
|
|
54
|
+
}
|