Repository navigation
Releases: Faide-cyber/dsh-workbuddy
Release list
v1.0.22
国内版又被整批拦截了一轮,这次找到的是根本原因,不是再打一个补丁。
1. 换行断点改用真实换行
1.0.18/1.0.19 用的是不换行空格 U+00A0 把字面串"打断",这一版实测发现它已经被静默清零了。对同一串 112 字符的最小触发指纹做四组对照:
| 变体 | 结果 |
|---|---|
| 原文 | 400 11128 |
| 空格 → U+00A0(1.0.18/1.0.19 线上形态) | 仍 400 |
| 空格 → U+200B | 400 |
空格 → \n |
200 |
空格 → \t |
200 |
网关在匹配前会归一化空白(NBSP 当空格、ZWSP 直接剥掉)。结论:用"不可见空白"做反指纹,一定会被下一次升级吃掉。断点改成真实换行后,即便网关继续归一化也拦不住。
2. 中文段落此前是零覆盖
旧分隔只在 char === ' ' 处动手。真实国内 system(9414 字符)里有 2275 个汉字、却只有 1071 个空格 —— 可换点仅 144 个,中文长句等于完全没处理,而网关匹配的正是逐字符字面串。
现在按 Unicode 宽字符段(CJK / 假名 / 韩文 / 全角)插入换行,触点在「前一字符与当前字符都是宽字符、且当前字符不是行首标点」处,所以不会出现以 , 或 。 开头的行。插入而非替换 —— 汉字一个不动。
3. 新增语义层:表驱动窄改写,对空白归一化免疫
src/fingerprints.ts,改的是词,不是空白,所以网关怎么归一化空白都不影响它。同时删掉了旧的身份横幅正则:它锚定句首的 You are an AI agent powered by DeepSeek Harness,而当前 DSH 的首段早已变成 You are a coding agent powered by the deepseek-v4.1-flash model. —— 旧正则在新版本上根本不命中,是死代码。
每条登记都带实测日期与证据,并有测试断言「没有日期的条目进不了表」「改写后的文本不得再含登记串」。无命中时逐字节返回原字符串,不破坏上游前缀缓存;分隔器是幂等的不动点。
4. 出站入口审计
全仓 /v2/chat/completions 只有两处:chatStream(全部真实流量)与 probeEffort(身体写死 PROBE_PROMPT,构造上安全)。后者补了文档闸门。
验证
tsc双配置 0;19 文件 / 163 测试全绿。- 离线喂真实国内 system(9414 字符,走构建产物):登记串命中 0/0、去掉空白后字符同序、无行首中文标点、不动点、最长连续段 1304 → 67、长度 9414 → 9432(+0.19%)。
- 已知上限(如实写出):无空格的长 ASCII 串(URL、base64、
a/b/c斜杠串)打不断;换行层只在国内区启用。
升级方式
插件市场更新,或 dsh plugin install dsh-workbuddy@1.0.22;升级后请从托盘完整重启 DSH。
v1.0.21
Fixed
- The 刷新 button appeared to do nothing to the credit figure. The cause was caching, not the network: the status route caches a per-account credit snapshot for the active/inactive interval from the settings page (15 minutes for the selected account by default), and the card's 刷新 button issued the same GET as its 60-second poll — while that cache was fresh, a click could only return the old number. 刷新 now sends
?refresh=1, which bypasses the credit TTL and reads upstream for real, while the poll keeps using the cache. The status response also gainedCache-Control: no-storeso a browser cannot cache a live document either. - The third README highlight was ambiguous: "education accounts are marked as unsupported" reads as "the entire education edition is unsupported". It is a sub-feature difference — the upstream refuses check-in and growth tasks for education accounts as enterprise accounts (
daily-checkinanswers400 code 10001, the growth endpoints 403), while sign-in, multi-account, model catalog, chat and credits all work normally. Reworded to the requested phrasing: the accounts line now says education accounts are supported, and the one-click check-in line drops the negation.
修复
- 「刷新」按钮点了积分不动。根因是缓存不是网络:状态路由按账号缓存积分快照,TTL 就是设置页那两个刷新间隔(当前账号默认 15 分钟),而「刷新」按钮与 60 秒轮询调的是同一个 GET——缓存还新鲜时点击只能读回旧值。现在「刷新」带
?refresh=1绕过 TTL 真正回源,轮询照旧走缓存;响应同时加Cache-Control: no-store。 - README 亮点第 3 条措辞有歧义:「教育公益版标记为不支持」被读成「整个教育版不支持」。实际是子功能差异——上游对教育公益版按企业账号拒绝签到与成长任务(
daily-checkin返回400 code 10001,成长接口 403),登录、多账号、模型目录、聊天、余额全部照常。已按用户给的措辞改成「已支持接入教育公益版」,并从一键签到条删掉该否定句。
v1.0.20
Changed
- Peer ranges for the seven
@deepseek-ai/dsh-*packages now use explicit||branches instead of a caret over a prerelease floor. DSH's loader passesincludePrereleaseand so admitted the old spelling, but plainnpm install/pnpm resolves with ordinary semver — and^0.2.0-rc.2carries its prerelease tag on the0.2.0tuple, so it never reaches0.2.1-rc.3and raisedERESOLVE. The new spelling is>=0.2.0-rc.2 <0.2.1-0 || >=0.2.1-rc.1 <0.3.0-0, measured to produce identical verdicts in both modes while still stopping at the 0.3 line. - Added
engines.dsh, spelled identically to those peer ranges. The plugin market's compatibility badge reads this field (from an npm manifest, not the repository), so two spellings of one contract would drift; a test asserts they are equal.
No functional change: prepareChatBody, the fingerprint break and the conversation headers are untouched.
变更
- 七处
@deepseek-ai/dsh-*peer 从^0.2.0-rc.2改成显式||分支。DSH 闸门用includePrerelease所以旧写法能过,但 npm/pnpm 走普通 semver——^0.2.0-rc.2的预发布标签挂在0.2.0元组上,够不到0.2.1-rc.3,安装会报ERESOLVE。新写法>=0.2.0-rc.2 <0.2.1-0 || >=0.2.1-rc.1 <0.3.0-0实测两种模式判定一致,且仍挡住 0.3。 - 新增
engines.dsh,与上述范围逐字相同——市场兼容性角标读的是这个字段(读 npm 包 manifest,不读仓库),两处不同写法会漂移,故用测试断言二者相等。
无功能改动:prepareChatBody、指纹打断与会话头均未触碰。
v1.0.19
Fixed
- The 1.0.18 fingerprint break had a gap. Measured against the live gateway, the filter scans
system,developerandassistanttext — and does not scanuserortool. 1.0.18 rewrote onlysystem, so whenever an assistant reply quoted DSH's own prompt (an entirely ordinary thing for a model to do), the intact run came back on the following turn: the system prompt was already clean and the request was still refused with400 code 11128. Assistant content is broken now too.userandtoolstay untouched on purpose — those carry the user's own words and file contents, and a no-break space there could be written straight back into a file by the model.
修复
- 1.0.18 的指纹打断有个缺口。实测网关扫的是
system、developer和assistant,不扫user与tool。1.0.18 只改了system,所以只要助手在回复里引用过 DSH 自己的提示词(模型很自然会做的事),被打断的子串下一轮就会重新出现——system 明明已经干净,请求照样 400code 11128。现在 assistant 正文也一并打断。user与tool保持原样是有意的:那里是用户自己的文字与文件内容,混进不换行空格会被模型写回文件。
v1.0.18
Fixed
- Domestic requests failed with 400
code 11128again: the domestic gateway stopped matching only the identity banner and now matches literal character runs from DSH's own prompt (the smallest run it rejected was 111 characters). Rewording runs one at a time cannot win that race, so the plugin breaks them instead: before forwarding, one space every so often in a domestic system message becomes a no-break space, so no literal run survives intact while the prompt's words, meaning and length are unchanged. System messages only, so no odd space can reach a file through a write the model performs. - DSH 0.2.1 refused to load the plugin: seven
@deepseek-ai/dsh-*peers were pinned to the exact0.2.0-rc.2, which DSH 0.2.1's compatibility check read as incompatible and rejected the whole row. They are^0.2.0-rc.2now (admits 0.2.x, stops at 0.3) and@earendil-works/pi-aiadmits both^0.87.1and^1.1.0. - Removed the
settings.register()call, which dsh-settings 0.2.1 deleted.
修复
- 国内版又重新每个请求都 400
code 11128:国内网关从「只认身份横幅」改成按字面连续子串匹配 DSH 自己提示词里的原文(实测最小触发串 111 字符)。逐个改词赢不了这场竞速,所以改成打断子串——转发前把国内 system 消息里每隔一段距离的空格换成不换行空格,任何连续子串都无法完整存活,而提示词文字、语义和字数都不变。只动 system 消息,避免 U+00A0 被写回文件。 - DSH 0.2.1 拒绝加载本插件:七处
@deepseek-ai/dsh-*peer 原本钉死0.2.0-rc.2,被兼容性检查整行拒绝。现改为^0.2.0-rc.2,@earendil-works/pi-ai放宽到^0.87.1 || ^1.1.0。 - 移除 dsh-settings 0.2.1 已删除的
settings.register()调用。
v1.0.17
Fixes
- Recognize the official domestic ype=ultimate account as Education.
- Read enterprise education quota from get-enterprise-user-usage.
- Keep Education accounts out of check-in and growth actions.
- Preserve Personal account behavior.
v1.0.16
Added
- Read the official account "type" field and show Personal / Education edition badges for domestic accounts.
- Education accounts keep sign-in, account management, model catalogs, credits, and chat, while unsupported check-in/growth actions are hidden and blocked; personal check-in behavior is unchanged.
- Encrypted desktop auth files can contribute edition identity without replacing the plugin's stored token.
新增
- 读取官方账号 "type" 字段,区分并显示国内版的「个人版」与「教育公益版」徽标。
- 教育公益版保留登录、账号管理、模型目录、余额和聊天功能,并隐藏/阻止不适用的签到与成长操作;个人版签到行为不变。
- 桌面端加密 auth 文件也可提供版型身份,且不会覆盖插件已保存的 token。
v1.0.15
Fixed
- Add the X-Conversation-ID, X-Conversation-Request-ID, and X-Conversation-Message-ID headers required by the international gateway, fixing HTTP 400 code 11128
equest illegal. - Make the combined settings card open on the domestic region by default.
修复
- 补齐国际版渠道校验所需的会话头三元组,修复 code 11128。
- 插件面板默认从国内版开始。
v1.0.14
v1.0.13
修复
- 没选档位时正文仍漏
<analysis>/<summary>标签:1.0.10 只让「上游只声明单个固定reasoning.effort」的模型有了可选档位,但选择器没有默认值,DSH 发出的请求不带reasoningEffort;无档位时 pi-ai 只在thinkingLevelMap.off是字符串时才发reasoning_effort,我们的off为null→ 一个字段都不发 → 上游不建reasoning_content通道 → 模型把草稿写进正文。shim 现在兜底:fixedEffortOf()按当前区域目录取该模型的固定 effort,prepareChatBody()在请求无reasoning_effort时补上,已显式选档的请求不受影响。
Full changelog: https://github.com/Faide-cyber/dsh-workbuddy/blob/main/CHANGELOG.md