dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
To play with DeepSeek's Completion API and check logprobs.
A fullscreen raw-prompt playground for DeepSeek Harness,
packaged as an agent mode. Every "Run" is an ordinary conversation turn whose model
call happens to be DeepSeek's raw
/beta/completions endpoint — so the
harness keeps doing the work it already knows: Chat, the built-in Trajectory, the session
list, token accounting and cancellation.
logprobs, then draws every position's candidate distribution as probability bars. It has
its own max_tokens and candidate count (1–20). The run is a real turn, so it appears in
Trajectory; the distribution rides the assistant message, so the bars come back after a tab
switch or a reload.Stop cancels the turn (and the upstream request).max_tokens / stop.From GitHub (pin a tag for reproducibility):
dsh plugin --profile <your-profile> add github:Zhichii/dsh-completion-playground#v0.3.0
Or open Settings → Plugins → Install, paste the same spec, and confirm. A git install
tracks the default branch unless you pin #<ref>.
The package ships plain ESM (index.js) and a plain browser bundle (client.js) — there is no
build step and no install script, so the install needs no build approval.
The Host half resolves the reference DEEPSEEK_API_KEY through the harness credential seam
(ctx.credentials) and falls back to the process environment. The value is sent only to the
configured upstream. Optional environment overrides:
| Variable | Meaning |
|---|---|
DSH_COMPLETION_BETA_BASE_URL | Upstream base URL, default https://api.deepseek.com/beta |
DSH_COMPLETION_ATTRIBUTION | User-Agent sent upstream (white-labelling) |
Ctrl/Cmd + Enter).The stop field is single-line, so line breaks are typed as escapes (decoded in the browser, sent upstream as real characters):
| Typed | Sent as the stop sequence |
|---|---|
\n | one line feed |
\n\n | two consecutive line feeds (stop at a blank line) |
\nUser: | line feed followed by User: |
\t | one tab |
\\ | one literal backslash |
Unknown escapes (\q) keep their backslash. At most 16 sequences; empty rows are dropped.
The bundle also ships a second mode, Gemini 模式 — a chat wrapper over the same endpoint that speaks a Gemini-style transcript instead of raw documents:
User
<your message>
Gemini
**Analyzing
No system prompt. The adapter never reads system or developer messages, and the mode's preset declares no prompt sections, so nothing the deployment would normally inject reaches the model. Persona and style live in the few-shot rounds instead.
No tool calls. The preset composes no tools and the adapter ignores tool declarations and tool
results; the request carries no tools field.
Few-shot prefix: gemini-prefix.md ships beside the module — a real Gemini-style transcript
(four rounds, <think> blocks and all) that leads every request. It carries both the format and
the persona, because this mode sends no system prompt.
Postfix: the prompt closes with Gemini\n<think>\n**Analyzing (the heading is left open), so the
model completes it, writes the analysis, closes </think> and then answers. Setting
geminiPostfix: "Gemini\n" instead makes the model emit <think> itself, so the stored answer
begins with the tag.
Both are overridable through the bundle row's config:
- id: completion-plan-b-host
name: 'dsh-completion-playground'
config:
geminiPrefix: | # replaces the shipped transcript entirely
User
你是谁
Gemini
…
geminiPostfix: "Gemini\n<think>\n**Analyzing" # or "Gemini\n" to let the model write <think>
geminiStops: ['\nUser\n'] # default: keep the model from speaking as the user
geminiEcho: true # echo the primed opener into the answer (default)
geminiMaxTokens: 2048 # default output cap
The shipped prefix is a stable ~4K-token prefix, so the provider's prompt cache should absorb most of its cost from the second request on.
Echo: the primed opener is re-emitted by the adapter as the answer's first text delta, so the
saved assistant message starts with <think>\n**Analyzing… even though that text was primed into
the prompt. The echo is derived from the postfix (the Gemini\n role tag is stripped), so it follows
whatever opener you configure; geminiEcho: false turns it off and leaves the prefill out of the
stored message.
Routing is decided on the Host from the session's own preset: a completion-gemini provider
route is pinned per request, so the mode needs no browser half and uses the shipped Chat UI
(no extra tab, no custom editor).
The composer's model selector may still show the deployment default: the pin is applied per request rather than written into the session's model selection, because that write would persist the route as the whole deployment's default model.
Preset id completion-gemini (recorded per session, therefore stable); display name Gemini 模式.
Run ──▶ ctx.remote.session.prompt(document)
──▶ Agent loop assembles a real turn
──▶ provider route `completion-beta` (host half): prompt = the last human user message
──▶ POST {baseURL}/completions stream: true
──▶ assistant text streams back; the editor appends it to the document
index.js): ctx.llm.registerAdapter(['completion-beta'], adapter); a
/completion-plan-b/max-tokens route receives each session's max_tokens + stop + logprobs;
an agent/request waterfall listener (prepended) pins the route and the request controls for
claimed sessions, so the deployment's default model is never rewritten.client.js): a watcher in conversation.input.dock notices the session's
agentPreset projection, claims it, and — once the session has history — registers this
mode's two conversation.view entries plus a conversation.composer chain takeover that
vacates the native composer.logprobs is not a field of LlmCallConfig, so
it travels on the same claim channel as max_tokens and the adapter reads it back through the
request's own sessionId. The per-position distribution leaves on the finish chunk's
replayState ({response}, with blocks omitted), which the harness stores on the assistant
message's source. The run is therefore an ordinary turn — in Trajectory, cancellable, metered
— and the browser half only reads the log back. At most 512 positions are stored; beyond that
only the count is kept.Developed and tested against DSH 0.1.7-rc.2, and re-verified against 0.2.0-rc.2
(engines.dsh). It binds to these extension points, which are public but may move between
harness versions:
conversation.view / conversation.composer / conversation.input.dock slots ·
agentPreset session projection · agentPreset declarations · agent/request waterfall and
LlmCallConfig · ctx.llm.registerAdapter · ctx.webServer.register · ctx.credentials ·
the session.prompt / session.cancel remotes · session.blank.
A session's mode is locked once its first turn commits (a harness invariant — even a failed turn opens one), so the Completion tab's session keeps that mode; start a new session to pick another mode.
npm test # activation smoke tests for both halves + stop-escape decoding
Both halves are dependency-free by design: the Host half uses only services reachable from
ctx, and the browser half never imports a harness client package.
If the deployment has no pnpm on PATH, mount the plugin by path in the profile's own patch
layer instead — dsh-client-modules resolves the nearest package.json from the row's module
location, so both halves load with no package install:
# <profile>/cordis.patch.yml
- insert:
- id: completion-plan-b-host
name: /absolute/path/to/dsh-completion-playground/index.js
- id: preset-completion-plan-b
name: '@deepseek-ai/dsh-agent-preset'
config:
id: completion-plan-b
name: Playground Mode
description: Fullscreen raw-prompt editor plus a Logprob probe; every Run is a real turn (/beta/completions).
order: 30
plugins: []
Host-side changes need a process restart (the loader does not re-import a changed module, and the
profile's HMR watches patch files, not module code). The browser bundle is stat-polled and
republished by content hash, so an open page picks a client.js edit up by itself. The diagnostic
GET /completion-plan-b/rev reports which revision the running Host loaded.
The connection trust gate is looked up per request rather than captured in apply(): a cold boot
can mount this row before the connection service exists, and a captured undefined would leave
the private routes answering unauthenticated callers for the rest of the process.
The manifest is npm-ready (publishConfig.access: public, files whitelist, no build step):
npm publish --access public
repository / homepage / bugs already point at this repo. Tag a release in git so the GitHub
install spec above can pin it (v0.3.0 matches this version).
MIT — see LICENSE.