webaiapi 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +184 -2
- package/bin/webapi.mjs +45 -0
- package/dist/browser/auth-capture.d.ts +110 -0
- package/dist/browser/auth-capture.d.ts.map +1 -0
- package/dist/browser/auth-capture.js +487 -0
- package/dist/browser/auth-capture.js.map +1 -0
- package/dist/browser/credentials.d.ts +102 -0
- package/dist/browser/credentials.d.ts.map +1 -0
- package/dist/browser/credentials.js +209 -0
- package/dist/browser/credentials.js.map +1 -0
- package/dist/browser/js-eval.d.ts +44 -0
- package/dist/browser/js-eval.d.ts.map +1 -0
- package/dist/browser/js-eval.js +20 -0
- package/dist/browser/js-eval.js.map +1 -0
- package/dist/browser/login-flow.d.ts +171 -0
- package/dist/browser/login-flow.d.ts.map +1 -0
- package/dist/browser/login-flow.js +606 -0
- package/dist/browser/login-flow.js.map +1 -0
- package/dist/browser/manager.d.ts +144 -0
- package/dist/browser/manager.d.ts.map +1 -0
- package/dist/browser/manager.js +586 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser/platforms.d.ts +96 -0
- package/dist/browser/platforms.d.ts.map +1 -0
- package/dist/browser/platforms.js +288 -0
- package/dist/browser/platforms.js.map +1 -0
- package/dist/browser/sse-capture.d.ts +23 -0
- package/dist/browser/sse-capture.d.ts.map +1 -0
- package/dist/browser/sse-capture.js +199 -0
- package/dist/browser/sse-capture.js.map +1 -0
- package/dist/browser/stealth.d.ts +12 -0
- package/dist/browser/stealth.d.ts.map +1 -0
- package/dist/browser/stealth.js +12 -0
- package/dist/browser/stealth.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +441 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +246 -0
- package/dist/config.js.map +1 -0
- package/dist/controllers/history-db.d.ts +56 -0
- package/dist/controllers/history-db.d.ts.map +1 -0
- package/dist/controllers/history-db.js +260 -0
- package/dist/controllers/history-db.js.map +1 -0
- package/dist/controllers/request-pool.d.ts +78 -0
- package/dist/controllers/request-pool.d.ts.map +1 -0
- package/dist/controllers/request-pool.js +222 -0
- package/dist/controllers/request-pool.js.map +1 -0
- package/dist/controllers/router.d.ts +172 -0
- package/dist/controllers/router.d.ts.map +1 -0
- package/dist/controllers/router.js +569 -0
- package/dist/controllers/router.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/log/api-logger.d.ts +55 -0
- package/dist/log/api-logger.d.ts.map +1 -0
- package/dist/log/api-logger.js +264 -0
- package/dist/log/api-logger.js.map +1 -0
- package/dist/log/debug-logger.d.ts +49 -0
- package/dist/log/debug-logger.d.ts.map +1 -0
- package/dist/log/debug-logger.js +285 -0
- package/dist/log/debug-logger.js.map +1 -0
- package/dist/log/logger.d.ts +16 -0
- package/dist/log/logger.d.ts.map +1 -0
- package/dist/log/logger.js +35 -0
- package/dist/log/logger.js.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +90 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/providers/base.d.ts +83 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +51 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/chatglm-dom-extract.d.ts +24 -0
- package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
- package/dist/providers/chatglm-dom-extract.js +175 -0
- package/dist/providers/chatglm-dom-extract.js.map +1 -0
- package/dist/providers/chatglm-dom.d.ts +110 -0
- package/dist/providers/chatglm-dom.d.ts.map +1 -0
- package/dist/providers/chatglm-dom.js +384 -0
- package/dist/providers/chatglm-dom.js.map +1 -0
- package/dist/providers/chatglm-sse.d.ts +119 -0
- package/dist/providers/chatglm-sse.d.ts.map +1 -0
- package/dist/providers/chatglm-sse.js +241 -0
- package/dist/providers/chatglm-sse.js.map +1 -0
- package/dist/providers/chatglm.d.ts +288 -0
- package/dist/providers/chatglm.d.ts.map +1 -0
- package/dist/providers/chatglm.js +1631 -0
- package/dist/providers/chatglm.js.map +1 -0
- package/dist/routes/chat.d.ts +117 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +1346 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/compress.d.ts +142 -0
- package/dist/routes/compress.d.ts.map +1 -0
- package/dist/routes/compress.js +551 -0
- package/dist/routes/compress.js.map +1 -0
- package/dist/routes/failover.d.ts +34 -0
- package/dist/routes/failover.d.ts.map +1 -0
- package/dist/routes/failover.js +221 -0
- package/dist/routes/failover.js.map +1 -0
- package/dist/routes/helpers.d.ts +174 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +525 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/meta.d.ts +31 -0
- package/dist/routes/meta.d.ts.map +1 -0
- package/dist/routes/meta.js +184 -0
- package/dist/routes/meta.js.map +1 -0
- package/dist/routes/sse.d.ts +82 -0
- package/dist/routes/sse.d.ts.map +1 -0
- package/dist/routes/sse.js +77 -0
- package/dist/routes/sse.js.map +1 -0
- package/dist/server/app.d.ts +24 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +292 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/middleware/api-key.d.ts +61 -0
- package/dist/server/middleware/api-key.d.ts.map +1 -0
- package/dist/server/middleware/api-key.js +95 -0
- package/dist/server/middleware/api-key.js.map +1 -0
- package/dist/server/middleware/rate-limit.d.ts +67 -0
- package/dist/server/middleware/rate-limit.d.ts.map +1 -0
- package/dist/server/middleware/rate-limit.js +134 -0
- package/dist/server/middleware/rate-limit.js.map +1 -0
- package/dist/server/middleware/timeout.d.ts +34 -0
- package/dist/server/middleware/timeout.d.ts.map +1 -0
- package/dist/server/middleware/timeout.js +64 -0
- package/dist/server/middleware/timeout.js.map +1 -0
- package/dist/server/types.d.ts +20 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/tools/build.d.ts +14 -0
- package/dist/tools/build.d.ts.map +1 -0
- package/dist/tools/build.js +105 -0
- package/dist/tools/build.js.map +1 -0
- package/dist/tools/clean.d.ts +32 -0
- package/dist/tools/clean.d.ts.map +1 -0
- package/dist/tools/clean.js +65 -0
- package/dist/tools/clean.js.map +1 -0
- package/dist/tools/convert.d.ts +50 -0
- package/dist/tools/convert.d.ts.map +1 -0
- package/dist/tools/convert.js +289 -0
- package/dist/tools/convert.js.map +1 -0
- package/dist/tools/names.d.ts +138 -0
- package/dist/tools/names.d.ts.map +1 -0
- package/dist/tools/names.js +578 -0
- package/dist/tools/names.js.map +1 -0
- package/dist/tools/parse.d.ts +31 -0
- package/dist/tools/parse.d.ts.map +1 -0
- package/dist/tools/parse.js +273 -0
- package/dist/tools/parse.js.map +1 -0
- package/dist/tools/placeholder.d.ts +21 -0
- package/dist/tools/placeholder.d.ts.map +1 -0
- package/dist/tools/placeholder.js +135 -0
- package/dist/tools/placeholder.js.map +1 -0
- package/dist/tools/prompts.d.ts +42 -0
- package/dist/tools/prompts.d.ts.map +1 -0
- package/dist/tools/prompts.js +69 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/protocol.d.ts +58 -0
- package/dist/tools/protocol.d.ts.map +1 -0
- package/dist/tools/protocol.js +287 -0
- package/dist/tools/protocol.js.map +1 -0
- package/dist/tools/repair.d.ts +83 -0
- package/dist/tools/repair.d.ts.map +1 -0
- package/dist/tools/repair.js +510 -0
- package/dist/tools/repair.js.map +1 -0
- package/dist/tools/workspace.d.ts +40 -0
- package/dist/tools/workspace.d.ts.map +1 -0
- package/dist/tools/workspace.js +224 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/types/message.d.ts +87 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +85 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/openai.d.ts +100 -0
- package/dist/types/openai.d.ts.map +1 -0
- package/dist/types/openai.js +66 -0
- package/dist/types/openai.js.map +1 -0
- package/dist/utils/errors.d.ts +82 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +115 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/mutex.d.ts +31 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +61 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/prompt.d.ts +150 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +514 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/text.d.ts +30 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +70 -0
- package/dist/utils/text.js.map +1 -0
- package/package.json +67 -4
- package/postinstall.mjs +34 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 交互式命令行提问工具(`webapi login` / `webapi logout` 用)。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么不引入 `prompts` / `inquirer`
|
|
5
|
+
* 本项目刻意保持**零运行时依赖**(见 `package.json`)。为了两个菜单拉一棵依赖树
|
|
6
|
+
* 不划算,而且这两个库在「非 TTY」下的行为各不相同,反而更难控。
|
|
7
|
+
*
|
|
8
|
+
* ## 结构:纯函数内核 + 薄 IO 外壳
|
|
9
|
+
* 把「怎么画选项列表」「用户敲的这串字符对应哪一项」做成**纯函数**
|
|
10
|
+
* ({@link renderChoiceList} / {@link resolveChoiceInput}),IO(raw mode、readline)
|
|
11
|
+
* 只留最薄一层({@link selectOne})。
|
|
12
|
+
*
|
|
13
|
+
* 理由很实际:**伪造 TTY 的单测又慢又脆**,而这里的 bug 恰恰集中在
|
|
14
|
+
* 「空输入该选哪个」「数字越界怎么办」「disabled 项被选中怎么办」这些
|
|
15
|
+
* **纯粹的分支判断**上 —— 拆出来就能直接喂字符串测,不用碰终端。
|
|
16
|
+
*
|
|
17
|
+
* ## ⚠️ 非 TTY 必须有降级路径
|
|
18
|
+
* `webapi login < ...`(管道)、CI、被其他脚本调用时 `stdin` 不是 TTY。
|
|
19
|
+
* 此时 raw mode 不可用(`setRawMode` 直接抛错),**绝不能**硬走交互渲染 ——
|
|
20
|
+
* 那种情况下进程会卡住等一个永远不会来的按键。这里统一退化成
|
|
21
|
+
* 「打印带编号的列表 + 读一行」,与 TTY 路径共用同一套 {@link resolveChoiceInput} 判定。
|
|
22
|
+
*/
|
|
23
|
+
import { createInterface } from 'node:readline';
|
|
24
|
+
/* ==================================================================== */
|
|
25
|
+
/* 颜色 / TTY */
|
|
26
|
+
/* ==================================================================== */
|
|
27
|
+
/**
|
|
28
|
+
* 是否输出 ANSI 颜色。
|
|
29
|
+
*
|
|
30
|
+
* 遵循 `NO_COLOR` 约定(https://no-color.org),且只在输出为 TTY 时上色 ——
|
|
31
|
+
* 否则 `webapi login > log.txt` 会把转义序列写进文件。
|
|
32
|
+
*/
|
|
33
|
+
export function supportsColor() {
|
|
34
|
+
if (process.env['NO_COLOR'])
|
|
35
|
+
return false;
|
|
36
|
+
return Boolean(process.stdout.isTTY);
|
|
37
|
+
}
|
|
38
|
+
function wrap(code, text) {
|
|
39
|
+
return supportsColor() ? `\u001b[${code}m${text}\u001b[0m` : text;
|
|
40
|
+
}
|
|
41
|
+
export const cyan = (text) => wrap(36, text);
|
|
42
|
+
export const bold = (text) => wrap(1, text);
|
|
43
|
+
export const dim = (text) => wrap(2, text);
|
|
44
|
+
/** 该码点在终端里是否占**两列**(CJK / 全角 / 韩文音节等)。 */
|
|
45
|
+
function isWideCodePoint(cp) {
|
|
46
|
+
return ((cp >= 0x1100 && cp <= 0x115f) || // 韩文字母
|
|
47
|
+
(cp >= 0x2e80 && cp <= 0xa4cf) || // CJK 部首 / 假名 / 汉字
|
|
48
|
+
(cp >= 0xac00 && cp <= 0xd7a3) || // 韩文音节
|
|
49
|
+
(cp >= 0xf900 && cp <= 0xfaff) || // CJK 兼容汉字
|
|
50
|
+
(cp >= 0xfe30 && cp <= 0xfe6f) || // CJK 兼容形式
|
|
51
|
+
(cp >= 0xff00 && cp <= 0xff60) || // 全角字符
|
|
52
|
+
(cp >= 0xffe0 && cp <= 0xffe6));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 字符串在终端里占的**列数**。
|
|
56
|
+
*
|
|
57
|
+
* ⚠️ 存在的理由:`String.prototype.length` / `padEnd` 数的是**码元**,
|
|
58
|
+
* 而中文、全角标点在终端占**两列**。用 `padEnd` 对齐「ChatGLM (智谱)」这种
|
|
59
|
+
* 中英混排的表,第二列会参差不齐 —— 菜单看着就是乱的。
|
|
60
|
+
*/
|
|
61
|
+
export function displayWidth(text) {
|
|
62
|
+
let width = 0;
|
|
63
|
+
// 用 for...of 按**码点**迭代:emoji 之类的代理对要算一个字符
|
|
64
|
+
for (const ch of text) {
|
|
65
|
+
width += isWideCodePoint(ch.codePointAt(0) ?? 0) ? 2 : 1;
|
|
66
|
+
}
|
|
67
|
+
return width;
|
|
68
|
+
}
|
|
69
|
+
/** 按**显示宽度**右填空格(`padEnd` 的中英混排安全版)。 */
|
|
70
|
+
export function padDisplay(text, width) {
|
|
71
|
+
return text + ' '.repeat(Math.max(0, width - displayWidth(text)));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 当前是否处于**可交互**环境(两端都是 TTY)。
|
|
75
|
+
*
|
|
76
|
+
* 只要有一端不是 TTY 就不能走 raw mode:`stdout` 被重定向时用户看不到菜单,
|
|
77
|
+
* `stdin` 被重定向时按键根本到不了我们手上。
|
|
78
|
+
*/
|
|
79
|
+
export function isInteractive() {
|
|
80
|
+
return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|
|
81
|
+
}
|
|
82
|
+
/* ==================================================================== */
|
|
83
|
+
/* 纯函数内核(可直接单测) */
|
|
84
|
+
/* ==================================================================== */
|
|
85
|
+
/**
|
|
86
|
+
* 把选项列表渲染成多行文本。
|
|
87
|
+
*
|
|
88
|
+
* 返回 `string[]` 而不是拼好的字符串:调用方需要知道**行数**才能在原地重绘
|
|
89
|
+
* (光标上移 N 行 → 清除 → 重画),而且逐行更好断言。
|
|
90
|
+
*/
|
|
91
|
+
export function renderChoiceList(choices, selectedIndex, options = {}) {
|
|
92
|
+
const { numbered = true, indent = ' ' } = options;
|
|
93
|
+
return choices.map((choice, i) => {
|
|
94
|
+
const isSelected = i === selectedIndex;
|
|
95
|
+
const pointer = isSelected ? cyan('❯') : ' ';
|
|
96
|
+
const number = numbered ? `${dim(`${i + 1}.`)} ` : '';
|
|
97
|
+
const label = isSelected ? bold(choice.label) : choice.label;
|
|
98
|
+
let tail = '';
|
|
99
|
+
if (choice.disabled) {
|
|
100
|
+
tail = ` ${dim(`✗ ${choice.disabled}`)}`;
|
|
101
|
+
}
|
|
102
|
+
else if (choice.hint) {
|
|
103
|
+
tail = ` ${dim(choice.hint)}`;
|
|
104
|
+
}
|
|
105
|
+
return `${pointer} ${indent}${number}${label}${tail}`;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 把用户输入的一行文本解析成「选中了第几项」。
|
|
110
|
+
*
|
|
111
|
+
* 与 {@link selectOne} 的**非 TTY 降级路径**共用同一套规则,保证两条路径
|
|
112
|
+
* 对「空输入 / 数字 / q / 越界」的处理完全一致 —— 否则会出现
|
|
113
|
+
* 「管道里能用、终端里不能用」这种最难复现的差异。
|
|
114
|
+
*
|
|
115
|
+
* 规则:
|
|
116
|
+
* - 空输入(直接回车)→ 默认项({@link defaultIndex},未指定则第 1 项)
|
|
117
|
+
* - `数字` → 第 N 项(1 起算)
|
|
118
|
+
* - `q` / `Q` → 取消(返回 `cancel`)
|
|
119
|
+
* - 其余、越界、以及选中 **disabled** 项 → `retry`(带原因,让调用方提示后重问)
|
|
120
|
+
*
|
|
121
|
+
* ⚠️ disabled 项**返回 retry 而不是静默忽略**:用户在非 TTY 下看不到「不可选」
|
|
122
|
+
* 的视觉提示,必须明确告诉他原因,否则他会以为自己选错了数字。
|
|
123
|
+
*/
|
|
124
|
+
export function resolveChoiceInput(raw, choices, defaultIndex = 0) {
|
|
125
|
+
const text = raw.trim();
|
|
126
|
+
if (text === '') {
|
|
127
|
+
return pick(defaultIndex, choices);
|
|
128
|
+
}
|
|
129
|
+
if (text === 'q' || text === 'Q') {
|
|
130
|
+
return { kind: 'cancel' };
|
|
131
|
+
}
|
|
132
|
+
if (!/^\d+$/.test(text)) {
|
|
133
|
+
return { kind: 'retry', reason: `无法识别的输入「${text}」(请输入编号,或 q 取消)` };
|
|
134
|
+
}
|
|
135
|
+
const index = Number(text) - 1;
|
|
136
|
+
return pick(index, choices);
|
|
137
|
+
}
|
|
138
|
+
function pick(index, choices) {
|
|
139
|
+
const choice = choices[index];
|
|
140
|
+
if (!choice) {
|
|
141
|
+
return { kind: 'retry', reason: `编号超出范围(可选 1~${choices.length})` };
|
|
142
|
+
}
|
|
143
|
+
if (choice.disabled) {
|
|
144
|
+
return { kind: 'retry', reason: `「${choice.label}」当前不可选:${choice.disabled}` };
|
|
145
|
+
}
|
|
146
|
+
return { kind: 'ok', index };
|
|
147
|
+
}
|
|
148
|
+
/** 从 `defaultIndex` 开始往后找第一个可选中的项(找不到返回 0)。 */
|
|
149
|
+
export function firstSelectableIndex(choices) {
|
|
150
|
+
const found = choices.findIndex((c) => !c.disabled);
|
|
151
|
+
return found >= 0 ? found : 0;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 把一段输入切成**逐个按键**。
|
|
155
|
+
*
|
|
156
|
+
* ## ⚠️ 为什么必须做这件事(真实缺陷,不是洁癖)
|
|
157
|
+
* `stdin` 的 `data` 事件**不保证一次只有一个按键**:
|
|
158
|
+
* - 按住方向键时终端会把多个 `\u001b[B` 合并成一个 chunk;
|
|
159
|
+
* - 粘贴、管道、`script` 这类 pty 转发会一次送进来一整串(如 `\u001b[B\r`);
|
|
160
|
+
* - 高延迟/慢终端下两次按键可能落在同一个 chunk 里。
|
|
161
|
+
*
|
|
162
|
+
* 若像最初那样用一个 `switch (chunk)` 精确匹配整块,**只有恰好等于
|
|
163
|
+
* `'\u001b[B'` 的 chunk 才生效**,其余情况全部落进 `default` 分支被丢掉 ——
|
|
164
|
+
* 表现为「方向键时灵时不灵」「按了回车没反应」,且完全不打日志。
|
|
165
|
+
*
|
|
166
|
+
* ## 返回值里的 `rest`
|
|
167
|
+
* 流式解析时末尾可能是**半个转义序列**(chunk 在 `\u001b` 或 `\u001b[` 处被切开),
|
|
168
|
+
* 这部分要留给下一个 chunk 拼接,所以放在 `rest` 里返回而不是当成按键。
|
|
169
|
+
*
|
|
170
|
+
* 但「单独按下 Esc」产生的**恰好也是**一个孤立 `\u001b` —— 两者无法只靠字节区分。
|
|
171
|
+
* 因此调用方在 `rest` 非空时起一个 ~40ms 的定时器:等不到后续字节,
|
|
172
|
+
* 就带 `flushTrailingEscape: true` 再解析一次,把它判定为 Esc。
|
|
173
|
+
*
|
|
174
|
+
* @param options.flushTrailingEscape 等待超时后的收尾解析:把末尾残缺的转义
|
|
175
|
+
* 序列当作「用户按了 Esc」(不这么做的话按 Esc 会永久挂住)。
|
|
176
|
+
*/
|
|
177
|
+
export function tokenizeKeys(input, options = {}) {
|
|
178
|
+
const tokens = [];
|
|
179
|
+
let i = 0;
|
|
180
|
+
while (i < input.length) {
|
|
181
|
+
const ch = input[i];
|
|
182
|
+
if (ch === '\u001b') {
|
|
183
|
+
const rest = input.slice(i);
|
|
184
|
+
if (rest.startsWith('\u001b[A') || rest.startsWith('\u001bOA')) {
|
|
185
|
+
tokens.push({ kind: 'up' });
|
|
186
|
+
i += 3;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (rest.startsWith('\u001b[B') || rest.startsWith('\u001bOB')) {
|
|
190
|
+
tokens.push({ kind: 'down' });
|
|
191
|
+
i += 3;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
// 其它 CSI 序列(Home/End/PageUp/Delete…)整段吃掉:
|
|
195
|
+
// 不能把 `[` `3` `~` 当字符输入,否则会在列表里触发莫名其妙的跳转
|
|
196
|
+
const csi = /^\u001b\[[0-9;]*[A-Za-z~]/.exec(rest);
|
|
197
|
+
if (csi) {
|
|
198
|
+
i += csi[0].length;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
// 可能是被切开的转义序列 → 留到下一个 chunk
|
|
202
|
+
const isPartial = rest === '\u001b' || rest === '\u001b[' || rest === '\u001bO' || /^\u001b\[[0-9;]*$/.test(rest);
|
|
203
|
+
if (isPartial) {
|
|
204
|
+
if (options.flushTrailingEscape) {
|
|
205
|
+
tokens.push({ kind: 'cancel' });
|
|
206
|
+
i = input.length;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
return { tokens, rest };
|
|
210
|
+
}
|
|
211
|
+
// 完整但未识别的 ESC 序列 → 当作 Esc
|
|
212
|
+
tokens.push({ kind: 'cancel' });
|
|
213
|
+
i += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (ch === '\r' || ch === '\n') {
|
|
217
|
+
tokens.push({ kind: 'enter' });
|
|
218
|
+
i += 1;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (ch === '\u0003') {
|
|
222
|
+
tokens.push({ kind: 'sigint' });
|
|
223
|
+
i += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (ch === '\u0004') {
|
|
227
|
+
// Ctrl+D:多数终端下等于 EOF
|
|
228
|
+
tokens.push({ kind: 'cancel' });
|
|
229
|
+
i += 1;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (ch >= ' ')
|
|
233
|
+
tokens.push({ kind: 'char', value: ch });
|
|
234
|
+
// 其余控制字符(\u0000 等)直接丢弃
|
|
235
|
+
i += 1;
|
|
236
|
+
}
|
|
237
|
+
return { tokens, rest: '' };
|
|
238
|
+
}
|
|
239
|
+
/* ==================================================================== */
|
|
240
|
+
/* IO 外壳 */
|
|
241
|
+
/* ==================================================================== */
|
|
242
|
+
/**
|
|
243
|
+
* 读一行输入;**流结束(EOF)时返回 `null`**。
|
|
244
|
+
*
|
|
245
|
+
* ⚠️ 必须区分「用户直接回车」(返回空串)与「输入流结束」(返回 null):
|
|
246
|
+
* 管道输入用完时 `readline` 只发 `close`,若把它当成空串,调用方会把
|
|
247
|
+
* 「没有输入」误判成「用户选了默认项」,在 CI 里表现为**静默走了默认分支**。
|
|
248
|
+
*/
|
|
249
|
+
function ask(question) {
|
|
250
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
251
|
+
return new Promise((resolve) => {
|
|
252
|
+
let settled = false;
|
|
253
|
+
const done = (value) => {
|
|
254
|
+
if (settled)
|
|
255
|
+
return;
|
|
256
|
+
settled = true;
|
|
257
|
+
rl.close();
|
|
258
|
+
resolve(value);
|
|
259
|
+
};
|
|
260
|
+
rl.on('close', () => done(null));
|
|
261
|
+
rl.question(question, (answer) => done(answer));
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
/** 读取一段文本输入(可带默认值 / 校验)。取消(EOF)返回 `null`。 */
|
|
265
|
+
export async function inputText(options) {
|
|
266
|
+
const { message, defaultValue, validate } = options;
|
|
267
|
+
const suffix = defaultValue ? ` ${dim(`[${defaultValue}]`)}` : '';
|
|
268
|
+
for (;;) {
|
|
269
|
+
const raw = await ask(`${bold(message)}${suffix} `);
|
|
270
|
+
if (raw === null)
|
|
271
|
+
return null; // EOF
|
|
272
|
+
const value = raw.trim() === '' ? (defaultValue ?? '') : raw.trim();
|
|
273
|
+
const problem = validate?.(value) ?? null;
|
|
274
|
+
if (problem) {
|
|
275
|
+
console.log(` ${dim(`✗ ${problem}`)}`);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/** 是 / 否确认。取消(EOF)返回 `null`。 */
|
|
282
|
+
export async function confirmYesNo(options) {
|
|
283
|
+
const { message, defaultYes = false } = options;
|
|
284
|
+
const hint = defaultYes ? 'Y/n' : 'y/N';
|
|
285
|
+
for (;;) {
|
|
286
|
+
const raw = await ask(`${bold(message)} ${dim(`[${hint}]`)} `);
|
|
287
|
+
if (raw === null)
|
|
288
|
+
return null;
|
|
289
|
+
const text = raw.trim().toLowerCase();
|
|
290
|
+
if (text === '')
|
|
291
|
+
return defaultYes;
|
|
292
|
+
if (['y', 'yes', '是', '对', '好'].includes(text))
|
|
293
|
+
return true;
|
|
294
|
+
if (['n', 'no', '否', '不'].includes(text))
|
|
295
|
+
return false;
|
|
296
|
+
console.log(` ${dim('✗ 请输入 y 或 n')}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** `stdin` 是否支持 raw mode(Windows 旧终端 / 非 TTY 下返回 false)。 */
|
|
300
|
+
function rawModeAvailable() {
|
|
301
|
+
const stdin = process.stdin;
|
|
302
|
+
if (!isInteractive() || typeof stdin.setRawMode !== 'function')
|
|
303
|
+
return false;
|
|
304
|
+
try {
|
|
305
|
+
stdin.setRawMode(true);
|
|
306
|
+
stdin.setRawMode(false);
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** 非 TTY 降级路径:打印带编号的列表,然后读一行。 */
|
|
314
|
+
async function selectOnePlain(message, choices, defaultIndex) {
|
|
315
|
+
console.log(`\n${bold(message)}`);
|
|
316
|
+
console.log(renderChoiceList(choices, defaultIndex).join('\n'));
|
|
317
|
+
for (;;) {
|
|
318
|
+
const raw = await ask(`${bold('请输入编号')} ${dim('[回车 = 默认项, q = 取消]')} `);
|
|
319
|
+
if (raw === null)
|
|
320
|
+
return null;
|
|
321
|
+
const resolution = resolveChoiceInput(raw, choices, defaultIndex);
|
|
322
|
+
if (resolution.kind === 'cancel')
|
|
323
|
+
return null;
|
|
324
|
+
if (resolution.kind === 'retry') {
|
|
325
|
+
console.log(` ${dim(`✗ ${resolution.reason}`)}`);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
return choices[resolution.index]?.value ?? null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** TTY 路径:raw mode + ↑/↓ 高亮选择。 */
|
|
332
|
+
function selectOneTty(message, choices, defaultIndex) {
|
|
333
|
+
return new Promise((resolve) => {
|
|
334
|
+
const stdin = process.stdin;
|
|
335
|
+
const out = process.stdout;
|
|
336
|
+
let selected = firstSelectableIndex(choices);
|
|
337
|
+
if (choices[defaultIndex] && !choices[defaultIndex]?.disabled)
|
|
338
|
+
selected = defaultIndex;
|
|
339
|
+
let rendered = 0;
|
|
340
|
+
let restores = 0; // 光标隐藏计数,确保 popStyle 与它配平
|
|
341
|
+
/** 已经 resolve 过:后续按键(可能还在缓冲里)必须全部丢弃。 */
|
|
342
|
+
let finished = false;
|
|
343
|
+
/** 跨 chunk 的按键缓冲(用于拼接被切开的转义序列)。 */
|
|
344
|
+
let pending = '';
|
|
345
|
+
/** 「末尾半个转义序列」的等待定时器(超时后判定为 Esc)。 */
|
|
346
|
+
let flushTimer;
|
|
347
|
+
const paint = () => {
|
|
348
|
+
// 光标上移到交互块首行行首,再清除到屏幕末尾 → 覆盖式重绘
|
|
349
|
+
if (rendered > 0)
|
|
350
|
+
out.write(`\u001b[${rendered}A\u001b[0J`);
|
|
351
|
+
const lines = [
|
|
352
|
+
bold(message),
|
|
353
|
+
...renderChoiceList(choices, selected),
|
|
354
|
+
dim(' ↑/↓ 选择 · Enter 确认 · Esc 取消'),
|
|
355
|
+
];
|
|
356
|
+
out.write(`${lines.join('\n')}\n`);
|
|
357
|
+
rendered = lines.length;
|
|
358
|
+
};
|
|
359
|
+
const cleanup = () => {
|
|
360
|
+
if (flushTimer)
|
|
361
|
+
clearTimeout(flushTimer);
|
|
362
|
+
flushTimer = undefined;
|
|
363
|
+
stdin.removeListener('data', onData);
|
|
364
|
+
stdin.removeListener('end', onEnd);
|
|
365
|
+
out.removeListener('resize', onResize);
|
|
366
|
+
try {
|
|
367
|
+
stdin.setRawMode(false);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// 终端已关闭时忽略
|
|
371
|
+
}
|
|
372
|
+
stdin.pause();
|
|
373
|
+
out.write(`\u001b[${restores}?25h`);
|
|
374
|
+
};
|
|
375
|
+
/** 结束并留下「一行结论」,避免菜单残留在终端里。 */
|
|
376
|
+
const finish = (index) => {
|
|
377
|
+
finished = true;
|
|
378
|
+
cleanup();
|
|
379
|
+
if (rendered > 0)
|
|
380
|
+
out.write(`\u001b[${rendered}A\u001b[0J`);
|
|
381
|
+
const choice = index === null ? undefined : choices[index];
|
|
382
|
+
if (choice) {
|
|
383
|
+
out.write(`${cyan('✔')} ${message} ${bold(choice.label)}\n`);
|
|
384
|
+
resolve(choice.value);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
out.write(`${dim(`✗ ${message}(已取消)`)}\n`);
|
|
388
|
+
resolve(null);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
const move = (delta) => {
|
|
392
|
+
let next = selected;
|
|
393
|
+
// 跳过 disabled 项;绕一圈都没有可选项时原地不动
|
|
394
|
+
for (let step = 0; step < choices.length; step += 1) {
|
|
395
|
+
next = (next + delta + choices.length) % choices.length;
|
|
396
|
+
if (!choices[next]?.disabled) {
|
|
397
|
+
selected = next;
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
/** 处理单个按键。 */
|
|
403
|
+
const applyKey = (token) => {
|
|
404
|
+
switch (token.kind) {
|
|
405
|
+
case 'up':
|
|
406
|
+
move(-1);
|
|
407
|
+
paint();
|
|
408
|
+
return;
|
|
409
|
+
case 'down':
|
|
410
|
+
move(1);
|
|
411
|
+
paint();
|
|
412
|
+
return;
|
|
413
|
+
case 'enter': {
|
|
414
|
+
const choice = choices[selected];
|
|
415
|
+
if (choice?.disabled) {
|
|
416
|
+
// 高亮停在 disabled 项上(正常情况下到不了这里)→ 给出原因而不是静默接受
|
|
417
|
+
out.write(`\u001b[${rendered}A\u001b[0J`);
|
|
418
|
+
rendered = 0;
|
|
419
|
+
out.write(`${dim(`✗ 「${choice.label}」当前不可选:${choice.disabled}`)}\n`);
|
|
420
|
+
paint();
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
finish(selected);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
// Esc / Ctrl+D → 取消
|
|
427
|
+
case 'cancel':
|
|
428
|
+
finish(null);
|
|
429
|
+
return;
|
|
430
|
+
// Ctrl+C → **也当作取消**,而不是直接 process.exit():
|
|
431
|
+
// 登录流程里浏览器可能已经启动,必须让调用方(有 try/finally)自己收尾,
|
|
432
|
+
// 否则会留下一个没人管的 Firefox 进程。
|
|
433
|
+
case 'sigint':
|
|
434
|
+
finish(null);
|
|
435
|
+
return;
|
|
436
|
+
case 'char': {
|
|
437
|
+
// 数字键:直接跳到第 N 项(与降级路径的编号习惯保持一致)
|
|
438
|
+
if (/^\d$/.test(token.value)) {
|
|
439
|
+
const index = Number(token.value) - 1;
|
|
440
|
+
if (choices[index] && !choices[index]?.disabled) {
|
|
441
|
+
selected = index;
|
|
442
|
+
paint();
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
/**
|
|
450
|
+
* 把新到的字节喂给解析器,**逐个**处理解析出来的按键。
|
|
451
|
+
*
|
|
452
|
+
* ⚠️ 必须逐个处理:一次 `data` 事件可能带多个按键(连按方向键、粘贴、
|
|
453
|
+
* pty 转发),整块匹配会漏掉除第一个以外的全部按键。
|
|
454
|
+
*/
|
|
455
|
+
const feed = (text, flush) => {
|
|
456
|
+
pending += text;
|
|
457
|
+
const { tokens, rest } = tokenizeKeys(pending, { flushTrailingEscape: flush });
|
|
458
|
+
pending = rest;
|
|
459
|
+
for (const token of tokens) {
|
|
460
|
+
if (finished)
|
|
461
|
+
return;
|
|
462
|
+
applyKey(token);
|
|
463
|
+
}
|
|
464
|
+
if (pending !== '') {
|
|
465
|
+
// 末尾是半个转义序列:等 40ms 看还有没有后续字节。
|
|
466
|
+
// 等不到 → 认定用户按的是 Esc(否则单独按 Esc 会永久挂住)。
|
|
467
|
+
if (!flush) {
|
|
468
|
+
if (flushTimer)
|
|
469
|
+
clearTimeout(flushTimer);
|
|
470
|
+
flushTimer = setTimeout(() => {
|
|
471
|
+
flushTimer = undefined;
|
|
472
|
+
if (!finished && pending !== '')
|
|
473
|
+
feed('', true);
|
|
474
|
+
}, 40);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
else if (flushTimer) {
|
|
478
|
+
clearTimeout(flushTimer);
|
|
479
|
+
flushTimer = undefined;
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
const onData = (chunk) => feed(chunk.toString('utf8'), false);
|
|
483
|
+
const onEnd = () => finish(null);
|
|
484
|
+
const onResize = () => paint();
|
|
485
|
+
stdin.setRawMode(true);
|
|
486
|
+
stdin.resume();
|
|
487
|
+
stdin.setEncoding('utf8');
|
|
488
|
+
out.write('\u001b[?25l'); // 隐藏光标,避免它在列表里乱跳
|
|
489
|
+
restores += 1;
|
|
490
|
+
paint();
|
|
491
|
+
stdin.on('data', onData);
|
|
492
|
+
stdin.on('end', onEnd);
|
|
493
|
+
out.on('resize', onResize);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* 让用户从列表里选一项。
|
|
498
|
+
*
|
|
499
|
+
* - TTY:↑/↓ 高亮 + Enter 确认(数字键可直接跳)
|
|
500
|
+
* - 非 TTY(管道 / CI):打印编号列表,读一行
|
|
501
|
+
* - 两者都用同一套 {@link resolveChoiceInput} 判定,行为一致
|
|
502
|
+
*
|
|
503
|
+
* @returns 选中的值;用户取消(Esc / Ctrl+C / EOF)返回 `null`。
|
|
504
|
+
*/
|
|
505
|
+
export async function selectOne(options) {
|
|
506
|
+
const { message, choices, defaultIndex = firstSelectableIndex(choices), forcePlain } = options;
|
|
507
|
+
if (choices.length === 0)
|
|
508
|
+
return null;
|
|
509
|
+
if (forcePlain || !rawModeAvailable()) {
|
|
510
|
+
return selectOnePlain(message, choices, defaultIndex);
|
|
511
|
+
}
|
|
512
|
+
return selectOneTty(message, choices, defaultIndex);
|
|
513
|
+
}
|
|
514
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 清洗 AI 回复文本。
|
|
3
|
+
*
|
|
4
|
+
* - 去除首尾空白(保留换行)
|
|
5
|
+
* - 过滤零宽字符与不可见控制字符
|
|
6
|
+
* - 移除 Unicode 替换字符 U+FFFD(编码错误时出现)
|
|
7
|
+
*/
|
|
8
|
+
export declare function sanitizeMessage(text: unknown): string;
|
|
9
|
+
/**
|
|
10
|
+
* 计算增量文本(**按长度切后缀**)。
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ 不用于 ChatGLM 正文:SSE 载荷本身已提供权威的增量/快照语义
|
|
13
|
+
* (见 `docs/hard-constraints.md`「text / think 载荷的语义」)。
|
|
14
|
+
* 这里保留是为了给「非 SSE 来源」的兜底路径用,以及在文档里作为对照。
|
|
15
|
+
*/
|
|
16
|
+
export declare function computeIncremental(lastText: string, currentText: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* 取 JSON 文本的**顶层字段名**(解析失败返回空数组)。
|
|
19
|
+
*
|
|
20
|
+
* 用途:侦察「网页平台自己的请求体长什么样」——判断能否把客户端工具定义交给平台、
|
|
21
|
+
* 用它的原生函数调用通道承载(见 `logs/chatglm_platform_request.txt`)。
|
|
22
|
+
* 请求体可能被截断/非 JSON,所以**绝不能抛异常**。
|
|
23
|
+
*/
|
|
24
|
+
export declare function topLevelJsonFields(body: string | null | undefined): string[];
|
|
25
|
+
/**
|
|
26
|
+
* 截断过长文本并附加说明(Python 的 `truncate_message`,原本只在已删除的平台
|
|
27
|
+
* Provider 里用;这里保留一个显式版本供调试脚本使用)。
|
|
28
|
+
*/
|
|
29
|
+
export declare function truncateMessage(text: string, maxLength?: number): string;
|
|
30
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAOrD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAOpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAS5E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,MAAM,CAMvE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文本工具 —— 合并 `legacy-python/src/providers/browser_utils.py` 与
|
|
3
|
+
* `playwright_manager.compute_incremental`(Python 里这两个函数**在两处重复**,
|
|
4
|
+
* TS 版只保留这一份)。
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from '../log/logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* 清洗 AI 回复文本。
|
|
9
|
+
*
|
|
10
|
+
* - 去除首尾空白(保留换行)
|
|
11
|
+
* - 过滤零宽字符与不可见控制字符
|
|
12
|
+
* - 移除 Unicode 替换字符 U+FFFD(编码错误时出现)
|
|
13
|
+
*/
|
|
14
|
+
export function sanitizeMessage(text) {
|
|
15
|
+
if (typeof text !== 'string')
|
|
16
|
+
return '';
|
|
17
|
+
let out = text.trim();
|
|
18
|
+
out = out.replace(/[\u200b-\u200f\u2028-\u202e\ufeff]/g, '');
|
|
19
|
+
out = out.replace(/\ufffd/g, '');
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 计算增量文本(**按长度切后缀**)。
|
|
24
|
+
*
|
|
25
|
+
* ⚠️ 不用于 ChatGLM 正文:SSE 载荷本身已提供权威的增量/快照语义
|
|
26
|
+
* (见 `docs/hard-constraints.md`「text / think 载荷的语义」)。
|
|
27
|
+
* 这里保留是为了给「非 SSE 来源」的兜底路径用,以及在文档里作为对照。
|
|
28
|
+
*/
|
|
29
|
+
export function computeIncremental(lastText, currentText) {
|
|
30
|
+
if (!currentText || !lastText) {
|
|
31
|
+
return currentText ? currentText : undefined;
|
|
32
|
+
}
|
|
33
|
+
// 当前文本比上次短 → 可能被截断或清空了,直接返回全量
|
|
34
|
+
if (currentText.length < lastText.length)
|
|
35
|
+
return currentText;
|
|
36
|
+
return currentText.slice(lastText.length);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 取 JSON 文本的**顶层字段名**(解析失败返回空数组)。
|
|
40
|
+
*
|
|
41
|
+
* 用途:侦察「网页平台自己的请求体长什么样」——判断能否把客户端工具定义交给平台、
|
|
42
|
+
* 用它的原生函数调用通道承载(见 `logs/chatglm_platform_request.txt`)。
|
|
43
|
+
* 请求体可能被截断/非 JSON,所以**绝不能抛异常**。
|
|
44
|
+
*/
|
|
45
|
+
export function topLevelJsonFields(body) {
|
|
46
|
+
if (!body)
|
|
47
|
+
return [];
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(body);
|
|
50
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
51
|
+
return [];
|
|
52
|
+
return Object.keys(parsed);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 截断过长文本并附加说明(Python 的 `truncate_message`,原本只在已删除的平台
|
|
60
|
+
* Provider 里用;这里保留一个显式版本供调试脚本使用)。
|
|
61
|
+
*/
|
|
62
|
+
export function truncateMessage(text, maxLength = 15000) {
|
|
63
|
+
if (typeof text !== 'string')
|
|
64
|
+
throw new TypeError('text must be a string');
|
|
65
|
+
if (text.length <= maxLength)
|
|
66
|
+
return text;
|
|
67
|
+
logger.warn(`AI 回复过长 (${text.length} 字符),已截断至 ${maxLength} 个字符`);
|
|
68
|
+
return `${text.slice(0, maxLength)}\n\n[webaiapi: ... (truncated, ${text.length - maxLength} chars removed)]`;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAExC,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;IAC7D,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,WAAmB;IAEnB,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;IACD,8BAA8B;IAC9B,IAAI,WAAW,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAC7D,OAAO,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA+B;IAChE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9E,OAAO,MAAM,CAAC,IAAI,CAAC,MAAiC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAS,GAAG,KAAK;IAC7D,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,uBAAuB,CAAC,CAAC;IAC3E,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,MAAM,aAAa,SAAS,MAAM,CAAC,CAAC;IACjE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,kCAAkC,IAAI,CAAC,MAAM,GAAG,SAAS,kBAAkB,CAAC;AAChH,CAAC"}
|