@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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渠道(docs/providers.md「渠道」):一个供应商下的多种接口(协议 + 地址 + 可选 key / headers / compat)。
|
|
3
|
+
*
|
|
4
|
+
* - 没有 `channels` 的供应商按单渠道处理:供应商级 `api` + `baseUrl` 就是隐式的 `default` 渠道,
|
|
5
|
+
* 模型上不出现 `channel` / `channels` 字段,行为与引入渠道之前完全相同。
|
|
6
|
+
* - 有 `channels` 时:模型 `channels[0]` 是首选,缺省 `defaultChannel`;模型级 `api` / `baseUrl`
|
|
7
|
+
* 覆盖在所选渠道之上(等价于匿名渠道)。
|
|
8
|
+
* - 模型引用 `provider/model@channel`:`@` 之后是该供应商的渠道名才当渠道,否则整串仍是 model id。
|
|
9
|
+
* - 渠道自己的 key 以 `<provider>@<channel>` 为键进 key 解析(config 的 `channels.<c>.apiKey` 或
|
|
10
|
+
* auth.json 的同名条目),没有时用供应商的 key。
|
|
11
|
+
*/
|
|
12
|
+
import type { ProviderConfig } from "../../config/types.js";
|
|
13
|
+
import type { Api, ProviderChannel } from "../types.js";
|
|
14
|
+
/** 隐式渠道名(单渠道供应商)。 */
|
|
15
|
+
export declare const DEFAULT_CHANNEL = "default";
|
|
16
|
+
/** 渠道 key 在 key 解析里的键。 */
|
|
17
|
+
export declare function channelKeyId(providerId: string, channel: string): string;
|
|
18
|
+
/** config 的 `channels` → 物化渠道表(跳过名字非法或缺 api / baseUrl 的,返回警告)。 */
|
|
19
|
+
export declare function parseChannels(providerId: string, config: ProviderConfig): {
|
|
20
|
+
channels: ProviderChannel[];
|
|
21
|
+
defaultChannel: string | undefined;
|
|
22
|
+
warnings: string[];
|
|
23
|
+
};
|
|
24
|
+
/** 模型的渠道表:去掉不存在的;空 → [defaultChannel]。 */
|
|
25
|
+
export declare function modelChannels(wanted: readonly string[] | undefined, known: readonly ProviderChannel[], defaultChannel: string, onUnknown: (name: string) => void): string[];
|
|
26
|
+
/**
|
|
27
|
+
* 拆 `provider/model@channel` 末尾的渠道:只看最后一个 `/` 之后的部分;渠道名不合法时返回 undefined。
|
|
28
|
+
* 是否真的是渠道由调用方结合供应商的渠道表判断。
|
|
29
|
+
*/
|
|
30
|
+
export declare function splitChannelRef(ref: string): {
|
|
31
|
+
base: string;
|
|
32
|
+
channel: string;
|
|
33
|
+
} | undefined;
|
|
34
|
+
/** `provider/model` 或 `provider/model@channel`(channel 为空时不带后缀)。 */
|
|
35
|
+
export declare function formatModelRef(ref: {
|
|
36
|
+
provider: string;
|
|
37
|
+
id: string;
|
|
38
|
+
channel?: string;
|
|
39
|
+
}): string;
|
|
40
|
+
/** Model / ModelRef → ModelRef(带上渠道,没有渠道时不出现该键)。 */
|
|
41
|
+
export declare function modelRefOf(model: {
|
|
42
|
+
provider: string;
|
|
43
|
+
id: string;
|
|
44
|
+
channel?: string | undefined;
|
|
45
|
+
}): {
|
|
46
|
+
provider: string;
|
|
47
|
+
id: string;
|
|
48
|
+
channel?: string;
|
|
49
|
+
};
|
|
50
|
+
/** 协议的短名(表格用)。 */
|
|
51
|
+
export declare function apiShortName(api: Api): string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渠道(docs/providers.md「渠道」):一个供应商下的多种接口(协议 + 地址 + 可选 key / headers / compat)。
|
|
3
|
+
*
|
|
4
|
+
* - 没有 `channels` 的供应商按单渠道处理:供应商级 `api` + `baseUrl` 就是隐式的 `default` 渠道,
|
|
5
|
+
* 模型上不出现 `channel` / `channels` 字段,行为与引入渠道之前完全相同。
|
|
6
|
+
* - 有 `channels` 时:模型 `channels[0]` 是首选,缺省 `defaultChannel`;模型级 `api` / `baseUrl`
|
|
7
|
+
* 覆盖在所选渠道之上(等价于匿名渠道)。
|
|
8
|
+
* - 模型引用 `provider/model@channel`:`@` 之后是该供应商的渠道名才当渠道,否则整串仍是 model id。
|
|
9
|
+
* - 渠道自己的 key 以 `<provider>@<channel>` 为键进 key 解析(config 的 `channels.<c>.apiKey` 或
|
|
10
|
+
* auth.json 的同名条目),没有时用供应商的 key。
|
|
11
|
+
*/
|
|
12
|
+
import { CHANNEL_NAME_PATTERN } from "../../config/types.js";
|
|
13
|
+
/** 隐式渠道名(单渠道供应商)。 */
|
|
14
|
+
export const DEFAULT_CHANNEL = "default";
|
|
15
|
+
/** 渠道 key 在 key 解析里的键。 */
|
|
16
|
+
export function channelKeyId(providerId, channel) {
|
|
17
|
+
return `${providerId}@${channel}`;
|
|
18
|
+
}
|
|
19
|
+
/** config 的 `channels` → 物化渠道表(跳过名字非法或缺 api / baseUrl 的,返回警告)。 */
|
|
20
|
+
export function parseChannels(providerId, config) {
|
|
21
|
+
const warnings = [];
|
|
22
|
+
const channels = [];
|
|
23
|
+
for (const [name, raw] of Object.entries(config.channels ?? {})) {
|
|
24
|
+
const c = raw;
|
|
25
|
+
if (!CHANNEL_NAME_PATTERN.test(name) || !c || !c.api || !c.baseUrl) {
|
|
26
|
+
warnings.push(`provider "${providerId}" channel "${name}" is invalid; ignored`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const channel = { name, api: c.api, baseUrl: c.baseUrl };
|
|
30
|
+
if (c.authHeader !== undefined)
|
|
31
|
+
channel.authHeader = c.authHeader;
|
|
32
|
+
if (c.headers !== undefined)
|
|
33
|
+
channel.headers = { ...c.headers };
|
|
34
|
+
if (c.compat !== undefined)
|
|
35
|
+
channel.compat = { ...c.compat };
|
|
36
|
+
channels.push(channel);
|
|
37
|
+
}
|
|
38
|
+
let defaultChannel = config.defaultChannel;
|
|
39
|
+
if (defaultChannel !== undefined && !channels.some((c) => c.name === defaultChannel)) {
|
|
40
|
+
warnings.push(`provider "${providerId}" defaultChannel "${defaultChannel}" not found`);
|
|
41
|
+
defaultChannel = undefined;
|
|
42
|
+
}
|
|
43
|
+
return { channels, defaultChannel: defaultChannel ?? channels[0]?.name, warnings };
|
|
44
|
+
}
|
|
45
|
+
/** 模型的渠道表:去掉不存在的;空 → [defaultChannel]。 */
|
|
46
|
+
export function modelChannels(wanted, known, defaultChannel, onUnknown) {
|
|
47
|
+
const names = new Set(known.map((c) => c.name));
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const name of wanted ?? []) {
|
|
50
|
+
if (!names.has(name))
|
|
51
|
+
onUnknown(name);
|
|
52
|
+
else if (!out.includes(name))
|
|
53
|
+
out.push(name);
|
|
54
|
+
}
|
|
55
|
+
return out.length > 0 ? out : [defaultChannel];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 拆 `provider/model@channel` 末尾的渠道:只看最后一个 `/` 之后的部分;渠道名不合法时返回 undefined。
|
|
59
|
+
* 是否真的是渠道由调用方结合供应商的渠道表判断。
|
|
60
|
+
*/
|
|
61
|
+
export function splitChannelRef(ref) {
|
|
62
|
+
const at = ref.lastIndexOf("@");
|
|
63
|
+
if (at <= 0 || at < ref.lastIndexOf("/"))
|
|
64
|
+
return undefined;
|
|
65
|
+
const channel = ref.slice(at + 1);
|
|
66
|
+
if (!CHANNEL_NAME_PATTERN.test(channel))
|
|
67
|
+
return undefined;
|
|
68
|
+
return { base: ref.slice(0, at), channel };
|
|
69
|
+
}
|
|
70
|
+
/** `provider/model` 或 `provider/model@channel`(channel 为空时不带后缀)。 */
|
|
71
|
+
export function formatModelRef(ref) {
|
|
72
|
+
return `${ref.provider}/${ref.id}${ref.channel !== undefined ? `@${ref.channel}` : ""}`;
|
|
73
|
+
}
|
|
74
|
+
/** Model / ModelRef → ModelRef(带上渠道,没有渠道时不出现该键)。 */
|
|
75
|
+
export function modelRefOf(model) {
|
|
76
|
+
return {
|
|
77
|
+
provider: model.provider,
|
|
78
|
+
id: model.id,
|
|
79
|
+
...(model.channel !== undefined ? { channel: model.channel } : {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** 协议的短名(表格用)。 */
|
|
83
|
+
export function apiShortName(api) {
|
|
84
|
+
switch (api) {
|
|
85
|
+
case "openai-completions":
|
|
86
|
+
return "chat";
|
|
87
|
+
case "openai-responses":
|
|
88
|
+
return "responses";
|
|
89
|
+
case "anthropic-messages":
|
|
90
|
+
return "messages";
|
|
91
|
+
case "google-generative-ai":
|
|
92
|
+
return "gemini";
|
|
93
|
+
default:
|
|
94
|
+
return api;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用 models.dev 缓存给自定义模型补元数据(docs/providers.md「模型元数据:models.dev」)。
|
|
3
|
+
*
|
|
4
|
+
* 优先级:用户配置写了的字段 > models.dev > 自定义缺省(maxTokens 8192、input ["text"]、
|
|
5
|
+
* reasoning false、不猜 contextWindow)。内置目录的模型不经过这里(目录本身就是人工校对的值)。
|
|
6
|
+
* 只读传入的索引,不联网。
|
|
7
|
+
*/
|
|
8
|
+
import type { ModelConfig } from "../../config/types.js";
|
|
9
|
+
import type { Model } from "../types.js";
|
|
10
|
+
import { type EnrichableField, type ModelsDevIndex, type ModelsDevMatch } from "./models-dev.js";
|
|
11
|
+
export type FieldSource = "config" | "catalog" | "models.dev" | "default";
|
|
12
|
+
export interface ModelMetadata {
|
|
13
|
+
sources: Record<EnrichableField, FieldSource>;
|
|
14
|
+
/** models.dev 匹配结果;未查(没有缓存或 `modelsDev: false`)为 undefined。 */
|
|
15
|
+
match?: ModelsDevMatch | undefined;
|
|
16
|
+
/** 是否查过 models.dev(有缓存且没关闭)。 */
|
|
17
|
+
looked: boolean;
|
|
18
|
+
/** models.dev 的 tool_call。 */
|
|
19
|
+
toolCall?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export type ModelsDevSource = ModelsDevIndex | (() => ModelsDevIndex | undefined) | undefined;
|
|
22
|
+
/** 惰性取索引:只有真的要补字段时才读缓存(启动时没有自定义模型就不读约 2 MB 的缓存)。 */
|
|
23
|
+
export declare function lazyIndex(source: ModelsDevSource): () => ModelsDevIndex | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* 补全一个自定义模型条目(config 的 `models[]` 或合成的模型)。返回补过字段的条目(不含
|
|
26
|
+
* `modelsDev` / `channels` 这些配置专用键)与每个字段的来源。
|
|
27
|
+
*/
|
|
28
|
+
export declare function enrichEntry(entry: ModelConfig, index: () => ModelsDevIndex | undefined): {
|
|
29
|
+
entry: Omit<ModelConfig, "modelsDev" | "channels">;
|
|
30
|
+
metadata: ModelMetadata;
|
|
31
|
+
};
|
|
32
|
+
/** 内置目录模型的来源(全部 catalog;目录没写 contextWindow / cost 的为缺省)。 */
|
|
33
|
+
export declare function catalogMetadata(model: Model): ModelMetadata;
|
|
34
|
+
export declare function sourceText(source: FieldSource): string;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用 models.dev 缓存给自定义模型补元数据(docs/providers.md「模型元数据:models.dev」)。
|
|
3
|
+
*
|
|
4
|
+
* 优先级:用户配置写了的字段 > models.dev > 自定义缺省(maxTokens 8192、input ["text"]、
|
|
5
|
+
* reasoning false、不猜 contextWindow)。内置目录的模型不经过这里(目录本身就是人工校对的值)。
|
|
6
|
+
* 只读传入的索引,不联网。
|
|
7
|
+
*/
|
|
8
|
+
import { ENRICHABLE_FIELDS, modelsDevFields, } from "./models-dev.js";
|
|
9
|
+
/** 惰性取索引:只有真的要补字段时才读缓存(启动时没有自定义模型就不读约 2 MB 的缓存)。 */
|
|
10
|
+
export function lazyIndex(source) {
|
|
11
|
+
if (typeof source !== "function")
|
|
12
|
+
return () => source;
|
|
13
|
+
let loaded = false;
|
|
14
|
+
let index;
|
|
15
|
+
return () => {
|
|
16
|
+
if (!loaded) {
|
|
17
|
+
loaded = true;
|
|
18
|
+
try {
|
|
19
|
+
index = source();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
index = undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return index;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function needsLookup(entry) {
|
|
29
|
+
return ENRICHABLE_FIELDS.some((field) => entry[field] === undefined);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 补全一个自定义模型条目(config 的 `models[]` 或合成的模型)。返回补过字段的条目(不含
|
|
33
|
+
* `modelsDev` / `channels` 这些配置专用键)与每个字段的来源。
|
|
34
|
+
*/
|
|
35
|
+
export function enrichEntry(entry, index) {
|
|
36
|
+
const { modelsDev, channels: _channels, ...rest } = entry;
|
|
37
|
+
const sources = {};
|
|
38
|
+
for (const field of ENRICHABLE_FIELDS) {
|
|
39
|
+
sources[field] = rest[field] !== undefined ? "config" : "default";
|
|
40
|
+
}
|
|
41
|
+
const metadata = { sources, looked: false };
|
|
42
|
+
if (modelsDev === false || (!needsLookup(rest) && modelsDev === undefined)) {
|
|
43
|
+
return { entry: rest, metadata };
|
|
44
|
+
}
|
|
45
|
+
const idx = index();
|
|
46
|
+
if (idx === undefined)
|
|
47
|
+
return { entry: rest, metadata };
|
|
48
|
+
metadata.looked = true;
|
|
49
|
+
const match = idx.match(entry.id, typeof modelsDev === "string" ? modelsDev : undefined);
|
|
50
|
+
metadata.match = match;
|
|
51
|
+
if (match === undefined)
|
|
52
|
+
return { entry: rest, metadata };
|
|
53
|
+
const fields = modelsDevFields(match.model);
|
|
54
|
+
if (fields.toolCall !== undefined)
|
|
55
|
+
metadata.toolCall = fields.toolCall;
|
|
56
|
+
const out = { ...rest };
|
|
57
|
+
for (const field of ENRICHABLE_FIELDS) {
|
|
58
|
+
if (out[field] !== undefined)
|
|
59
|
+
continue;
|
|
60
|
+
const value = fields[field];
|
|
61
|
+
if (value === undefined)
|
|
62
|
+
continue;
|
|
63
|
+
out[field] = structuredClone(value);
|
|
64
|
+
sources[field] = "models.dev";
|
|
65
|
+
}
|
|
66
|
+
if (out.name === undefined && fields.name !== undefined)
|
|
67
|
+
out.name = fields.name;
|
|
68
|
+
return { entry: out, metadata };
|
|
69
|
+
}
|
|
70
|
+
/** 内置目录模型的来源(全部 catalog;目录没写 contextWindow / cost 的为缺省)。 */
|
|
71
|
+
export function catalogMetadata(model) {
|
|
72
|
+
const sources = {};
|
|
73
|
+
for (const field of ENRICHABLE_FIELDS) {
|
|
74
|
+
sources[field] = model[field] !== undefined ? "catalog" : "default";
|
|
75
|
+
}
|
|
76
|
+
return { sources, looked: false };
|
|
77
|
+
}
|
|
78
|
+
const SOURCE_TEXT = {
|
|
79
|
+
config: "config",
|
|
80
|
+
catalog: "目录",
|
|
81
|
+
"models.dev": "models.dev",
|
|
82
|
+
default: "缺省",
|
|
83
|
+
};
|
|
84
|
+
export function sourceText(source) {
|
|
85
|
+
return SOURCE_TEXT[source];
|
|
86
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* models.dev 缓存(docs/providers.md「模型元数据:models.dev」)。
|
|
3
|
+
*
|
|
4
|
+
* - 缓存文件 `<dataDir>/models-dev.json`:`{ version, url, fetchedAt, etag?, providers }`,providers 是
|
|
5
|
+
* `trimModelsDev()` 裁剪后的数据(约 2.3 MB,原始约 5 MB)。写入走同目录临时文件 + rename。
|
|
6
|
+
* - **启动不联网**:`loadModelsDevIndex()` 只读缓存(按路径 + mtime 记忆,同一进程只解析一次)。
|
|
7
|
+
* - 联网只在 `ama providers add|refresh`、`ama models discover`、`ama models refresh-catalog` 调
|
|
8
|
+
* `refreshModelsDev()` 时发生:缓存 24 小时内不重拉(`force` 例外),带 `If-None-Match`;304 只刷新时间;
|
|
9
|
+
* 失败时返回旧缓存与 warning。`AMA_MODELS_DEV_URL` 换数据源。
|
|
10
|
+
*/
|
|
11
|
+
import { ModelsDevIndex, type ModelsDevData } from "./models-dev.js";
|
|
12
|
+
export declare const MODELS_DEV_URL = "https://models.dev/api.json";
|
|
13
|
+
export declare const MODELS_DEV_URL_ENV = "AMA_MODELS_DEV_URL";
|
|
14
|
+
export declare const MODELS_DEV_FILE = "models-dev.json";
|
|
15
|
+
export declare const MODELS_DEV_TTL_MS: number;
|
|
16
|
+
export declare const MODELS_DEV_TIMEOUT_MS = 30000;
|
|
17
|
+
export interface ModelsDevCacheFile {
|
|
18
|
+
version: 1;
|
|
19
|
+
url: string;
|
|
20
|
+
/** ISO 8601。 */
|
|
21
|
+
fetchedAt: string;
|
|
22
|
+
etag?: string;
|
|
23
|
+
providers: ModelsDevData;
|
|
24
|
+
}
|
|
25
|
+
export declare function modelsDevCachePath(dataDir: string): string;
|
|
26
|
+
export declare function modelsDevUrl(env?: Readonly<Record<string, string | undefined>>): string;
|
|
27
|
+
/** 读缓存;不存在或损坏返回 undefined(损坏不报错:下次拉取会覆盖)。 */
|
|
28
|
+
export declare function readModelsDevCache(dataDir: string): ModelsDevCacheFile | undefined;
|
|
29
|
+
export declare function writeModelsDevCache(dataDir: string, file: ModelsDevCacheFile): void;
|
|
30
|
+
/** 只读缓存构造索引(不联网);没有缓存返回 undefined。 */
|
|
31
|
+
export declare function loadModelsDevIndex(dataDir: string): ModelsDevIndex | undefined;
|
|
32
|
+
export type RefreshStatus = "fresh" | "updated" | "not-modified" | "stale" | "unavailable";
|
|
33
|
+
export interface RefreshResult {
|
|
34
|
+
status: RefreshStatus;
|
|
35
|
+
index?: ModelsDevIndex;
|
|
36
|
+
fetchedAt?: string;
|
|
37
|
+
url: string;
|
|
38
|
+
warning?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface RefreshOptions {
|
|
41
|
+
dataDir: string;
|
|
42
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
43
|
+
/** 忽略 TTL(`ama models refresh-catalog`)。 */
|
|
44
|
+
force?: boolean;
|
|
45
|
+
ttlMs?: number;
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
now?: () => number;
|
|
48
|
+
fetch?: typeof fetch;
|
|
49
|
+
}
|
|
50
|
+
/** 按需拉取 models.dev 并更新缓存;失败时回落旧缓存(status `stale`)或无数据(`unavailable`)。 */
|
|
51
|
+
export declare function refreshModelsDev(options: RefreshOptions): Promise<RefreshResult>;
|
|
52
|
+
/** 一行状态说明(命令输出用)。 */
|
|
53
|
+
export declare function describeRefresh(result: RefreshResult): string;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* models.dev 缓存(docs/providers.md「模型元数据:models.dev」)。
|
|
3
|
+
*
|
|
4
|
+
* - 缓存文件 `<dataDir>/models-dev.json`:`{ version, url, fetchedAt, etag?, providers }`,providers 是
|
|
5
|
+
* `trimModelsDev()` 裁剪后的数据(约 2.3 MB,原始约 5 MB)。写入走同目录临时文件 + rename。
|
|
6
|
+
* - **启动不联网**:`loadModelsDevIndex()` 只读缓存(按路径 + mtime 记忆,同一进程只解析一次)。
|
|
7
|
+
* - 联网只在 `ama providers add|refresh`、`ama models discover`、`ama models refresh-catalog` 调
|
|
8
|
+
* `refreshModelsDev()` 时发生:缓存 24 小时内不重拉(`force` 例外),带 `If-None-Match`;304 只刷新时间;
|
|
9
|
+
* 失败时返回旧缓存与 warning。`AMA_MODELS_DEV_URL` 换数据源。
|
|
10
|
+
*/
|
|
11
|
+
import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { ModelsDevIndex, trimModelsDev } from "./models-dev.js";
|
|
14
|
+
export const MODELS_DEV_URL = "https://models.dev/api.json";
|
|
15
|
+
export const MODELS_DEV_URL_ENV = "AMA_MODELS_DEV_URL";
|
|
16
|
+
export const MODELS_DEV_FILE = "models-dev.json";
|
|
17
|
+
export const MODELS_DEV_TTL_MS = 24 * 60 * 60 * 1000;
|
|
18
|
+
export const MODELS_DEV_TIMEOUT_MS = 30_000;
|
|
19
|
+
export function modelsDevCachePath(dataDir) {
|
|
20
|
+
return join(dataDir, MODELS_DEV_FILE);
|
|
21
|
+
}
|
|
22
|
+
export function modelsDevUrl(env = process.env) {
|
|
23
|
+
const custom = env[MODELS_DEV_URL_ENV]?.trim();
|
|
24
|
+
return custom ? custom : MODELS_DEV_URL;
|
|
25
|
+
}
|
|
26
|
+
/** 读缓存;不存在或损坏返回 undefined(损坏不报错:下次拉取会覆盖)。 */
|
|
27
|
+
export function readModelsDevCache(dataDir) {
|
|
28
|
+
try {
|
|
29
|
+
const value = JSON.parse(readFileSync(modelsDevCachePath(dataDir), "utf8"));
|
|
30
|
+
if (typeof value !== "object" || value === null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const file = value;
|
|
33
|
+
if (file.version !== 1 || typeof file.fetchedAt !== "string")
|
|
34
|
+
return undefined;
|
|
35
|
+
if (typeof file.providers !== "object" || file.providers === null)
|
|
36
|
+
return undefined;
|
|
37
|
+
return file;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function writeModelsDevCache(dataDir, file) {
|
|
44
|
+
const path = modelsDevCachePath(dataDir);
|
|
45
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
46
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
47
|
+
writeFileSync(tmp, JSON.stringify(file));
|
|
48
|
+
renameSync(tmp, path);
|
|
49
|
+
memo = undefined;
|
|
50
|
+
}
|
|
51
|
+
let memo;
|
|
52
|
+
/** 只读缓存构造索引(不联网);没有缓存返回 undefined。 */
|
|
53
|
+
export function loadModelsDevIndex(dataDir) {
|
|
54
|
+
const path = modelsDevCachePath(dataDir);
|
|
55
|
+
let key;
|
|
56
|
+
try {
|
|
57
|
+
const stat = statSync(path);
|
|
58
|
+
key = `${path}\0${stat.mtimeMs}\0${stat.size}`;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
if (memo?.key === key)
|
|
64
|
+
return memo.index;
|
|
65
|
+
const file = readModelsDevCache(dataDir);
|
|
66
|
+
const index = file !== undefined ? new ModelsDevIndex(file.providers) : undefined;
|
|
67
|
+
memo = { key, index };
|
|
68
|
+
return index;
|
|
69
|
+
}
|
|
70
|
+
/** 按需拉取 models.dev 并更新缓存;失败时回落旧缓存(status `stale`)或无数据(`unavailable`)。 */
|
|
71
|
+
export async function refreshModelsDev(options) {
|
|
72
|
+
const url = modelsDevUrl(options.env);
|
|
73
|
+
const now = options.now ?? Date.now;
|
|
74
|
+
const cached = readModelsDevCache(options.dataDir);
|
|
75
|
+
const cachedIndex = () => cached !== undefined ? new ModelsDevIndex(cached.providers) : undefined;
|
|
76
|
+
const age = cached !== undefined ? now() - Date.parse(cached.fetchedAt) : Infinity;
|
|
77
|
+
if (cached !== undefined &&
|
|
78
|
+
cached.url === url &&
|
|
79
|
+
!options.force &&
|
|
80
|
+
age >= 0 &&
|
|
81
|
+
age < (options.ttlMs ?? MODELS_DEV_TTL_MS)) {
|
|
82
|
+
return {
|
|
83
|
+
status: "fresh",
|
|
84
|
+
index: cachedIndex(),
|
|
85
|
+
fetchedAt: cached.fetchedAt,
|
|
86
|
+
url,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const doFetch = options.fetch ?? fetch;
|
|
90
|
+
try {
|
|
91
|
+
const headers = { accept: "application/json" };
|
|
92
|
+
if (cached?.etag !== undefined && cached.url === url)
|
|
93
|
+
headers["if-none-match"] = cached.etag;
|
|
94
|
+
const response = await doFetch(url, {
|
|
95
|
+
headers,
|
|
96
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? MODELS_DEV_TIMEOUT_MS),
|
|
97
|
+
});
|
|
98
|
+
const fetchedAt = new Date(now()).toISOString();
|
|
99
|
+
if (response.status === 304 && cached !== undefined) {
|
|
100
|
+
writeModelsDevCache(options.dataDir, { ...cached, fetchedAt });
|
|
101
|
+
return { status: "not-modified", index: cachedIndex(), fetchedAt, url };
|
|
102
|
+
}
|
|
103
|
+
if (!response.ok)
|
|
104
|
+
throw new Error(`HTTP ${response.status}`);
|
|
105
|
+
const providers = trimModelsDev(await response.json());
|
|
106
|
+
const etag = response.headers.get("etag") ?? undefined;
|
|
107
|
+
writeModelsDevCache(options.dataDir, {
|
|
108
|
+
version: 1,
|
|
109
|
+
url,
|
|
110
|
+
fetchedAt,
|
|
111
|
+
...(etag !== undefined ? { etag } : {}),
|
|
112
|
+
providers,
|
|
113
|
+
});
|
|
114
|
+
return { status: "updated", index: new ModelsDevIndex(providers), fetchedAt, url };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
118
|
+
if (cached !== undefined) {
|
|
119
|
+
return {
|
|
120
|
+
status: "stale",
|
|
121
|
+
index: cachedIndex(),
|
|
122
|
+
fetchedAt: cached.fetchedAt,
|
|
123
|
+
url,
|
|
124
|
+
warning: `models.dev 拉取失败(${reason}),沿用 ${cached.fetchedAt} 的缓存`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
status: "unavailable",
|
|
129
|
+
url,
|
|
130
|
+
warning: `models.dev 拉取失败(${reason}),没有缓存可用`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** 一行状态说明(命令输出用)。 */
|
|
135
|
+
export function describeRefresh(result) {
|
|
136
|
+
const size = result.index
|
|
137
|
+
? `${result.index.providerCount} 家供应商、${result.index.modelCount} 个模型`
|
|
138
|
+
: "无数据";
|
|
139
|
+
const text = {
|
|
140
|
+
fresh: "缓存未过期",
|
|
141
|
+
updated: "已更新",
|
|
142
|
+
"not-modified": "未变化(304)",
|
|
143
|
+
stale: "拉取失败,用旧缓存",
|
|
144
|
+
unavailable: "不可用",
|
|
145
|
+
};
|
|
146
|
+
return `models.dev:${text[result.status]}(${size}${result.fetchedAt ? `,${result.fetchedAt}` : ""})`;
|
|
147
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* models.dev 模型元数据(docs/providers.md「模型元数据:models.dev」):裁剪、索引、匹配、映射。
|
|
3
|
+
*
|
|
4
|
+
* 数据源 `https://models.dev/api.json` 是「供应商 → 模型」两层表,同一个模型 id 会在几十家转售商下
|
|
5
|
+
* 重复出现且取值不一。`ModelsDevIndex.match()` 按文档里的顺序挑一条:显式 `provider/model` →
|
|
6
|
+
* `vendor/model` 形状的 id → 同名条目的 `canonical_model_id` 指向的原厂条目 → 原厂供应商 →
|
|
7
|
+
* 多数一致 → 归一化 id(去前缀 / `:后缀` / `-latest` / 日期)后重试 → 未匹配。
|
|
8
|
+
*
|
|
9
|
+
* 本模块只做纯计算(不读文件、不联网);缓存与拉取在 models-dev-cache.ts。
|
|
10
|
+
*/
|
|
11
|
+
import type { ModelCost } from "../types.js";
|
|
12
|
+
/** 用到的模型字段(name、推理、工具调用、输入模态、上下限、价格、canonical);其余写缓存时丢掉。 */
|
|
13
|
+
export interface ModelsDevModel {
|
|
14
|
+
id: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
reasoning?: boolean;
|
|
17
|
+
tool_call?: boolean;
|
|
18
|
+
modalities?: {
|
|
19
|
+
input?: string[];
|
|
20
|
+
};
|
|
21
|
+
limit?: {
|
|
22
|
+
context?: number;
|
|
23
|
+
output?: number;
|
|
24
|
+
};
|
|
25
|
+
cost?: {
|
|
26
|
+
input?: number;
|
|
27
|
+
output?: number;
|
|
28
|
+
cache_read?: number;
|
|
29
|
+
cache_write?: number;
|
|
30
|
+
};
|
|
31
|
+
canonical_model_id?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ModelsDevProvider {
|
|
34
|
+
id: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
models: Record<string, ModelsDevModel>;
|
|
37
|
+
}
|
|
38
|
+
export type ModelsDevData = Record<string, ModelsDevProvider>;
|
|
39
|
+
/**
|
|
40
|
+
* 原厂供应商(models.dev 的供应商 id,顺序即优先级)。通义在 `alibaba`、Llama 在 `llama`、
|
|
41
|
+
* 智谱国际站在 `zai`;models.dev 没有 `qwen` / `meta` 这样的供应商 id。
|
|
42
|
+
*/
|
|
43
|
+
export declare const FIRST_PARTY_PROVIDERS: readonly string[];
|
|
44
|
+
/** maxTokens 的上限:models.dev 给原厂上限(常与上下文相同),每次请求都会作为 max_tokens 发出。 */
|
|
45
|
+
export declare const MODELS_DEV_MAX_OUTPUT = 65536;
|
|
46
|
+
export type MatchKind = "explicit" | "prefix" | "canonical" | "vendor" | "consensus" | "single";
|
|
47
|
+
export interface ModelsDevMatch {
|
|
48
|
+
/** 选中条目 `provider/model`。 */
|
|
49
|
+
ref: string;
|
|
50
|
+
model: ModelsDevModel;
|
|
51
|
+
kind: MatchKind;
|
|
52
|
+
/** 经归一化才匹配到时的 id(如去掉日期后缀)。 */
|
|
53
|
+
normalized?: string;
|
|
54
|
+
/** 同名条目数。 */
|
|
55
|
+
candidates: number;
|
|
56
|
+
/** 多条取值不一致时的说明。 */
|
|
57
|
+
warning?: string;
|
|
58
|
+
}
|
|
59
|
+
/** 映射到 ama Model 的字段(缺的不给)。 */
|
|
60
|
+
export interface ModelsDevFields {
|
|
61
|
+
name?: string;
|
|
62
|
+
contextWindow?: number;
|
|
63
|
+
maxTokens?: number;
|
|
64
|
+
input?: ("text" | "image")[];
|
|
65
|
+
reasoning?: boolean;
|
|
66
|
+
cost?: ModelCost;
|
|
67
|
+
/** models.dev 的 tool_call;Model 上没有对应字段,只用于展示与写入过滤。 */
|
|
68
|
+
toolCall?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/** 校验并裁剪 api.json:只留用到的字段;形状不对的供应商 / 模型跳过。整体不是对象抛错。 */
|
|
71
|
+
export declare function trimModelsDev(raw: unknown): ModelsDevData;
|
|
72
|
+
/**
|
|
73
|
+
* 依次尝试的 id(小写、去重):原样 → 去 `vendor/` 前缀 → 去 `:free` 一类后缀 → 去 `-latest` →
|
|
74
|
+
* 去日期后缀(`-0902`、`-20250514`、`-2025-05-14`)。
|
|
75
|
+
*/
|
|
76
|
+
export declare function idCandidates(id: string): string[];
|
|
77
|
+
export declare class ModelsDevIndex {
|
|
78
|
+
private readonly byId;
|
|
79
|
+
private readonly byRef;
|
|
80
|
+
readonly data: ModelsDevData;
|
|
81
|
+
constructor(data: ModelsDevData);
|
|
82
|
+
get providerCount(): number;
|
|
83
|
+
get modelCount(): number;
|
|
84
|
+
/** `provider/model`(不分大小写)。 */
|
|
85
|
+
get(ref: string): ModelsDevModel | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* 匹配一个模型 id。`explicit` 是配置里的 `modelsDev: "provider/model"`:找得到就用,找不到返回
|
|
88
|
+
* undefined(调用方 warning),不再回落到按 id 猜。
|
|
89
|
+
*/
|
|
90
|
+
match(id: string, explicit?: string): ModelsDevMatch | undefined;
|
|
91
|
+
private choose;
|
|
92
|
+
}
|
|
93
|
+
/** models.dev 条目 → ama Model 字段(规则见 docs/providers.md)。 */
|
|
94
|
+
export declare function modelsDevFields(model: ModelsDevModel): ModelsDevFields;
|
|
95
|
+
/** 可由 models.dev 补的 Model 字段(展示来源用)。 */
|
|
96
|
+
export declare const ENRICHABLE_FIELDS: readonly ["contextWindow", "maxTokens", "input", "reasoning", "cost"];
|
|
97
|
+
export type EnrichableField = (typeof ENRICHABLE_FIELDS)[number];
|
|
98
|
+
/** 匹配方式的中文说明(表格与 `models list`)。 */
|
|
99
|
+
export declare function matchLabel(match: ModelsDevMatch | undefined): string;
|