@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
|
@@ -3,23 +3,78 @@
|
|
|
3
3
|
* 每一项标出来自哪一层(default / user / profile / project),并给出将使用的模型与原因
|
|
4
4
|
* (`config.defaultModel` 或零配置选择)。只读;config 里的字面量 apiKey 只显示种类。[B6]
|
|
5
5
|
*
|
|
6
|
+
* 缺省值来自 config/key-docs.ts 的 DISPLAY_DEFAULTS(含 DEFAULT_CONFIG 不写的 cache / codemode 等段),
|
|
7
|
+
* `codemode.mode` 不写时显示跟随预设的结果与原因;`--tools-preset` / `--codemode` 作为 cli 层叠加;
|
|
8
|
+
* 预设写的是旧名(codemode)时显示规范名并提示。
|
|
9
|
+
*
|
|
6
10
|
* [W3-B12] 「供应商」节:config 里出现的供应商与 baseUrl 来自环境变量(`OPENAI_BASE_URL` /
|
|
7
11
|
* `ANTHROPIC_BASE_URL`)的内置供应商,列出协议、生效 baseUrl 与来源、config 里每个模型的协议
|
|
8
12
|
* (模型级 `api` 生效后的值)。
|
|
9
13
|
*/
|
|
14
|
+
import { metadataOf, modelFlags, sourcesLine } from "./model-meta.js";
|
|
10
15
|
import { loadConfigFile } from "../../config/load.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
16
|
+
import { PROFILE_DEFAULTS, cliOverridesToConfig, mergeConfig, mergeProjectAndCli, } from "../../config/merge.js";
|
|
17
|
+
import { DISPLAY_DEFAULTS } from "../../config/key-docs.js";
|
|
18
|
+
import { AUTH_FILE, CONFIG_FILE, HOOKS_FILE, projectFile, resolveConfigDir, resolveDataDir, } from "../../config/paths.js";
|
|
19
|
+
import { spawnSync } from "node:child_process";
|
|
20
|
+
import { existsSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { modelsDevCachePath } from "../../ai/providers/models-dev-cache.js";
|
|
23
|
+
import { initConfigDir } from "../../config/init.js";
|
|
24
|
+
import { CONFIG_SCHEMA_FILE } from "../../config/json-schema.js";
|
|
25
|
+
import { CODEMODE_MODES, TOOLS_PRESET_ALIASES, TOOLS_PRESET_INPUTS, canonicalPreset, } from "../../config/types.js";
|
|
26
|
+
import { codemodeAvailability, detectSandboxCapability } from "../../codemode/capability.js";
|
|
13
27
|
import { baseUrlEnvOf } from "../../ai/providers/registry.js";
|
|
14
28
|
import { classifyKeyValue } from "../../config/auth-file.js";
|
|
15
|
-
import {
|
|
29
|
+
import { CODEMODE_TOOL, resolveCodemodeMode, resolvePreset } from "../../tools/presets.js";
|
|
16
30
|
import { builtinTools } from "../../tools/registry.js";
|
|
17
31
|
import { parseSubArgs, UsageError } from "../args.js";
|
|
18
|
-
import { pickDefaultModel } from "../default-model.js";
|
|
32
|
+
import { noModelGuidance, pickDefaultModel } from "../default-model.js";
|
|
19
33
|
import { ExitCode } from "../exit-codes.js";
|
|
20
34
|
import { buildRegistry, loadUserLevel } from "./context.js";
|
|
21
35
|
export const CONFIG_USAGE = `用法:ama config show [--json] [--profile <文件>] [--auth-file <文件>]
|
|
36
|
+
[--tools-preset <名>] [--codemode off|on|only]
|
|
37
|
+
ama config path 配置目录、数据目录与各文件路径
|
|
38
|
+
ama config edit 用 $VISUAL / $EDITOR 打开 config.json(没有编辑器时打印路径)
|
|
22
39
|
`;
|
|
40
|
+
/** `ama config path`:目录与文件路径,标出是否存在。 */
|
|
41
|
+
function showPaths(io) {
|
|
42
|
+
const configDir = resolveConfigDir({ env: io.env });
|
|
43
|
+
const dataDir = resolveDataDir({ env: io.env });
|
|
44
|
+
const mark = (path) => `${path}${existsSync(path) ? "" : " (不存在)"}`;
|
|
45
|
+
const lines = [
|
|
46
|
+
`配置目录 ${mark(configDir)}`,
|
|
47
|
+
` config.json ${mark(join(configDir, CONFIG_FILE))}`,
|
|
48
|
+
` config.schema.json ${mark(join(configDir, CONFIG_SCHEMA_FILE))}`,
|
|
49
|
+
` auth.json ${mark(join(configDir, AUTH_FILE))}`,
|
|
50
|
+
` hooks.json ${mark(join(configDir, HOOKS_FILE))}`,
|
|
51
|
+
`数据目录 ${mark(dataDir)}`,
|
|
52
|
+
` sessions/ ${mark(join(dataDir, "sessions"))}`,
|
|
53
|
+
` models-dev.json ${mark(modelsDevCachePath(dataDir))}`,
|
|
54
|
+
`项目级 ${mark(projectFile(io.cwd, CONFIG_FILE))}`,
|
|
55
|
+
];
|
|
56
|
+
io.stdout(`${lines.join("\n")}\n`);
|
|
57
|
+
return ExitCode.Ok;
|
|
58
|
+
}
|
|
59
|
+
/** `ama config edit`:不存在先 init;`$VISUAL` / `$EDITOR`(可带参数)打开,没有就打印路径。 */
|
|
60
|
+
function editConfig(io) {
|
|
61
|
+
const configDir = resolveConfigDir({ env: io.env });
|
|
62
|
+
const path = join(configDir, CONFIG_FILE);
|
|
63
|
+
if (!existsSync(path))
|
|
64
|
+
initConfigDir(configDir);
|
|
65
|
+
const editor = (io.env["VISUAL"] ?? io.env["EDITOR"] ?? "").trim();
|
|
66
|
+
if (editor === "") {
|
|
67
|
+
io.stdout(`${path}\n(没有设置 $VISUAL / $EDITOR,请用编辑器打开上面的文件)\n`);
|
|
68
|
+
return ExitCode.Ok;
|
|
69
|
+
}
|
|
70
|
+
const quoted = process.platform === "win32" ? `"${path}"` : `'${path.replace(/'/g, `'\\''`)}'`;
|
|
71
|
+
const result = spawnSync(`${editor} ${quoted}`, { stdio: "inherit", shell: true });
|
|
72
|
+
if (result.error !== undefined || result.status !== 0) {
|
|
73
|
+
io.stderr(`ama: 编辑器退出异常(${editor});文件在 ${path}\n`);
|
|
74
|
+
return ExitCode.RuntimeError;
|
|
75
|
+
}
|
|
76
|
+
return ExitCode.Ok;
|
|
77
|
+
}
|
|
23
78
|
function isObject(value) {
|
|
24
79
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
80
|
}
|
|
@@ -58,13 +113,16 @@ export async function describeModel(config, registry) {
|
|
|
58
113
|
return { ref: undefined, reason: "注册表未装配" };
|
|
59
114
|
const picked = await pickDefaultModel(registry);
|
|
60
115
|
if (picked === undefined)
|
|
61
|
-
return { ref: undefined, reason:
|
|
116
|
+
return { ref: undefined, reason: noModelGuidance(registry) };
|
|
62
117
|
const ref = `${picked.provider.id}/${picked.model.id}`;
|
|
63
118
|
if (picked.via === "local")
|
|
64
|
-
return { ref, reason: `零配置:本地 ${picked.provider.id}
|
|
119
|
+
return { ref, reason: `零配置:本地 ${picked.provider.id} 可达;${picked.rule}` };
|
|
65
120
|
const key = await registry.resolveApiKey(picked.provider.id);
|
|
66
121
|
const origin = key.origin !== undefined ? ` ${key.origin}` : "";
|
|
67
|
-
return {
|
|
122
|
+
return {
|
|
123
|
+
ref,
|
|
124
|
+
reason: `零配置:${picked.provider.id} 有 key(${key.source}${origin});${picked.rule}`,
|
|
125
|
+
};
|
|
68
126
|
}
|
|
69
127
|
/** config 里出现的供应商 + baseUrl 来自环境变量的内置供应商。 */
|
|
70
128
|
export function describeProviders(config, registry) {
|
|
@@ -82,7 +140,27 @@ export function describeProviders(config, registry) {
|
|
|
82
140
|
api: provider.api,
|
|
83
141
|
baseUrl: provider.baseUrl,
|
|
84
142
|
...(env !== undefined ? { baseUrlEnv: env } : {}),
|
|
85
|
-
|
|
143
|
+
...(provider.channels !== undefined
|
|
144
|
+
? {
|
|
145
|
+
channels: provider.channels.map((c) => ({
|
|
146
|
+
name: c.name,
|
|
147
|
+
api: c.api,
|
|
148
|
+
baseUrl: c.baseUrl,
|
|
149
|
+
})),
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
models: provider.models
|
|
153
|
+
.filter((m) => ids.has(m.id))
|
|
154
|
+
.map((m) => {
|
|
155
|
+
const sources = sourcesLine(metadataOf(registry, provider.id, m.id));
|
|
156
|
+
return {
|
|
157
|
+
id: m.id,
|
|
158
|
+
api: m.api,
|
|
159
|
+
...(m.channels !== undefined ? { channels: [...m.channels] } : {}),
|
|
160
|
+
flags: modelFlags(m),
|
|
161
|
+
...(sources !== undefined ? { sources } : {}),
|
|
162
|
+
};
|
|
163
|
+
}),
|
|
86
164
|
});
|
|
87
165
|
}
|
|
88
166
|
return out;
|
|
@@ -94,13 +172,18 @@ function providerLines(providers) {
|
|
|
94
172
|
for (const p of providers) {
|
|
95
173
|
const env = p.baseUrlEnv !== undefined ? `(baseUrl 来自环境变量 ${p.baseUrlEnv})` : "";
|
|
96
174
|
lines.push(` ${p.id} ${p.api} ${p.baseUrl}${env}`);
|
|
97
|
-
for (const
|
|
98
|
-
lines.push(`
|
|
175
|
+
for (const c of p.channels ?? [])
|
|
176
|
+
lines.push(` @${c.name} ${c.api} ${c.baseUrl}`);
|
|
177
|
+
for (const m of p.models) {
|
|
178
|
+
lines.push(` ${p.id}/${m.id} ${m.api} ${m.flags}`);
|
|
179
|
+
if (m.sources !== undefined)
|
|
180
|
+
lines.push(` ${m.sources}`);
|
|
181
|
+
}
|
|
99
182
|
}
|
|
100
183
|
return lines;
|
|
101
184
|
}
|
|
102
|
-
function layersOf(level, project, effective) {
|
|
103
|
-
const layers = [{ name: "default", label: "内置缺省", value:
|
|
185
|
+
function layersOf(level, project, effective, cli) {
|
|
186
|
+
const layers = [{ name: "default", label: "内置缺省", value: DISPLAY_DEFAULTS }];
|
|
104
187
|
const user = loadConfigFile("config", level.userConfigPath)?.value;
|
|
105
188
|
if (user !== undefined)
|
|
106
189
|
layers.push({ name: "user", label: level.userConfigPath, value: user });
|
|
@@ -123,6 +206,8 @@ function layersOf(level, project, effective) {
|
|
|
123
206
|
}
|
|
124
207
|
layers.push({ name: "project", label: ".ama/config.json", value: unflatten(accepted) });
|
|
125
208
|
}
|
|
209
|
+
if (cli !== undefined && Object.keys(cli).length > 0)
|
|
210
|
+
layers.push({ name: "cli", label: "命令行", value: cli });
|
|
126
211
|
return layers;
|
|
127
212
|
}
|
|
128
213
|
function unflatten(flat) {
|
|
@@ -149,51 +234,129 @@ export function sourcesOf(effective, layers) {
|
|
|
149
234
|
}
|
|
150
235
|
return sources;
|
|
151
236
|
}
|
|
237
|
+
/** codemode 生效模式与原因(跟随预设时写明预设与运行时 Node 是否隔离网络)。 */
|
|
238
|
+
export function describeCodemode(config, nodeVersion) {
|
|
239
|
+
const capability = detectSandboxCapability(nodeVersion);
|
|
240
|
+
const resolved = resolveCodemodeMode(config, capability.strict);
|
|
241
|
+
const sandbox = capability.strict
|
|
242
|
+
? `Node ${capability.nodeMajor} 网络已隔离`
|
|
243
|
+
: `Node ${capability.nodeMajor} < 25 网络未隔离`;
|
|
244
|
+
const reason = resolved.source === "config"
|
|
245
|
+
? `codemode.mode 显式设置(${sandbox})`
|
|
246
|
+
: `跟随预设 ${resolved.preset}(${sandbox})`;
|
|
247
|
+
const out = {
|
|
248
|
+
mode: resolved.mode,
|
|
249
|
+
source: resolved.source,
|
|
250
|
+
reason,
|
|
251
|
+
strict: capability.strict,
|
|
252
|
+
};
|
|
253
|
+
if (resolved.mode !== "off") {
|
|
254
|
+
const availability = codemodeAvailability(config.codemode?.requireStrict, capability);
|
|
255
|
+
if (!availability.available)
|
|
256
|
+
out.unavailable = availability.warning;
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/** 各层里把 tools.preset 写成旧名(别名)的:`user(写的是旧名 codemode)`。 */
|
|
261
|
+
function presetAliasNotes(layers) {
|
|
262
|
+
const notes = [];
|
|
263
|
+
for (const layer of layers) {
|
|
264
|
+
const preset = layer.value?.tools?.preset;
|
|
265
|
+
if (preset !== undefined && Object.hasOwn(TOOLS_PRESET_ALIASES, preset))
|
|
266
|
+
notes.push(`${layer.name}(${layer.label})的 tools.preset 写的是旧名 ${preset},规范名 ${canonicalPreset(preset)}`);
|
|
267
|
+
}
|
|
268
|
+
return notes;
|
|
269
|
+
}
|
|
270
|
+
function choice(name, value, all) {
|
|
271
|
+
if (value === undefined)
|
|
272
|
+
return undefined;
|
|
273
|
+
if (all.includes(value))
|
|
274
|
+
return value;
|
|
275
|
+
throw new UsageError(`--${name} 的取值应为 ${all.join(" | ")}(收到 ${value})`);
|
|
276
|
+
}
|
|
152
277
|
export async function runConfig(argv, io, deps) {
|
|
153
|
-
const { positionals, values, flags } = parseSubArgs(argv, ["profile", "auth-file"], ["json"]);
|
|
278
|
+
const { positionals, values, flags } = parseSubArgs(argv, ["profile", "auth-file", "tools-preset", "codemode"], ["json"]);
|
|
154
279
|
const action = positionals[0] ?? "show";
|
|
155
280
|
if (flags.has("help")) {
|
|
156
281
|
io.stdout(CONFIG_USAGE);
|
|
157
282
|
return ExitCode.Ok;
|
|
158
283
|
}
|
|
284
|
+
if (action === "path")
|
|
285
|
+
return showPaths(io);
|
|
286
|
+
if (action === "edit")
|
|
287
|
+
return editConfig(io);
|
|
159
288
|
if (action !== "show")
|
|
160
289
|
throw new UsageError(`未知的 config 子命令:${action}`);
|
|
290
|
+
const cli = {};
|
|
291
|
+
const presetFlag = choice("tools-preset", values.get("tools-preset"), TOOLS_PRESET_INPUTS);
|
|
292
|
+
if (presetFlag !== undefined)
|
|
293
|
+
cli.toolsPreset = presetFlag;
|
|
294
|
+
const codemodeFlag = choice("codemode", values.get("codemode"), CODEMODE_MODES);
|
|
295
|
+
if (codemodeFlag !== undefined)
|
|
296
|
+
cli.codemode = codemodeFlag;
|
|
161
297
|
const level = loadUserLevel(io, {
|
|
162
298
|
profile: values.get("profile"),
|
|
163
299
|
authFile: values.get("auth-file"),
|
|
164
300
|
});
|
|
165
301
|
const project = loadConfigFile("config", projectFile(io.cwd, CONFIG_FILE))?.value;
|
|
166
|
-
const merged = mergeProjectAndCli(level.merged, project,
|
|
302
|
+
const merged = mergeProjectAndCli(level.merged, project, cli);
|
|
167
303
|
const config = merged.config;
|
|
168
|
-
const layers = layersOf(level, project, config);
|
|
169
|
-
|
|
304
|
+
const layers = layersOf(level, project, config, cliOverridesToConfig(cli));
|
|
305
|
+
// 展示:生效配置补上 DEFAULT_CONFIG 不写的缺省(cache、codemode.inlineBudget 等),来源 default
|
|
306
|
+
const shown = mergeConfig(DISPLAY_DEFAULTS, config);
|
|
307
|
+
const sources = sourcesOf(shown, layers);
|
|
170
308
|
const registry = deps === undefined ? undefined : await buildRegistry(level, io, deps);
|
|
171
309
|
const model = await describeModel(config, registry);
|
|
172
310
|
const providers = describeProviders(config, registry);
|
|
311
|
+
const codemode = describeCodemode(config);
|
|
173
312
|
const builtin = new Set(builtinTools().map((tool) => tool.name));
|
|
174
|
-
|
|
313
|
+
if (codemode.mode !== "off" && codemode.unavailable === undefined)
|
|
314
|
+
builtin.add(CODEMODE_TOOL);
|
|
315
|
+
const preset = resolvePreset({
|
|
316
|
+
config,
|
|
317
|
+
available: (name) => builtin.has(name),
|
|
318
|
+
strict: codemode.strict,
|
|
319
|
+
});
|
|
320
|
+
const notes = presetAliasNotes(layers);
|
|
175
321
|
const warnings = [...level.warnings, ...merged.warnings];
|
|
322
|
+
const rows = [...flatten(shown)].map(([path, value]) => ({
|
|
323
|
+
path,
|
|
324
|
+
value,
|
|
325
|
+
source: sources.get(path) ?? "default",
|
|
326
|
+
}));
|
|
327
|
+
if (config.codemode?.mode === undefined)
|
|
328
|
+
rows.push({
|
|
329
|
+
path: "codemode.mode",
|
|
330
|
+
value: codemode.mode,
|
|
331
|
+
source: `default(${codemode.reason})`,
|
|
332
|
+
});
|
|
333
|
+
rows.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
176
334
|
if (flags.has("json")) {
|
|
177
|
-
const entries =
|
|
335
|
+
const entries = rows.map(({ path, value, source }) => ({
|
|
178
336
|
path,
|
|
179
337
|
value: path.endsWith(".apiKey") ? display(path, value) : value,
|
|
180
|
-
source
|
|
338
|
+
source,
|
|
181
339
|
}));
|
|
182
|
-
io.stdout(`${JSON.stringify({ model, providers, tools: preset.builtin,
|
|
340
|
+
io.stdout(`${JSON.stringify({ model, providers, tools: preset.builtin, preset: preset.preset, codemode, entries, layers: layers.map((l) => ({ name: l.name, file: l.label })), notes, warnings }, null, 2)}\n`);
|
|
183
341
|
return ExitCode.Ok;
|
|
184
342
|
}
|
|
185
|
-
const lines = ["生效配置(来源:default 内置 ← user ← profile ← project
|
|
343
|
+
const lines = ["生效配置(来源:default 内置 ← user ← profile ← project 只能收紧 ← cli)"];
|
|
186
344
|
for (const layer of layers.slice(1))
|
|
187
345
|
lines.push(` ${layer.name}:${layer.label}`);
|
|
188
346
|
lines.push("");
|
|
189
|
-
const
|
|
190
|
-
const width = Math.min(60, Math.max(...
|
|
191
|
-
for (const [text, source] of
|
|
192
|
-
lines.push(` ${text.padEnd(width)} ${source}`);
|
|
347
|
+
const texts = rows.map((row) => [`${row.path} = ${display(row.path, row.value)}`, row.source]);
|
|
348
|
+
const width = Math.min(60, Math.max(...texts.map(([text]) => (text ?? "").length)));
|
|
349
|
+
for (const [text, source] of texts)
|
|
350
|
+
lines.push(` ${(text ?? "").padEnd(width)} ${source}`);
|
|
193
351
|
lines.push(...providerLines(providers));
|
|
194
352
|
lines.push("");
|
|
195
353
|
lines.push(`模型:${model.ref ?? "(无)"} ${model.reason}`);
|
|
196
354
|
lines.push(`工具:${preset.builtin.join(", ")}(预设 ${preset.preset},codemode ${preset.codemode})`);
|
|
355
|
+
lines.push(`codemode:${codemode.mode} ${codemode.reason}`);
|
|
356
|
+
if (codemode.unavailable !== undefined)
|
|
357
|
+
lines.push(` ${codemode.unavailable}`);
|
|
358
|
+
for (const note of notes)
|
|
359
|
+
lines.push(`提示:${note}`);
|
|
197
360
|
for (const warning of [...warnings, ...preset.warnings])
|
|
198
361
|
lines.push(`警告:${warning}`);
|
|
199
362
|
io.stdout(`${lines.join("\n")}\n`);
|
|
@@ -7,6 +7,7 @@ import { loadConfigFile } from "../../config/load.js";
|
|
|
7
7
|
import { mergeBaseLayers } from "../../config/merge.js";
|
|
8
8
|
import { CONFIG_FILE, resolveConfigDir, resolveDataDir, userFile } from "../../config/paths.js";
|
|
9
9
|
import { loadProfile } from "../../config/profile.js";
|
|
10
|
+
import { hideFakeProvider } from "../fake-visibility.js";
|
|
10
11
|
export function loadUserLevel(io, options = {}) {
|
|
11
12
|
const configDir = resolveConfigDir({ env: io.env });
|
|
12
13
|
const dataDir = resolveDataDir({ env: io.env });
|
|
@@ -32,10 +33,13 @@ export function loadUserLevel(io, options = {}) {
|
|
|
32
33
|
return result;
|
|
33
34
|
}
|
|
34
35
|
export async function buildRegistry(level, io, deps) {
|
|
35
|
-
|
|
36
|
+
// 列表类子命令(doctor / models list / providers list / config show)缺省不列 fake
|
|
37
|
+
const registry = await deps.providers.create({
|
|
36
38
|
config: level.merged.config,
|
|
37
39
|
cwd: io.cwd,
|
|
38
40
|
authFile: level.authFile,
|
|
39
41
|
authEnv: level.profile?.authEnv ?? true,
|
|
42
|
+
dataDir: level.dataDir,
|
|
40
43
|
});
|
|
44
|
+
return hideFakeProvider(registry, io.env);
|
|
41
45
|
}
|
|
@@ -18,7 +18,8 @@ import { loadHookConfigs } from "../../hooks/config.js";
|
|
|
18
18
|
import { AMA_VERSION } from "../../version.js";
|
|
19
19
|
import { parseSubArgs } from "../args.js";
|
|
20
20
|
import { ExitCode } from "../exit-codes.js";
|
|
21
|
-
import {
|
|
21
|
+
import { describeProxy, inspectProxy } from "../proxy.js";
|
|
22
|
+
import { describeCodemode, describeModel } from "./config.js";
|
|
22
23
|
import { buildRegistry, loadUserLevel } from "./context.js";
|
|
23
24
|
export const DOCTOR_USAGE = `用法:ama doctor [--profile <文件>] [--auth-file <文件>] [--trust | --no-trust]
|
|
24
25
|
`;
|
|
@@ -184,6 +185,11 @@ function terminalSection(report, io) {
|
|
|
184
185
|
const tui = io.stdinIsTTY && io.stdoutIsTTY && env["TERM"] !== "dumb";
|
|
185
186
|
report.item(`缺省界面:${tui ? "终端界面" : "行式(--no-tui 等价)"}`);
|
|
186
187
|
}
|
|
188
|
+
function proxySection(report, io) {
|
|
189
|
+
report.section("代理");
|
|
190
|
+
for (const line of describeProxy(inspectProxy(io.env)))
|
|
191
|
+
report.item(line);
|
|
192
|
+
}
|
|
187
193
|
export async function runDoctor(argv, io, deps) {
|
|
188
194
|
const { values, flags } = parseSubArgs(argv, ["profile", "auth-file"], ["trust", "no-trust"]);
|
|
189
195
|
if (flags.has("help")) {
|
|
@@ -223,6 +229,10 @@ export async function runDoctor(argv, io, deps) {
|
|
|
223
229
|
for (const warning of merged.warnings)
|
|
224
230
|
report.item(` 收紧:${warning}`);
|
|
225
231
|
report.item(`有效权限模式:${merged.config.permission?.mode ?? "default"}`);
|
|
232
|
+
const codemode = describeCodemode(merged.config);
|
|
233
|
+
report.item(`codemode:${codemode.mode}(${codemode.reason})`);
|
|
234
|
+
if (codemode.unavailable !== undefined)
|
|
235
|
+
report.item(` ${codemode.unavailable}`);
|
|
226
236
|
}
|
|
227
237
|
catch {
|
|
228
238
|
// probeLine 已报告
|
|
@@ -240,6 +250,7 @@ export async function runDoctor(argv, io, deps) {
|
|
|
240
250
|
await keySection(report, io, level, deps);
|
|
241
251
|
hookSection(report, io, level, trusted);
|
|
242
252
|
report.item(`用户级 hooks.json:${userFile(level, HOOKS_FILE)}`);
|
|
253
|
+
proxySection(report, io);
|
|
243
254
|
terminalSection(report, io);
|
|
244
255
|
io.stdout(report.text());
|
|
245
256
|
return report.problems > 0 ? ExitCode.Config : ExitCode.Ok;
|
|
@@ -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,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama init [--force]`(docs/providers.md「配置目录」):建配置目录与缺省文件,逐个报告状态。
|
|
3
|
+
*/
|
|
4
|
+
import { INIT_NEXT_STEPS, 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
|
+
io.stdout(`\n${INIT_NEXT_STEPS.join("\n")}\n`);
|
|
22
|
+
return ExitCode.Ok;
|
|
23
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -103,7 +103,7 @@ async function run(ctx) {
|
|
|
103
103
|
return ExitCode.NoModel;
|
|
104
104
|
}
|
|
105
105
|
const { model, provider } = found;
|
|
106
|
-
const key = await registry.resolveApiKey(provider.id);
|
|
106
|
+
const key = await registry.resolveApiKey(provider.id, model.channel);
|
|
107
107
|
if (key.apiKey === undefined && provider.requiresApiKey) {
|
|
108
108
|
io.stderr(`ama: ${provider.id} 没有 API key(ama auth set ${provider.id})\n`);
|
|
109
109
|
return ExitCode.NoModel;
|
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
* 带供应商的鉴权头,打印 id 列表并标出已配置的条目。
|
|
6
6
|
*
|
|
7
7
|
* `--probe`:同一中转下不同模型支持的协议不同,对每个 id 依次试供应商协议 → completions →
|
|
8
|
-
* responses → messages
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* responses → messages(去重),各发一次最小请求(maxTokens 16,见到首个流事件即判可用并断开),
|
|
9
|
+
* 记第一个成功的协议;模型之间并发(`--concurrency`,缺省 6),单次超时 `--probe-timeout`(缺省
|
|
10
|
+
* 15 s)。每模型最多 3 次请求,`--limit`(缺省 30)限制探测的模型数,执行前打印预估;401 / 403 立即
|
|
11
|
+
* 停止,429 降并发并重试一次、仍 429 停止(见 probe-runner.ts)。
|
|
11
12
|
*
|
|
12
13
|
* `--write`:新条目合并进用户级 config.json 的 `providers.<id>.models`——已有同 id 不覆盖;只写
|
|
13
14
|
* `id` 与探到的 `api`(与供应商协议相同时省略);带 `--probe` 时只写探测成功的模型。不猜
|
|
14
15
|
* `contextWindow`(自动压缩随之关闭,输出 warning)。写前备份为 `config.json.bak`。
|
|
16
|
+
*
|
|
17
|
+
* models.dev:列表之后按需刷新缓存(24 小时内不重拉),每个模型标出上下文、输出、图片、工具调用与
|
|
18
|
+
* 匹配结果;`--write` 跳过 models.dev 标明不支持工具调用的模型。元数据不写进配置——运行时从缓存补。
|
|
15
19
|
*/
|
|
16
20
|
import type { Api, Model, ProviderData, ProviderRegistryApi } from "../../ai/types.js";
|
|
17
21
|
import type { ModelsAction } from "./models.js";
|
|
18
22
|
export declare const DISCOVER_TIMEOUT_MS = 15000;
|
|
19
|
-
export declare const PROBE_TIMEOUT_MS = 30000;
|
|
20
23
|
export declare const DEFAULT_PROBE_LIMIT = 30;
|
|
21
24
|
/** 中转常见的三种协议,按此顺序探测(供应商协议排最前)。 */
|
|
22
25
|
export declare const PROBE_APIS: readonly Api[];
|
|
@@ -28,13 +31,22 @@ export declare function discoverModels(provider: ProviderData, apiKey: string |
|
|
|
28
31
|
export declare function probeOrder(provider: ProviderData): Api[];
|
|
29
32
|
export interface ProbeOptions {
|
|
30
33
|
timeoutMs?: number;
|
|
34
|
+
/** 同时在途的模型数(每个模型内按协议顺序依次试);缺省 6。 */
|
|
35
|
+
concurrency?: number;
|
|
36
|
+
/** 测试用:429 重试前的退避。 */
|
|
37
|
+
retryDelayMs?: number;
|
|
31
38
|
/** 每次请求后回调。 */
|
|
32
39
|
onAttempt?: (id: string, api: Api, error: string | undefined) => void;
|
|
33
|
-
/**
|
|
40
|
+
/** 每个模型探完立即回调(按完成顺序,进度用)。 */
|
|
41
|
+
onSettled?: () => void;
|
|
42
|
+
/** 每个模型探完回调,按模型顺序(不按完成顺序)。 */
|
|
34
43
|
onResult?: (id: string, api: Api | undefined) => void;
|
|
35
44
|
/** 因鉴权失败或限流提前停止时回调。 */
|
|
36
45
|
onStop?: (reason: string) => void;
|
|
37
46
|
}
|
|
38
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* 返回已探测模型 → 第一个成功的协议(都失败为 undefined);超出 `limit` 或因提前停止没探完的不在表里。
|
|
49
|
+
* 模型之间并发(有界),同一模型内按协议顺序依次试,第一个成功即停。
|
|
50
|
+
*/
|
|
39
51
|
export declare function probeModelApis(registry: ProviderRegistryApi, provider: ProviderData, ids: string[], limit: number, options?: ProbeOptions): Promise<Map<string, Api | undefined>>;
|
|
40
52
|
export declare const DISCOVER_ACTION: ModelsAction;
|