From d19e49de1f768e73dffd68bbb298f64a8e27a55e Mon Sep 17 00:00:00 2001 From: NaturePorter Date: Fri, 13 Nov 2026 16:05:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=9F=BA=E7=A1=80=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E6=97=A0=E6=97=A5=E9=A2=9D=E5=BA=A6=E6=97=B6=E9=A2=9D=E5=BA=A6?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=95=B4=E5=BC=A0=E6=8A=A5=E9=94=99=EF=BC=9B?= =?UTF-8?q?basic=20=E6=A8=A1=E5=9E=8B=E6=94=B9=E6=A0=87=E3=80=8C=E5=85=8D?= =?UTF-8?q?=E8=B4=B9=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 14 ++++++++++++++ README.md | 14 ++++++++++---- docs/internals.md | 9 ++++++--- docs/monkeycode-model-billing.md | 19 +++++++++++++------ package.json | 2 +- src/monkeycode/catalog.mjs | 7 ++++++- src/monkeycode/credits.mjs | 16 ++++++++++++---- src/monkeycode/runtime.mjs | 6 +++++- tests/catalog.test.mjs | 27 +++++++++++++-------------- tests/monkeycode.test.mjs | 27 +++++++++++++++++++++++++++ tests/multi-provider.test.mjs | 4 ++-- 11 files changed, 109 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4427019..762d263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ > 每个版本一节,**一条一行**,说用户能感知的变化。 > 格式与规矩见 [UPDATING.md](./UPDATING.md)。 +## 0.2.45 — 2026-11-13 + +**修:基础会员没有日额度时额度卡片整张报错「暂时无法获取额度」** + +- 平台套餐调整:基础会员改为永久免费、**不赠送每日额度**(官方前端 + `dailyQuotaBasic: "不赠送额度"`,Pro / Ultra 仍是 100M / 300M 每天);这类账号钱包里 + `daily_token_limit` / `daily_token_balance` 恒为 0,插件照旧画「每日额度」窗口,被额度构造器判 + `limit > 0` 不成立而抛错,连「积分余额 / 今日消耗」一起看不到 +- 现在上限为 0 时不画这条窗口:卡片照常显示积分余额与今日消耗 +- 模型后缀随套餐改名:`monkeycode-basic/…` 标 `· 免费`(平台叫「免费使用」), + `monkeycode-pro` / `monkeycode-ultra` 才是 `· 每日额度`;旧缓存读出即重算,不用重拉目录 +- 档位反推表只保留 `pro: 100M / ultra: 300M`:基础会员日额度为 0,不能再靠钱包数值反推档位 +- 回归测试锁住 0/0 形态不再冒成 `usage.error`,并锁住 0/0 账号仍能读额度 + ## 0.2.44 — 2026-11-09 **新增:国内站额度卡片显示「今日消耗」** diff --git a/README.md b/README.md index 7bd9b20..0722e6f 100644 --- a/README.md +++ b/README.md @@ -131,12 +131,13 @@ | 后缀 | 含义 | 上游 id 形态 | |---|---|---| -| `· 每日额度` | 走订阅档位的每日 token 额度(basic / pro / ultra 三档按权限放开) | `monkeycode-basic/…`、`monkeycode-pro/…`、`monkeycode-ultra/…` | +| `· 免费` | 基础会员免费档可用的模型(basic 模型;2026-11-13 起基础会员不再赠送日额度) | `monkeycode-basic/…` | +| `· 每日额度` | 走订阅档位的每日 token 额度(pro / ultra 按权限放开) | `monkeycode-pro/…`、`monkeycode-ultra/…` | | `· 积分` | 直接扣积分 | 不带前缀 | - **每日额度用完之后,还是这条模型继续扣积分** —— 不会"跳到另一条模型"上。后缀只说明这条模型**主要**走哪种计费, 账号级开关「额度耗尽后消耗积分」默认就是开的(可在网页控制台关掉) -- **每日额度与积分是同一个账号的两条读数**,不是三个独立额度池:三档的差别是**能调哪些模型**,额度只有一个当日读数 +- **每日额度与积分是同一个账号的两条读数**,不是三个独立额度池:档位的差别是**能调哪些模型**,额度只有一个当日读数 - **积分孪生默认隐藏**:同一个模型如果既有档位条目又有积分条目,列表里只留档位那条(它额度用完会自动转积分,能力是超集)。 怀疑两档其实不是同一权重时,设 `MAGPIE_MONKEYCODE_SHOW_CREDIT_TWINS=1` 让两条都出来 - **上下文窗口只声明有实测证据的**:DeepSeek 系 1,048,576(服务端 400 原文);没证据的(如 `glm-5`)不声明 —— @@ -153,7 +154,8 @@ | 供应商 | 代表模型 | 备注 | |---|---|---| -| `monkeycode` | `DeepSeek-Flash · 每日额度` / `GLM-5.3-Flash · 每日额度` | 档位条目按订阅权限放开;basic 调 pro/ultra 前缀会被上游 403 | +| `monkeycode` | `DeepSeek-Flash · 免费` / `GLM-5.3-Flash · 免费` | 基础会员免费档可用;pro / ultra 前缀按订阅权限放开,basic 调会被上游 403 | +| `monkeycode` | `DeepSeek-Flash · 每日额度` / `HY3 · 每日额度` | 走 pro / ultra 的每日 token 额度 | | `monkeycode` | `DeepSeek-Flash · 积分` / `GLM-5 · 积分` | 按积分计费;有档位孪生的会被隐藏 | | `baizhi` | `deepseek-v4-pro`、`deepseek-v4-flash` | 按量扣积分,1,048,576 上下文 | | `baizhi` | `glm-5` / `kimi-k2.6` / `qwen3.5-plus` 等 | 未知能力的模型照常列出,但不声明窗口 / 图片 | @@ -236,9 +238,13 @@ magpie plugin list **国际版点网页登录,界面报「已登录,但 magpie 无法列出它」?** 0.2.36 已修。根因不在国际站:magpie 的插件宿主只在登录结果带 `refresh` 字段时才把 oauth 登录写进 `plugin-auth.json`,缺这一格时界面照旧显示成功、账号却没落盘。升级后重登一次即可。 -**为什么模型列表里少了一条「· 积分」的?** 它和某个「· 每日额度」条目是同一个模型,默认只留档位那条。 +**为什么模型列表里少了一条「· 积分」的?** 它和某个「· 免费」/「· 每日额度」条目是同一个模型,默认只留档位那条。 想两条都看:设环境变量 `MAGPIE_MONKEYCODE_SHOW_CREDIT_TWINS=1` 再刷新。 +**为什么基础会员没有「每日额度」这条读数?** 2026-11-13 平台调整了套餐:基础会员改为永久免费、**不赠送每日额度** +(钱包里 `daily_token_limit` 恒为 0),Pro / Ultra 分别是每天 100M / 300M Token。基础会员的卡片只剩「积分余额 / 今日消耗」, +这是套餐本身,不是读取失败。 + **为什么看不到 pro / ultra 档的模型?** 这些模型需要对应订阅。插件按账号当前档位过滤目录,basic 账号不会看到没有权限的 pro / ultra 条目;这不是列表坏了,也不存在一个叫「已锁定」的标记。 **额度条显示「剩余额度未知」?** 平台接口暂时读不到(网络抖动或未登录态查额度)。推理不受影响,下一轮刷新会恢复。 diff --git a/docs/internals.md b/docs/internals.md index 48cc481..17fe088 100644 --- a/docs/internals.md +++ b/docs/internals.md @@ -390,7 +390,9 @@ oma_… 裸 token(缺密钥,请 三个细节: -- **每日额度只有上限与剩余都有才画**。缺剩余时把 0 当剩余,会让用户以为今天已经用光。 +- **每日额度只有上限与剩余都有、且上限 > 0 才画**。缺剩余时把 0 当剩余,会让用户以为今天已经用光; + 上限为 0 也不画——2026-11-13 起基础会员(免费档)钱包恒为 0/0,单独画一条 `limit: 0` 的窗口会被额度契约判不合法, + 整张卡片会变成「暂时无法获取额度」(Pro / Ultra 仍是 100M / 300M 每天)。 - **负余额**(真机见过 −8.191)不能直接喂进度条:改成 `balance: 0` + `display: "-8.191 积分(已透支)"`。 - `signIn` 不因 cookie 401 写 `expired`:额度走 cookie、推理走 `oma_`,cookie 失效不影响发消息;标 expired 会把还能用的号判死。 @@ -457,11 +459,12 @@ POST /api/v1/users/wallet/checkin {captcha_token} ### 显示名:一眼看出按什么计费 -`prettyModelName()` 给每条模型加后缀(2026-11-09 起): +`prettyModelName()` 给每条模型加后缀(2026-11-09 起;2026-11-13 按新套餐调整 basic): | 上游 `model` | 卡片显示名 | |---|---| -| `monkeycode-basic/deepseek-flash`、`monkeycode-pro/…`、`monkeycode-ultra/…` | `DeepSeek-Flash · 每日额度`(三档同名,差别在权限) | +| `monkeycode-basic/…` | `DeepSeek-Flash · 免费`(基础会员免费档,不赠送日额度) | +| `monkeycode-pro/…`、`monkeycode-ultra/…` | `HY3 · 每日额度`(走 100M / 300M 的当日额度) | | `deepseek-flash`(无前缀) | `DeepSeek-Flash · 积分` | `readCatalog()` 读出时会用当前的 `prettyModelName(apiId ?? name)` 重算 `displayName` —— diff --git a/docs/monkeycode-model-billing.md b/docs/monkeycode-model-billing.md index 4f4822d..91c2b9c 100644 --- a/docs/monkeycode-model-billing.md +++ b/docs/monkeycode-model-billing.md @@ -144,9 +144,13 @@ featureValues:{ … dailyQuotaBasic:"每天 10M Token", dailyQuotaPro:"每天 10 features:{ … dailyQuotaBasic:"每日额度:每天 10M Token", dailyQuotaPro:"每日额度:每天 100M Token", dailyQuotaUltra:"每日额度:每天 300M Token" … } ``` -与本地常量 **完全一致**:`src/monkeycode/credits.mjs:33` -`PLAN_DAILY_LIMIT = { basic: 10_000_000, pro: 100_000_000, ultra: 300_000_000 }`。 -(`resolveTier()` 正是用这个等式反推档位,见 `credits.mjs:179-188` —— 这条交叉验证成立。) +与本地常量 **完全一致**:`src/monkeycode/credits.mjs` + +> **2026-11-13 更正**:平台已改套餐 —— 基础会员(`basic`)变成永久免费、**不赠送每日额度** +> (前端 `dailyQuotaBasic: "不赠送额度"`、`status: "unsupported"`;真机 6 个 basic 账号钱包 +> `daily_token_limit` / `daily_token_balance` 全部为 0),只有 Pro 100M / Ultra 300M 仍成立。 +> 因此 `PLAN_DAILY_LIMIT` 现在只有 `{ pro, ultra }`,`basic` 只能由 `/users/subscription` +> 的 `plan` 字段判定,不能再靠日额度反推。A5 的原文保留为 11-09 的取证快照。 ### A6 · 档位与权限**只由 `model` 字符串前缀决定**(平台前端自己就是这么判的) @@ -357,9 +361,12 @@ function Xm(e){ const t=e?.remark?.trim(); return t ? jR(t) : Xc(e?.model) } ### 4.5 显示名契约 -1. **档位条目**:`<品牌>-<版本> · 每日额度`(把 `基础档/专业档/旗舰档` 换掉: - 用户要判断的是「这条吃不吃日额度」,档位名由账号自己决定,写进名字反而每次都要解释)。 - 若想保留档位信息,可写 `· 每日额度(基础)`,但**必须**先出现「每日额度」。 +> **2026-11-13 更新(覆盖下面第 1 条)**:`basic` 前缀改标 `· 免费` —— 基础会员不再赠送日额度, +> 平台模型选择器里 basic 模型标的就是「免费使用」;`· 每日额度` 只留给 `monkeycode-pro` / +> `monkeycode-ultra`。§4.4 表里的 `· 每日额度` 是 11-09 的取证快照,不再作为现行契约。 + +1. ~~**档位条目**:`<品牌>-<版本> · 每日额度`~~ → 现在只有 pro / ultra 标 `· 每日额度`, + basic 标 `· 免费`。 2. **无前缀条目**:`<品牌>-<版本> · 积分`(现状正确,不动)。 3. **转积分的提示不要塞进模型名**:它是**账号级状态**,读 `GET /api/v1/users/subscription` 的 `enable_credit_consumption`(A4), diff --git a/package.json b/package.json index 5c0dac0..be961c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "magpie-monkeycode", - "version": "0.2.44", + "version": "0.2.45", "description": "MonkeyCode 国内站 / 国际站 + 百智云 magpie 插件:百智云「本机导入」「浏览器登录」成功后自动开通并写入国内 MonkeyCode(后台执行、失败不影响百智云登录、按 uid 去重);百智云只保留这两条登录路,国内站只认百智云身份,国际站独立(API Key / 账号密码 / 本机导入 / 浏览器);支持双方邀请码、网关签名与「每日额度 / 积分」计费标识。", "type": "module", "main": "./index.mjs", diff --git a/src/monkeycode/catalog.mjs b/src/monkeycode/catalog.mjs index e326d1e..308f88e 100644 --- a/src/monkeycode/catalog.mjs +++ b/src/monkeycode/catalog.mjs @@ -69,9 +69,14 @@ const BRANDS = Object.freeze({ * 平台前端也是这个口径(`ja()` 取前缀、`Im()` 按 plan 判权限)。 * 日额度耗尽后三档一律默认自动转扣积分(平台「额度耗尽后消耗积分」开关,默认开), * 所以名字里该说的是「这条吃不吃日额度」,不是「基础/专业/旗舰」。 + * + * ⚠ 2026-11-13 起 basic 前缀不再标「每日额度」:平台把基础会员改成**永久免费、不赠送 + * 日额度**(官方前端 `dailyQuotaBasic: "不赠送额度"`、`status: "unsupported"`), + * 模型选择器里 basic 模型标的是「免费使用」。所以这条只说明「免费档可用」, + * 真正吃日额度的是 pro / ultra 前缀。 */ const TIERS = Object.freeze({ - "monkeycode-basic": "每日额度", + "monkeycode-basic": "免费", "monkeycode-pro": "每日额度", "monkeycode-ultra": "每日额度", }) diff --git a/src/monkeycode/credits.mjs b/src/monkeycode/credits.mjs index c338957..35f10ae 100644 --- a/src/monkeycode/credits.mjs +++ b/src/monkeycode/credits.mjs @@ -29,8 +29,15 @@ const MAX_POW_ATTEMPTS_TOTAL = 5_000_000 /** 订阅档位只认这三个值,其余一律当「档位未知」(不猜)。 */ export const PLAN_LABELS = Object.freeze({ basic: "Basic", pro: "Pro", ultra: "Ultra" }) -/** 每日额度的档位 → 计费 token 上限。 */ -export const PLAN_DAILY_LIMIT = Object.freeze({ basic: 10_000_000, pro: 100_000_000, ultra: 300_000_000 }) +/** + * 每日额度的档位 → 计费 token 上限。 + * + * ⚠ 只有 pro / ultra 有日额度。2026-11-13 核实:平台把 basic 改成**永久免费、不赠送额度** + * (官方前端 `dailyQuotaBasic: "不赠送额度"`,`status: "unsupported"`),这类账号钱包里 + * `daily_token_limit` / `daily_token_balance` 恒为 0。所以 0 **不能**反推成 basic —— + * basic 只认 `/users/subscription` 的 `plan` 字段。 + */ +export const PLAN_DAILY_LIMIT = Object.freeze({ pro: 100_000_000, ultra: 300_000_000 }) /** * 把用户可能粘贴的 cookie 串归一成可以直接放进 `Cookie` 头的值。 @@ -276,8 +283,9 @@ export async function fetchPlan(cookie, site, { fetchImpl = fetch, timeoutMs = 1 * * 1. `GET /api/v1/users/subscription` 的 `plan`(明确的说法,最可信); * 2. 该端点不给 plan 时(2026-11-04 国内站实测返回 undefined),用钱包的 - * `daily_token_limit` 反推 —— 三档的日额度是固定的 10M / 100M / 300M, - * 见 `PLAN_DAILY_LIMIT`。数值对不上就不猜。 + * `daily_token_limit` 反推 —— **只有 pro / ultra 能反推**(100M / 300M,见 + * `PLAN_DAILY_LIMIT`)。basic 现在没有日额度、钱包恒为 0,反推不出来, + * 只认第 1 条;数值对不上就不猜。 * * 用途只有一个:把模型目录收窄到这个账号真能吃的额度池(`filterByTier`)。 * 拿不到档位时**宁可不过滤**,也不要把列表清空。 diff --git a/src/monkeycode/runtime.mjs b/src/monkeycode/runtime.mjs index 795f643..2c3eaa7 100644 --- a/src/monkeycode/runtime.mjs +++ b/src/monkeycode/runtime.mjs @@ -269,7 +269,11 @@ async function readUsage(site, credential, fetchImpl) { const windows = [] // 每日额度:数量型窗口。span = 一天(上游不下发重置时刻,编一个 resetsAt 就是编造)。 // 只有上限与剩余都有才画(缺剩余时把 0 当剩余会让用户以为今天已用光)。 - if (wallet.dailyTokenLimit !== undefined && wallet.dailyTokenBalance !== undefined) { + // ⚠ 上限为 0 也不能画:按积分计费的账号(`enable_credit_consumption: true`)钱包里 + // `daily_token_limit` / `daily_token_balance` 恒为 0,画出来会被 `usageWindow` 判 + // `limit > 0` 不成立而抛 QuotaShapeError —— 整张额度卡片变成「暂时无法获取额度」 + // (2026-11-13 真机:6 个 basic 账号全部 0/0)。没有每日额度就是没有这条窗口。 + if (wallet.dailyTokenLimit !== undefined && wallet.dailyTokenLimit > 0 && wallet.dailyTokenBalance !== undefined) { windows.push(usageWindow({ name: "每日额度", amount: Math.max(0, wallet.dailyTokenLimit - wallet.dailyTokenBalance), diff --git a/tests/catalog.test.mjs b/tests/catalog.test.mjs index 89a07f8..ec3fe91 100644 --- a/tests/catalog.test.mjs +++ b/tests/catalog.test.mjs @@ -58,13 +58,12 @@ test("fetchCatalog:平台没有可用模型时报失败,不返回空表", as assert.equal(result.ok, false) }) -test("prettyModelName:档位一律标「每日额度」,无前缀才标「积分」", async () => { +test("prettyModelName:basic 标「免费」,pro / ultra 标「每日额度」,无前缀标「积分」", async () => { const { entryOf, prettyModelName } = await import("../src/monkeycode/catalog.mjs") - // 依据 docs/monkeycode-model-billing.md §4.5: - // - 三档(basic/pro/ultra)吃的都是同一个「当日免费额度」,耗尽后默认自动转扣积分 - // (官方前端「额度耗尽后消耗积分」开关,A1/A2/A5)—— 名字里该说的是「这条吃不吃日额度」; - // 档位名(基础/专业/旗舰)由账号自己的订阅决定,写进名字反而每次都要解释。 - assert.equal(prettyModelName("monkeycode-basic/glm-5.3-flash"), "GLM-5.3-Flash · 每日额度") + // 2026-11-13 平台口径变更:基础会员「永久免费、不赠送额度」 + // (官方前端 `dailyQuotaBasic: "不赠送额度"`,模型选择器里 basic 模型标「免费使用」), + // 所以 basic 前缀不能再标「每日额度」;只有 pro / ultra 吃日额度。 + assert.equal(prettyModelName("monkeycode-basic/glm-5.3-flash"), "GLM-5.3-Flash · 免费") assert.equal(prettyModelName("monkeycode-pro/hy3"), "HY3 · 每日额度") assert.equal(prettyModelName("monkeycode-ultra/qwen3.7-max"), "Qwen3.7-Max · 每日额度") // 无前缀 = 官方「付费模型 / 消耗积分使用」分组,直接扣积分(同上 A7)。 @@ -74,7 +73,7 @@ test("prettyModelName:档位一律标「每日额度」,无前缀才标「 assert.equal(prettyModelName(""), "") // 缓存条目上的 displayName 是同一套口径(读缓存时算出来的那个字段,用户看到的就是它)。 const entry = entryOf({ id: "u1", model: "monkeycode-basic/deepseek-flash", interface_type: "anthropic" }) - assert.equal(entry.displayName, "DeepSeek-Flash · 每日额度") + assert.equal(entry.displayName, "DeepSeek-Flash · 免费") }) test("probeCatalog:只有 200 才算能用,403/异常一律不可用", async () => { @@ -331,7 +330,7 @@ async function withCacheDir(fn) { } } -test("readCatalog ⑤:旧缓存的「基础档/专业档/旗舰档」读出即重算成「每日额度」,且只读不改文件", async () => { +test("readCatalog ⑤:旧缓存的「基础档/专业档/旗舰档」读出即重算成「免费 / 每日额度」,且只读不改文件", async () => { const { readCatalog } = await import("../src/monkeycode/catalog.mjs") await withCacheDir(({ dir, models }) => { const file = join(dir, "monkeycode-models-monkeycode.json") @@ -342,15 +341,15 @@ test("readCatalog ⑤:旧缓存的「基础档/专业档/旗舰档」读出即 assert.equal(catalog.fetchedAt, 1) assert.equal(catalog.tier, "basic", "落盘的档位要带回来(runtime 靠它收窄)") - // 三个档位一律「每日额度」;无前缀继续「积分」。 + // basic 前缀 = 「免费」,pro / ultra 前缀 = 「每日额度」;无前缀继续「积分」。 assert.deepEqual( catalog.models.map((model) => model.displayName), [ - "GLM-5.3-Flash · 每日额度", + "GLM-5.3-Flash · 免费", "HY3 · 每日额度", "Qwen3.7-Max · 每日额度", "DeepSeek-Flash · 积分", - "DeepSeek-Flash · 每日额度", + "DeepSeek-Flash · 免费", ], ) // 除了 displayName,其它字段一个字都不许动(uuid 还要用来区分记录)。 @@ -359,7 +358,7 @@ test("readCatalog ⑤:旧缓存的「基础档/专业档/旗舰档」读出即 models.map((model) => ({ ...model, displayName: model.displayName - .replace(/ · 基础档$/, " · 每日额度") + .replace(/ · 基础档$/, " · 免费") .replace(/ · 专业档$/, " · 每日额度") .replace(/ · 旗舰档$/, " · 每日额度"), })), @@ -381,7 +380,7 @@ test("readCatalog + filterByTier:重算后的目录照常去重(积分孪生 const narrowed = filterByTier(catalog.models, catalog.tier) assert.deepEqual(idsOf(narrowed), ["monkeycode-basic-glm-5-3-flash", "monkeycode-basic-deepseek-flash"]) // 留下来的那条也必须是重算过的名字(否则「去重对了、名字还是旧的」会漏网)。 - assert.equal(narrowed[1].displayName, "DeepSeek-Flash · 每日额度") + assert.equal(narrowed[1].displayName, "DeepSeek-Flash · 免费") // 逃生阀:只关去重,权限过滤照旧(basic 账号仍然看不到 pro / ultra)。 const previousOptOut = process.env.MAGPIE_MONKEYCODE_SHOW_CREDIT_TWINS @@ -394,7 +393,7 @@ test("readCatalog + filterByTier:重算后的目录照常去重(积分孪生 ) // 逃生阀下重算照样生效(改名与去重是两件事)。 assert.equal(escaped.find((model) => model.id === "deepseek-flash").displayName, "DeepSeek-Flash · 积分") - assert.equal(escaped.find((model) => model.id === "monkeycode-basic-deepseek-flash").displayName, "DeepSeek-Flash · 每日额度") + assert.equal(escaped.find((model) => model.id === "monkeycode-basic-deepseek-flash").displayName, "DeepSeek-Flash · 免费") } finally { if (previousOptOut === undefined) delete process.env.MAGPIE_MONKEYCODE_SHOW_CREDIT_TWINS else process.env.MAGPIE_MONKEYCODE_SHOW_CREDIT_TWINS = previousOptOut diff --git a/tests/monkeycode.test.mjs b/tests/monkeycode.test.mjs index 4c4604b..88bc3b7 100644 --- a/tests/monkeycode.test.mjs +++ b/tests/monkeycode.test.mjs @@ -166,6 +166,33 @@ test("额度:钱包型只给余额,数量型给 amount/limit,未配 cookie assert.equal(noCookie.windows.length, 0) }) +test("额度:每日额度上限为 0(按积分计费)时不画这条窗口,也不许把整张卡片变成错误", async () => { + const plugin = await makePlugin(site)({ client: {} }) + const auth = { type: "api", key: JSON.stringify({ ...credential, session_cookie: "sess", user_id: "u1" }) } + + const original = globalThis.fetch + globalThis.fetch = async (url) => { + const text = String(url) + if (text.endsWith("/api/v1/users/wallet")) { + // 2026-11-13 真机:`enable_credit_consumption: true` 的 basic 账号恒为 0/0。 + return Response.json({ code: 0, data: { balance: 20_400_000, daily_token_balance: 0, daily_token_limit: 0 } }) + } + if (text.endsWith("/api/v1/users/subscription")) { + return Response.json({ code: 0, data: { plan: "basic" } }) + } + throw new Error(`unexpected ${text}`) + } + try { + const usage = await plugin.auth.usage(async () => auth) + assert.equal(usage.error, undefined, "limit=0 不许冒成 usage.error") + assert.equal(usage.windows.some((w) => w.name === "每日额度"), false) + const credit = usage.windows.find((w) => w.name === "积分余额") + assert.equal(credit.balance, 20_400) + } finally { + globalThis.fetch = original + } +}) + // ── loader ─────────────────────────────────────────────────────────── test("loader:签名基于最终 body,且不把 SDK 的 x-api-key 带出去", async () => { diff --git a/tests/multi-provider.test.mjs b/tests/multi-provider.test.mjs index 0647ca1..6f4575f 100644 --- a/tests/multi-provider.test.mjs +++ b/tests/multi-provider.test.mjs @@ -1239,8 +1239,8 @@ const MONKEYCODE_FACTORIES = [ ] const UPGRADE_NAMES = { - "monkeycode-basic-glm-5-3-flash": "GLM-5.3-Flash · 每日额度", - "monkeycode-basic-deepseek-flash": "DeepSeek-Flash · 每日额度", + "monkeycode-basic-glm-5-3-flash": "GLM-5.3-Flash · 免费", + "monkeycode-basic-deepseek-flash": "DeepSeek-Flash · 免费", "qwen3-6-plus": "Qwen3.6-Plus · 积分", }