gausszhou/dsh-opencode-session-id
dsh session IDs for opencode, zero config.
Project Overview项目介绍
This is a DeepSeek Harness (DSH) plugin for opencode session ID. It automatically adds compliant session ID headers to outgoing HTTP requests for the opencode gateway. Use it when working with opencode or opencode-go model providers. It only covers fetch-based protocols, and does not support websocket transport.
这是DeepSeek Harness(DSH)的opencode会话ID插件,默认无需额外配置。可自动为发往opencode网关的出站HTTP请求添加符合要求的会话ID请求头,使用opencode或opencode-go模型时可用,仅支持走fetch的请求协议,不覆盖websocket传输。
请帮我了解并安装插件:【dsh-opencode-session-id】【https://github.com/gausszhou/dsh-opencode-session-id】
Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。
Or use CLI install (for developers)或使用命令行安装(适合开发者)
CLI Install命令行安装
dsh plugin --profile web add "@gausszhou/dsh-opencode-session-id"
把 gausszhou/dsh-opencode-session-id 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-opencode-session-id
dsh session IDs for opencode, zero config.
English | 简体中文
A DeepSeek Harness (dsh) plugin: when you use an opencode model (providers such as opencode / opencode-go that point at the opencode.ai gateway), it makes the actual outgoing HTTP requests carry a session id — the same way the opencode client itself does.
Usage
Add the plugin to a dsh profile (install by package name once published to npm):
dsh plugin --profile web add "@gausszhou/dsh-opencode-session-id"
After installing, restart dsh web (systemctl --user restart dsh-web) so the bundle takes effect. The default configuration works out of the box: requests to opencode.ai automatically get x-opencode-session (the session header used by the opencode gateway) plus x-session-affinity / x-client-request-id / x-session-id. The header value defaults to a pure-alphanumeric nanoid(8) derived from the uuid portion of the session id (e.g. 0RpJJnxJ — the session- prefix does not participate in the hash; the token is deterministically derived from the uuid via SHA-256). With verbose: true, the journal logs the mapping between the original id and the wire token:
journalctl --user -u dsh-web -f | grep opencode-session-id
How it works
The opencode gateway branch uses x-opencode-session to carry the session id; this plugin listens on the llm/stream scope, wraps fetch, and adds that header at the wire layer. By default it hashes the uuid portion of session-<uuid> (the session- prefix is excluded) into an alphanumeric nanoid(8) before it goes on the wire. Only request headers are touched — the request body, URL, method, and everything else pass through unchanged. See docs/design.md for the full design rationale.
Configuration
Zero configuration needed by default (the install command above is all you need). To enable injection logging through the patch layer:
- id: opencode-session-id
config:
verbose: true
All options (each optional, defaults shown):
| Key | Default | Description |
|---|---|---|
providers |
[opencode, opencode-go] |
llm-pi-ai route names whose sessionId should be tagged |
hosts |
[opencode.ai] |
URL host suffixes (including subdomains) that get session headers |
baseURLs |
[] |
Additional exact URL prefixes to match (custom gateways) |
headers |
[x-opencode-session, x-session-affinity, x-client-request-id, x-session-id] |
Request header names to inject |
extraHeaders |
{} |
Optional static extra headers (e.g. opencode fingerprint family x-opencode-client: native / x-opencode-request: dsh) |
userAgent |
empty | Override User-Agent (opencode itself sends opencode/<version>; untouched by default) |
sessionIdEnv |
empty | Environment variable name to fall back on for the session id |
verbose |
false |
Log every injection (including the original id → wire token mapping) |
seedSessionId |
false |
Seed options.sessionId for opencode routes |
nanoidSessionId |
true |
Hash session-<uuid> to a nanoid(8) before sending; false sends the raw id |
nanoidLength |
8 |
Token length (4–32) |
nanoidAlphabet |
alphanumeric |
alphanumeric (pure A-Za-z0-9, no _/-) or urlsafe (classic 64-character set) |
disableFetchInjection |
false |
When true, keep only the waterfall session scoping |
Verification
node test/verify.mjs # 10 checks: unit tests + real pi-ai wire request + concurrent isolation + headers-only guarantee
node test/smoke-apply.mjs # apply() wiring: listener registration, scoped fetch, mount/dispose lifecycle
verify.mjs fires a real opencode-go request through the pi-ai bundled with the dsh CLI, asserting that the wire request headers really carry the session id; it also verifies concurrent-session isolation and that non-opencode endpoints are unaffected.
Notes & limitations
- The session id comes from
options.sessionId(agent-loop fills it in per session); without a session context, the fallback chain issessionIdEnv>DSH_SESSION_ID(the process's startup session in web deployments) > an in-process random id. - Covers protocols that go through
fetch, such asopenai-completions/openai-responses/anthropic-messages;transport: websocketdoes not use fetch and is out of scope. - The global fetch wrapper only appends request headers when an opencode endpoint is matched — nothing else is changed. The wire token is a one-way SHA-256 hash of the uuid portion of
session-<uuid>(thesession-prefix excluded, e.g.0RpJJnxJ), so the backend cannot reverse it to the original id; changingnanoidAlphabet/nanoidLengthchanges every token, breaking association with old records.
liangmianya/dsh-synapse
alaliqing/claude-paper
omdsh-dev/dsh-annotation
Anionex/dsh-turn-rewind
hanshenmesen/dsh-turn-delete
qkycir-123/dsh-run2skill
Tyan66666/billion-context-dsh
PKUfudawei/dsh-capability-menu