@huai_xin/dsh-workbuddy 0.1.13 → 0.1.14

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.
@@ -394,7 +394,7 @@ data: [DONE]
394
394
  | INTL scoped → `500`(openresty/APISIX,HTML 错误页) | 2026-10-21 起持续;`/v3/config` 正常 ✅ |
395
395
  | `glm-5.1` 图片能力两个端点矛盾 | scoped 报 `false`、`/v3/config` 报 `true`,实测能看图(📖 参考实现据此写了覆盖白名单) |
396
396
  | 目录包含渠道不服务的模型 | 见 `11102`(§6)✅ |
397
- | 长上下文下"说话说一半就收尾"(`finish_reason: stop`,无工具调用) | 上游/模型行为,**不是插件问题**。实测:同一提示、同一套工具、只改前面的对话长度 —— 0k 2/2 正常、30k 1/2(一次 181 字后 `stop`)、89k 1/2;每次 finish 诊断块都标 `workbuddy-intl/deepseek-v4.1-flash`。判据:流里**没有任何 tool-call 分片**、`finish_reason` 就是 `stop`(若丢帧会是 `tool_calls` 且能看到分片)。已排除:采样(四档温度 16/16 正常)、工具 schema/数量(70 个 / 单个 / 简化 schema 9/9 正常)、提示词校验(海外版无此错误,请求体按原样转发)。复现:`node test/live/long-context-probe.mjs 2`;排查:`node test/live/toolcall-audit.mjs <会话前缀>`、`long-context-probe.mjs`、`repro-probe.mjs`。缓解只有换模型/压缩上下文/回一句"继续" —— 合法的 `stop` 不能当错误重试。 |
397
+ | 长上下文下"说话说一半就收尾"(`finish_reason: stop`,无工具调用) | 上游/模型行为,**不是插件问题**。对外跟踪入口:[issue #1](https://github.com/2424830124/dsh-workbuddy/issues/1)(含两次真实截断的 `responseId`/`outputTokens` 与已排除项)。实测:同一提示、同一套工具、只改前面的对话长度 —— 0k 2/2 正常、30k 1/2(一次 181 字后 `stop`)、89k 1/2;每次 finish 诊断块都标 `workbuddy-intl/deepseek-v4.1-flash`。判据:流里**没有任何 tool-call 分片**、`finish_reason` 就是 `stop`(若丢帧会是 `tool_calls` 且能看到分片)。已排除:采样(五档 16/16 与 2–3/8 两个实验都无差别)、工具 schema/数量(70 个 / 单个 / 简化 schema 9/9 正常)、`prompt_cache_key` 与 `stream_options`(去掉后 1/8 vs 2/8)、提示词校验(海外版无 11128 之外的拦截,请求体按原样转发)。复现:`node test/live/long-context-probe.mjs 2`、`node test/live/repro-probe.mjs 3 deepseek-v4.1-flash 280000`;取证:`node test/live/session-tail-live.mjs <会话前缀> 8 dsh-model-picker`(读 `response.stopReason` 原话)。缓解只有换模型/压缩上下文/回一句"继续" —— 合法的 `stop` 不能当错误重试。 |
398
398
 
399
399
  ### 4.7 模型选择器里每一项元数据的来源
400
400
 
@@ -694,6 +694,22 @@ POST /v2/chat/completions {"model":"glm-4.6", …}
694
694
 
695
695
  结论:这是**行首锚定的品牌指纹**(「某 AI agent powered by &lt;品牌&gt; Harness」),不是内容审查。规避方式:把这一句改写成中性表述(本插件统一改写为 `You are an AI agent.`,两个部署都改)✅。
696
696
 
697
+ #### 7.1.1 规则扩大:整段 DSH 提示词被拦(2026-10-23)
698
+
699
+ 同一天再次实测:**完整的 DSH 系统提示词(5.7k 字符)整段被拦**,而短提示词通过。二分结果:
700
+
701
+ | 送什么 | 结果 |
702
+ | --- | --- |
703
+ | 完整 DSH 提示词(只做 7.1 的开头改写) | **拦(11128)** |
704
+ | 同一份,只去掉最后那段 Web GUI 开发指引 | 过 ✅ |
705
+ | 只送那一段(1002 字符) | 过 ✅ |
706
+ | 那一段的每一句单独送 | 全都过 ✅ |
707
+ | 中性提示词填充到 5.7k / 10k 字符 | 过 ✅(不是长度) |
708
+
709
+ 所以**不是一个词、也不是长度**,而是「提示词整体 + 那段开发指引」的组合命中。那段内容是 `pnpm run dev:web` / `apps/web` / HMR / "do not start a replacement server" —— **给改 harness 自身的人看的**,对一次聊天补全毫无用处,所以插件直接**整行删掉**,并把 `DeepSeek Harness` 统一改写成 `this harness`(顺序很重要:先删行再改名,否则模式匹配不到原文)。
710
+
711
+ > 注意:这条规则**会继续扩大**。再遇到 11128 时,用 `node test/live/cn-prompt-fingerprint.mjs` 二分定位新命中的段落,再决定删还是改,别猜。
712
+
697
713
  ### 7.2 其它渠道相关事实
698
714
 
699
715
  - `X-Conversation-ID` 可复用;一旦被判定为异常渠道,**换新会话标识无效**(实测:换标识 + 切备用主机仍被拒),但换一个**合法 system 提示词**立刻恢复 ✅。
@@ -930,6 +946,8 @@ provider 与全部 HTTP 路由都没注册,设置面板只剩一个 `HTTP 404`
930
946
  | `test/live/long-context-probe.mjs [次数] [模型]` | 只改上下文长度,看提前收尾率(可复现的对照实验) |
931
947
  | `test/live/context-size-probe.mjs [字符数…]` | 填充上下文实际值多少 token(网关 `inputTokens` 为准) |
932
948
  | `test/live/thinking-field-probe.mjs [次数] [模型] [部署]` | 带/不带 `thinking` 字段时思考量对比(档位才是开关) |
949
+ | `test/live/dsh-prompt-probe.mjs [次数] [字符数…]` | **用会话里存的 DSH 原版系统提示词** + 真实 70 工具集跑长上下文,看会不会调用工具(2026-10-23:0k/90k/280k 各 3 次,9/9 都调用 `read`) |
950
+ | `test/live/system-prompt-probe.mjs [次数]` | 判定上游是否注入/覆盖 system:两个代号实验 + 不给 system 时它自认是谁(答「DeepSeek」= 无厂商注入)+ 语言服从性 |
933
951
  | `test/live/request-structure.mjs` / `test/live/free-models.mjs` | 各厂商请求结构、免费档清单的逐字段试探 |
934
952
  | `test/live/verify-policy.mjs` | 实时目录扣掉台账里 `dead` 的判定后,两版的条目数对照 |
935
953
  | **契约与 UI 参考(写 UI 插件用)** | |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huai_xin/dsh-workbuddy",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "WorkBuddy model provider for DeepSeek Harness (international + China deployments)",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/adapter.js CHANGED
@@ -607,23 +607,34 @@ export class WorkBuddyAdapter {
607
607
  }
608
608
 
609
609
  /**
610
- * Neutralise the one system-prompt fingerprint the China gateway blocks.
610
+ * Neutralise the system-prompt fingerprints the China gateway blocks.
611
611
  *
612
- * Verified 2026-10-21 against `copilot.tencent.com`: a system message whose
613
- * text *begins* with `You are an AI agent powered by DeepSeek Harness`
614
- * (case-insensitive, trailing period optional) is answered with
615
- * `code 11128 Illegal API invocation from an unapproved channel`. The bare
616
- * phrase, a leading word, and the same sentence with another noun all pass,
617
- * so the rule is an anchored brand fingerprint rather than a content filter.
618
- * Rewriting that opening keeps every other instruction intact.
612
+ * Verified 2026-10-21 against `copilot.tencent.com`: a system message whose text
613
+ * *begins* with `You are an AI agent powered by DeepSeek Harness` is answered with
614
+ * `code 11128 Illegal API invocation from an unapproved channel`.
619
615
  *
620
- * Applied to both deployments: the international gateway accepts the
621
- * original wording, but one prompt shape for both routes is simpler to
622
- * reason about and cannot regress when the rule spreads.
616
+ * Verified again 2026-10-23: the rule now catches more of the harness prompt. The
617
+ * whole 5.7k-character prompt is rejected while a short one passes, and bisecting it
618
+ * shows the harness's Web-GUI development guidance at the end is part of what
619
+ * trips the check (dropping that paragraph unblocks the same prompt). That guidance
620
+ * is instructions for a coding session about the harness's own web shell — useless
621
+ * to a chat completion — so it is dropped for this route rather than rewritten.
622
+ * Brand mentions are generalised for the same reason.
623
+ *
624
+ * Applied to both deployments: the international gateway accepts the original
625
+ * wording, but one prompt shape for both routes is simpler to reason about.
623
626
  */
624
627
  sanitizeSystem(text) {
625
628
  if (typeof text !== 'string') return text
626
- return text.replace(/^[ \t\r\n]*you are an ai agent powered by deepseek harness\.?/i, 'You are an AI agent.')
629
+ return text
630
+ .replace(/^[ \t\r\n]*you are an ai agent powered by deepseek harness\.?/i, 'You are an AI agent.')
631
+ // Drop the Web-GUI development paragraphs: `pnpm run dev:web`, `apps/web`,
632
+ // the HMR receiver and the "do not start a replacement server" advice are all
633
+ // for editing the harness itself, and this route never needs them. This runs
634
+ // before the brand rename below, or the pattern would no longer match.
635
+ .replace(/[^\n]*(?:pnpm run dev:web|apps\/web|client-plugin HMR|DeepSeek Harness Web GUI|replacement server)[^\n]*\n?/gi, '')
636
+ .replace(/DeepSeek Harness/g, 'this harness')
637
+ .replace(/\n{3,}/g, '\n\n')
627
638
  }
628
639
 
629
640
  buildBody(options, model, entry, imageUrls) {