Bundle
dsh-web-search-doubao
Doubao feedcoop global_search provider for the DeepSeek Harness web capability seam (ctx.web)
- Source
- JayLi52
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-web-search-doubao
中文 | [English](#english)
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)的**豆包联网搜索插件**:把字节跳动 feedcoop `global_search` API 接入 `ctx.web` 能力接缝,替换内置搜索提供方。
这是一个**树外 bundle 插件**(out-of-tree bundle):向 `ctx.web` 注册一个 `WebSearchProvider`(id: `doubao`),自带 `cordis.patch.yml` 层——装入 profile 后自动挂载**并自动把搜索选择切到 `doubao`**。**零运行时依赖**,不修改任何 harness 源码。
## 安装
在 harness 仓库根目录(源码运行用 `pnpm dsh ...`,安装版用 `dsh ...`):
```sh
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
```
安装会:把包链接进 profile、把它的 bundle 层加入 `dsh.profile.bundles`、挂载提供方、切换 `searchProvider: doubao`。装完即用,无需手改配置。
## 配置 token
只需提供 feedcoop Bearer token,推荐环境变量方式——在 `$DSH_HOME/.env`(Windows 默认 `C:\Users\<你>\.dsh\.env`)写一行:
```sh
DOUBAO_SEARCH_API_KEY=<你的-token>
```
然后**重启一次** `dsh web`(环境变量在启动时加载)。之后改 token 以外的配置都走 profile patch 热重载,不用再重启。
也可以在 profile 的 `cordis.patch.yml` 里内联(覆盖环境变量):
```yaml
- id: web-search-doubao
name: dsh-web-search-doubao
config:
apiKey: <你的-token>
```
验证组合结果:
```sh
dsh --profile web --dump-config | grep -A3 web-search-doubao
```
在 Web UI 新会话里让模型联网搜索(`web_search` 工具)即走豆包。想切回内置搜索,在 profile 的 `cordis.patch.yml` 加:
```yaml
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: deepseek-official
```
(profile patch 晚于 bundle 层应用,后写者赢。)
## 配置项
| 字段 | 默认值 | 说明 |
|---|---|---|
| `apiKey` | `''` | Bearer token;为空时回退读取 `$<apiKeyEnv>`。两者皆空 → 提供方不可用 |
| `apiKeyEnv` | `DOUBAO_SEARCH_API_KEY` | 存放 token 的环境变量名 |
| `baseURL` | `https://open.feedcoopapi.com` | API 基址 |
| `docCount` | `10` | 请求未带 `maxResults` 时的默认 `DocCount` |
| `maxSnippetLength` | `300` | 每条结果摘要长度上限 |
## 映射规则
feedcoop `Result.Documents[]` → 接缝 `WebSearchSource`:`Url`→`url`(缺失丢弃)、`Title`→`title`、`Snippet[]` 中 `Type==='text'` 的 `Text` 换行拼接→`snippet`、`DocumentInfo.PublishTime`→`publishedAt`。`maxResults` 截断由接缝负责;图片类 Snippet 忽略。feedcoop 的错误信封(HTTP 200 + `ResponseMetadata.Error`,如 `invalid_api_key`)会被抛成显式错误,不会静默成"无结果"。
## 排障
| 症状 | 原因与处理 |
|---|---|
| 工具调用报 `unknown tool ""`,模型只剩 thinking 死循环 | **不是本插件的问题**:harness 的 `llm-deepseek` 适配器对"续包带空串 id/name"的流(DashScope 兼容模式等 OpenAI 兼容端点)有解析 bug,会把工具名覆盖成空串。修复见 deepseek-harness `packages/llm/llm-deepseek/src/translate.ts`(仅当非空才覆盖)。用 DeepSeek 官方端点不受影响 |
| `Doubao API error: invalid_api_key` | token 错或未设置;检查 `$DSH_HOME/.env` 或 patch 里的 `apiKey`,改 env 需重启 |
| `WEB_PROVIDER_CONFIGURED_UNAVAILABLE` | 选了 `doubao` 但 `available()` 为 false——即没配 token |
| `WEB_PROVIDER_AMBIGUOUS` | 多个可用提供方且没配 `searchProvider`;显式指定 id |
| 改了 `cordis.patch.yml` 没生效 | patch 是热重载的;若整层解析失败会保留旧树并打日志,检查 YAML 是否为顶层数组 |
## 自证路由(A/B)
怀疑搜索没走豆包时,用 `--patch` 覆盖层投毒 key 跑一次性任务:错 key 必报 `invalid_api_key`(或空结果),真 key 正常——两次唯一变量是 doubao 的 key,即可证明路由。
```yaml
# wrong-key-test.yml
- id: web-search-doubao
name: dsh-web-search-doubao
config:
apiKey: sk-invalid-for-ab-test-0000000000
```
```sh
dsh --profile headless --patch ./wrong-key-test.yml "用 web_search 搜 海淀必去景点"
```
## 分享给别人
**profile 目录本身不可移植**(`package.json` 里是本机 `link:` 绝对路径;key 与模型配置按设计不在 profile 内)。分享"配方":把本仓库链接发给对方,执行:
```sh
# 1. 装插件(自动挂载 + 自动切换搜索),并在 $DSH_HOME/.env 自备 token
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
# 2.(可选)开 Claude Code 委托:先让包可解析
# npm 安装版:dsh plugin --profile web add @deepseek-ai/dsh-subagent-claude-code
# 源码运行版:harness 仓库 apps/cli/package.json 加
# "@deepseek-ai/dsh-subagent-claude-code": "workspace:^" 后 pnpm install
# 再在 ~/.dsh/profiles/web/cordis.patch.yml 追加:
# - insert:
# - id: subagent-claude-code
# name: '@deepseek-ai/dsh-subagent-claude-code'
# 3.(可选)跳过 ~/.agents 共享技能注入:启动环境设 DSH_AGENTS_HOME=<空目录>
```
模型 key(`DEEPSEEK_API_KEY` 或 Models 页配置)由对方自备。
---
<a id="english"></a>
# English
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) web
capability seam (`ctx.web`) search provider backed by the Doubao / ByteDance
feedcoop `global_search` API. Out-of-tree bundle plugin: registers a
`WebSearchProvider` (id `doubao`) and ships a `cordis.patch.yml` layer that
mounts it **and switches the seam's search selection to `doubao`** on install.
Zero runtime dependencies; no harness source changes.
## Install
```sh
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
```
## Token
Set `DOUBAO_SEARCH_API_KEY=<token>` in `$DSH_HOME/.env` and restart once, or
inline it via the profile patch (`config.apiKey` on the `web-search-doubao`
row). Verify with `dsh --profile web --dump-config`. To switch back to the
shipped provider, override `searchProvider: deepseek-official` on the `web`
row in the profile patch (later layers win).
## Config fields
| Field | Default | Meaning |
|---|---|---|
| `apiKey` | `''` | Bearer token; falls back to `$<apiKeyEnv>`. Empty → unavailable. |
| `apiKeyEnv` | `DOUBAO_SEARCH_API_KEY` | Env var holding the token. |
| `baseURL` | `https://open.feedcoopapi.com` | Endpoint base. |
| `docCount` | `10` | Default `DocCount` without `maxResults`. |
| `maxSnippetLength` | `300` | `MaxSnippetLength` per request. |
## Mapping & errors
`Documents[]` maps to `WebSearchSource` (`url`/`title`/`snippet`/`publishedAt`);
text-type snippet parts joined with newlines; image parts ignored; the seam
owns `maxResults` truncation. feedcoop error envelopes (HTTP 200 +
`ResponseMetadata.Error`, e.g. `invalid_api_key`) are thrown as explicit
errors, never silently mapped to "no results".
## Troubleshooting
- `unknown tool ""` with endless thinking: **not this plugin** — the harness
`llm-deepseek` adapter overwrites parsed tool-call name/id with the empty
strings that OpenAI-compatible endpoints (e.g. DashScope) send on
continuation chunks. Fix: only overwrite when non-empty, in
`packages/llm/llm-deepseek/src/translate.ts`. The official DeepSeek endpoint
is unaffected.
- `invalid_api_key`: wrong/missing token; env changes need a restart.
- `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`: `doubao` selected but no token set.
- `WEB_PROVIDER_AMBIGUOUS`: several usable providers, no `searchProvider` set.
## License
[MIT](LICENSE)
Install
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
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-doubao from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.