dsh-buddy-guard
Fix the CodeBuddy / buddy (Tencent) channel returning HTTP 400 on every request in DeepSeek Harness:
buddy: 请求被拦截,请重新发送 Illegal API invocation from an unapproved channel
dsh plugin add github:AsterLuo/dsh-buddy-guard --profile <your-profile>
# pin a version (recommended):
dsh plugin add github:AsterLuo/dsh-buddy-guard#v0.1.0 --profile <your-profile>
Restart DSH afterwards — it is required.
The problem
Pick any model on the buddy channel (hy4-preview, deepseek-v4.1-flash, hy3, …) and every turn fails
with HTTP 400 INVALID_REQUEST. The same account and the same endpoint work fine as soon
as the request stops carrying the DSH system prompt.
Root cause (measured 2026-10-21)
The upstream does a prefix match on the system content. If the system text starts with
You are an AI agent powered by DeepSeek Harness.
it is rejected outright. None of the following matter — every one was changed and the status stayed 400:
X-Domain(copilot.tencent.comvswww.codebuddy.cn)X-Product-Code/X-Product/X-Agent-PurposeX-IDE-Name/X-IDE-Type/X-IDE-Version/User-Agent- the endpoint (
copilot.tencent.comandwww.codebuddy.cnbehave identically) - the model (
hy4-preview,hy3,deepseek-v4.1-flashare all rejected)
Boundary tests (same account, same endpoint, same user message):
| system content | result |
|---|---|
You are an AI agent powered by DeepSeek Harness. |
400 |
| the same line with one leading space | 200 |
| one leading letter / period | 200 |
| trailing space / newline / period / a whole paragraph | 400 |
| the sentence inside a user message | 200 |
only DeepSeek Harness, or lowercase deepseek harness |
200 |
It matches the start of the system text; prefixing any character breaks the match, and appending anything does not help.
How it works
The plugin listens on system-prompt/assemble and returns a modified assembly whose first
non-empty section gets one leading space. renderPrompt joins sections with \n\n, so the
whole rendered system text then starts with that space.
Why not llm/stream
The first version hooked llm/stream and called next(modifiedOptions). That did nothing,
silently. Cordis implements waterfall as:
const next = () => (cbs.shift() ?? inner)(...args);
next takes no arguments — the modified options were dropped on the floor. The plugin
loaded, logged, showed up in --dump-config, and the outgoing request was byte-for-byte
unchanged.
Replacing arguments only works through a listener's return value.
Install
dsh plugin add github:AsterLuo/dsh-buddy-guard --profile <your-profile>
This copies the package into your profile's node_modules and registers it in
dsh.profile.bundles. Your own cordis.patch.yml is left untouched.
Then restart DSH — the config is read once at startup.
Manual install
- Copy this repo into
<DSH_HOME>/profiles/<profile>/node_modules/dsh-buddy-guard/ - Append
"dsh-buddy-guard"todsh.profile.bundlesin that profile'spackage.json - Add
"dsh-buddy-guard": "0.1.0"todependenciesin the same file - Verify with
--dump-configand look for thebuddy-guardrow - Restart DSH
Configuration
- id: buddy-guard
name: 'dsh-buddy-guard'
config:
enabled: true
providers:
- buddy
enabled— master switch.providers— which providers get the prefix. Defaults to['buddy']; other providers pass through untouched.
Verify it worked
After restarting, switch to a buddy model and send a message. A normal reply means it
works. Still getting 400?
- Re-run
--dump-configand confirm thebuddy-guardrow is there. - Confirm
lib/index.jsexists and is not empty. - Confirm the package is listed in
dsh.profile.bundles— the most commonly missed step. - Confirm you really restarted DSH.
Caveat
This bypasses upstream content moderation. The rule can change at any time. If the
same error returns, re-run the boundary tests to find the new trigger before changing
GUARD_PREFIX.
The account in question is a CodeBuddy China account (www.codebuddy.cn, the JWT iss
points there) while the client sends the international product shape. That mismatch is
itself what the upstream means by "unapproved channel" — this plugin only makes it work for
now, it does not fix the underlying mismatch. Using workbuddy (international) avoids the
check entirely.
Test
npm test
License
MIT
No comments yet. Be the first to write one.