deepseek-web-retrieval 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/README.md +33 -16
- package/dist/cli.js +307 -174
- package/docs/adr/0001-refuse-drift-between-plan-and-apply.md +7 -3
- package/docs/adr/0002-shared-config-base-layer.md +5 -1
- package/docs/adr/0003-need-content-per-call-boolean.md +49 -0
- package/docs/agents/claude-code.md +16 -6
- package/docs/agents/codex.md +14 -8
- package/docs/agents/domain.md +2 -2
- package/docs/agents/issue-tracker.md +5 -5
- package/docs/agents/opencode-v2.md +29 -15
- package/docs/agents/pi.md +41 -12
- package/docs/configuration.md +24 -7
- package/docs/design/config-layering-design.md +10 -5
- package/docs/design/installer-design.md +57 -25
- package/docs/design/search-content-design.md +133 -0
- package/docs/integration.md +19 -16
- package/docs/research/control-matrix.md +39 -34
- package/docs/research/mcp-compatibility.md +3 -1
- package/docs/research/ori-question-sourcing.md +31 -20
- package/docs/research/result-quality-passthrough.md +9 -7
- package/docs/research/search-api-defaults.md +4 -2
- package/docs/research/search-inline-content.md +49 -9
- package/package.json +3 -2
- package/src/core/auth.ts +7 -0
- package/src/core/client.ts +98 -27
- package/src/core/config-summary.ts +3 -0
- package/src/core/constants.ts +30 -2
- package/src/core/descriptions.ts +17 -2
- package/src/core/env.ts +7 -1
- package/src/core/format.ts +35 -5
- package/src/core/options.ts +56 -0
- package/src/core/search.ts +106 -15
- package/src/core/types.ts +29 -0
- package/src/installer/apply.ts +4 -4
- package/src/installer/cli.ts +2 -2
- package/src/installer/config-command.ts +4 -3
- package/src/installer/hosts/claude-code.ts +3 -17
- package/src/installer/hosts/codex.ts +3 -17
- package/src/installer/hosts/index.ts +2 -2
- package/src/installer/hosts/opencode.ts +1 -1
- package/src/installer/hosts/pi.ts +14 -15
- package/src/installer/hosts/shared.ts +23 -0
- package/src/installer/ownership.ts +2 -2
- package/src/installer/paths.ts +2 -2
- package/src/installer/{state.ts → record.ts} +15 -15
- package/src/installer/types.ts +1 -1
- package/src/installer/uninstall.ts +4 -4
- package/src/mcp/serve.ts +1 -2
- package/src/mcp/server.ts +19 -19
- package/src/opencode/plugin.ts +15 -10
- package/src/pi/extension.ts +26 -17
- package/src/mcp/auth.ts +0 -11
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Refuse drift between plan and apply
|
|
2
2
|
|
|
3
|
+
Status: Accepted — shipped in 0.3.0 (see [CHANGELOG](../../CHANGELOG.md)).
|
|
4
|
+
|
|
3
5
|
The installer's plan previews the previous value each `set` op replaces, and the
|
|
4
6
|
install record must snapshot exactly that value for uninstall to restore. We
|
|
5
|
-
decided that apply re-verifies the current value at every `set` path still
|
|
7
|
+
decided that apply re-verifies that the current value at every `set` path still
|
|
6
8
|
equals the plan-time `previous`, refuses with guidance when it does not
|
|
7
9
|
("config changed since the plan was rendered — re-run"), and records the
|
|
8
10
|
plan-time snapshot — so the preview, the secret guard, and the record all
|
|
@@ -12,9 +14,11 @@ describe one snapshot taken once, at plan time.
|
|
|
12
14
|
|
|
13
15
|
- **Inherit the plan-time snapshot silently.** Single source, but apply would
|
|
14
16
|
overwrite an edit made between plan review and `--apply` without the user's
|
|
15
|
-
knowledge — violating the installer's first
|
|
17
|
+
knowledge — violating the [installer's first
|
|
18
|
+
principle](../design/installer-design.md#principles).
|
|
16
19
|
- **Keep re-deriving `previous` at write time** (previous status quo). The
|
|
17
|
-
preview and the record can disagree, and the secret guard
|
|
20
|
+
preview and the record can disagree, and the secret guard (the
|
|
21
|
+
`withSecretGuard` wrapper in `src/installer/hosts/index.ts`), which checks the
|
|
18
22
|
plan-time value, no longer covers what is actually recorded.
|
|
19
23
|
|
|
20
24
|
## Consequences
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Share one config base layer across hosts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Status: Accepted — shipped in 0.7.0 (see [CHANGELOG](../../CHANGELOG.md)).
|
|
4
|
+
|
|
5
|
+
The option pipeline was single-sourced — names, defaults, and clamping resolved through
|
|
6
|
+
one chain (`src/core/constants.ts` → `src/core/env.ts` → `src/core/options.ts`) — but the
|
|
7
|
+
channels feeding it were per
|
|
4
8
|
host: `DEEPSEEK_*` shell variables on Pi, only `ctx.options` on OpenCode, and
|
|
5
9
|
on Codex only the names the installer's `env_vars` entry forwards — just
|
|
6
10
|
`DEEPSEEK_API_KEY`, so every other knob set in the shell silently never
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Expose need_content as the agent's per-call boolean
|
|
2
|
+
|
|
3
|
+
Status: Accepted — shipped in 0.10.0 (see [CHANGELOG](../../CHANGELOG.md)).
|
|
4
|
+
|
|
5
|
+
DeepSeek's Search API accepts a `need_content` boolean — return each result's page body —
|
|
6
|
+
that this repo had hardcoded `false` since the first release: the wire field arrived, the
|
|
7
|
+
pipeline dropped it, and no search result ever carried a page body
|
|
8
|
+
([search-inline-content.md](../research/search-inline-content.md)). The same research
|
|
9
|
+
pinned why the value cannot travel alone: DeepSeek documents no size bound for the
|
|
10
|
+
returned content, host output caps run as tight as Pi's 20 KB MCP-path truncation, and
|
|
11
|
+
the 30 s default search timeout does not budget for a server-side page crawl. We decided
|
|
12
|
+
that the boolean itself becomes a per-call tool parameter on the model-facing surfaces
|
|
13
|
+
(the MCP server and the Pi extension), defaulting to `false`, while the deployment owns
|
|
14
|
+
two envelope-only knobs that apply whenever content flows: `searchContentMaxChars` (the
|
|
15
|
+
per-result body budget, default 1,500) and `searchContentTimeoutMs` (the timeout a
|
|
16
|
+
content call runs on, default 60 s). Neither knob is ever a tool parameter — the model
|
|
17
|
+
cannot see which host caps its output, so it cannot own a budget.
|
|
18
|
+
|
|
19
|
+
## Considered Options
|
|
20
|
+
|
|
21
|
+
- **A tristate `searchContent: off | on | auto` config mode** gating whether the
|
|
22
|
+
parameter is exposed. The wire value is a boolean; `auto` is invented vocabulary, and
|
|
23
|
+
no per-call parameter in this repo (`count`, fetch `maxChars`) is mode-gated. The
|
|
24
|
+
`on` state's only real beneficiary is OpenCode, whose `websearch` provider input the
|
|
25
|
+
host fixes to `query` — the same upstream gap that already blocks per-call `count`
|
|
26
|
+
([opencode-v2.md](../agents/opencode-v2.md)).
|
|
27
|
+
- **Default-on inline content** (Jina's architecture). DeepSeek documents no size bound
|
|
28
|
+
for `content`; a default `count=10` response at typical page sizes runs 30–110 KB
|
|
29
|
+
against host caps that truncate near 20 KB, and per-request billing makes the call
|
|
30
|
+
free, not the context bloat.
|
|
31
|
+
- **The previous status quo** (hardcoded `false`). An agent that needs page bodies must
|
|
32
|
+
guess from summaries which URLs to fetch; a wrong guess is a silent miss.
|
|
33
|
+
|
|
34
|
+
## Consequences
|
|
35
|
+
|
|
36
|
+
The model decides per call whether a search carries page bodies — one round-trip
|
|
37
|
+
replaces search-plus-fetch when recall matters, and summaries stay the default when
|
|
38
|
+
they suffice. A page body replaces its result's digest, clamped to
|
|
39
|
+
`searchContentMaxChars` with an ellipsis marker, so a response's content volume is
|
|
40
|
+
bounded by budget × count and can never blow a host cap by an undocumented server-side
|
|
41
|
+
size. The text channel renders bodies as indented Markdown that keeps heading and list
|
|
42
|
+
structure; digests stay one-line. `searchContentMaxChars: 0` drops bodies entirely (the
|
|
43
|
+
digest renders) — a deployment kill switch that still pays the slower call, so leaving
|
|
44
|
+
the parameter false is the better tool for the model. A result whose content comes back
|
|
45
|
+
empty — the API documents per-result absence — falls back to its summary, so a content
|
|
46
|
+
call degrades to today's output rather than to nothing. OpenCode stays summary-only
|
|
47
|
+
until its provider input widens upstream. Design detail (budget arithmetic, rendering,
|
|
48
|
+
per-adapter composition) lives in the
|
|
49
|
+
[search content design note](../design/search-content-design.md).
|
|
@@ -38,20 +38,23 @@ The quickest option is the installer CLI:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
npx deepseek-web-retrieval init --host claude-code --scope project \
|
|
41
|
-
--search <
|
|
41
|
+
--search <optional|preferred|forced|off> --fetch <optional|preferred|forced|off>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
It prints the full plan — every file, old value → new value, and notes about existing MCP
|
|
45
45
|
servers — and writes nothing until you pass `--apply`. Add `--pin` to register the exact
|
|
46
46
|
version of the CLI you are running instead of the always-latest package name. `uninstall`
|
|
47
47
|
removes recorded additions and restores snapshotted values that have not since been edited.
|
|
48
|
+
|
|
48
49
|
`--scope project` registers the server in `./.mcp.json` (shareable via VCS) and writes tier
|
|
49
50
|
artifacts to `./.claude/settings.json` and `./CLAUDE.md`; `--scope global` uses
|
|
50
51
|
`~/.claude.json`, `~/.claude/settings.json`, and `~/.claude/CLAUDE.md` instead — the two
|
|
51
52
|
scopes use disjoint files, so both can coexist. An `off` capability is written as the
|
|
52
53
|
tool's full id in the `permissions.deny` array — Claude Code's own mechanism, which removes
|
|
53
54
|
the tool from the model's context while the server keeps running — merging with any entries
|
|
54
|
-
you put there yourself.
|
|
55
|
+
you put there yourself.
|
|
56
|
+
|
|
57
|
+
When `claude` is on PATH, `init` also probes `claude --version` and
|
|
55
58
|
adds a plan note when the installed release differs from the tested lock (see
|
|
56
59
|
[hosts.jsonc](../hosts.jsonc)) — version-anchored behavior such as the deny rules may have
|
|
57
60
|
drifted between the two.
|
|
@@ -168,9 +171,16 @@ The model calls `mcp__deepseek__deepseek_web_search` or `mcp__deepseek__deepseek
|
|
|
168
171
|
|
|
169
172
|
The search tool accepts an optional `original_question` argument — the user's question in
|
|
170
173
|
their own words — forwarded as DeepSeek's `ori_question` to sharpen search intent; omit it
|
|
171
|
-
when the query already stands alone.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
when the query already stands alone. It also takes an optional `count` (1–50) for the call,
|
|
175
|
+
and the fetch tool takes an optional `maxChars` (0–1,000,000) per-call output budget; each
|
|
176
|
+
overrides the configured default for that call, so the model can widen a truncated fetch or
|
|
177
|
+
ask for more results without rephrasing the query. When configured domain or language
|
|
178
|
+
operators change the query actually sent, the result text opens with
|
|
179
|
+
`Searched for: <effective query>` (plus any degradation applied to fit the API's
|
|
180
|
+
128-character limit), so the model can attribute results to the configuration in effect.
|
|
181
|
+
|
|
182
|
+
Tool output is capped at 25k tokens by default (`MAX_MCP_OUTPUT_TOKENS`, a Claude Code
|
|
183
|
+
environment setting), and successful
|
|
174
184
|
text results longer than 50,000 characters are saved to a file and referenced — not
|
|
175
185
|
dropped silently.
|
|
176
186
|
|
|
@@ -249,7 +259,7 @@ one vocabulary pair, one pipeline. `—` marks host-integration entries the file
|
|
|
249
259
|
| Claude Code | locked in [`docs/hosts.jsonc`](../hosts.jsonc) |
|
|
250
260
|
| MCP revision | `2026-07-28` negotiated; server accepts `2024-11-05`–`2026-07-28` |
|
|
251
261
|
| MCP SDK | `@modelcontextprotocol/server` 2.3.1 |
|
|
252
|
-
| Runtime | Node.js 20
|
|
262
|
+
| Runtime | Node.js 20 or newer (stdio) |
|
|
253
263
|
| DeepSeek API | `/v1/tools/search`, `/v1/tools/fetch` |
|
|
254
264
|
|
|
255
265
|
Tested with Claude Code at the `docs/hosts.jsonc` lock on Linux over stdio: the keyless
|
package/docs/agents/codex.md
CHANGED
|
@@ -17,10 +17,10 @@ The tools appear in Codex as `mcp__deepseek__deepseek_web_search` and
|
|
|
17
17
|
[Control tiers](#control-tiers) for routing it away.
|
|
18
18
|
|
|
19
19
|
The server recognizes Codex's MCP client identity (`codex-mcp-client`, declared in the
|
|
20
|
-
initialize handshake) and returns text-only tool results
|
|
21
|
-
blocks with the serialized `structuredContent` JSON when it is present, so for
|
|
22
|
-
structured mirror is omitted and the model reads clean Markdown. Other
|
|
23
|
-
both the text and `structuredContent`.
|
|
20
|
+
initialize handshake) and returns text-only tool results for it. Codex replaces the
|
|
21
|
+
content blocks with the serialized `structuredContent` JSON when it is present, so for
|
|
22
|
+
Codex the structured mirror is omitted and the model reads clean Markdown. Other
|
|
23
|
+
clients receive both the text and `structuredContent`.
|
|
24
24
|
|
|
25
25
|
For shared search/fetch limits, retries, and privacy behavior, see
|
|
26
26
|
[General behavior](../../README.md#general-behavior).
|
|
@@ -42,7 +42,7 @@ The quickest option is the installer CLI:
|
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
npx deepseek-web-retrieval init --host codex --scope global \
|
|
45
|
-
--search <
|
|
45
|
+
--search <optional|preferred|forced|off> --fetch <optional|preferred|forced|off>
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
It prints the full plan — every file, old value → new value, and notes about existing
|
|
@@ -117,7 +117,7 @@ built-in fetch tool, so the tiers differ per capability:
|
|
|
117
117
|
|
|
118
118
|
| Capability | Optional | Preferred | Forced |
|
|
119
119
|
| --- | --- | --- | --- |
|
|
120
|
-
| Search | Tools registered; the built-in `web_search` stays available | Plus an AGENTS.md rules block steering the model to `mcp__deepseek__deepseek_web_search` | Exclusion: `web_search = "disabled"` at the top level of config.toml |
|
|
120
|
+
| Search | Tools registered; the built-in `web_search` stays available | Plus an AGENTS.md rules block steering the model to `mcp__deepseek__deepseek_web_search` | Exclusion: `web_search = "disabled"` at the top level of `config.toml` |
|
|
121
121
|
| Fetch | Tools registered | Plus the rules block | De-facto: no built-in fetch tool exists |
|
|
122
122
|
|
|
123
123
|
The installer maps each tier to these artifacts. `AGENTS.md` rules land in
|
|
@@ -148,7 +148,13 @@ The model calls `mcp__deepseek__deepseek_web_search` or `mcp__deepseek__deepseek
|
|
|
148
148
|
|
|
149
149
|
The search tool accepts an optional `original_question` argument — the user's question in
|
|
150
150
|
their own words — forwarded as DeepSeek's `ori_question` to sharpen search intent; omit it
|
|
151
|
-
when the query already stands alone.
|
|
151
|
+
when the query already stands alone. It also takes an optional `count` (1–50) for the call,
|
|
152
|
+
and the fetch tool takes an optional `maxChars` (0–1,000,000) per-call output budget; each
|
|
153
|
+
overrides the configured default for that call, so the model can widen a truncated fetch or
|
|
154
|
+
ask for more results without rephrasing the query. When configured domain or language
|
|
155
|
+
operators change the query actually sent, the result text opens with
|
|
156
|
+
`Searched for: <effective query>` (plus any degradation applied to fit the API's
|
|
157
|
+
128-character limit), so the model can attribute results to the configuration in effect.
|
|
152
158
|
|
|
153
159
|
## Configuration
|
|
154
160
|
|
|
@@ -225,7 +231,7 @@ one vocabulary pair, one pipeline. `—` marks host-integration entries the file
|
|
|
225
231
|
| Codex | locked in [`docs/hosts.jsonc`](../hosts.jsonc) |
|
|
226
232
|
| MCP revision | `2025-06-18` negotiated (`mcp_2026_07_28` behind a flag); server accepts `2024-11-05`–`2026-07-28` |
|
|
227
233
|
| MCP SDK | `@modelcontextprotocol/server` 2.3.1 |
|
|
228
|
-
| Runtime | Node.js 20
|
|
234
|
+
| Runtime | Node.js 20 or newer (stdio) |
|
|
229
235
|
| DeepSeek API | `/v1/tools/search`, `/v1/tools/fetch` |
|
|
230
236
|
|
|
231
237
|
Tested with Codex 0.163.0 on Linux over stdio.
|
package/docs/agents/domain.md
CHANGED
|
@@ -14,7 +14,7 @@ If any of these files don't exist, **proceed silently**. Don't flag their absenc
|
|
|
14
14
|
|
|
15
15
|
Single-context repo (most repos):
|
|
16
16
|
|
|
17
|
-
```
|
|
17
|
+
```text
|
|
18
18
|
/
|
|
19
19
|
├── CONTEXT.md
|
|
20
20
|
├── docs/adr/
|
|
@@ -25,7 +25,7 @@ Single-context repo (most repos):
|
|
|
25
25
|
|
|
26
26
|
Multi-context repo (presence of `CONTEXT-MAP.md` at the root):
|
|
27
27
|
|
|
28
|
-
```
|
|
28
|
+
```text
|
|
29
29
|
/
|
|
30
30
|
├── CONTEXT-MAP.md
|
|
31
31
|
├── docs/adr/ ← system-wide decisions
|
|
@@ -5,7 +5,7 @@ Issues and specs for this repo live as GitHub issues. Use the `gh` CLI for all o
|
|
|
5
5
|
## Conventions
|
|
6
6
|
|
|
7
7
|
- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
|
|
8
|
-
- **Read an issue**: `gh issue view <number> --comments
|
|
8
|
+
- **Read an issue**: `gh issue view <number> --comments` for reading; add `--json body,labels,comments` (with `--jq` to project fields) when scripting.
|
|
9
9
|
- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
|
|
10
10
|
- **Comment on an issue**: `gh issue comment <number> --body "..."`
|
|
11
11
|
- **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
|
|
@@ -15,7 +15,7 @@ Infer the repo from `git remote -v`; `gh` does this automatically when run insid
|
|
|
15
15
|
|
|
16
16
|
## Pull requests as a triage surface
|
|
17
17
|
|
|
18
|
-
**PRs as a request surface: no.** _(
|
|
18
|
+
**PRs as a request surface: no.** _(Maintainers only: set to `yes` if this repo treats external PRs as feature requests; the `/triage` skill reads this flag.)_
|
|
19
19
|
|
|
20
20
|
When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents:
|
|
21
21
|
|
|
@@ -39,7 +39,7 @@ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tic
|
|
|
39
39
|
|
|
40
40
|
- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`.
|
|
41
41
|
- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #<map>` at the top of the child body. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
|
|
42
|
-
- **Blocking**: GitHub's **native issue dependencies**, the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`).
|
|
43
|
-
- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0
|
|
42
|
+
- **Blocking**: GitHub's **native issue dependencies**, the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`). Read the resulting block count from the issue's REST representation — `gh api repos/<owner>/<repo>/issues/<n> --jq .issue_dependencies_summary.blocked_by` (open blockers only, the live gate; `gh issue view --json` does not expose this field). Where dependencies aren't available, fall back to a `Blocked by: #<n>, #<n>` line at the top of the child body. A ticket is unblocked when every blocker is closed.
|
|
43
|
+
- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0` read as above, or an open issue in the `Blocked by` line) or an assignee; first in map order wins.
|
|
44
44
|
- **Claim**: `gh issue edit <n> --add-assignee @me`, the session's first write.
|
|
45
|
-
- **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer
|
|
45
|
+
- **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer to the map's Decisions-so-far (link the resolved child; include the gist URL if the resolving session created one).
|
|
@@ -22,7 +22,7 @@ For configuration layers, the full knob mapping, and defaults, see the
|
|
|
22
22
|
|
|
23
23
|
- OpenCode v2 with `@opencode/plugin` in the `^2.0.32` peer range; the tested version
|
|
24
24
|
is recorded in [`docs/hosts.jsonc`](../hosts.jsonc)
|
|
25
|
-
- Node.js 20
|
|
25
|
+
- Node.js 20 or newer and npm when using the installer CLI
|
|
26
26
|
- A DeepSeek account with access to `/v1/tools/search` and `/v1/tools/fetch`
|
|
27
27
|
- A funded DeepSeek account; Search and Fetch are billed per successful request
|
|
28
28
|
- A DeepSeek credential stored in OpenCode, or `DEEPSEEK_API_KEY`
|
|
@@ -41,11 +41,14 @@ npx deepseek-web-retrieval init --host opencode --scope <project|global> \
|
|
|
41
41
|
|
|
42
42
|
It prints the full plan — every file, old value → new value — and writes nothing until
|
|
43
43
|
you pass `--apply`. Add `--pin` to register the exact version of the CLI you are running
|
|
44
|
-
instead of the always-latest package name. It snapshots the current `websearch.provider`
|
|
45
|
-
replaces it, merges `permissions` without touching yours,
|
|
46
|
-
`opencode.jsonc`, and `uninstall` restores recorded values that
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
instead of the always-latest package name. It snapshots the current `websearch.provider`
|
|
45
|
+
before the forced tier replaces it, merges `permissions` without touching yours,
|
|
46
|
+
preserves comments in `opencode.jsonc`, and `uninstall` restores recorded values that
|
|
47
|
+
have not since been edited.
|
|
48
|
+
|
|
49
|
+
> [!NOTE]
|
|
50
|
+
> Search has no `preferred` tier on OpenCode: the provider is host-level config, never
|
|
51
|
+
> a model choice, so the CLI rejects it.
|
|
49
52
|
|
|
50
53
|
### OpenCode CLI install
|
|
51
54
|
|
|
@@ -176,9 +179,20 @@ Fetch https://opencode.ai/v2/docs/build/plugins and summarize the plugin lifecyc
|
|
|
176
179
|
The model calls `websearch` (provider `deepseek`) or `deepseek_fetch`. When
|
|
177
180
|
`fetchOverrideWebfetch` is enabled, Markdown fetches go through `webfetch` instead.
|
|
178
181
|
|
|
179
|
-
DeepSeek's optional `ori_question` is not sent on this path
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
DeepSeek's optional `ori_question` is not sent on this path, and the model cannot request a
|
|
183
|
+
per-call result count or inline page content (`need_content`): OpenCode's `websearch` tool
|
|
184
|
+
input is fixed to `query` (verified unchanged at `@opencode/schema` 2.1.4, the drift check
|
|
185
|
+
above the 2.0.32 lock), so the provider has no channel for either — search stays
|
|
186
|
+
summary-only here while the MCP server and the Pi extension expose both parameters. Upstream requests:
|
|
187
|
+
[anomalyco/opencode#58635](https://github.com/anomalyco/opencode/issues/58635) (session linkage)
|
|
188
|
+
and [#58636](https://github.com/anomalyco/opencode/issues/58636) (per-call `count`); see the
|
|
189
|
+
[research note](../research/ori-question-sourcing.md). The fetch tools are not constrained:
|
|
190
|
+
they accept an optional per-call `maxChars` (0–1,000,000) that overrides the configured
|
|
191
|
+
`fetchMaxChars` for one call, so the model can widen the budget after seeing a
|
|
192
|
+
`[content truncated]` marker. The effective-query header and query degradation notes have no
|
|
193
|
+
channel on this path either — OpenCode's result shape is closed — but degradation still runs,
|
|
194
|
+
and a query that exceeds the length limit and cannot be degraded further surfaces as an
|
|
195
|
+
error.
|
|
182
196
|
|
|
183
197
|
## Configuration
|
|
184
198
|
|
|
@@ -202,14 +216,14 @@ environment or file channel.
|
|
|
202
216
|
|
|
203
217
|
| Option | Environment | Default | Description |
|
|
204
218
|
| --- | --- | --- | --- |
|
|
205
|
-
| `searchEnabled` | `DEEPSEEK_ENABLE_SEARCH` | `true` | Register the DeepSeek search provider at all.
|
|
219
|
+
| `searchEnabled` | `DEEPSEEK_ENABLE_SEARCH` | `true` | Register the DeepSeek search provider at all. In `options`, only an explicit `false` disables it; the environment twin also accepts `0`/`no`/`off`. |
|
|
206
220
|
| `count` | `DEEPSEEK_SEARCH_COUNT` | `10` | Results requested from DeepSeek, 1–50. Billing is per request, not per result. |
|
|
207
221
|
| `maxResults` | `DEEPSEEK_SEARCH_MAX_RESULTS` | `10` | Results returned to the model after filtering, 0–50; defaults to `count` when unset. `0` returns no results. |
|
|
208
222
|
| `minRerank` | `DEEPSEEK_SEARCH_MIN_RERANK` | `0` | Drop results below this relevance score. DeepSeek scores are 0–3. A result without a finite score passes while the threshold is `0` and is dropped once it is positive. |
|
|
209
223
|
| `minAuthority` | `DEEPSEEK_SEARCH_MIN_AUTHORITY` | `0` | Drop known authorities below this tier. Authority is 0–4. |
|
|
210
|
-
| `allowUnknownAuthority` | `DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY` | `true` | Keep results whose authority is missing or unknown.
|
|
211
|
-
| `blockedDomains` | `DEEPSEEK_SEARCH_BLOCKED_DOMAINS` |
|
|
212
|
-
| `includeDomains` | `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` |
|
|
224
|
+
| `allowUnknownAuthority` | `DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY` | `true` | Keep results whose authority is missing or unknown. In `options`, only an explicit `false` disables it; the environment twin also accepts `0`/`no`/`off`. |
|
|
225
|
+
| `blockedDomains` | `DEEPSEEK_SEARCH_BLOCKED_DOMAINS` | unset | Add `-site:` operators to the search query. |
|
|
226
|
+
| `includeDomains` | `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` | unset | Restrict results with `site:` operators. |
|
|
213
227
|
| `language` | `DEEPSEEK_SEARCH_LANGUAGE` | unset | Add a `lang:` operator, for example `zh,en`. |
|
|
214
228
|
| `searchLocalization` | `DEEPSEEK_SEARCH_LOCALIZATION` | unset | Valid IPv4 or IPv6 address sent as DeepSeek's `localization` to prefer geo-localized results; invalid values are ignored. Deployment-level only, never a per-call parameter. |
|
|
215
229
|
| `maxSummaryChars` | `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | `1200` | Per-result summary cap, 0–1,000,000. |
|
|
@@ -225,8 +239,8 @@ environment or file channel.
|
|
|
225
239
|
| `fetchTimeoutMs` | `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
226
240
|
| `fetchOverrideWebfetch` | — | `false` | Replace the built-in `webfetch`. |
|
|
227
241
|
| `fetchRegisterTool` | — | `true` | Register the separate `deepseek_fetch` tool. |
|
|
228
|
-
| `fetchAllowedDomains` | `DEEPSEEK_FETCH_ALLOWED_DOMAINS` |
|
|
229
|
-
| `fetchBlockedDomains` | `DEEPSEEK_FETCH_BLOCKED_DOMAINS` |
|
|
242
|
+
| `fetchAllowedDomains` | `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | unset | If non-empty, only these hosts and subdomains may be fetched. |
|
|
243
|
+
| `fetchBlockedDomains` | `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
230
244
|
| `fetchBlockPrivateHosts` | `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. |
|
|
231
245
|
|
|
232
246
|
### Credentials and retries
|
package/docs/agents/pi.md
CHANGED
|
@@ -8,7 +8,9 @@ start. The same build also ships an MCP server over stdio as the fallback path
|
|
|
8
8
|
([below](#the-mcp-fallback-path)); the extension is the recommended one:
|
|
9
9
|
|
|
10
10
|
- The tools are declared to the model like built-ins (`exposure: "direct"` is Pi's own
|
|
11
|
-
default for extension tools — the MCP path
|
|
11
|
+
default for extension tools — the MCP path defaults its tools to
|
|
12
|
+
`exposure: "codemode"`, which hides them from the model unless the entry opts into
|
|
13
|
+
`direct`; that trap does not exist here).
|
|
12
14
|
- Results bypass Pi's MCP layer entirely: no 20 KB middle truncation and no 60 s
|
|
13
15
|
per-request timeout; the adapter's own output cap is the only limit.
|
|
14
16
|
- The key is read from the Pi process environment — no `env` forwarding, no `${VAR}`
|
|
@@ -19,7 +21,8 @@ When loaded, it adds:
|
|
|
19
21
|
- A `deepseek_web_search` tool backed by DeepSeek Search
|
|
20
22
|
- A `deepseek_fetch` tool backed by DeepSeek Fetch
|
|
21
23
|
|
|
22
|
-
Pi 1.3.0 ships no built-in web tool, so the registered tools are the only web path
|
|
24
|
+
Pi 1.3.0 ships no built-in web tool, so the registered tools are the only web path (see
|
|
25
|
+
[Control tiers](#control-tiers)). For
|
|
23
26
|
shared search/fetch limits, retries, and privacy behavior, see
|
|
24
27
|
[General behavior](../../README.md#general-behavior).
|
|
25
28
|
For configuration layers, the full knob mapping, and defaults, see the
|
|
@@ -29,7 +32,7 @@ For configuration layers, the full knob mapping, and defaults, see the
|
|
|
29
32
|
|
|
30
33
|
- Pi with host SDKs in the `^1.3.0` peer range (`>=1.3.0 <2.0.0`); the tested
|
|
31
34
|
version is recorded in [`docs/hosts.jsonc`](../hosts.jsonc)
|
|
32
|
-
- Node.js 20
|
|
35
|
+
- Node.js 20 or newer and npm when using the installer CLI or MCP fallback
|
|
33
36
|
- A DeepSeek account with access to `/v1/tools/search` and `/v1/tools/fetch`
|
|
34
37
|
- A funded DeepSeek account; Search and Fetch are billed per successful request
|
|
35
38
|
- `DEEPSEEK_API_KEY` set in the shell that launches Pi
|
|
@@ -55,7 +58,8 @@ source at the next session start (the first launch fetches the package from npm;
|
|
|
55
58
|
to install the [MCP fallback path](#the-mcp-fallback-path) instead. `uninstall` removes
|
|
56
59
|
recorded additions and restores unchanged configuration values from their snapshots.
|
|
57
60
|
|
|
58
|
-
For upgrades from 0.4.
|
|
61
|
+
For upgrades from a 0.4.x or earlier install (MCP was Pi's default path before 0.5.0),
|
|
62
|
+
select `--path mcp` explicitly to retain the old path, or use
|
|
59
63
|
the extension default to migrate; follow the shared
|
|
60
64
|
[upgrade instructions](../integration.md#upgrading-existing-installs).
|
|
61
65
|
|
|
@@ -86,6 +90,27 @@ pi install /absolute/path/to/deepseek-web-retrieval
|
|
|
86
90
|
The extension entry imports only host-supplied modules (`@earendil-works/pi-coding-agent`,
|
|
87
91
|
`@earendil-works/pi-ai`) and the package's own `src/core/`, so a plain clone works.
|
|
88
92
|
|
|
93
|
+
## Control tiers
|
|
94
|
+
|
|
95
|
+
Pi 1.3.0 ships no built-in web tool, so the registered tools are the only web path at
|
|
96
|
+
every tier — forced is de-facto rather than exclusion:
|
|
97
|
+
|
|
98
|
+
| Capability | Optional | Preferred | Forced |
|
|
99
|
+
| --- | --- | --- | --- |
|
|
100
|
+
| Search | Tools registered — already the only web search | Plus an AGENTS.md rules block steering the model to the search tool | De-facto: no built-in competitor; web-capable MCP servers in `mcp.json` are disabled |
|
|
101
|
+
| Fetch | Tools registered — already the only web fetch | Plus the rules block | De-facto: same |
|
|
102
|
+
|
|
103
|
+
The installer maps each tier to these artifacts. The rules block lands in
|
|
104
|
+
`~/.pi/agent/AGENTS.md` (global) or `./AGENTS.md` (project), naming the path's tool
|
|
105
|
+
ids (`deepseek_web_search` for the extension, `mcp__deepseek__deepseek_web_search` for
|
|
106
|
+
the MCP fallback). Under a forced tier, web-capable MCP servers detected in
|
|
107
|
+
`~/.pi/agent/mcp.json` or `.pi/mcp.json` get `enabled: false` (each prior value
|
|
108
|
+
snapshotted for uninstall); a web-capable `packages` or `extensions` source in
|
|
109
|
+
settings.json cannot be excluded — Pi has no per-package kill switch — so `init`
|
|
110
|
+
refuses the tier instead of promising routing it cannot deliver. The `off` tier is the
|
|
111
|
+
`deepseekWebRetrieval` settings namespace described under
|
|
112
|
+
[Configuration](#configuration).
|
|
113
|
+
|
|
89
114
|
## Authentication
|
|
90
115
|
|
|
91
116
|
`DEEPSEEK_API_KEY` is the only source: the extension runs inside the Pi process and reads
|
|
@@ -110,14 +135,20 @@ The search tool accepts an optional `original_question` input — the user's que
|
|
|
110
135
|
own words — forwarded as DeepSeek's `ori_question` to sharpen search intent. When the model
|
|
111
136
|
leaves it blank, the extension falls back to the most recent user message in the session
|
|
112
137
|
(best-effort; truncated to the API's 128-character limit). The MCP fallback path has no
|
|
113
|
-
session access, so there a blank input simply omits the parameter.
|
|
138
|
+
session access, so there a blank input simply omits the parameter. The search tool also
|
|
139
|
+
takes an optional `count` (1–50) for the call, and the fetch tool an optional `maxChars`
|
|
140
|
+
(0–1,000,000) per-call output budget; each overrides the configured default for that call.
|
|
141
|
+
When configured domain or language operators change the query actually sent, the result text
|
|
142
|
+
opens with `Searched for: <effective query>` (plus any degradation applied to fit the API's
|
|
143
|
+
128-character limit), so the model can attribute results to the configuration in effect.
|
|
114
144
|
|
|
115
145
|
## Configuration
|
|
116
146
|
|
|
117
147
|
The runtime config surface is the same `DEEPSEEK_*` environment the MCP server reads
|
|
118
148
|
(identical defaults and clamping), set in the shell that launches Pi, plus the
|
|
119
149
|
`deepseekWebRetrieval` settings namespace for the off switches (written by the installer;
|
|
120
|
-
it outranks the environment and is preserved by Pi's own settings rewrites).
|
|
150
|
+
it outranks the environment and is preserved by Pi's own settings rewrites). Invalid
|
|
151
|
+
`DEEPSEEK_*` values are dropped at startup and the shared default applies.
|
|
121
152
|
|
|
122
153
|
The shared config file (`~/.config/deepseek-web-retrieval/config.json`, camelCase keys —
|
|
123
154
|
on Windows, `%APPDATA%\deepseek-web-retrieval\config.json`)
|
|
@@ -157,7 +188,7 @@ one vocabulary pair, one pipeline. `—` marks host-integration entries the file
|
|
|
157
188
|
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `fetchTimeoutMs` | `30000` | Fetch timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
158
189
|
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | `fetchAllowedDomains` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
159
190
|
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | `fetchBlockedDomains` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
160
|
-
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `fetchBlockPrivateHosts` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. Set `false`/`0` to disable. |
|
|
191
|
+
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `fetchBlockPrivateHosts` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. Set `false`/`0`/`no`/`off` to disable. |
|
|
161
192
|
|
|
162
193
|
### Credentials and retries
|
|
163
194
|
|
|
@@ -167,8 +198,6 @@ one vocabulary pair, one pipeline. `—` marks host-integration entries the file
|
|
|
167
198
|
| `DEEPSEEK_MAX_RETRIES` | `maxRetries` | `2` | Retries for 408, 425, 429, and 5xx responses, 0–5. |
|
|
168
199
|
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `retryBaseDelayMs` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
169
200
|
|
|
170
|
-
Invalid values fall back to the shared default.
|
|
171
|
-
|
|
172
201
|
## Troubleshooting
|
|
173
202
|
|
|
174
203
|
| Error or symptom | What to do |
|
|
@@ -192,9 +221,9 @@ Invalid values fall back to the shared default.
|
|
|
192
221
|
| Runtime | Inside the Pi process (Node, host-provided) |
|
|
193
222
|
| DeepSeek API | `/v1/tools/search`, `/v1/tools/fetch` |
|
|
194
223
|
|
|
195
|
-
Tested with Pi 1.3.0 on Linux. The extension API
|
|
196
|
-
`ToolDefinition` shape and the settings `packages` key
|
|
197
|
-
(see [the per-host reference](../research/control-matrix.md#pi)).
|
|
224
|
+
Tested with Pi 1.3.0 on Linux. The extension API surface this package relies on — the
|
|
225
|
+
`ToolDefinition` shape and the settings `packages` key — is verified at the locked
|
|
226
|
+
version (see [the per-host reference](../research/control-matrix.md#pi)).
|
|
198
227
|
|
|
199
228
|
## Uninstall
|
|
200
229
|
|
package/docs/configuration.md
CHANGED
|
@@ -13,7 +13,7 @@ guides: [Codex](agents/codex.md), [Claude Code](agents/claude-code.md),
|
|
|
13
13
|
|
|
14
14
|
Every knob resolves through one chain, low → high, identically on every host:
|
|
15
15
|
|
|
16
|
-
```
|
|
16
|
+
```text
|
|
17
17
|
built-in defaults < shared config file < DEEPSEEK_* environment < host-native config
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -26,7 +26,7 @@ variable arrives, not a fifth layer).
|
|
|
26
26
|
## The shared config file
|
|
27
27
|
|
|
28
28
|
`$XDG_CONFIG_HOME/deepseek-web-retrieval/config.json` when `XDG_CONFIG_HOME` is
|
|
29
|
-
set (this wins on every platform, Windows included); otherwise
|
|
29
|
+
set to a non-empty value (this wins on every platform, Windows included); otherwise
|
|
30
30
|
`~/.config/deepseek-web-retrieval/config.json` on Linux and macOS and
|
|
31
31
|
`%APPDATA%\deepseek-web-retrieval\config.json` on Windows. camelCase keys:
|
|
32
32
|
|
|
@@ -49,7 +49,7 @@ environment, or OpenCode's stored credential).
|
|
|
49
49
|
| Knob class | Shared file | Examples |
|
|
50
50
|
| --- | --- | --- |
|
|
51
51
|
| API behavior — the user↔DeepSeek relationship | yes — that is the point of the file | `count`, `blockedDomains`, `language`, `maxRetries` |
|
|
52
|
-
| Host-sensitive — interacts with host output caps and deadlines | carries the safe defaults; a host layer is the recommended override point | `searchTimeoutMs`, `fetchTimeoutMs`, `fetchMaxChars`, `maxSummaryChars` |
|
|
52
|
+
| Host-sensitive — interacts with host output caps and deadlines | carries the safe defaults; a host layer is the recommended override point | `searchTimeoutMs`, `fetchTimeoutMs`, `fetchMaxChars`, `maxSummaryChars`, `searchContentMaxChars`, `searchContentTimeoutMs` |
|
|
53
53
|
| Host integration — the host's tool landscape | rejected — warned about and ignored | `searchEnabled`, `setDefaultWebsearch`, `apiKeySource` |
|
|
54
54
|
|
|
55
55
|
Keep host-independent intent in the shared file; prefer a host layer when a
|
|
@@ -58,8 +58,8 @@ host-sensitive knob would cross its host's cap or deadline.
|
|
|
58
58
|
## The knob vocabulary
|
|
59
59
|
|
|
60
60
|
One knob, two names: the camelCase key for the shared file and OpenCode's
|
|
61
|
-
options, the `DEEPSEEK_*` variable for the environment. The table
|
|
62
|
-
from the same config vocabulary the adapters resolve through, so it cannot
|
|
61
|
+
options, the `DEEPSEEK_*` variable for the environment. The table is
|
|
62
|
+
generated from the same config vocabulary the adapters resolve through, so it cannot
|
|
63
63
|
drift from the code (`bun run docs:matrix` regenerates it; CI checks it).
|
|
64
64
|
|
|
65
65
|
<!-- generated: knob-table — edit src/core/config-summary.ts or env.ts, then run `bun run docs:matrix` -->
|
|
@@ -76,6 +76,8 @@ drift from the code (`bun run docs:matrix` regenerates it; CI checks it).
|
|
|
76
76
|
| `language` | `DEEPSEEK_SEARCH_LANGUAGE` | unset |
|
|
77
77
|
| `searchLocalization` | `DEEPSEEK_SEARCH_LOCALIZATION` | unset |
|
|
78
78
|
| `maxSummaryChars` | `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | 1200 |
|
|
79
|
+
| `searchContentMaxChars` | `DEEPSEEK_SEARCH_CONTENT_MAX_CHARS` | 1500 |
|
|
80
|
+
| `searchContentTimeoutMs` | `DEEPSEEK_SEARCH_CONTENT_TIMEOUT_MS` | 60000 |
|
|
79
81
|
| `searchTimeoutMs` | `DEEPSEEK_SEARCH_TIMEOUT_MS` | 30000 |
|
|
80
82
|
| `fetchMaxChars` | `DEEPSEEK_FETCH_MAX_CHARS` | 16000 |
|
|
81
83
|
| `fetchAllowedDomains` | `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | unset |
|
|
@@ -84,6 +86,7 @@ drift from the code (`bun run docs:matrix` regenerates it; CI checks it).
|
|
|
84
86
|
| `fetchBlockPrivateHosts` | `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | true |
|
|
85
87
|
| `maxRetries` | `DEEPSEEK_MAX_RETRIES` | 2 |
|
|
86
88
|
| `retryBaseDelayMs` | `DEEPSEEK_RETRY_BASE_DELAY_MS` | 250 |
|
|
89
|
+
| `baseUrl` | `DEEPSEEK_BASE_URL` | https://api.deepseek.com |
|
|
87
90
|
|
|
88
91
|
<!-- /generated: knob-table -->
|
|
89
92
|
|
|
@@ -96,8 +99,9 @@ drift from the code (`bun run docs:matrix` regenerates it; CI checks it).
|
|
|
96
99
|
`fetchBlockPrivateHosts`, `searchEnabled`, and `fetchEnabled` are on by
|
|
97
100
|
default; the environment can only turn them off (`false`, `0`, `no`, or
|
|
98
101
|
`off`). The last two have no file key — they are host-integration keys — so
|
|
99
|
-
they exist only as `DEEPSEEK_ENABLE_SEARCH` and `DEEPSEEK_ENABLE_FETCH`.
|
|
100
|
-
|
|
102
|
+
they exist only as `DEEPSEEK_ENABLE_SEARCH` and `DEEPSEEK_ENABLE_FETCH`.
|
|
103
|
+
Setting any of them to `true` explicitly changes nothing: the default is
|
|
104
|
+
already on.
|
|
101
105
|
- **Invalid environment values are dropped** at startup and the default
|
|
102
106
|
applies. `npx deepseek-web-retrieval config` reports every dropped or
|
|
103
107
|
unknown `DEEPSEEK_*` variable as a warning and exits 1, alongside file
|
|
@@ -105,5 +109,18 @@ drift from the code (`bun run docs:matrix` regenerates it; CI checks it).
|
|
|
105
109
|
- **`searchLocalization` must be a valid IPv4 or IPv6 address**; anything else
|
|
106
110
|
is dropped at option resolution. It is deployment-level configuration, never
|
|
107
111
|
a per-call tool parameter.
|
|
112
|
+
- **The content envelope is deployment-level too.** `searchContentMaxChars` and
|
|
113
|
+
`searchContentTimeoutMs` apply only when a call asks for inline page content
|
|
114
|
+
(`need_content: true`, a per-call tool parameter on the MCP server and the Pi
|
|
115
|
+
extension; OpenCode's provider input has no channel for it, so search stays
|
|
116
|
+
summary-only there). They are never tool parameters — the model cannot see
|
|
117
|
+
which host caps its output. `searchContentMaxChars: 0` drops page bodies
|
|
118
|
+
entirely and the summary digest renders.
|
|
119
|
+
- **`baseUrl` routes the retrieval API** (`/v1/tools/search` and
|
|
120
|
+
`/v1/tools/fetch` are composed from it). It is infrastructure routing for
|
|
121
|
+
proxies, gateways, and mock upstreams — not a provider switch, and the package
|
|
122
|
+
never falls back to another search service. Only an http(s) URL survives
|
|
123
|
+
resolution (trailing slashes are stripped); anything else drops back to
|
|
124
|
+
`https://api.deepseek.com`.
|
|
108
125
|
- **Domains** in the environment are comma-separated; entries that are not
|
|
109
126
|
domains are dropped (and reported by `config`).
|
|
@@ -46,7 +46,7 @@ shared base strengthens rather than weakens them (one policy instead of three dr
|
|
|
46
46
|
|
|
47
47
|
Precedence, low → high, identical semantics in every adapter:
|
|
48
48
|
|
|
49
|
-
```
|
|
49
|
+
```text
|
|
50
50
|
built-in defaults < shared config file < DEEPSEEK_* environment < host-native config
|
|
51
51
|
```
|
|
52
52
|
|
|
@@ -133,9 +133,13 @@ A bad shared value now fails everywhere at once, so effective configuration must
|
|
|
133
133
|
|
|
134
134
|
## What this design does not change
|
|
135
135
|
|
|
136
|
-
- `need_content`
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
- `need_content` is no longer hardcoded `false` — it became a per-call tool parameter
|
|
137
|
+
with a deployment-owned envelope
|
|
138
|
+
([search-content-design.md](search-content-design.md),
|
|
139
|
+
[ADR-0003](../adr/0003-need-content-per-call-boolean.md)).
|
|
140
|
+
- `ori_question` remains per-call-only — supplied through the tool input named
|
|
141
|
+
`original_question` (with the Pi session fallback) and sent to the API as `ori_question`;
|
|
142
|
+
it is not configurable.
|
|
139
143
|
- Auth surfaces, capability tiers, and the installer's plan/confirm flow.
|
|
140
144
|
|
|
141
145
|
## Testing
|
|
@@ -154,7 +158,8 @@ existing layers changes. Documentation updates ship with the code: README gains
|
|
|
154
158
|
"Configuration" section with the precedence table and the two-vocabulary table; the host
|
|
155
159
|
guides' option tables gain a shared-file column; the control-matrix note's Pi sentence
|
|
156
160
|
("There is no per-extension options channel: the runtime config surface is the
|
|
157
|
-
`DEEPSEEK_*` environment") is updated to name the file as part of that surface.
|
|
161
|
+
`DEEPSEEK_*` environment") is updated to name the file as part of that surface. All of
|
|
162
|
+
these updates are shipped and in place.
|
|
158
163
|
|
|
159
164
|
**Amendment, 2026-10-23** — two changes approved after this design was confirmed alter
|
|
160
165
|
the effective behavior of *untouched* configurations, superseding the "no existing
|