@armadra/agent 0.7.3 → 0.7.5
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 +48 -0
- package/CHANGELOG.zh-CN.md +48 -0
- package/dist/agent/retry.d.ts +14 -5
- package/dist/agent/retry.js +30 -8
- package/dist/agent/session-cache-key.d.ts +8 -0
- package/dist/agent/session-cache-key.js +46 -0
- package/dist/agent/session-cache.d.ts +2 -3
- package/dist/agent/session-cache.js +19 -37
- package/dist/agent/session-classifier.d.ts +3 -2
- package/dist/agent/session-classifier.js +36 -10
- package/dist/agent/session-compaction.d.ts +24 -5
- package/dist/agent/session-compaction.js +54 -20
- package/dist/agent/session-core.d.ts +2 -0
- package/dist/agent/session-run.d.ts +12 -0
- package/dist/agent/session-run.js +29 -10
- package/dist/agent/session-subagent.d.ts +8 -1
- package/dist/agent/session-subagent.js +37 -14
- package/dist/agent/session-sync.d.ts +8 -2
- package/dist/agent/session-sync.js +7 -10
- package/dist/agent/session-tools.js +3 -2
- package/dist/agent/subagent-fork.d.ts +67 -0
- package/dist/agent/subagent-fork.js +87 -0
- package/dist/agent/subagent-registry.d.ts +2 -2
- package/dist/agent/subagent-registry.js +2 -2
- package/dist/agent/tool-availability.d.ts +8 -0
- package/dist/agent/tool-availability.js +8 -0
- package/dist/agent/tool-runner.js +13 -4
- package/dist/agent/worktree.d.ts +8 -0
- package/dist/agent/worktree.js +51 -4
- package/dist/agents/parse.js +6 -1
- package/dist/agents/task-record.js +3 -0
- package/dist/agents/types.d.ts +2 -0
- package/dist/ai/apis/anthropic-messages.js +10 -5
- package/dist/ai/apis/anthropic-request.d.ts +2 -1
- package/dist/ai/apis/anthropic-request.js +15 -4
- package/dist/ai/apis/cache-params.js +2 -1
- package/dist/ai/apis/google-generative-ai.js +4 -2
- package/dist/ai/apis/google-request.js +2 -1
- package/dist/ai/apis/max-tokens.d.ts +42 -0
- package/dist/ai/apis/max-tokens.js +121 -0
- package/dist/ai/apis/openai-completions.js +10 -5
- package/dist/ai/apis/openai-request.js +4 -2
- package/dist/ai/apis/openai-responses-request.js +3 -2
- package/dist/ai/apis/openai-responses.js +9 -5
- package/dist/ai/apis/shared.d.ts +3 -1
- package/dist/ai/apis/shared.js +21 -3
- package/dist/ai/cache/fingerprint.d.ts +4 -1
- package/dist/ai/cache/fingerprint.js +18 -1
- package/dist/ai/cache/miss.d.ts +2 -1
- package/dist/ai/cache/miss.js +9 -3
- package/dist/ai/cache/reporting.js +5 -1
- package/dist/ai/cache/types.d.ts +10 -2
- package/dist/ai/cache/warmer.d.ts +6 -1
- package/dist/ai/cache/warmer.js +7 -0
- package/dist/ai/context.d.ts +12 -4
- package/dist/ai/context.js +43 -24
- package/dist/ai/fake/fake-provider.d.ts +8 -1
- package/dist/ai/fake/fake-provider.js +19 -7
- package/dist/ai/fake/fake-script.d.ts +2 -0
- package/dist/ai/http.d.ts +17 -9
- package/dist/ai/http.js +33 -13
- package/dist/ai/image-intern.d.ts +29 -0
- package/dist/ai/image-intern.js +58 -0
- package/dist/ai/json-body.d.ts +63 -0
- package/dist/ai/json-body.js +286 -0
- package/dist/ai/overflow.js +5 -0
- package/dist/ai/providers/catalog-data.js +13 -13
- package/dist/ai/providers/catalog.d.ts +33 -0
- package/dist/ai/providers/catalog.js +105 -6
- package/dist/ai/providers/enrich.d.ts +13 -3
- package/dist/ai/providers/enrich.js +87 -31
- package/dist/ai/sse.d.ts +3 -2
- package/dist/ai/sse.js +3 -2
- package/dist/ai/types.d.ts +9 -2
- package/dist/bundle/ama.cjs +3637 -1973
- package/dist/cli/bootstrap.js +13 -5
- package/dist/cli/compose-agents.js +3 -0
- package/dist/cli/compose-extensions.js +2 -0
- package/dist/cli/compose-request.d.ts +20 -0
- package/dist/cli/compose-request.js +37 -0
- package/dist/cli/compose-session.js +2 -2
- package/dist/cli/deps.d.ts +1 -1
- package/dist/cli/subcommands/model-meta.d.ts +2 -1
- package/dist/cli/subcommands/model-meta.js +3 -2
- package/dist/codemode/host-side.d.ts +11 -4
- package/dist/codemode/host-side.js +25 -6
- package/dist/codemode/tool.d.ts +2 -0
- package/dist/codemode/tool.js +4 -0
- package/dist/config/json-schema.js +9 -2
- package/dist/config/key-docs.js +13 -4
- package/dist/config/schema-w5.js +9 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/config/schema.js +19 -3
- package/dist/config/settings-registry.js +6 -0
- package/dist/config/types-w5.d.ts +2 -0
- package/dist/config/types.d.ts +19 -1
- package/dist/config/types.js +4 -0
- package/dist/i18n/catalog.d.ts +13 -2
- package/dist/i18n/messages/cli.d.ts +2 -0
- package/dist/i18n/messages/cli.js +2 -0
- package/dist/i18n/messages/config-keys.d.ts +10 -0
- package/dist/i18n/messages/config-keys.js +12 -2
- package/dist/i18n/messages/config.d.ts +14 -0
- package/dist/i18n/messages/config.js +4 -0
- package/dist/i18n/messages/errors.d.ts +3 -2
- package/dist/i18n/messages/errors.js +15 -2
- package/dist/i18n/messages/report.d.ts +2 -0
- package/dist/i18n/messages/report.js +2 -0
- package/dist/i18n/messages/settings.d.ts +4 -0
- package/dist/i18n/messages/settings.js +6 -2
- package/dist/i18n/messages/subcommands.d.ts +2 -2
- package/dist/i18n/messages/subcommands.js +4 -2
- package/dist/modes/acp/acp-server.js +30 -18
- package/dist/modes/acp/acp-sessions.d.ts +22 -0
- package/dist/modes/acp/acp-sessions.js +68 -0
- package/dist/modes/context-report.js +3 -2
- package/dist/modes/print/json-event.d.ts +12 -1
- package/dist/modes/print/json-event.js +48 -1
- package/dist/modes/rpc/rpc-mode.d.ts +1 -0
- package/dist/modes/rpc/rpc-mode.js +9 -2
- package/dist/modes/session-report.d.ts +1 -1
- package/dist/modes/session-report.js +12 -6
- package/dist/rpc.d.ts +5 -2
- package/dist/session/line-reader.d.ts +28 -0
- package/dist/session/line-reader.js +82 -0
- package/dist/session/list.d.ts +14 -0
- package/dist/session/list.js +150 -0
- package/dist/session/manager.d.ts +23 -3
- package/dist/session/manager.js +91 -62
- package/dist/session/migrate.d.ts +2 -1
- package/dist/session/migrate.js +2 -1
- package/dist/session/offload.d.ts +51 -0
- package/dist/session/offload.js +195 -0
- package/dist/session/projection.d.ts +16 -3
- package/dist/session/projection.js +96 -29
- package/dist/session/scan.d.ts +3 -3
- package/dist/session/scan.js +9 -18
- package/dist/session/store.d.ts +15 -4
- package/dist/session/store.js +54 -38
- package/dist/session/types.d.ts +7 -2
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.js +5 -4
- package/dist/tools/glob.d.ts +2 -2
- package/dist/tools/glob.js +2 -2
- package/dist/tools/grep.js +4 -6
- package/dist/tools/image-file.js +2 -1
- package/dist/tools/read-lines.d.ts +71 -0
- package/dist/tools/read-lines.js +224 -0
- package/dist/tools/read.d.ts +6 -2
- package/dist/tools/read.js +47 -27
- package/dist/tools/task.d.ts +9 -0
- package/dist/tools/task.js +21 -8
- package/dist/tools/truncate.d.ts +7 -0
- package/dist/tools/truncate.js +11 -0
- package/dist/tools/types.d.ts +13 -0
- package/dist/trace/build-index.js +13 -1
- package/dist/tui/ansi.d.ts +2 -0
- package/dist/tui/ansi.js +7 -3
- package/dist/tui/components/editor-buffer.js +2 -2
- package/dist/tui/components/editor.js +5 -6
- package/dist/tui/keys.js +2 -2
- package/dist/tui/stdin-buffer.js +3 -3
- package/docs/acp.md +8 -1
- package/docs/agents.md +42 -6
- package/docs/codemode.md +4 -2
- package/docs/en/acp.md +3 -2
- package/docs/en/host-api.md +1 -1
- package/docs/en/permissions.md +2 -2
- package/docs/en/providers.md +54 -20
- package/docs/en/rpc.md +23 -7
- package/docs/en/sessions.md +4 -2
- package/docs/en/tui.md +2 -2
- package/docs/permissions.md +4 -1
- package/docs/providers.md +85 -22
- package/docs/rpc.md +22 -6
- package/docs/session-format.md +13 -2
- package/docs/sessions.md +3 -1
- package/docs/tui.md +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求体序列化(docs/memory-plan.md D3、§2.3)。
|
|
3
|
+
*
|
|
4
|
+
* 带图请求体里 base64 占绝大部分字节;`JSON.stringify(body)` 会先拼出整份中间字符串,再由 fetch
|
|
5
|
+
* 编码成 UTF-8。这里先廉价扫一遍:没有 ≥ {@link LARGE_STRING_BYTES} 的字符串就照旧走原生;有就只沿
|
|
6
|
+
* 「普通对象 / 数组」结构拼片段——小子树仍交给原生 `JSON.stringify`,大字符串经检查无需转义时原样
|
|
7
|
+
* 作为一个片段。片段两种用法:`serializeJsonBody` 一次分配结果 Buffer 依次写入;`jsonFetchBody`
|
|
8
|
+
* (`postJson` 用)逐片段编码成流、声明总字节数,不在内存里留整份请求体。
|
|
9
|
+
*
|
|
10
|
+
* 结果与 `Buffer.from(JSON.stringify(body), "utf8")` 逐字节相同:自写部分只有结构(`{`、`,`、
|
|
11
|
+
* 键、`[`)与已验证无需转义的大字符串(需要转义的大字符串整个交给原生);`toJSON`、`undefined` /
|
|
12
|
+
* 函数 / symbol 的跳过与 `null`、数字格式、转义全部由原生处理(带 `toJSON` 的值经单键容器序列化,
|
|
13
|
+
* 保证 `toJSON(key)` 收到与原生相同的键)。
|
|
14
|
+
*
|
|
15
|
+
* 图片由转换器包成 {@link LargeString}(`prefix + text`):片段路径直接写转录里的原字符串,不经模板串
|
|
16
|
+
* 拼接后的扁平化;无需转义的结论与字节数按 ImageBlock 缓存,同一张图每进程只扫一次。流式发送时大片段
|
|
17
|
+
* 按 {@link STREAM_CHUNK_CHARS} 切块编码。
|
|
18
|
+
*/
|
|
19
|
+
/** 达到这个长度(UTF-16 码元)的字符串才走片段路径。 */
|
|
20
|
+
export const LARGE_STRING_BYTES = 64 * 1024;
|
|
21
|
+
/** 检查是否需要转义时每次交给原生的长度:结果是新生代里的小字符串,随即可回收。 */
|
|
22
|
+
const CHECK_CHUNK = 16 * 1024;
|
|
23
|
+
/**
|
|
24
|
+
* 大字符串无需转义、可原样写入:逐段让原生 `JSON.stringify` 判断(长度恰好多出两个引号即没有
|
|
25
|
+
* 任何转义)。引号、反斜杠、控制字符、孤立代理项都会让长度变化;成对代理项若恰被切在段界上
|
|
26
|
+
* 也会被判为需要转义——只会多走原生,不会错。实测比同义的正则快一倍多(原生的转义扫描是向量化的)。
|
|
27
|
+
* 每个大字符串每次序列化只查这一次。
|
|
28
|
+
*/
|
|
29
|
+
function isPlain(value) {
|
|
30
|
+
plainScans.count++;
|
|
31
|
+
for (let i = 0; i < value.length; i += CHECK_CHUNK) {
|
|
32
|
+
const chunk = value.slice(i, i + CHECK_CHUNK);
|
|
33
|
+
if (JSON.stringify(chunk).length !== chunk.length + 2)
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
/** 短字符串无需转义(`LargeString.prefix` 用)。 */
|
|
39
|
+
const isShortPlain = (value) => JSON.stringify(value).length === value.length + 2;
|
|
40
|
+
/** `isPlain` 的调用次数(测试用:同一块图片第二次序列化不应再扫)。 */
|
|
41
|
+
export const plainScans = { count: 0 };
|
|
42
|
+
/**
|
|
43
|
+
* 请求体里的大字符串叶子 `prefix + text`(data URL 或裸 base64),用来代替模板串拼接:拼接得到的
|
|
44
|
+
* cons string 在每次序列化时都会被扁平化成一份新的整图字符串。片段路径直接写 `prefix` 与 `text`
|
|
45
|
+
* (`text` 是转录里的原字符串,不拷贝);`text` 无需转义的结论按 `key`(转录里身份稳定的 ImageBlock)
|
|
46
|
+
* 缓存,同一块每进程只扫一次。约定:同一 `key` 的 `text` 不变。其它遍历者看到的是一个带 `toJSON`
|
|
47
|
+
* 的对象,原生 `JSON.stringify` 得到相同字符串。由 {@link largeString} 构造。
|
|
48
|
+
*/
|
|
49
|
+
export class LargeString {
|
|
50
|
+
prefix;
|
|
51
|
+
key;
|
|
52
|
+
text;
|
|
53
|
+
constructor(prefix, key, text) {
|
|
54
|
+
this.prefix = prefix;
|
|
55
|
+
this.key = key;
|
|
56
|
+
this.text = text;
|
|
57
|
+
}
|
|
58
|
+
toJSON() {
|
|
59
|
+
return this.prefix + this.text;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* `prefix + text` 作为请求体的值:`text` 够大且 `prefix` 自身无需转义时给 {@link LargeString},
|
|
64
|
+
* 否则就是拼好的字符串(小图与以前完全相同)。
|
|
65
|
+
*/
|
|
66
|
+
export function largeString(prefix, key, text) {
|
|
67
|
+
if (text.length < LARGE_STRING_BYTES || !isShortPlain(prefix))
|
|
68
|
+
return prefix + text;
|
|
69
|
+
return new LargeString(prefix, key, text);
|
|
70
|
+
}
|
|
71
|
+
/** 已确认无需转义的 `LargeString.text`:键是 `key`,值是当时的 UTF-8 字节数(同时省掉再数一遍)。 */
|
|
72
|
+
const plainBytes = new WeakMap();
|
|
73
|
+
/** `LargeString.text` 可原样写入时返回其 UTF-8 字节数,否则 undefined。 */
|
|
74
|
+
function plainLargeBytes(value) {
|
|
75
|
+
if (!isShortPlain(value.prefix))
|
|
76
|
+
return undefined;
|
|
77
|
+
const known = plainBytes.get(value.key);
|
|
78
|
+
if (known !== undefined && known.length === value.text.length)
|
|
79
|
+
return known.bytes;
|
|
80
|
+
if (!isPlain(value.text))
|
|
81
|
+
return undefined;
|
|
82
|
+
const bytes = Buffer.byteLength(value.text, "utf8");
|
|
83
|
+
plainBytes.set(value.key, { length: value.text.length, bytes });
|
|
84
|
+
return bytes;
|
|
85
|
+
}
|
|
86
|
+
/** 结构遍历的深度上限:更深(或有环)时整棵子树交给原生,环由原生照常抛 TypeError。 */
|
|
87
|
+
const MAX_DEPTH = 64;
|
|
88
|
+
const isLargeString = (value) => typeof value === "string" && value.length >= LARGE_STRING_BYTES;
|
|
89
|
+
/** 只遍历原型为 Object.prototype / null 的普通对象和数组,且自身与原型链上都没有 `toJSON`。 */
|
|
90
|
+
function isContainer(value) {
|
|
91
|
+
if (typeof value !== "object" || value === null)
|
|
92
|
+
return false;
|
|
93
|
+
if (typeof value.toJSON === "function")
|
|
94
|
+
return false;
|
|
95
|
+
if (Array.isArray(value))
|
|
96
|
+
return true;
|
|
97
|
+
const proto = Object.getPrototypeOf(value);
|
|
98
|
+
return proto === Object.prototype || proto === null;
|
|
99
|
+
}
|
|
100
|
+
/** 收集含大字符串的容器(片段路径只深入这些容器);返回 `value` 本身是否含大字符串。 */
|
|
101
|
+
function collectLarge(value, marked, depth) {
|
|
102
|
+
if (isLargeString(value))
|
|
103
|
+
return true;
|
|
104
|
+
if (value instanceof LargeString)
|
|
105
|
+
return value.text.length >= LARGE_STRING_BYTES;
|
|
106
|
+
if (depth >= MAX_DEPTH || !isContainer(value))
|
|
107
|
+
return false;
|
|
108
|
+
let found = false;
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
for (let i = 0; i < value.length; i++) {
|
|
111
|
+
if (collectLarge(value[i], marked, depth + 1))
|
|
112
|
+
found = true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
for (const key of Object.keys(value)) {
|
|
117
|
+
if (collectLarge(value[key], marked, depth + 1))
|
|
118
|
+
found = true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (found)
|
|
122
|
+
marked.add(value);
|
|
123
|
+
return found;
|
|
124
|
+
}
|
|
125
|
+
/** 原生序列化 `holder[key] = value` 这一项的值;被原生跳过(undefined / 函数 / symbol)时 undefined。 */
|
|
126
|
+
function nativeValue(key, value) {
|
|
127
|
+
if (typeof value !== "object" && typeof value !== "function" && typeof value !== "bigint") {
|
|
128
|
+
return JSON.stringify(value);
|
|
129
|
+
}
|
|
130
|
+
// 对象、函数与 bigint 可能有 toJSON(key):放进单键容器,让原生以同一个键调用
|
|
131
|
+
const wrapped = JSON.stringify({ [key]: value });
|
|
132
|
+
if (wrapped === "{}")
|
|
133
|
+
return undefined;
|
|
134
|
+
return wrapped.slice(JSON.stringify(key).length + 2, -1);
|
|
135
|
+
}
|
|
136
|
+
/** 片段:已拼好的 JSON 文本与大字符串交替;连续的小文本先在字符串里累积。 */
|
|
137
|
+
class Pieces {
|
|
138
|
+
parts = [];
|
|
139
|
+
/** 已推入 `parts` 的 UTF-8 字节数。 */
|
|
140
|
+
bytes = 0;
|
|
141
|
+
pending = "";
|
|
142
|
+
text(chunk) {
|
|
143
|
+
this.pending += chunk;
|
|
144
|
+
}
|
|
145
|
+
/** 大字符串原样写入(引号与 `head` 进前一个小片段);`bytes` 已知时不再数一遍。 */
|
|
146
|
+
large(value, head = "", bytes = Buffer.byteLength(value, "utf8")) {
|
|
147
|
+
const before = `${this.pending}"${head}`;
|
|
148
|
+
this.parts.push(before, value);
|
|
149
|
+
this.bytes += Buffer.byteLength(before, "utf8") + bytes;
|
|
150
|
+
this.pending = '"';
|
|
151
|
+
}
|
|
152
|
+
finish() {
|
|
153
|
+
if (this.pending.length > 0) {
|
|
154
|
+
this.parts.push(this.pending);
|
|
155
|
+
this.bytes += Buffer.byteLength(this.pending, "utf8");
|
|
156
|
+
}
|
|
157
|
+
this.pending = "";
|
|
158
|
+
return this.parts;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** 写一项的值;返回是否写了(对象里被原生跳过的属性不写)。数组里跳过的值写 `null`。 */
|
|
162
|
+
function writeEntry(key, value, marked, out, prefix, depth) {
|
|
163
|
+
if (isLargeString(value)) {
|
|
164
|
+
if (isPlain(value)) {
|
|
165
|
+
out.text(prefix);
|
|
166
|
+
out.large(value);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
out.text(prefix + JSON.stringify(value)); // 需要转义:只有这一个字符串交给原生
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (value instanceof LargeString && value.text.length >= LARGE_STRING_BYTES) {
|
|
174
|
+
const bytes = plainLargeBytes(value);
|
|
175
|
+
out.text(prefix);
|
|
176
|
+
if (bytes !== undefined)
|
|
177
|
+
out.large(value.text, value.prefix, bytes);
|
|
178
|
+
else
|
|
179
|
+
out.text(JSON.stringify(value.toJSON())); // 需要转义:交给原生
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
// 深度与 collectLarge 一致;有环时越过上限交给原生,由它抛 TypeError
|
|
183
|
+
if (depth < MAX_DEPTH && isContainer(value) && marked.has(value)) {
|
|
184
|
+
out.text(prefix);
|
|
185
|
+
writeContainer(value, marked, out, depth);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
const text = nativeValue(key, value);
|
|
189
|
+
if (text === undefined)
|
|
190
|
+
return false;
|
|
191
|
+
out.text(prefix + text);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
function writeContainer(value, marked, out, depth) {
|
|
195
|
+
if (Array.isArray(value)) {
|
|
196
|
+
out.text("[");
|
|
197
|
+
for (let i = 0; i < value.length; i++) {
|
|
198
|
+
const prefix = i > 0 ? "," : "";
|
|
199
|
+
if (!writeEntry(String(i), value[i], marked, out, prefix, depth + 1))
|
|
200
|
+
out.text(`${prefix}null`);
|
|
201
|
+
}
|
|
202
|
+
out.text("]");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
out.text("{");
|
|
206
|
+
let first = true;
|
|
207
|
+
for (const key of Object.keys(value)) {
|
|
208
|
+
const prefix = `${first ? "" : ","}${JSON.stringify(key)}:`;
|
|
209
|
+
if (writeEntry(key, value[key], marked, out, prefix, depth + 1))
|
|
210
|
+
first = false;
|
|
211
|
+
}
|
|
212
|
+
out.text("}");
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 含大字符串时按顺序给出各片段(拼起来就是 `JSON.stringify(body)`)与 UTF-8 总字节数;
|
|
216
|
+
* 不含时返回 undefined(调用方照旧走原生)。
|
|
217
|
+
*/
|
|
218
|
+
function jsonParts(body) {
|
|
219
|
+
const marked = new Set();
|
|
220
|
+
if (!collectLarge(body, marked, 0))
|
|
221
|
+
return undefined;
|
|
222
|
+
const out = new Pieces();
|
|
223
|
+
writeEntry("", body, marked, out, "", 0); // 顶层:键为 "",与原生调用 toJSON 的键相同
|
|
224
|
+
const parts = out.finish();
|
|
225
|
+
return { parts, length: out.bytes };
|
|
226
|
+
}
|
|
227
|
+
/** 与 `Buffer.from(JSON.stringify(body), "utf8")` 逐字节相同;大字符串不经中间字符串。 */
|
|
228
|
+
export function serializeJsonBody(body) {
|
|
229
|
+
const split = jsonParts(body);
|
|
230
|
+
if (split === undefined)
|
|
231
|
+
return Buffer.from(JSON.stringify(body), "utf8");
|
|
232
|
+
// 一次分配、依次写入:不再有整份中间字符串,也不需要 Buffer.concat 的第二份拷贝
|
|
233
|
+
const buf = Buffer.allocUnsafe(split.length);
|
|
234
|
+
let offset = 0;
|
|
235
|
+
for (const part of split.parts)
|
|
236
|
+
offset += buf.write(part, offset, "utf8");
|
|
237
|
+
if (offset !== split.length) {
|
|
238
|
+
throw new Error(`serializeJsonBody: wrote ${offset} of ${split.length} bytes`);
|
|
239
|
+
}
|
|
240
|
+
return buf;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* 流式请求体每块最多编码的码元数:大片段(一整张图)按游标切片(V8 切片串不拷贝)逐块编码,
|
|
244
|
+
* 发送期间只多出一块的 UTF-8 字节,而不是一整张图。
|
|
245
|
+
*/
|
|
246
|
+
export const STREAM_CHUNK_CHARS = 256 * 1024;
|
|
247
|
+
/**
|
|
248
|
+
* 给 fetch 的请求体。不含大字符串时就是 `JSON.stringify(body)`(与以前完全相同);含大字符串时是
|
|
249
|
+
* 逐片段编码的流,并给出总字节数。不交给 fetch 一个 Buffer:Node 的 fetch 会把 BufferSource
|
|
250
|
+
* 请求体再复制两份(实测 mock 300 步带图峰值反而从约 1.0 GB 升到 1.85 GB),流则按片段边读边发,
|
|
251
|
+
* 同一时刻只多出一块(≤ {@link STREAM_CHUNK_CHARS} 码元)的 UTF-8 字节。字节序列与 `serializeJsonBody` 相同。
|
|
252
|
+
*/
|
|
253
|
+
export function jsonFetchBody(body) {
|
|
254
|
+
const split = jsonParts(body);
|
|
255
|
+
if (split === undefined)
|
|
256
|
+
return { body: JSON.stringify(body) };
|
|
257
|
+
const { parts } = split;
|
|
258
|
+
let next = 0;
|
|
259
|
+
let offset = 0; // 当前片段已发出的码元数
|
|
260
|
+
const stream = new ReadableStream({
|
|
261
|
+
pull(controller) {
|
|
262
|
+
const part = parts[next];
|
|
263
|
+
if (part === undefined) {
|
|
264
|
+
controller.close();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
let end = Math.min(part.length, offset + STREAM_CHUNK_CHARS);
|
|
268
|
+
// 不把成对代理项切开(片段里只有成对的:孤立代理项已被原生转义)
|
|
269
|
+
const last = part.charCodeAt(end - 1);
|
|
270
|
+
if (end < part.length && last >= 0xd800 && last <= 0xdbff)
|
|
271
|
+
end--;
|
|
272
|
+
const piece = offset === 0 && end === part.length ? part : part.slice(offset, end);
|
|
273
|
+
if (end === part.length) {
|
|
274
|
+
parts[next++] = ""; // 发完即放手,片段(拼出来的小文本)可尽早回收
|
|
275
|
+
offset = 0;
|
|
276
|
+
}
|
|
277
|
+
else
|
|
278
|
+
offset = end;
|
|
279
|
+
controller.enqueue(Buffer.from(piece, "utf8"));
|
|
280
|
+
},
|
|
281
|
+
cancel() {
|
|
282
|
+
parts.length = 0;
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
return { body: stream, contentLength: split.length };
|
|
286
|
+
}
|
package/dist/ai/overflow.js
CHANGED
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
export const OVERFLOW_PATTERNS = [
|
|
14
14
|
[/prompt is too long/i, "Anthropic: prompt is too long: N tokens > M maximum"],
|
|
15
15
|
[/request_too_large/i, "Anthropic: 413 request_too_large"],
|
|
16
|
+
// [ME-C] 只有 max-tokens.ts 判定「可用输出 < 1024、不能收紧重发」时这条错误才会冒到会话层
|
|
17
|
+
[
|
|
18
|
+
/input length and `?max_tokens`? exceed context limit/i,
|
|
19
|
+
"Anthropic: input length and max_tokens exceed context limit: X + Y > Z",
|
|
20
|
+
],
|
|
16
21
|
[/exceeds the context window/i, "OpenAI: Your input exceeds the context window of this model"],
|
|
17
22
|
[/maximum context length is \d+ tokens/i, "OpenAI / OpenRouter / DeepSeek"],
|
|
18
23
|
[
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* UPDATE_CATALOG=1 pnpm vitest run src/ai/providers/catalog.test.ts
|
|
4
4
|
*/
|
|
5
5
|
export const CATALOG_SOURCES = {
|
|
6
|
-
anthropic: '{"version":1,"provider":"anthropic","modelsDev":"anthropic","models":[{"id":"claude-fable-5-1","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-fable-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-8","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-7","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":2048},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-6","promptCache":{"short":300,"long":3600,"minTokens":4096},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-6","promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-5","promptCache":{"short":300,"long":3600,"minTokens":1024}},{"id":"claude-haiku-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}},{"id":"claude-opus-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}}]}',
|
|
6
|
+
anthropic: '{"version":1,"provider":"anthropic","modelsDev":"anthropic","small":"claude-haiku-4-5","models":[{"id":"claude-fable-5-1","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-fable-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-8","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-7","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":2048},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-6","promptCache":{"short":300,"long":3600,"minTokens":4096},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-6","promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-5","promptCache":{"short":300,"long":3600,"minTokens":1024}},{"id":"claude-haiku-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}},{"id":"claude-opus-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}}]}',
|
|
7
7
|
chatgpt: '{"version":1,"provider":"chatgpt","modelsDev":false,"models":[]}',
|
|
8
|
-
dashscope: '{"version":1,"provider":"dashscope","modelsDev":"alibaba-cn","models":[{"id":"qwen3.8-max","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.7-max","maxTokens":131072,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.7-plus","maxTokens":65536,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-plus","compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-flash","compat":{"supportsReasoningEffort":false}}]}',
|
|
9
|
-
deepseek: '{"version":1,"provider":"deepseek","modelsDev":"deepseek","models":[{"id":"deepseek-v4-pro","maxTokens":384000,"cost":{"input":1.32,"output":3.96,"cacheRead":0.044},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价","promptCache":{"short":3600,"minTokens":2048}},{"id":"deepseek-flash","maxTokens":384000,"cost":{"input":0.3,"output":1.2,"cacheRead":0.006},"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价","promptCache":{"short":3600,"minTokens":2048}}]}',
|
|
10
|
-
google: '{"version":1,"provider":"google","modelsDev":"google","models":[{"id":"gemini-3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.7-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash-lite","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.1-pro-preview","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3-flash-preview","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-2.5-pro","thinkingLevelMap":{"off":null,"minimal":128,"low":2048,"medium":8192,"high":32768}},{"id":"gemini-2.5-flash","thinkingLevelMap":{"minimal":128,"low":2048,"medium":8192,"high":24576}},{"id":"gemini-2.5-flash-lite","thinkingLevelMap":{"minimal":512,"low":2048,"medium":8192,"high":24576}}]}',
|
|
11
|
-
groq: '{"version":1,"provider":"groq","modelsDev":"groq","models":[{"id":"openai/gpt-oss-120b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"openai/gpt-oss-20b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"openai/gpt-oss-safeguard-20b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"qwen/qwen3.8-27b","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"qwen/qwen3.6-27b","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"default","xhigh":null}},{"id":"llama-3.3-70b-versatile"},{"id":"llama-3.1-8b-instant"}]}',
|
|
8
|
+
dashscope: '{"version":1,"provider":"dashscope","modelsDev":"alibaba-cn","small":"qwen3.8-flash","models":[{"id":"qwen3.8-max","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.7-max","maxTokens":131072,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.7-plus","maxTokens":65536,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-plus","compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-flash","compat":{"supportsReasoningEffort":false}}]}',
|
|
9
|
+
deepseek: '{"version":1,"provider":"deepseek","modelsDev":"deepseek","small":"deepseek-flash","models":[{"id":"deepseek-v4-pro","maxTokens":384000,"cost":{"input":1.32,"output":3.96,"cacheRead":0.044},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价","promptCache":{"short":3600,"minTokens":2048},"compat":{"requiresReasoningContentOnAssistantMessages":true}},{"id":"deepseek-flash","aliases":["deepseek-v4-flash"],"maxTokens":384000,"cost":{"input":0.3,"output":1.2,"cacheRead":0.006},"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价","promptCache":{"short":3600,"minTokens":2048},"compat":{"requiresReasoningContentOnAssistantMessages":true}}]}',
|
|
10
|
+
google: '{"version":1,"provider":"google","modelsDev":"google","small":"gemini-3.5-flash-lite","models":[{"id":"gemini-3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.7-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash-lite","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.1-pro-preview","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3-flash-preview","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-2.5-pro","thinkingLevelMap":{"off":null,"minimal":128,"low":2048,"medium":8192,"high":32768}},{"id":"gemini-2.5-flash","thinkingLevelMap":{"minimal":128,"low":2048,"medium":8192,"high":24576}},{"id":"gemini-2.5-flash-lite","thinkingLevelMap":{"minimal":512,"low":2048,"medium":8192,"high":24576}}]}',
|
|
11
|
+
groq: '{"version":1,"provider":"groq","modelsDev":"groq","small":"openai/gpt-oss-20b","models":[{"id":"openai/gpt-oss-120b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"openai/gpt-oss-20b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"openai/gpt-oss-safeguard-20b","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"qwen/qwen3.8-27b","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"qwen/qwen3.6-27b","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"default","xhigh":null}},{"id":"llama-3.3-70b-versatile"},{"id":"llama-3.1-8b-instant"}]}',
|
|
12
12
|
lmstudio: '{"version":1,"provider":"lmstudio","modelsDev":false,"models":[]}',
|
|
13
|
-
minimax: '{"version":1,"provider":"minimax","modelsDev":"minimax-cn","models":[{"id":"MiniMax-M3"},{"id":"MiniMax-M2.7","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}},{"id":"MiniMax-M2.7-highspeed","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}},{"id":"MiniMax-M2.5","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}}]}',
|
|
14
|
-
mistral: '{"version":1,"provider":"mistral","modelsDev":"mistral","models":[{"id":"mistral-large-latest"},{"id":"mistral-medium-latest","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null}},{"id":"mistral-small-latest","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null}},{"id":"magistral-medium-latest","cost":{"cacheRead":0.2}},{"id":"codestral-latest"},{"id":"devstral-latest","name":"Devstral 2","contextWindow":262144,"maxTokens":262144,"reasoning":false,"input":["text"],"cost":{"input":0.4,"output":2,"cacheRead":0.04,"cacheWrite":0}},{"id":"devstral-medium-latest","name":"Devstral 2 (latest)","contextWindow":262144,"maxTokens":262144,"reasoning":false,"input":["text"],"cost":{"input":0.4,"output":2,"cacheRead":0.04,"cacheWrite":0}},{"id":"ministral-8b-latest","cost":{"cacheRead":0.01}},{"id":"pixtral-large-latest","cost":{"cacheRead":0.2}}]}',
|
|
15
|
-
moonshot: '{"version":1,"provider":"moonshot","modelsDev":"moonshotai-cn","models":[{"id":"kimi-k3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":true}},{"id":"kimi-k2.7-code","thinkingLevelMap":{"off":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}},{"id":"kimi-k2.7-code-highspeed","thinkingLevelMap":{"off":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}},{"id":"kimi-k2.6","promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}}]}',
|
|
13
|
+
minimax: '{"version":1,"provider":"minimax","modelsDev":"minimax-cn","small":"MiniMax-M2.5","models":[{"id":"MiniMax-M3"},{"id":"MiniMax-M2.7","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}},{"id":"MiniMax-M2.7-highspeed","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}},{"id":"MiniMax-M2.5","channels":["messages","chat","messages-intl","chat-intl"],"thinkingLevelMap":{"off":null},"promptCache":{"short":300}}]}',
|
|
14
|
+
mistral: '{"version":1,"provider":"mistral","modelsDev":"mistral","small":"mistral-small-latest","models":[{"id":"mistral-large-latest"},{"id":"mistral-medium-latest","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null}},{"id":"mistral-small-latest","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null}},{"id":"magistral-medium-latest","cost":{"cacheRead":0.2}},{"id":"codestral-latest"},{"id":"devstral-latest","name":"Devstral 2","contextWindow":262144,"maxTokens":262144,"reasoning":false,"input":["text"],"cost":{"input":0.4,"output":2,"cacheRead":0.04,"cacheWrite":0}},{"id":"devstral-medium-latest","name":"Devstral 2 (latest)","contextWindow":262144,"maxTokens":262144,"reasoning":false,"input":["text"],"cost":{"input":0.4,"output":2,"cacheRead":0.04,"cacheWrite":0}},{"id":"ministral-8b-latest","cost":{"cacheRead":0.01}},{"id":"pixtral-large-latest","cost":{"cacheRead":0.2}}]}',
|
|
15
|
+
moonshot: '{"version":1,"provider":"moonshot","modelsDev":"moonshotai-cn","small":"kimi-k2.6","models":[{"id":"kimi-k3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":true}},{"id":"kimi-k2.7-code","thinkingLevelMap":{"off":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}},{"id":"kimi-k2.7-code-highspeed","thinkingLevelMap":{"off":null},"promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}},{"id":"kimi-k2.6","promptCache":{"short":300},"compat":{"supportsReasoningEffort":false}}]}',
|
|
16
16
|
ollama: '{"version":1,"provider":"ollama","modelsDev":false,"models":[]}',
|
|
17
|
-
openai: '{"version":1,"provider":"openai","modelsDev":"openai","models":[{"id":"gpt-6.1-sol","contextWindow":272000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-sol","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-luna","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-astra","contextWindow":272000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.5","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4-mini","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4-nano","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5-mini","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4.1","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4o","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4o-mini","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"o4-mini","name":"o4-mini","contextWindow":200000,"maxTokens":100000,"reasoning":true,"input":["text","image"],"cost":{"input":1.1,"output":4.4,"cacheRead":0.275,"cacheWrite":0},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"o3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}}]}',
|
|
18
|
-
openrouter: '{"version":1,"provider":"openrouter","modelsDev":"openrouter","models":[{"id":"anthropic/claude-opus-5.5","name":"Anthropic: Claude Opus 5.5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"anthropic/claude-sonnet-5.5","name":"Anthropic: Claude Sonnet 5.5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"anthropic/claude-haiku-4.5","name":"Anthropic: Claude Haiku 4.5"},{"id":"openai/gpt-6-sol","name":"OpenAI: GPT-6 Sol","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"openai/gpt-5.5","name":"OpenAI: GPT-5.5","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"openai/gpt-5.4-mini","name":"OpenAI: GPT-5.4 Mini","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"google/gemini-3.8-flash","name":"Google: Gemini 3.8 Flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"google/gemini-3.1-pro-preview","name":"Google: Gemini 3.1 Pro Preview","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"deepseek/deepseek-v4-pro","name":"DeepSeek: DeepSeek V4 Pro 0423","contextWindow":1024000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh"},"compat":{"requiresReasoningContentOnAssistantMessages":true}},{"id":"moonshotai/kimi-k3","name":"MoonshotAI: Kimi K3","maxTokens":131072,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null}},{"id":"qwen/qwen3.7-max","name":"Qwen: Qwen3.7 Max"},{"id":"z-ai/glm-5.3","name":"Z.ai: GLM 5.3","maxTokens":943718,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null}},{"id":"x-ai/grok-4.7","name":"SpaceXAI: Grok 4.7","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}}]}',
|
|
19
|
-
stepfun: '{"version":1,"provider":"stepfun","modelsDev":"stepfun","models":[{"id":"step-5-preview"},{"id":"step-3.7-flash","channels":["messages","chat","messages-intl","chat-intl"]},{"id":"step-3.5-flash","channels":["messages","chat","messages-intl","chat-intl"]}]}',
|
|
17
|
+
openai: '{"version":1,"provider":"openai","modelsDev":"openai","small":"gpt-6-luna","models":[{"id":"gpt-6.1-sol","contextWindow":272000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-sol","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-luna","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-6-astra","contextWindow":272000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.5","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4","contextWindow":272000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4-mini","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5.4-nano","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-5-mini","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4.1","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4o","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"gpt-4o-mini","promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"o4-mini","name":"o4-mini","contextWindow":200000,"maxTokens":100000,"reasoning":true,"input":["text","image"],"cost":{"input":1.1,"output":4.4,"cacheRead":0.275,"cacheWrite":0},"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}},{"id":"o3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null},"promptCache":{"short":300,"long":86400,"minTokens":1024}}]}',
|
|
18
|
+
openrouter: '{"version":1,"provider":"openrouter","modelsDev":"openrouter","small":"openai/gpt-5.4-mini","models":[{"id":"anthropic/claude-opus-5.5","name":"Anthropic: Claude Opus 5.5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"anthropic/claude-sonnet-5.5","name":"Anthropic: Claude Sonnet 5.5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"anthropic/claude-haiku-4.5","name":"Anthropic: Claude Haiku 4.5"},{"id":"openai/gpt-6-sol","name":"OpenAI: GPT-6 Sol","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"openai/gpt-5.5","name":"OpenAI: GPT-5.5","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"openai/gpt-5.4-mini","name":"OpenAI: GPT-5.4 Mini","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"compat":{"supportsMidConvoSystemMessages":true}},{"id":"google/gemini-3.8-flash","name":"Google: Gemini 3.8 Flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"google/gemini-3.1-pro-preview","name":"Google: Gemini 3.1 Pro Preview","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"deepseek/deepseek-v4-pro","name":"DeepSeek: DeepSeek V4 Pro 0423","contextWindow":1024000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh"},"compat":{"requiresReasoningContentOnAssistantMessages":true}},{"id":"moonshotai/kimi-k3","name":"MoonshotAI: Kimi K3","maxTokens":131072,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null}},{"id":"qwen/qwen3.7-max","name":"Qwen: Qwen3.7 Max"},{"id":"z-ai/glm-5.3","name":"Z.ai: GLM 5.3","maxTokens":943718,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null}},{"id":"x-ai/grok-4.7","name":"SpaceXAI: Grok 4.7","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}}]}',
|
|
19
|
+
stepfun: '{"version":1,"provider":"stepfun","modelsDev":"stepfun","small":"step-3.5-flash","models":[{"id":"step-5-preview"},{"id":"step-3.7-flash","channels":["messages","chat","messages-intl","chat-intl"]},{"id":"step-3.5-flash","channels":["messages","chat","messages-intl","chat-intl"]}]}',
|
|
20
20
|
tencent: '{"version":1,"provider":"tencent","modelsDev":"tencent-tokenhub","models":[{"id":"hy4-preview","promptCache":{"short":300,"long":3600}},{"id":"hy3","cost":{"input":0.139,"output":0.556,"cacheRead":0.0348,"cacheWrite":0},"_reason":"快照价为 0;官方价格页(2026-10)1 / 4 / 0.25 元每百万 token,按快照同一汇率(约 0.139)折算","promptCache":{"short":300,"long":3600}}]}',
|
|
21
|
-
volcengine: '{"version":1,"provider":"volcengine","modelsDev":"volcengine","models":[{"id":"doubao-seed-2-1-pro-260628"},{"id":"doubao-seed-2-1-turbo-260628"},{"id":"doubao-seed-2-0-code-preview-260215"},{"id":"doubao-seed-2-0-lite-260428"},{"id":"deepseek-v4-pro-ga-260813"},{"id":"glm-5-3-flash-260828"}]}',
|
|
21
|
+
volcengine: '{"version":1,"provider":"volcengine","modelsDev":"volcengine","small":"doubao-seed-2-0-lite-260428","models":[{"id":"doubao-seed-2-1-pro-260628"},{"id":"doubao-seed-2-1-turbo-260628"},{"id":"doubao-seed-2-0-code-preview-260215"},{"id":"doubao-seed-2-0-lite-260428"},{"id":"deepseek-v4-pro-ga-260813"},{"id":"glm-5-3-flash-260828"}]}',
|
|
22
22
|
xai: '{"version":1,"provider":"xai","modelsDev":"xai","models":[{"id":"grok-4.7","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"grok-4.6","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"}},{"id":"grok-4.5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"grok-4.3","thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}}]}',
|
|
23
|
-
zhipu: '{"version":1,"provider":"zhipu","modelsDev":"zhipuai","models":[{"id":"glm-5.3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5.3-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5.2","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5-turbo","name":"GLM-5-Turbo","contextWindow":200000,"maxTokens":131072,"reasoning":true,"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsReasoningEffort":false}},{"id":"glm-4.7","compat":{"supportsReasoningEffort":false}}]}',
|
|
23
|
+
zhipu: '{"version":1,"provider":"zhipu","modelsDev":"zhipuai","small":"glm-5.3-flash","models":[{"id":"glm-5.3","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5.3-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5.2","thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null},"compat":{"supportsReasoningEffort":true}},{"id":"glm-5-turbo","name":"GLM-5-Turbo","contextWindow":200000,"maxTokens":131072,"reasoning":true,"input":["text"],"cost":{"input":1.2,"output":4,"cacheRead":0.24,"cacheWrite":0},"compat":{"supportsReasoningEffort":false}},{"id":"glm-4.7","compat":{"supportsReasoningEffort":false}}]}',
|
|
24
24
|
};
|
|
@@ -29,6 +29,8 @@ export type CatalogEntry = Partial<Omit<CatalogModel, "cost">> & {
|
|
|
29
29
|
_reason?: string;
|
|
30
30
|
/** 模型级协议(OpenAI 推理模型走 responses 等)。 */
|
|
31
31
|
api?: Api;
|
|
32
|
+
/** [ME-C0] 中转 / 自定义模型按 id 匹配到本条目时使用的别名(小写、去厂商前缀后比较);不进 Model。 */
|
|
33
|
+
aliases?: string[];
|
|
32
34
|
};
|
|
33
35
|
/** `catalog/*.json` 的文件形状(覆盖格式)。 */
|
|
34
36
|
export interface CatalogSourceFile {
|
|
@@ -36,6 +38,8 @@ export interface CatalogSourceFile {
|
|
|
36
38
|
provider: string;
|
|
37
39
|
/** 快照里对应的 models.dev 供应商 id;false = 没有(本地服务)。 */
|
|
38
40
|
modelsDev?: string | false;
|
|
41
|
+
/** [ME-C0] 本供应商用于 auto 模式分类的小模型 id。 */
|
|
42
|
+
small?: string;
|
|
39
43
|
models: CatalogEntry[];
|
|
40
44
|
}
|
|
41
45
|
/** 从快照继承的字段(顺序即冗余检查与来源展示的顺序)。 */
|
|
@@ -69,6 +73,35 @@ export declare function parseCatalogFile(value: unknown, source: string, index?:
|
|
|
69
73
|
export declare function loadBuiltinCatalog(index?: ModelsDevIndex): Map<string, CatalogModel[]>;
|
|
70
74
|
/** 最近一次 `loadBuiltinCatalog()` 里,该目录模型从快照继承的字段(来源展示用)。 */
|
|
71
75
|
export declare function catalogInherited(provider: string, modelId: string): readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* [ME-D] 中转 / 自定义模型按 id 匹配内置目录(docs/model-efficiency-plan.md D10):小写、去一层
|
|
78
|
+
* `vendor/` 前缀与 `:latest` 后精确比较;键是第一方条目的 id(含 `/` 的聚合商条目不进索引)与各条
|
|
79
|
+
* `aliases`。同一个键落在两条上即 ambiguous,不命中。精确不中时再去掉思考档后缀(`-low` 等)试一次。
|
|
80
|
+
*/
|
|
81
|
+
export interface CatalogAliasHit {
|
|
82
|
+
/** 目录条目 `provider/id`。 */
|
|
83
|
+
ref: string;
|
|
84
|
+
/** 合并后的目录模型(深拷贝;内置快照口径)。 */
|
|
85
|
+
model: CatalogModel;
|
|
86
|
+
/** 目录条目对应的 models.dev 快照条目。 */
|
|
87
|
+
snapshotRef?: string;
|
|
88
|
+
/** 去掉思考档后缀才命中:思考档由中转按 id 决定,调用方不继承思考设置。 */
|
|
89
|
+
tier?: string;
|
|
90
|
+
}
|
|
91
|
+
export declare function normalizeModelId(id: string): string;
|
|
92
|
+
export type AliasTarget = {
|
|
93
|
+
provider: string;
|
|
94
|
+
id: string;
|
|
95
|
+
snapshotRef?: string;
|
|
96
|
+
} | "ambiguous";
|
|
97
|
+
/** 别名索引(测试可传入自造的目录源)。 */
|
|
98
|
+
export declare function buildAliasIndex(sources?: Readonly<Record<string, string>>): Map<string, AliasTarget>;
|
|
99
|
+
/** 按 id 唯一命中的目录条目(没有或 ambiguous 返回 undefined)。 */
|
|
100
|
+
export declare function catalogByAlias(id: string): CatalogAliasHit | undefined;
|
|
101
|
+
/** 显式指定的目录条目 `provider/id`(`models[].catalog`)。 */
|
|
102
|
+
export declare function catalogByRef(ref: string): CatalogAliasHit | undefined;
|
|
103
|
+
/** [ME-D] 供应商目录里给 auto 模式分类用的小模型 id(D12)。 */
|
|
104
|
+
export declare function catalogSmall(provider: string): string | undefined;
|
|
72
105
|
/** 目录条目 → Model(补 provider / api 与缺省 input)。 */
|
|
73
106
|
export declare function toModel(entry: CatalogModel, provider: string, api: Model["api"]): Model;
|
|
74
107
|
/** 自定义模型缺省:maxTokens 8192、reasoning false、input ["text"]、name = id;不猜 contextWindow。 */
|