Bundle
dsh-web-search-opencode-go
Fix DSH web_search through OpenCode Go / Zen: auto-inject x-opencode-session. Drop-in patched fork of @deepseek-ai/dsh-web-search-deepseek (DeepSeek Harness).
- Source
- leeyoung1
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-web-search-opencode-go
[中文说明](README.zh.md)
**Fix DSH `web_search` when the search provider is routed through OpenCode Go / OpenCode Zen.** The gateway rejects Anthropic Messages requests that do not carry `x-opencode-session`:
```text
Error from provider (Console Go): Request is missing x-opencode-session and cannot be routed efficiently.
Please see https://opencode.ai/docs/go/#where-can-i-use-it
```
This repository is a **drop-in patched fork of `@deepseek-ai/dsh-web-search-deepseek`** for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness). It automatically injects:
- `x-opencode-session` — the current DSH agent session id (or a configured id / provider-wide UUID fallback), and
- `x-opencode-client: dsh`
so the built-in `web_search` tool works again without touching the official DSH installation.
**TL;DR:** store an OpenCode Go key in DSH → set `web-search-deepseek.baseURL` → run the installer → restart `dsh web` → use `web_search` as usual. Details: [Usage](#usage).
## What this changes
This is **not** a new CLI and **not** a new `web_search` command. After
installation and a `dsh web` restart:
- your existing `web-search-deepseek` settings stay in place;
- every ordinary `web_search` call from the agent goes through the patched provider;
- the patched provider adds the OpenCode Go / Zen routing headers automatically.
No profile patch, no extra tool, and no new prompt are needed.
## The problem
DSH's built-in web search provider calls an Anthropic-compatible Messages endpoint:
```text
POST {baseURL}/messages
```
If you point it at OpenCode Go:
```yaml
web-search-deepseek:
baseURL: https://opencode.ai/zen/go/v1
```
the upstream provider sends only its normal headers (`x-api-key`, `authorization`, `anthropic-version`, …). OpenCode Go additionally requires a session-routing header and returns `MissingSessionID` / HTTP 400 without it. The native `web_search_20250305` tool itself works on OpenCode Go; only the routing header was missing.
## The fix
This fork keeps the official provider behavior and adds:
- automatic `x-opencode-session` / `x-opencode-client` injection for `opencode.ai` endpoints;
- explicit `headers` and `sessionId` config fields for other gateways;
- a safe installer that copies the patched package into the DSH web profile at the path the bundle already resolves:
```text
~/.dsh/profiles/web/node_modules/@deepseek-ai/dsh-web-search-deepseek
```
The official package under your DSH installation (`/opt/homebrew/...`, `npm -g`, etc.) is **never modified**.
## Quick start
Requires Node.js 20+ (or just a working `dsh` + `pnpm`) and an existing DSH web
profile. There are two install paths; **Option A** is the one the plugin market
uses.
### Option A — install as a DSH bundle (recommended)
```bash
dsh plugin --profile web add github:leeyoung1/dsh-web-search-opencode-go
# restart dsh web
```
The package declares `dsh.bundle`, so `dsh plugin` automatically adds it to
`dsh.profile.bundles`. Its `cordis.patch.yml` disables the official
`web-search-deepseek` row and inserts this patched provider in its place.
After the npm package is published, the command gets shorter:
```bash
dsh plugin --profile web add dsh-web-search-opencode-go
# restart dsh web
```
### Option B — drop-in copy (offline / no pnpm)
This copies the package into the profile's `@deepseek-ai` slot, shadowing the
official package. It needs no package manager and works on macOS, Linux, and
Windows.
macOS / Linux:
```bash
git clone https://github.com/leeyoung1/dsh-web-search-opencode-go.git
cd dsh-web-search-opencode-go
./mount.sh
# restart dsh web
```
Windows (PowerShell or cmd):
```powershell
git clone https://github.com/leeyoung1/dsh-web-search-opencode-go.git
cd dsh-web-search-opencode-go
node .\bin\dsh-web-search-opencode-go.mjs
# restart dsh web
```
`mount.sh` is a POSIX convenience wrapper around the same Node installer.
### Non-default profile or DSH home
macOS / Linux:
```bash
DSH_PROFILE_DIR=/path/to/profile ./mount.sh
# or: DSH_HOME=/path/to/dsh-home ./mount.sh
```
Windows:
```powershell
$env:DSH_PROFILE_DIR = "C:\path\to\profile"
node .\bin\dsh-web-search-opencode-go.mjs
```
### Useful flags (Option B)
```text
--dry-run show what would change, without touching the profile
--uninstall move the patched copy aside and restore the previous entry
--help usage and environment variables
```
Then restart `dsh web`. The running process must be restarted because DSH loads plugins at boot.
## Usage
### 1. Store the OpenCode Go API key in DSH
Open **Settings → Models** and store your OpenCode Go key under either:
- `DEEPSEEK_API_KEY` (the provider default), or
- `OPENCODE_GO_API_KEY` (then set `apiKeyEnv: OPENCODE_GO_API_KEY` in the config below).
The key is resolved on every search, so rotating it does not require a restart.
### 2. Point the built-in web search provider at OpenCode Go
In `~/.dsh/settings.yaml`:
```yaml
web-search-deepseek:
baseURL: https://opencode.ai/zen/go/v1
apiKeyEnv: DEEPSEEK_API_KEY # default; OPENCODE_GO_API_KEY also works
model: deepseek-v4-flash # default
```
### 3. Install the patch and restart
Follow [Quick start](#quick-start) above, then restart `dsh web`.
### 4. Use it normally
There is no new command. Ask the agent in natural language:
```text
搜索一下 DeepSeek Harness GitHub 的最新信息
```
or have it call the tool directly:
```text
web_search: DeepSeek Harness GitHub
```
Expected: normal results; no `MissingSessionID` error. Each auxiliary search is
recorded in the DSH session log as `web/deepseek-search-llm-request`.
## Configuration
Your existing settings continue to work:
```yaml
web-search-deepseek:
baseURL: https://opencode.ai/zen/go/v1
apiKeyEnv: DEEPSEEK_API_KEY # default; OPENCODE_GO_API_KEY also works
model: deepseek-v4-flash # default
```
Optional new fields:
```yaml
web-search-deepseek:
baseURL: https://opencode.ai/zen/go/v1
headers:
x-opencode-client: dsh # override any automatic header
sessionId: my-fixed-session # explicit OpenCode routing session
```
Header precedence:
1. explicit `headers['x-opencode-session']`
2. `sessionId` config
3. current DSH agent session id
4. provider-wide UUID fallback (programmatic calls outside an agent turn)
`x-opencode-client` defaults to `dsh` and can also be overridden.
## How installation works
There are two supported install paths:
- **DSH bundle (Option A):** `package.json` declares
`dsh.bundle.patch = ./cordis.patch.yml`. `dsh plugin add` installs the package
and adds it to `dsh.profile.bundles`; the patch disables the official
`web-search-deepseek` row and inserts this provider under the same settings
namespace (`web-search-deepseek`) and provider id (`deepseek-official`).
- **Drop-in copy (Option B):** the Node installer copies this package to
`<profile>/node_modules/@deepseek-ai/dsh-web-search-deepseek`. Node resolves
that path before the shared `profiles/node_modules`, so the existing official
bundle row loads the patched provider instead.
Either way you keep your existing `web-search-deepseek` settings; no settings
rewrite is required.
For the drop-in copy, if the destination already exists it is moved aside to
`dsh-web-search-deepseek.unpatched-<timestamp>` instead of being deleted. After
a DSH upgrade or a `pnpm`/`npm` reinstall that restores the official package,
run the installer again and restart `dsh web`.
## Uninstall / rollback
Use the cross-platform uninstaller on any OS:
```bash
npx dsh-web-search-opencode-go --uninstall
# or, from a clone:
node ./bin/dsh-web-search-opencode-go.mjs --uninstall
# restart dsh web
```
It moves the patched copy to `dsh-web-search-deepseek.uninstalled-<timestamp>`
and restores the most recent `.unpatched-*` entry when one exists. If no backup
exists, Node resolves the official package again.
Manual equivalent:
- macOS / Linux:
```bash
rm -rf ~/.dsh/profiles/web/node_modules/@deepseek-ai/dsh-web-search-deepseek
# restart dsh web
```
- Windows PowerShell:
```powershell
Remove-Item -Recurse -Force "$env:USERPROFILE\.dsh\profiles\web\node_modules\@deepseek-ai\dsh-web-search-deepseek"
# restart dsh web
```
## Compatibility
- DSH `0.1.x` line (verified on `0.1.1-rc.2`).
- The patched provider is API-compatible with `@deepseek-ai/dsh-web-search-deepseek@0.1.1-rc.2`.
- OpenCode Go / OpenCode Zen Anthropic-compatible endpoint.
- Node.js 20+.
- macOS, Linux, and Windows. The installer copies files and uses no symlinks
or administrator-only APIs; CI runs the installer test on all three OSes.
## Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Still `MissingSessionID` after install | `dsh web` was not restarted | Restart `dsh web`. |
| `WEB_PROVIDER_CREDENTIAL_MISSING` | No key stored for `DEEPSEEK_API_KEY` | Store it in DSH Settings → Models, or set `apiKeyEnv: OPENCODE_GO_API_KEY`. |
| `DeepSeek search request failed` / HTTP 401/403 | Wrong key for the selected endpoint | Use an OpenCode Go key for `opencode.ai`, or point `baseURL` back at DeepSeek's official endpoint with a DeepSeek key. |
| Provider unavailable | Unparseable `baseURL` | Use the full base that includes `/v1`, e.g. `https://opencode.ai/zen/go/v1`. |
| Search broke after a DSH upgrade | The profile restored the official package | Re-run the installer (`./mount.sh`, `npx dsh-web-search-opencode-go`) and restart. |
| `EPERM` / `EBUSY` while installing on Windows | `dsh web` is running and the profile files are locked | Stop `dsh web`, run the installer again, then restart. |
## Development
```bash
npm test # header + cross-platform installer tests (dependency-free)
npm run link-deps # optional: link official packages for full-provider imports
node ./bin/dsh-web-search-opencode-go.mjs --dry-run
```
Tests only import `lib/headers.js`, which has no dependencies. `link-deps` is
only needed when importing the full `lib/index.js` provider in a clone; the
installed copy resolves the official packages through the profile's
`node_modules` parents.
## Repository metadata (for search)
Suggested GitHub repository name, description, and topics:
- **Name:** `dsh-web-search-opencode-go`
- **Description:** `Fix DSH web_search through OpenCode Go / Zen: auto-inject x-opencode-session. Drop-in patched fork of @deepseek-ai/dsh-web-search-deepseek.`
- **Topics:** `dsh`, `deepseek-harness`, `deepseek`, `opencode`, `opencode-go`, `opencode-zen`, `web-search`, `websearch`, `dsh-plugin`, `x-opencode-session`, `MissingSessionID`, `cross-platform`, `windows`, `macos`, `linux`
See [docs/publishing.md](docs/publishing.md) for ready-to-run `gh` and `npm` commands.
## License and attribution
MIT. The provider implementation is derived from
[`@deepseek-ai/dsh-web-search-deepseek`](https://www.npmjs.com/package/@deepseek-ai/dsh-web-search-deepseek)
by DeepSeek, also MIT-licensed. The original license is preserved in [LICENSE](LICENSE).
This is an unofficial community patch and is not affiliated with DeepSeek or OpenCode.
Install
dsh plugin --profile web add github:leeyoung1/dsh-web-search-opencode-go
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-web-search-opencode-go from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.