@wengine-ai/llms 2.3.239 → 2.3.2391
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/README.md +1 -1
- package/dist/cjs/server.cjs +1 -1
- package/dist/cjs/server.cjs.map +2 -2
- package/dist/esm/server.mjs +1 -1
- package/dist/esm/server.mjs.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -93,6 +93,7 @@ npm install -g @wengine-ai/claude-code-router-next@latest && ccr restart
|
|
|
93
93
|
|
|
94
94
|
| 版本 | 发布内容 |
|
|
95
95
|
| --- | --- |
|
|
96
|
+
| **v2.3.2391** | <ul><li>**用量按日统计按本地时区分组**: `byDay` 此前取 UTC 日期,本地 0:00–8:00 的请求(UTC 仍是昨天)被归到前一天——表现为「过了零点后昨天的消耗还在涨、今天的偏少」;改用 `date(timestamp,'localtime')` 按进程时区分组,历史记录无需迁移即自动重新归类。</li></ul> |
|
|
96
97
|
| **v2.3.239** | <ul><li>**供应商慢网探测与黄色 ⚠️ 告警**: 后台对每个供应商的 `/models` 可达性探测现在记录延迟,超过 `PROBE_SLOW_THRESHOLD_MS`(默认 3000ms)在 provider 卡片显示黄色 ⚠️;`GET /api/providers/health` 追加 `probes`,手动探测返回 latency/status/isSlow。慢但成功不开熔断,仅作 UI 提示。</li><li>**用量汇总改 SQL 聚合,UI 不再随机卡顿**: `/api/providers/quota`、`/api/usage` 的 summary 此前 `SELECT *` 全量物化 + JS 聚合阻塞 event loop,是 health/quota 随机卡顿的共享根因;改为 SQL `COUNT/SUM/AVG/GROUP BY`,语义不变。</li><li>**UI 刷新循环重做,杜绝请求重叠**: Providers health/quota 改 60s 自调度 single-flight;Usage 改 30s 串行队列(上一个未返回下一个顺延);`/api/clients` 仅 mount 刷新(操作后复用响应、不再 visibility 补拉);页面隐藏时暂停。</li><li>**Image 路由根因修复**: image agent 此前在路由前改写 `req.body.model`,导致用量记录丢失客户端真实模型(如 ccr-opus)并绕过 family image 路由;现按客户端原始模型识别 family 路由图片。同时修复 `promoteToolResultImages` 把所有数组型 tool_result 内容替换为占位符、丢失文本/结构化内容的问题。</li><li>**移除已弃用的 Codex 多账号管理**: 删除账号列表、切换、后台自动维护及对应 API/CLI/UI;Codex 仍作为普通 provider/client 完整支持(检测、`/v1/responses`、transformer、takeover、用量归属),历史账号文件与 `~/.codex/auth.json` 保持不动。</li><li>**路由优先级:模型族优先于 explicit `provider,model`**: 开启 family routing 时请求先走模型族映射,命中即用;family 未命中才解析客户端显式指定,最后落默认路由。</li></ul> |
|
|
97
98
|
| **v2.3.238** | <ul><li>**更新成功后服务自动重启**: 修复 `performUpdate` 跑完 `npm install -g` 只返回“请手动重启”、从不真正重启的问题;现在成功后复用 `/api/restart` 的自重启模式自动重启服务,前端轮询 `checkForUpdates` 返回 `hasUpdate:false` 后自动刷新页面加载新前端。</li><li>**更新请求并发锁**: 新增模块级 `updateInProgress` 守卫,刷新页面丢失 UI 状态后再次点击“立即更新”不会再触发第二次 `npm install -g`。</li><li>**超时文案补全包名**: `app.update_timeout` 改为“手动执行 `npm install -g @wengine-ai/claude-code-router-next@latest`”,照抄即可成功。</li></ul> |
|
|
98
99
|
| **v2.3.237** | <ul><li>**更新操作显示进度并限制等待时间**: 点击“立即更新”后禁用弹窗按钮并显示“更新中…”状态,避免重复安装;前端请求与后端 `npm install -g` 均设置 5 分钟超时,后端输出缓冲提高到 4 MB,超时会显示可读错误而非永久挂起。</li><li>**精简 Claude 项目指引**: 删除可由 manifests、CLI help 和仓库结构直接推导的常驻说明,保留非显然的安全、发布与架构约束,减少每次会话的固定上下文开销。</li></ul> |
|
|
@@ -102,7 +103,6 @@ npm install -g @wengine-ai/claude-code-router-next@latest && ccr restart
|
|
|
102
103
|
| **v2.3.233** | <ul><li>**修复「立即更新」点击失败(404)**: UI `ApiClient` 的 `baseUrl` 已是 `/api`,但 `performUpdate()` 又传入 `/api/update/perform` 导致实际请求变成 `/api/api/update/perform`;现改为 `/update/perform`,更新请求重新落到服务端 `/api/update/perform`。</li><li>**修复更新弹窗永远显示「暂无更新日志」**: `checkForUpdates` 此前 `changelog` 恒为空字符串。现在检测到新版本时,优先从已发布 npm 包对应版本 README 的 changelog 表提取摘要,取不到再 fallback 到 GitHub `CHANGELOG.md` 对应版本段,两级都失败才回退兜底文案,网络错误不影响版本检查。</li></ul> |
|
|
103
104
|
| **v2.3.232** | <ul><li>**严格项目级路由成为权威边界**: 项目配置非空 `Router` 后,目标缺失、格式错误、被禁用、不健康或额度耗尽不再静默回落到全局,而是返回稳定错误码;项目内显式 fallback 仍可用,同时关闭全局 Router/custom router、全局 fallback、客户端与 subagent model override 等项目外逃逸路径。</li><li>**Provider 级代理策略**: 新增顶层 `PROXY_GLOBAL_ENABLED` 与 provider 级 `proxy_enabled`;全局关闭时仅显式标记的 provider 使用共享 `PROXY_URL`,其余直连,未配置或开启时保持全部走代理的旧行为。推理、fallback、健康探测、额度查询、wakeup、provider API tokenizer 等出站请求统一遵循该策略。</li><li>**代理安全校验与 UI 控制**: 保存配置前仅允许 `http://`、`https://`、空值或环境变量占位符,非法协议/畸形 URL 逐项报错且不覆盖原配置;设置页新增「全局生效」开关、provider 卡片新增独立代理开关,并提示仅使用可信代理。ProxyAgent 改为按 URL 缓存复用,关闭时释放,日志自动脱敏代理凭据。</li><li>**per-client adapters 与 pi 上下文路由**: runtime 下沉到 core 并用 adapter 统一 Claude Code、Codex、pi、qwen-code、opencode 的差异;pi 新增 `extendedContextRatio`(默认 80%),不再生成/消费 `[1m]` 后缀,longContext 改用绝对阈值链。</li><li>**修复严格路由、客户端识别与用量回归**: 畸形项目 target 不再逃逸全局;Codex Responses 请求不再被误判为 Claude Code;修复非流式 `upstreamModel` 丢失、失败请求串用上一请求 tokens、`response.completed` 将 usage merge base 归零、项目路由失败清除会话用量基线等问题。</li><li>**修复 runtime 生命周期与错误处理**: `createCcrServer({ port })` 正确采用传入端口,401/403 认证不再挂起,provider/transformer/tokenizer 初始化完成后才监听,preset 注册失败不再静默吞掉。</li></ul> |
|
|
104
105
|
| **v2.3.231** | <ul><li>**项目级接管默认仅接管 Claude Code**: 此前打开项目「CCR 接管」默认接管全部客户端(Claude Code、pi、qwen-code、opencode),会把 `.pi/settings.json`、`.qwen/settings.json`、`opencode.json` 等配置写进项目目录(opencode 首次运行还会自行生成 `AGENTS.md`),污染项目根目录;现在所有默认路径(主开关、多选清空、legacy `enabled: true`)都只接管 Claude Code,其余客户端在多选中显式勾选才接管。</li><li>**修复「检查更新」永远提示已是最新(双重 bug)**: 后端 `checkForUpdates`/`performUpdate` 硬编码了已从 npm unpublish 的旧包名 `claude-code-router-next`,`npm view` 404 被 catch 静默吞掉、恒返回「无更新」,「立即更新」也因同样的错包名安装失败,现改为从 `package.json` 动态读取包名(`@wengine-ai/claude-code-router-next`),今后改包名不会再失效;另外前端更新弹窗条件要求 `changelog` 非空而后端该字段恒为空串,即使有新版本也不弹窗,现去掉该强制判断(弹窗内已有「暂无更新日志」兜底文案)。</li><li>**发布确认点闸门(release gate)**: `scripts/release.sh` 新增 `validate_release_docs`,发布前(含 dry-run)强制校验:6 个 `package.json` 版本一致、`CHANGELOG.md` 有该版本的非空段落、两份 README 表格有该版本行、版本号严格大于 npm 已发布 latest(逐段数字比较,registry 不可达时警告跳过);任一不满足即中止发布。</li><li>**版本号策略:多位 patch 日常小迭代**: 自本版本起日常小迭代在 patch 段追加一位数字(`2.3.23` → `2.3.231` → `2.3.232`),避免每日发布推高主版本数字;patch 按数字比较,用过 `2.3.23x` 后下一个功能版本是 `2.3.240`(`2.3.24` 会被闸门当降级拦截)或直接升 `2.4.0`。</li></ul> |
|
|
105
|
-
| **v2.3.23** | <ul><li>**修复状态栏 token 速率虚高(撞到 999 上限)**: `ccr statusline` 的 token 速率常显示几百、极端撞到 999 上限,与「用量统计」的几十 t/s 对不上。根因是 token-speed 插件流式过程中每秒上报的是「最近 1 秒到达的 token 数」滑动窗口值,而 SSE delta 常成批到达(同一时间戳)使瞬时计数虚高;现改为与用量统计同一套解码平均公式(`输出 token ÷ (总耗时 − TTFT)`)上报,速率随流式收敛到最终值、与用量统计一致,并移除失效的滑动窗口记账。</li><li>**状态栏默认改为无图标表格风格**: 默认主题不再带装饰图标,模块之间改用细竖线 `│` 分隔,呈简洁表格样式,默认模块顺序为「模型 │ 工作目录 │ git 分支 │ 上下文进度条 │ token 速率 │ 会话总 token」。动机是歧义宽度的 emoji 图标(如闪电 `⚡` U+26A1)会让 Claude Code 误算状态栏显示宽度、在双击等重绘时产生数字重影/位移;改用定宽字符或不带图标可避免。图标仍支持在 UI 中自定义。</li><li>**修复 UI 状态栏图标无法删除 + 旧圆圈模块迁移**: 切换所选模块时图标搜索框(`IconSearchInput`)不随 `value` 同步、与模块真实图标脱节导致看似删不掉,现已在 `value` 变化时同步;同时加载配置时把旧 `contextCircle` 模块迁移为 `contextBar`,配置弹窗显示长条进度条而非旧圆圈图标。</li><li>**`build:ui` 构建后同步产物到 CLI/根 dist**: `pnpm build:ui` 现会把 `index.html` 同步到 `packages/cli/dist` 与根 `dist`,使单独运行 `build:ui` 也能更新本地运行中的 ccr 实际读取的包。</li></ul> |
|
|
106
106
|
|
|
107
107
|
> 仅保留最近 10 个版本,更早版本的发布摘要见 [CHANGELOG-archive.md](./CHANGELOG-archive.md),完整详细变更记录见 [CHANGELOG.md](./CHANGELOG.md)。
|
|
108
108
|
|
package/dist/cjs/server.cjs
CHANGED
|
@@ -396,7 +396,7 @@ ${this.toMarkdown(s,t+1)}`:`${o}${r}: ${s}`).join(`
|
|
|
396
396
|
AVG(CASE WHEN status = 'success' AND ttft IS NOT NULL THEN ttft END) AS avgTtft,
|
|
397
397
|
AVG(CASE WHEN status = 'success' AND tokens_per_second IS NOT NULL THEN tokens_per_second END) AS avgTokensPerSecond
|
|
398
398
|
FROM usage_records ${t.sql}
|
|
399
|
-
`).get(...t.params);return{totalRequests:o.totalRequests,successCount:o.successCount,errorCount:o.totalRequests-o.successCount,totalInputTokens:o.totalInputTokens,totalOutputTokens:o.totalOutputTokens,totalCacheReadInputTokens:o.totalCacheReadInputTokens,totalCacheCreationInputTokens:o.totalCacheCreationInputTokens,avgTtft:o.avgTtft!=null?Math.round(o.avgTtft):null,avgTokensPerSecond:o.avgTokensPerSecond!=null?Math.round(o.avgTokensPerSecond):null,byModel:nt(n,t,"model"),byProvider:nt(n,t,"provider"),byScenario:nt(n,t,"scenario_type"),byFamily:nt(n,t,"model_family || '/' || scenario_type","model_family IS NOT NULL AND model_family != ''"),byDay:nt(n,t,"
|
|
399
|
+
`).get(...t.params);return{totalRequests:o.totalRequests,successCount:o.successCount,errorCount:o.totalRequests-o.successCount,totalInputTokens:o.totalInputTokens,totalOutputTokens:o.totalOutputTokens,totalCacheReadInputTokens:o.totalCacheReadInputTokens,totalCacheCreationInputTokens:o.totalCacheCreationInputTokens,avgTtft:o.avgTtft!=null?Math.round(o.avgTtft):null,avgTokensPerSecond:o.avgTokensPerSecond!=null?Math.round(o.avgTokensPerSecond):null,byModel:nt(n,t,"model"),byProvider:nt(n,t,"provider"),byScenario:nt(n,t,"scenario_type"),byFamily:nt(n,t,"model_family || '/' || scenario_type","model_family IS NOT NULL AND model_family != ''"),byDay:nt(n,t,"date(timestamp, 'localtime')"),byClient:nt(n,t,"CASE WHEN client_type IS NULL OR client_type = '' THEN 'unknown' ELSE client_type END")}}function zt(n){let e=Ht(),t=no(n);br.run(Di(t)),Fi(e)}function Tr(n){let e=Ht(),t=Ui(n),o=Number.isFinite(n.page)&&n.page>0?Math.floor(n.page):1,r=Number.isFinite(n.pageSize)&&n.pageSize>0?Math.min(Math.floor(n.pageSize),El):50,s=(o-1)*r,i=e.prepare(`SELECT COUNT(*) AS count FROM usage_records ${t.sql}`).get(...t.params),l=e.prepare(`SELECT * FROM usage_records ${t.sql} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t.params,r,s),a=ji(e,n);return{records:l.map(Rl),summary:a,total:i.count,page:o,pageSize:r}}function Bt(n,e,t){let o=Ht();return ji(o,{startTime:n,endTime:e,status:t})}function Cr(n){let e=Ht();if(!n){e.prepare("DELETE FROM usage_records").run();return}e.prepare("DELETE FROM usage_records WHERE timestamp < ?").run(n)}function Ol(){be&&(be.pragma("wal_checkpoint(TRUNCATE)"),be.close(),be=null,br=null)}function $e(n){if(n==null)return null;if(typeof n=="number")return n;let e=parseFloat(String(n));return isNaN(e)?null:e}function vr(n){let e=(0,Ne.join)((0,to.tmpdir)(),"claude-code-router"),t=(0,Ne.join)(e,`session-${n}.json`);if((0,re.existsSync)(t))try{let o=(0,re.readFileSync)(t,"utf-8"),r=JSON.parse(o);return{ttft:$e(r.timeToFirstToken),tokensPerSecond:$e(r.tokensPerSecond)}}catch{}try{let o=(0,re.readdirSync)(e),r=new RegExp(`^session-${n}-\\d+\\.json$`),s=o.filter(i=>r.test(i));if(s.length>0){let i=s.sort().reverse(),l=(0,Ne.join)(e,i[0]);try{let a=(0,re.readFileSync)(l,"utf-8"),c=JSON.parse(a);return{ttft:$e(c.timeToFirstToken),tokensPerSecond:$e(c.tokensPerSecond)}}catch{return{ttft:null,tokensPerSecond:null}}}}catch{}return{ttft:null,tokensPerSecond:null}}function Al(n,e,t){return Ht().prepare("SELECT MIN(timestamp) AS timestamp FROM usage_records WHERE provider = ? AND timestamp >= ? AND timestamp <= ?").get(n,e,t)?.timestamp??void 0}var re,Ne,to,Ni,eo,gl,kr,hl,yl,_l,Mi,be,br,$i,Pl,El,Jt=w(()=>{"use strict";re=require("fs"),Ne=require("path"),to=require("os"),Ni=Y(require("better-sqlite3"),1),eo=(0,Ne.join)((0,to.homedir)(),".claude-code-router","data"),gl=(0,Ne.join)(eo,"usage.sqlite"),kr=(0,Ne.join)(eo,"usage.jsonl"),hl=1,yl=180,_l=3600*1e3,Mi="legacy_usage_jsonl_migrated_at",be=null,br=null,$i=0;Pl=`
|
|
400
400
|
COUNT(*) AS count,
|
|
401
401
|
COALESCE(SUM(CASE WHEN status = 'success' THEN input_tokens ELSE 0 END), 0) AS inputTokens,
|
|
402
402
|
COALESCE(SUM(CASE WHEN status = 'success' THEN output_tokens ELSE 0 END), 0) AS outputTokens,
|