Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

DSH patch: per-conversation x-opencode-session

Fix the 400 MissingSessionID rejections from OpenCode Go inside DeepSeek Harness (DSH), with a real per-conversation id instead of a static one.

Scope: @deepseek-ai/dsh-llm-pi-ai 0.1.2-rc.1 (as bundled with @deepseek-ai/dsh; verified 2026-09-07). The patcher verifies every anchor before writing and fails loudly on layout drift — it never half-applies.

What the patch does

lib/index.js#requestHeaders() gains:

  • isOpenCodeTarget(model) — provider id opencode-go/opencode, or a baseUrl containing opencode.ai;
  • for those targets only: x-opencode-session: sessionId ?? "dsh-sessionless", added after the profile headers, so a deployment's static header can never override the per-conversation value;
  • sessionless callers (rare) send a fixed fallback id, so the header is never absent.

Why this choke point: the Harness already passes a stable per-conversation session id (agent loop, session titles, compaction all forward it) down to dsh-llm-pi-ai — but pi-ai only forwards it into generic affinity headers (x-client-request-id, x-session-affinity), never x-opencode-session, and only when a provider opts into them. Patching requestHeaders() covers all three pi-ai API adapters (openai-completions, openai-responses, anthropic-messages) in one place and survives pi-ai upgrades (it only touches the DSH package; a DSH upgrade re-runs the patcher).

Apply

Run as a user able to write the target files — typically root inside the DSH container:

# A) from the host
docker exec -u root <container> bash apply-opencode-session.sh
# B) from a root shell inside the container
bash apply-opencode-session.sh

# status / rollback
bash apply-opencode-session.sh --check
bash apply-opencode-session.sh --revert

Then restart the harness (docker restart <container> or your service manager) — modules are cached per process, so the patch only loads on process start.

Default target paths: the DSH install tree and the web profile tree ($DSH_HOME/.dsh/profiles/...). They are hardlinked; the script dedups by inode, so one write fixes both names. Override with DSH_HOME / DSH_TARGETS (see the script header).

Persist the patcher (recommended)

The patched module lives in the container writable layer: it is lost on container recreation, image upgrade, or host migration, and it is not covered by DSH data backups (backups only carry the ~/.dsh volume). Incident (2026-09-08): a standby DSH restored from a data backup hit 400 MissingSessionID again because the patch lived only in the primary's container layer.

So keep the patcher in the persistent home volume, next to the other dev patches, and re-apply after every container recreation / DSH upgrade:

# one-time: store the patcher in the persistent volume
cp apply-opencode-session.sh patch-dsh-llm-pi-ai.mjs ~/.dsh/dev-plugins/patches/

# apply / re-apply (idempotent; --check first if unsure)
docker exec -u root -e DSH_HOME=/home/node <container> \
  bash /home/node/.dsh/dev-plugins/patches/apply-opencode-session.sh
docker restart <container>

Pass -e DSH_HOME=/home/node explicitly. Inside the container the compose env sets DSH_HOME=/home/node/.dsh, which makes the script's default profile target resolve to a non-existent …/.dsh/.dsh/profiles/... and silently skip it.

Notes:

  • The patcher, its anchors check, and the *.opencode-session-backup files survive with the volume; only the patched lib/index.js needs re-applying.
  • On boot DSH re-syncs the profile-tree copy of dsh-llm-pi-ai from the (patched) global module, so after a restart one apply covers both targets (observed 2026-09-08).

Deployed at

Host Container Image Applied Entry
nas-n100 deepseek-harness owen-dsh:0.1.2-rc.1 2026-09-07 intranet http://192.168.23.22:3080
tcloud-01 deepseek-harness owen-dsh:0.1.2-rc.1 2026-09-08 https://dsh.app.bulabula.space (basic auth)

Patcher persisted in ~/.dsh/dev-plugins/patches/ on both nodes (included in DSH data backups since 2026-09-08).

No-code stopgap (no restart needed)

~/.dsh/settings.yaml:

llm-pi-ai:
  providers:
    opencode-go:
      headers:
        x-opencode-session: your-static-id

dsh-llm-pi-ai re-reads profiles per request, so this lands on the next request without a restart. Tradeoff: every conversation shares one id — enough to stop the 400s, weaker for OpenCode's prompt-cache routing. Once the patch is applied, the dynamic value wins (see merge order above); remove the static block afterwards to keep the config honest.

Compatibility

  • The patch touches only @deepseek-ai/dsh-llm-pi-ai. It is independent of your @earendil-works/pi-ai version and of the openai npm SDK version inside it — any SDK that supports defaultHeaders (v4+) forwards the injected header. You do not need any offline upgrade tarballs; everything needed is the two files in this directory.
  • Your DSH must already ship the opencode-go provider (bundled pi-ai ≥ 0.84). If it does not, upgrade DSH first — that is outside this patch's scope.
  • Verified against dsh-llm-pi-ai 0.1.2-rc.1 (2026-09-07). If a future DSH release changes the layout, the patcher refuses to run ("anchor not found") instead of half-applying — please open an issue with your dsh-llm-pi-ai version (grep '"version"' <path-to>/dsh-llm-pi-ai/package.json) so the new anchors can be added.