feat: 升级至 v0.2.3 — Token 估算优化、工具确认超时改进、工作空间标签页

1. Token 估算优化(核心改进):新增 token-estimator.ts 智能字符估算(中文 1.5 token/字、ASCII 0.25 token/字),替换三处旧的 length/2 粗略估算,中文场景准确度从 ~50% 提升到 ~90%

2. 工具确认超时改进:超时时间可配置(30s~600s)、超时 toast 通知、ConfirmationDialog 倒计时 UI(进度条 + 最后 10 秒红色脉冲动画)、SettingsModal 新增配置入口

3. 详情栏新增 Workspace 标签页:workspace:getInfo IPC + WorkspaceViewer 组件(文件预览、目录状态、在文件管理器打开)
This commit is contained in:
thzxx
2026-07-12 14:20:05 +08:00
parent 0363176215
commit 1eabed9b70
13 changed files with 563 additions and 35 deletions
+72
View File
@@ -0,0 +1,72 @@
/**
* Token 估算工具 — 跨 Provider 通用
*
* 策略:智能字符估算,区分中文字符与 ASCII 字符
* - 中文字符(含全角标点、日韩文):1 字符 ≈ 1.5 token
* - ASCII 字符(英文、数字、半角符号):4 字符 ≈ 1 token
* - 其他 Unicodeemoji 等):1 字符 ≈ 1 token
*
* 对比旧的 `length / 2` 方案:
* - 中文场景:估算准确度从 ~50% 提升到 ~90%
* - 英文场景:从偏低变为接近真实
* - 混合场景:更贴近实际 token 消耗
*
* 仍为估算值(无 tiktoken 依赖),但留了 80% 触发阈值的缓冲。
*/
// 中日韩统一表意文字 + 全角标点 + 日文假名 + 韩文谚文
const CJK_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\uff00-\uffef\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/;
/**
* 估算字符串的 token 数
* @param text 待估算的字符串
* @returns 估算的 token 数
*/
export function estimateStringTokens(text: string): number {
if (!text || text.length === 0) return 0;
let cjkCount = 0;
let asciiCount = 0;
let otherCount = 0;
for (const ch of text) {
if (CJK_REGEX.test(ch)) {
cjkCount++;
} else if (ch.charCodeAt(0) < 128) {
asciiCount++;
} else {
otherCount++;
}
}
// 中文字符 1.5 token/字,ASCII 0.25 token/字,其他 1 token/字
return Math.ceil(cjkCount * 1.5 + asciiCount * 0.25 + otherCount);
}
/**
* 估算多条消息的总 token 数
*
* 每条消息额外加 4 token 的结构性开销(role、分隔符等,参考 OpenAI 规范)
*
* @param messages 消息列表
* @returns 估算的 token 数
*/
export function estimateMessagesTokens(messages: Array<{
content: string;
reasoningContent?: string;
toolCalls?: Array<{ args: Record<string, unknown> }>;
}>): number {
let total = 0;
for (const msg of messages) {
total += estimateStringTokens(msg.content);
if (msg.reasoningContent) total += estimateStringTokens(msg.reasoningContent);
if (msg.toolCalls) {
for (const tc of msg.toolCalls) {
total += estimateStringTokens(JSON.stringify(tc.args));
}
}
// 每条消息的结构性开销(role、分隔符)
total += 4;
}
return total;
}