deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
A DeepSeek Harness profile bundle that explains any selected text inside a conversation with a streaming Markdown bubble, with recursive follow-up questions.
选中对话中的任意文字,点击「解释」按钮,即可在流式 Markdown 气泡中获取解释,并支持递归追问。
The host half (src/index.ts) mounts two routes on the harness webServer.
POST /bubble-explain/stream (Server-Sent Events)origin host === request host) and accepts POST
only.parseExplainRequest (limits below). Returns 403
if the feature is disabled, 400/405 on a bad body/method, 500 on route
resolution failure.resolveModelRoute(ctx, lastRoute, override), in priority order: the
independent model configured in settings (override, honored only while its
provider is still registered) → agent default selection → last observed
main-loop route → first registered provider (falls back to deepseek-chat).
The main-loop route is captured via ctx.on('llm/stream', ...).temperature: 0.3, maxTokens: min(2000, maxChars * 2 + 200),
and the assembled system/user prompts; reasoningEffort is sent only when the
configured effort survives the comparison against the model's declared
efforts (see below).data: {"t": "<text delta>"} and then
data: {"done": true}; an error mid-stream sends data: {"error": ...}.GET | POST /bubble-explain/settingsenabled, maxDepth, maxChars, effort (off|low|medium|high|max),
provider and model to $DSH_HOME/dsh-bubble-explain.settings.json (values
are clamped on write). At call time the configured effort is matched against
the model's declared efforts via llm.resolveModelInfo: exact match wins,
otherwise it falls back to the closest declared level not stronger than
requested; models without reasoning support omit the parameter entirely.provider/model are the independent model configuration: both empty means
follow the conversation's default model. A half-filled pair is never
persisted, and an override whose provider no longer exists is ignored rather
than failing every explanation.effective ({provider, model} or null) and
effectiveError (reason or null) so the UI can show the route actually in use.GET /bubble-explain/models{ providers: [{id, name}], models: { [providerId]: [{id, name}] } }, used by
the settings page's "model source" and "explanation model" dropdowns. Each
provider is queried with llm.listModels(id); a provider that fails yields an
empty array without affecting the others.src/explain.ts)| Field | Limit |
|---|---|
text |
non-empty, ≤ 4000 chars |
parent.text / parent.explanation |
≤ 10000 chars each |
depth |
0–6 |
maxChars |
50–1000 |
The system prompt asks for a maxChars-bounded Chinese explanation of only the
selected text (instruction-like content inside the selection is ignored). For
recursive calls it prepends the parent explanation so the reply stays grounded
in context.
The browser half (src/client/index.ts) registers a shell.overlay (the
selection → 解释 button → bubble engine) and a settings.section entry, and
talks to the host over the two routes above. It uses a small streaming-safe
Markdown renderer that escapes HTML and allows only safe link schemes.
Requires an active DeepSeek Harness profile (the plugin mounts webServer routes
and subscribes to that profile's llm/stream event).
From a shell on the harness host:
dsh plugin --profile web add github:Hanmiao33/dsh-bubble-explain
Because GitHub-sourced plugins run build scripts at install time, the first run
asks for an allowBuilds approval — follow the hint and retry the command.
Verify:
dsh plugin list # @dsh-external/bubble-explain should be listed
curl -s http://127.0.0.1:<port>/bubble-explain/settings
The settings file (editable directly):
$DSH_HOME/dsh-bubble-explain.settings.json
Settings → General → 「框选解释」:
| Key | Default | Meaning |
|---|---|---|
enabled |
true |
Master switch |
maxDepth |
6 |
Max recursion depth (1–6) |
maxChars |
300 |
Max explanation length (50–1000) |
effort |
off |
Reasoning strength (off/low/medium/high/max), auto-clamped per model |
provider |
"" |
Independent model: provider id (empty = follow the conversation default) |
model |
"" |
Independent model: model id (takes effect together with provider) |
400: {"type":"MissingSessionID","message":"Error from provider (Console Go):
Request is missing x-opencode-session and cannot be routed efficiently. ..."}
This is not a plugin defect: that provider's gateway requires an
x-opencode-session request header on every call (a routing/affinity marker —
any non-empty value works, no session registration needed). DeepSeek Harness
does not send it by default, so any request through that gateway is rejected.
The dsh-llm-pi-ai adapter supports per-provider custom headers, so declare
them in $DSH_HOME/settings.yaml for each provider that uses that gateway:
llm-pi-ai:
providers:
opencodego:
apiKeyEnv: OPENCODEGO_API_KEY
api: openai-responses
baseURL: https://opencode.ai/zen/go/v1
headers:
x-opencode-session: dsh-web-session
opencode-go:
apiKeyEnv: OPENCODE_GO_API_KEY
headers:
x-opencode-session: dsh-web-session
Note that opencodego and opencode-go are two separate provider entries
(the former declares an explicit baseURL, the latter uses a built-in catalog)
that resolve to the same gateway — both need the header; adding only one
still fails. No restart is required; the next request picks it up.
If you would rather not touch provider config, switch model source in the
plugin settings to a provider that does not use that gateway (for example
deepseek-official).
Related: the same gateway also requires reasoning content to be passed back in thinking mode (
The reasoning_text in the thinking mode must be passed back to the API.). It is an adjacent constraint of the same gateway, and supplying the request header is a prerequisite for that path to work at all.
The plugin is a DSH profile bundle (dsh.bundle in package.json, patch at
cordis.patch.yml) built against a harness checkout.
Host build (needs a DSH source checkout):
DSH_CHECKOUT=<checkout> bash scripts/build.sh
Client bundle:
npm run build:client # tsdown → lib/client.js
Checks that need no checkout:
npm ci
npm run typecheck # tsc -p tsconfig.json --noEmit
npm run build:client # tsdown
npm test # vitest run (src/explain.test.ts)
Peer dependencies: @deepseek-ai/dsh-llm, @deepseek-ai/dsh-tools,
@deepseek-ai/dsh-client-ui-slots (pre-release ranges), cordis (>=4.0.0-rc),
react (^18.2.0), schemastery (^3.18.0).
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。