Bundle
dsh-web-search-opencode
OpenCode-style web search (Exa / Parallel MCP) provider for the DeepSeek Harness ctx.web seam. Gives any model, including opencode-go's deepseek-v4-flash, a working web_search tool without a DeepSeek official API key.
- Source
- FANXING-0710
- stars
- 2 stars
- License
- MIT
- Updated
- Updated 10 days ago
Readme
# dsh-web-search-opencode
为 DeepSeek Harness(`dsh`)的 `ctx.web` 搜索能力缝提供 **OpenCode 同款搜索** 的 provider 插件:让使用 opencode-go key 驱动 `deepseek-v4-flash` 等模型的会话,`web_search` 工具可以直接可用,不需要 DeepSeek 官方 API key。
## 原理
opencode 的 web 搜索**不经过 opencode-go 服务器**(`opencode.ai/zen/go/v1` 只有 chat/completions、messages、models、responses、usage 五个端点,没有搜索端点),而是客户端直连第三方 MCP 端点(见 sst/opencode 的 `tool/websearch.ts` + `tool/mcp-websearch.ts`):
| 后端 | 端点 | 工具名 |
| --- | --- | --- |
| Exa | `https://mcp.exa.ai/mcp` | `web_search_exa` |
| Parallel | `https://search.parallel.ai/mcp` | `web_search` |
请求为 JSON-RPC 2.0 `tools/call`,25 秒超时,响应是直接 JSON 或 SSE(`data: ` 前缀行)。本插件完全复刻这套行为,注册进 DSH 的 `ctx.web` 缝:
```
模型(如 opencode-go/deepseek-v4-flash)
→ 调用 web_search 工具(DSH tool-web 插件注册)
→ ctx.web.search()(DSH 搜索能力缝)
→ 本插件 OpenCodeGoSearchProvider.search()
→ JSON-RPC → Exa / Parallel MCP
→ 返回 { content: 全文, sources: [{url,title,snippet,publishedAt}] }
→ tool-web 格式化成 markdown 结果给模型
```
DSH 默认的 `web-search-deepseek` provider 需要 `DEEPSEEK_API_KEY`(DeepSeek 官方 API,走 Anthropic 兼容端点的 `web_search_20250305` 服务端工具),只有 opencode-go key 时不可用(报 `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`)。本插件的 `available()` 恒为 true(两个 MCP 端点免 key),并覆盖 `web` 行的 `searchProvider` 指向它。
## 安装
```powershell
# npm 安装(推荐)
npx dsh plugin --profile web add dsh-web-search-opencode
# 或直接从 GitHub 安装(pnpm ≥10 首次会要求把包名加入 profile 的
# pnpm-workspace.yaml 的 allowBuilds 再重跑)
npx dsh plugin --profile web add github:FANXING-0710/dsh-web-search-opencode
```
装完**重启** `dsh web` 生效(正在运行的实例是启动时加载插件树的)。
## 配置
默认无需任何配置。可选配置项(在 profile 的 `cordis.patch.yml` 覆盖 `web-search-opencode` 行的 `config`,或设置环境变量):
| 配置项 | 环境变量 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `provider` | `OPENCODE_WEBSEARCH_PROVIDER` | `auto` | `auto`(按查询确定性 50/50)\| `exa` \| `parallel` |
| `exaApiKey` | `EXA_API_KEY` | 空 | 附加为 `?exaApiKey=` 查询参数(同 opencode) |
| `parallelApiKey` | `PARALLEL_API_KEY` | 空 | 附加为 `Authorization: Bearer` |
| `numResults` | — | `8` | 结果数(同 opencode 默认) |
| `searchType` | — | `auto` | Exa 检索模式 `auto`/`fast`/`deep` |
| `livecrawl` | — | `fallback` | Exa 实时爬取策略 `fallback`/`preferred` |
| `contextMaxCharacters` | — | `10000` | Exa 每结果上下文上限 |
| `timeoutMs` | — | `25000` | 单请求超时(同 opencode) |
## 开发
```powershell
npm install # 安装 @deepseek-ai/dsh-web(测试用)
npm test # node --test 单元测试(不联网)
node scripts/smoke.mjs # 真实搜索冒烟测试(联网,可选)
```
### 手动冒烟测试
```powershell
node -e "import('./provider.js').then(async (m) => { const p = new m.OpenCodeGoSearchProvider({ provider: 'exa', exaApiKey: '', parallelApiKey: '', numResults: 3, searchType: 'auto', livecrawl: 'fallback', contextMaxCharacters: 10000, modelName: 'opencode-go/deepseek-v4-flash', timeoutMs: 25000 }); const r = await p.search({ query: 'DeepSeek V4 flash release', maxResults: 3 }); console.log(r.content.slice(0, 500)); console.log(r.sources); })"
```
## 文件结构(官方 bundle 格式)
```
dsh-web-search-opencode/
├── package.json # 官方格式:main 指向 lib/ 产物,声明 dsh.bundle + publishConfig
├── tsconfig.json # tsc 构建配置(ESM/NodeNext,产物 lib/ + 类型声明)
├── src/
│ ├── index.ts # cordis 函数插件(name/inject/Config/apply,schemastery 校验)
│ ├── provider.ts # OpenCodeGoSearchProvider + MCP 协议与结果解析
│ └── types.ts # MCP/Exa/Parallel 线上格式类型
├── lib/ # tsc 构建产物(index.js/provider.js/types + lib/types/*.d.ts)
├── cordis.patch.yml # bundle 补丁:插入插件行 + 覆盖 web.searchProvider
├── tests/
│ └── provider.test.js # 单元测试(node --test,对 lib/ 产物断言)
└── scripts/
└── smoke.mjs # 真实搜索冒烟脚本(联网,对 lib/ 产物调用)
```
## License
MIT
Install
dsh plugin --profile web add github:FANXING-0710/dsh-web-search-opencode
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 from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.