deepseek-web-retrieval 0.6.0 → 0.7.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 +12 -1
- package/README.md +79 -10
- package/dist/cli.js +2203 -1826
- package/docs/adr/0002-shared-config-base-layer.md +43 -0
- package/docs/agents/codex.md +48 -27
- package/docs/agents/opencode-v2.md +57 -33
- package/docs/agents/pi.md +48 -27
- package/docs/design/config-layering-design.md +180 -0
- package/docs/design/installer-design.md +8 -0
- package/docs/integration.md +6 -3
- package/docs/research/control-matrix.md +15 -2
- package/docs/research/mcp-compatibility.md +4 -1
- package/docs/research/ori-question-sourcing.md +336 -0
- package/docs/research/result-quality-passthrough.md +159 -0
- package/docs/research/search-api-defaults.md +18 -2
- package/docs/research/search-inline-content.md +244 -0
- package/examples/opencode.global.jsonc +3 -2
- package/package.json +2 -1
- package/src/core/auth.ts +3 -0
- package/src/core/client.ts +26 -4
- package/src/core/config-file.ts +168 -0
- package/src/core/config-summary.ts +82 -0
- package/src/core/constants.ts +15 -1
- package/src/core/descriptions.ts +6 -2
- package/src/core/env.ts +99 -32
- package/src/core/format.ts +19 -1
- package/src/core/options.ts +22 -2
- package/src/core/search.ts +6 -0
- package/src/core/types.ts +11 -0
- package/src/installer/cli.ts +50 -16
- package/src/installer/config-command.ts +116 -0
- package/src/installer/hosts/codex.ts +5 -3
- package/src/installer/hosts/opencode.ts +9 -5
- package/src/installer/hosts/pi.ts +10 -6
- package/src/installer/ownership.ts +54 -1
- package/src/installer/paths.ts +7 -1
- package/src/installer/state.ts +72 -19
- package/src/installer/types.ts +10 -0
- package/src/mcp/auth.ts +2 -3
- package/src/mcp/cli.ts +4 -3
- package/src/mcp/serve.ts +10 -1
- package/src/mcp/server.ts +7 -2
- package/src/opencode/plugin.ts +22 -2
- package/src/pi/extension.ts +78 -9
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Share one config base layer across hosts
|
|
2
|
+
|
|
3
|
+
The option pipeline was single-sourced, but the channels feeding it were per
|
|
4
|
+
host: `DEEPSEEK_*` shell variables on Pi, only `ctx.options` on OpenCode, and
|
|
5
|
+
on Codex only the names the installer's `env_vars` entry forwards — just
|
|
6
|
+
`DEEPSEEK_API_KEY`, so every other knob set in the shell silently never
|
|
7
|
+
reached the server. One intent ("20 results, block pinterest.com") took up to
|
|
8
|
+
three configuration acts in two vocabularies. We decided that a shared config
|
|
9
|
+
file becomes the base layer under every existing channel, with the precedence
|
|
10
|
+
`built-in defaults < shared config file < DEEPSEEK_* environment < host-native
|
|
11
|
+
config`, a three-class parameter taxonomy that isolates host integration in
|
|
12
|
+
the host-native layer and rejects it from the file, and no API key in the
|
|
13
|
+
file — auth keeps its existing channels.
|
|
14
|
+
|
|
15
|
+
## Considered Options
|
|
16
|
+
|
|
17
|
+
- **Unify on the file alone** (retire the environment and host-option
|
|
18
|
+
vocabularies so there is one configuration act). But host integration —
|
|
19
|
+
`searchEnabled`/`fetchEnabled`, `setDefaultWebsearch`,
|
|
20
|
+
`fetchOverrideWebfetch`, `fetchRegisterTool`, `apiKeySource` — describes the
|
|
21
|
+
host's tool landscape, not the user↔DeepSeek relationship, so the host layer
|
|
22
|
+
must keep owning it, and retiring `DEEPSEEK_*` would break every existing
|
|
23
|
+
shell profile.
|
|
24
|
+
- **Keep the per-host channels as the only surface** (previous status quo).
|
|
25
|
+
The Codex `env_vars` trap stays — knobs set in the shell reach the server
|
|
26
|
+
only by hand-editing `config.toml` — and the same knob keeps two
|
|
27
|
+
vocabularies across hosts.
|
|
28
|
+
|
|
29
|
+
## Consequences
|
|
30
|
+
|
|
31
|
+
One file — `$XDG_CONFIG_HOME/deepseek-web-retrieval/config.json`, default
|
|
32
|
+
`~/.config/deepseek-web-retrieval/config.json`, camelCase keys — configures
|
|
33
|
+
every host, and host layers keep winning: installer-written intent and
|
|
34
|
+
explicit per-host overrides always outrank the base, bounding the blast
|
|
35
|
+
radius of a bad shared value. Unknown keys and host-integration keys in the
|
|
36
|
+
file draw a one-line stderr warning and are otherwise ignored. Because a bad
|
|
37
|
+
shared value now fails everywhere at once, every adapter prints a
|
|
38
|
+
deviations-from-defaults summary of its effective configuration.
|
|
39
|
+
|
|
40
|
+
The installer's Codex `env_vars` entry forwards every `DEEPSEEK_*` name, so
|
|
41
|
+
environment overrides work on Codex without hand-editing `config.toml`.
|
|
42
|
+
Design detail (per-adapter composition, validation, visibility, rollout)
|
|
43
|
+
lives in the [layering design note](../design/config-layering-design.md).
|
package/docs/agents/codex.md
CHANGED
|
@@ -44,7 +44,9 @@ npx deepseek-web-retrieval init --host codex --scope global \
|
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
It prints the full plan — every file, old value → new value, and notes about existing
|
|
47
|
-
MCP servers — and writes nothing until you pass `--apply`. `
|
|
47
|
+
MCP servers — and writes nothing until you pass `--apply`. Add `--pin` to register the
|
|
48
|
+
exact version of the CLI you are running instead of the always-latest package name.
|
|
49
|
+
`uninstall` removes recorded
|
|
48
50
|
additions and restores snapshotted values that have not since been edited. Codex's config
|
|
49
51
|
lives in `~/.codex/config.toml` at the user level only, so the server registration and kill switch
|
|
50
52
|
are written there even for `--scope project`; the rules file follows the scope. An `off`
|
|
@@ -142,45 +144,64 @@ Fetch https://learn.chatgpt.com/docs/extend/mcp and summarize the config keys.
|
|
|
142
144
|
|
|
143
145
|
The model calls `mcp__deepseek__deepseek_web_search` or `mcp__deepseek__deepseek_fetch`.
|
|
144
146
|
|
|
147
|
+
The search tool accepts an optional `original_question` argument — the user's question in
|
|
148
|
+
their own words — forwarded as DeepSeek's `ori_question` to sharpen search intent; omit it
|
|
149
|
+
when the query already stands alone.
|
|
150
|
+
|
|
145
151
|
## Configuration
|
|
146
152
|
|
|
147
153
|
Set these in the server's `env` table. Values map onto the shared option pipeline, so
|
|
148
154
|
defaults and clamping match the other adapters. `DEEPSEEK_API_KEY` goes in `env_vars`.
|
|
149
155
|
|
|
156
|
+
> [!NOTE]
|
|
157
|
+
> A shared config file — `~/.config/deepseek-web-retrieval/config.json`
|
|
158
|
+
> (Windows: `%APPDATA%\deepseek-web-retrieval\config.json`), camelCase keys —
|
|
159
|
+
> sits under the environment layer and works with no env forwarding at all: the server
|
|
160
|
+
> reads the file itself, making it the way to set knobs without editing `env_vars` (the
|
|
161
|
+
> installer's `env_vars` entry also forwards every `DEEPSEEK_*` name). The file carries
|
|
162
|
+
> neither the API key nor the host-integration switches. Run
|
|
163
|
+
> `npx deepseek-web-retrieval config` to see every knob's effective value and source
|
|
164
|
+
> (it replays file warnings visibly and exits 1 on file problems); `config --search "<query>"`
|
|
165
|
+
> verifies key, config, and network with one billed search.
|
|
166
|
+
|
|
150
167
|
### Search
|
|
151
168
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
169
|
+
The "Config file" column names each key's camelCase twin in the shared config file —
|
|
170
|
+
one vocabulary pair, one pipeline. `—` marks host-integration entries the file rejects.
|
|
171
|
+
|
|
172
|
+
| Env variable | Config file | Default | Description |
|
|
173
|
+
| --- | --- | --- | --- |
|
|
174
|
+
| `DEEPSEEK_ENABLE_SEARCH` | — | `true` | Register the search tool. Only an explicit `false`/`0`/`no`/`off` disables it; at least one tool must stay enabled. |
|
|
175
|
+
| `DEEPSEEK_SEARCH_COUNT` | `count` | `10` | Results requested from DeepSeek, 1–50. Billing is per request, not per result. |
|
|
176
|
+
| `DEEPSEEK_SEARCH_MAX_RESULTS` | `maxResults` | `10` | Results returned to the model after filtering, 0–50; defaults to `DEEPSEEK_SEARCH_COUNT` when unset. `0` returns no results. |
|
|
177
|
+
| `DEEPSEEK_SEARCH_MIN_RERANK` | `minRerank` | `0` | Drop results below this relevance score (0–3); results without a finite score pass at zero and are dropped at a positive threshold. |
|
|
178
|
+
| `DEEPSEEK_SEARCH_MIN_AUTHORITY` | `minAuthority` | `0` | Drop known authorities below this tier. Authority is 0–4. |
|
|
179
|
+
| `DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY` | `allowUnknownAuthority` | `true` | Keep results whose authority is missing or unknown. Set `false`/`0`/`no`/`off` to drop them. |
|
|
180
|
+
| `DEEPSEEK_SEARCH_BLOCKED_DOMAINS` | `blockedDomains` | unset | Comma-separated; adds `-site:` operators to the query. |
|
|
181
|
+
| `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` | `includeDomains` | unset | Comma-separated; restricts results with `site:` operators. |
|
|
182
|
+
| `DEEPSEEK_SEARCH_LANGUAGE` | `language` | unset | Adds a `lang:` operator, for example `zh,en`. |
|
|
183
|
+
| `DEEPSEEK_SEARCH_LOCALIZATION` | `searchLocalization` | 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. |
|
|
184
|
+
| `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | `maxSummaryChars` | `1200` | Per-result summary cap, 0–1,000,000. |
|
|
185
|
+
| `DEEPSEEK_SEARCH_TIMEOUT_MS` | `searchTimeoutMs` | `30000` | Search timeout, 1,000–120,000 ms. |
|
|
165
186
|
|
|
166
187
|
### Fetch
|
|
167
188
|
|
|
168
|
-
| Env variable | Default | Description |
|
|
169
|
-
| --- | --- | --- |
|
|
170
|
-
| `DEEPSEEK_ENABLE_FETCH` | `true` | Register the fetch tool. Same false-only semantics as `DEEPSEEK_ENABLE_SEARCH`. |
|
|
171
|
-
| `DEEPSEEK_FETCH_MAX_CHARS` | `16000` | Maximum characters returned, including the title, 0–1,000,000. |
|
|
172
|
-
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
173
|
-
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
174
|
-
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
175
|
-
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. |
|
|
189
|
+
| Env variable | Config file | Default | Description |
|
|
190
|
+
| --- | --- | --- | --- |
|
|
191
|
+
| `DEEPSEEK_ENABLE_FETCH` | — | `true` | Register the fetch tool. Same false-only semantics as `DEEPSEEK_ENABLE_SEARCH`. |
|
|
192
|
+
| `DEEPSEEK_FETCH_MAX_CHARS` | `fetchMaxChars` | `16000` | Maximum characters returned, including the title, 0–1,000,000. |
|
|
193
|
+
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `fetchTimeoutMs` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
194
|
+
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | `fetchAllowedDomains` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
195
|
+
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | `fetchBlockedDomains` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
196
|
+
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `fetchBlockPrivateHosts` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. |
|
|
176
197
|
|
|
177
198
|
### Credentials and retries
|
|
178
199
|
|
|
179
|
-
| Env variable | Default | Description |
|
|
180
|
-
| --- | --- | --- |
|
|
181
|
-
| `DEEPSEEK_API_KEY` | required | DeepSeek API key, forwarded via `env_vars`. The server refuses to start without it. |
|
|
182
|
-
| `DEEPSEEK_MAX_RETRIES` | `
|
|
183
|
-
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
200
|
+
| Env variable | Config file | Default | Description |
|
|
201
|
+
| --- | --- | --- | --- |
|
|
202
|
+
| `DEEPSEEK_API_KEY` | — | required | DeepSeek API key, forwarded via `env_vars`. The server refuses to start without it. |
|
|
203
|
+
| `DEEPSEEK_MAX_RETRIES` | `maxRetries` | `2` | Retries for 408, 425, 429, and 5xx responses, 0–5. |
|
|
204
|
+
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `retryBaseDelayMs` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
184
205
|
|
|
185
206
|
## Troubleshooting
|
|
186
207
|
|
|
@@ -38,7 +38,8 @@ npx deepseek-web-retrieval init --host opencode --scope <project|global> \
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
It prints the full plan — every file, old value → new value — and writes nothing until
|
|
41
|
-
you pass `--apply`.
|
|
41
|
+
you pass `--apply`. Add `--pin` to register the exact version of the CLI you are running
|
|
42
|
+
instead of the always-latest package name. It snapshots the current `websearch.provider` before the forced tier
|
|
42
43
|
replaces it, merges `permissions` without touching yours, preserves comments in
|
|
43
44
|
`opencode.jsonc`, and `uninstall` restores recorded values that have not since been edited.
|
|
44
45
|
Search has no `preferred` tier on OpenCode (the provider is host-level config, never a
|
|
@@ -112,11 +113,14 @@ follow the [upgrade instructions](../integration.md#upgrading-existing-installs)
|
|
|
112
113
|
**Global checkout**
|
|
113
114
|
|
|
114
115
|
```bash
|
|
115
|
-
git clone https://github.com/
|
|
116
|
+
git clone https://github.com/guokhou/deepseek-web-retrieval.git \
|
|
116
117
|
~/.config/opencode/vendor/deepseek-web-retrieval
|
|
117
118
|
```
|
|
118
119
|
|
|
119
|
-
Use `"package": "./vendor/deepseek-web-retrieval"`.
|
|
120
|
+
Use `"package": "./vendor/deepseek-web-retrieval"`. On Windows the global config root is
|
|
121
|
+
`%APPDATA%\opencode\` (unless `XDG_CONFIG_HOME` is explicitly set), so clone into
|
|
122
|
+
`%APPDATA%\opencode\vendor\deepseek-web-retrieval` there — the same root the installer
|
|
123
|
+
writes to.
|
|
120
124
|
|
|
121
125
|
**Project checkout**
|
|
122
126
|
|
|
@@ -131,7 +135,8 @@ Use `"package": "./.opencode/vendor/deepseek-web-retrieval"`.
|
|
|
131
135
|
**Auto-discovery**
|
|
132
136
|
|
|
133
137
|
Clone or copy the repository into `~/.config/opencode/plugins/deepseek-web-retrieval` or
|
|
134
|
-
`.opencode/plugins/deepseek-web-retrieval
|
|
138
|
+
`.opencode/plugins/deepseek-web-retrieval` (on Windows, `%APPDATA%\opencode\plugins\…`).
|
|
139
|
+
Auto-discovered plugins do not receive options,
|
|
135
140
|
so `webfetch` stays in place; the `deepseek` search provider and `deepseek_fetch` are still
|
|
136
141
|
added.
|
|
137
142
|
|
|
@@ -169,47 +174,66 @@ Fetch https://opencode.ai/v2/docs/build/plugins and summarize the plugin lifecyc
|
|
|
169
174
|
The model calls `websearch` (provider `deepseek`) or `deepseek_fetch`. When
|
|
170
175
|
`fetchOverrideWebfetch` is enabled, Markdown fetches go through `webfetch` instead.
|
|
171
176
|
|
|
177
|
+
DeepSeek's optional `ori_question` is not sent on this path: OpenCode's `websearch` tool
|
|
178
|
+
input is fixed to `query` at 2.0.32, so the provider has no channel for it (see the
|
|
179
|
+
[research note](../research/ori-question-sourcing.md)).
|
|
180
|
+
|
|
172
181
|
## Configuration
|
|
173
182
|
|
|
174
183
|
Set these in the plugin's `options` object.
|
|
175
184
|
|
|
185
|
+
> [!NOTE]
|
|
186
|
+
> These options use the same camelCase vocabulary as the shared config file
|
|
187
|
+
> (`~/.config/deepseek-web-retrieval/config.json`; on Windows,
|
|
188
|
+
> `%APPDATA%\deepseek-web-retrieval\config.json`), with the `DEEPSEEK_*` environment in
|
|
189
|
+
> between: `shared file < environment < options`. Configure once in the file — it works on
|
|
190
|
+
> every host — and override per host here in `options`; existing `options` keep winning
|
|
191
|
+
> exactly as before. `npx deepseek-web-retrieval config` shows the file/env/defaults view
|
|
192
|
+
> of every knob (these `options` sit above it, so check them here when it differs).
|
|
193
|
+
|
|
176
194
|
### Search
|
|
177
195
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
|
184
|
-
|
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
196
|
+
The "Environment" column names each option's `DEEPSEEK_*` twin — the plugin reads the
|
|
197
|
+
environment as the layer beneath these options, and the same camelCase keys also work
|
|
198
|
+
in the shared config file beneath both. `—` marks host-integration options with no
|
|
199
|
+
environment or file channel.
|
|
200
|
+
|
|
201
|
+
| Option | Environment | Default | Description |
|
|
202
|
+
| --- | --- | --- | --- |
|
|
203
|
+
| `searchEnabled` | `DEEPSEEK_ENABLE_SEARCH` | `true` | Register the DeepSeek search provider at all. Only an explicit `false` disables it. |
|
|
204
|
+
| `count` | `DEEPSEEK_SEARCH_COUNT` | `10` | Results requested from DeepSeek, 1–50. Billing is per request, not per result. |
|
|
205
|
+
| `maxResults` | `DEEPSEEK_SEARCH_MAX_RESULTS` | `10` | Results returned to the model after filtering, 0–50; defaults to `count` when unset. `0` returns no results. |
|
|
206
|
+
| `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. |
|
|
207
|
+
| `minAuthority` | `DEEPSEEK_SEARCH_MIN_AUTHORITY` | `0` | Drop known authorities below this tier. Authority is 0–4. |
|
|
208
|
+
| `allowUnknownAuthority` | `DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY` | `true` | Keep results whose authority is missing or unknown. Only an explicit `false` disables it. |
|
|
209
|
+
| `blockedDomains` | `DEEPSEEK_SEARCH_BLOCKED_DOMAINS` | `[]` | Add `-site:` operators to the search query. |
|
|
210
|
+
| `includeDomains` | `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` | `[]` | Restrict results with `site:` operators. |
|
|
211
|
+
| `language` | `DEEPSEEK_SEARCH_LANGUAGE` | unset | Add a `lang:` operator, for example `zh,en`. |
|
|
212
|
+
| `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. |
|
|
213
|
+
| `maxSummaryChars` | `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | `1200` | Per-result summary cap, 0–1,000,000. |
|
|
214
|
+
| `searchTimeoutMs` | `DEEPSEEK_SEARCH_TIMEOUT_MS` | `30000` | Search timeout, 1,000–120,000 ms. |
|
|
215
|
+
| `setDefaultWebsearch` | — | `false` | Make `deepseek` the default websearch provider when the plugin loads. |
|
|
192
216
|
|
|
193
217
|
### Fetch
|
|
194
218
|
|
|
195
|
-
| Option | Default | Description |
|
|
196
|
-
| --- | --- | --- |
|
|
197
|
-
| `fetchEnabled` | `true` | Register any DeepSeek fetch tooling (the separate tool and the webfetch override). |
|
|
198
|
-
| `fetchMaxChars` | `16000` | Maximum characters returned, including the title, 0–1,000,000. |
|
|
199
|
-
| `fetchTimeoutMs` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
200
|
-
| `fetchOverrideWebfetch` | `false` | Replace the built-in `webfetch`. |
|
|
201
|
-
| `fetchRegisterTool` | `true` | Register the separate `deepseek_fetch` tool. |
|
|
202
|
-
| `fetchAllowedDomains` | `[]` | If non-empty, only these hosts and subdomains may be fetched. |
|
|
203
|
-
| `fetchBlockedDomains` | `[]` | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
204
|
-
| `fetchBlockPrivateHosts` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. |
|
|
219
|
+
| Option | Environment | Default | Description |
|
|
220
|
+
| --- | --- | --- | --- |
|
|
221
|
+
| `fetchEnabled` | `DEEPSEEK_ENABLE_FETCH` | `true` | Register any DeepSeek fetch tooling (the separate tool and the webfetch override). |
|
|
222
|
+
| `fetchMaxChars` | `DEEPSEEK_FETCH_MAX_CHARS` | `16000` | Maximum characters returned, including the title, 0–1,000,000. |
|
|
223
|
+
| `fetchTimeoutMs` | `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
224
|
+
| `fetchOverrideWebfetch` | — | `false` | Replace the built-in `webfetch`. |
|
|
225
|
+
| `fetchRegisterTool` | — | `true` | Register the separate `deepseek_fetch` tool. |
|
|
226
|
+
| `fetchAllowedDomains` | `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | `[]` | If non-empty, only these hosts and subdomains may be fetched. |
|
|
227
|
+
| `fetchBlockedDomains` | `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | `[]` | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
228
|
+
| `fetchBlockPrivateHosts` | `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. |
|
|
205
229
|
|
|
206
230
|
### Credentials and retries
|
|
207
231
|
|
|
208
|
-
| Option | Default | Description |
|
|
209
|
-
| --- | --- | --- |
|
|
210
|
-
| `apiKeySource` | `"auto"` | Credential strategy: `"auto"`, `"opencode"`, or `"env"`. |
|
|
211
|
-
| `maxRetries` | `
|
|
212
|
-
| `retryBaseDelayMs` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
232
|
+
| Option | Environment | Default | Description |
|
|
233
|
+
| --- | --- | --- | --- |
|
|
234
|
+
| `apiKeySource` | — | `"auto"` | Credential strategy: `"auto"`, `"opencode"`, or `"env"`. |
|
|
235
|
+
| `maxRetries` | `DEEPSEEK_MAX_RETRIES` | `2` | Retries for 408, 425, 429, and 5xx responses, 0–5. |
|
|
236
|
+
| `retryBaseDelayMs` | `DEEPSEEK_RETRY_BASE_DELAY_MS` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
213
237
|
|
|
214
238
|
## Troubleshooting
|
|
215
239
|
|
package/docs/agents/pi.md
CHANGED
|
@@ -42,7 +42,9 @@ npx deepseek-web-retrieval init --host pi --scope <project|global> \
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
It prints the full plan — every file, old value → new value, and notes about existing
|
|
45
|
-
packages and MCP servers — and writes nothing until you pass `--apply`.
|
|
45
|
+
packages and MCP servers — and writes nothing until you pass `--apply`. Add `--pin` to
|
|
46
|
+
register the exact version of the CLI you are running instead of the always-latest
|
|
47
|
+
package name. The default path is
|
|
46
48
|
the extension: the plan appends `npm:deepseek-web-retrieval` to the `packages` array in
|
|
47
49
|
`~/.pi/agent/settings.json` (global) or `.pi/settings.json` (project), and Pi resolves the
|
|
48
50
|
source at the next session start (the first launch fetches the package from npm;
|
|
@@ -102,6 +104,12 @@ Fetch https://pi.dev/docs/latest/extensions and summarize the extension lifecycl
|
|
|
102
104
|
The model calls `deepseek_web_search` or `deepseek_fetch` — the same names over both paths;
|
|
103
105
|
only the MCP fallback prefixes them with `mcp__deepseek__`.
|
|
104
106
|
|
|
107
|
+
The search tool accepts an optional `original_question` input — the user's question in their
|
|
108
|
+
own words — forwarded as DeepSeek's `ori_question` to sharpen search intent. When the model
|
|
109
|
+
leaves it blank, the extension falls back to the most recent user message in the session
|
|
110
|
+
(best-effort; truncated to the API's 128-character limit). The MCP fallback path has no
|
|
111
|
+
session access, so there a blank input simply omits the parameter.
|
|
112
|
+
|
|
105
113
|
## Configuration
|
|
106
114
|
|
|
107
115
|
The runtime config surface is the same `DEEPSEEK_*` environment the MCP server reads
|
|
@@ -109,40 +117,53 @@ The runtime config surface is the same `DEEPSEEK_*` environment the MCP server r
|
|
|
109
117
|
`deepseekWebRetrieval` settings namespace for the off switches (written by the installer;
|
|
110
118
|
it outranks the environment and is preserved by Pi's own settings rewrites).
|
|
111
119
|
|
|
120
|
+
The shared config file (`~/.config/deepseek-web-retrieval/config.json`, camelCase keys —
|
|
121
|
+
on Windows, `%APPDATA%\deepseek-web-retrieval\config.json`)
|
|
122
|
+
also sits in this surface, layered under the environment, and needs no forwarding on any
|
|
123
|
+
path — the extension and the MCP server both read the file themselves. One file therefore
|
|
124
|
+
configures every host running this package, with this host's environment and settings
|
|
125
|
+
still outranking it. `npx deepseek-web-retrieval config` prints what actually resolves —
|
|
126
|
+
each knob's value and source, with file warnings surfaced and `--search "<query>"` running
|
|
127
|
+
one billed search through it all.
|
|
128
|
+
|
|
112
129
|
### Search
|
|
113
130
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
131
|
+
The "Config file" column names each key's camelCase twin in the shared config file —
|
|
132
|
+
one vocabulary pair, one pipeline. `—` marks host-integration entries the file rejects.
|
|
133
|
+
|
|
134
|
+
| Env variable | Config file | Default | Description |
|
|
135
|
+
| --- | --- | --- | --- |
|
|
136
|
+
| `DEEPSEEK_ENABLE_SEARCH` | — | `true` | Register the search tool. Only an explicit `false`/`0`/`no`/`off` disables it; at least one tool must stay enabled. |
|
|
137
|
+
| `DEEPSEEK_SEARCH_COUNT` | `count` | `10` | Results requested from DeepSeek, 1–50. Billing is per request, not per result. |
|
|
138
|
+
| `DEEPSEEK_SEARCH_MAX_RESULTS` | `maxResults` | `10` | Results returned to the model after filtering, 0–50; defaults to `DEEPSEEK_SEARCH_COUNT` when unset. `0` returns no results. |
|
|
139
|
+
| `DEEPSEEK_SEARCH_MIN_RERANK` | `minRerank` | `0` | Drop results below this relevance score (0–3); results without a finite score pass at zero and are dropped at a positive threshold. |
|
|
140
|
+
| `DEEPSEEK_SEARCH_MIN_AUTHORITY` | `minAuthority` | `0` | Drop known authorities below this tier. Authority is 0–4. |
|
|
141
|
+
| `DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY` | `allowUnknownAuthority` | `true` | Keep results whose authority is missing or unknown. Set `false`/`0`/`no`/`off` to drop them. |
|
|
142
|
+
| `DEEPSEEK_SEARCH_BLOCKED_DOMAINS` | `blockedDomains` | unset | Comma-separated; adds `-site:` operators to the query. |
|
|
143
|
+
| `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` | `includeDomains` | unset | Comma-separated; restricts results with `site:` operators. |
|
|
144
|
+
| `DEEPSEEK_SEARCH_LANGUAGE` | `language` | unset | Adds a `lang:` operator, for example `zh,en`. |
|
|
145
|
+
| `DEEPSEEK_SEARCH_LOCALIZATION` | `searchLocalization` | 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. |
|
|
146
|
+
| `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | `maxSummaryChars` | `1200` | Per-result summary cap, 0–1,000,000. |
|
|
147
|
+
| `DEEPSEEK_SEARCH_TIMEOUT_MS` | `searchTimeoutMs` | `30000` | Search timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
127
148
|
|
|
128
149
|
### Fetch
|
|
129
150
|
|
|
130
|
-
| Env variable | Default | Description |
|
|
131
|
-
| --- | --- | --- |
|
|
132
|
-
| `DEEPSEEK_ENABLE_FETCH` | `true` | Register the fetch tool. Same false-only semantics as `DEEPSEEK_ENABLE_SEARCH`. |
|
|
133
|
-
| `DEEPSEEK_FETCH_MAX_CHARS` | `16000` | Maximum characters returned, including the title, 0–1,000,000. The only output cap on this path. |
|
|
134
|
-
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
135
|
-
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
136
|
-
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
137
|
-
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. Set `false`/`0` to disable. |
|
|
151
|
+
| Env variable | Config file | Default | Description |
|
|
152
|
+
| --- | --- | --- | --- |
|
|
153
|
+
| `DEEPSEEK_ENABLE_FETCH` | — | `true` | Register the fetch tool. Same false-only semantics as `DEEPSEEK_ENABLE_SEARCH`. |
|
|
154
|
+
| `DEEPSEEK_FETCH_MAX_CHARS` | `fetchMaxChars` | `16000` | Maximum characters returned, including the title, 0–1,000,000. The only output cap on this path. |
|
|
155
|
+
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `fetchTimeoutMs` | `30000` | Fetch timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
156
|
+
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | `fetchAllowedDomains` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
157
|
+
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | `fetchBlockedDomains` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
158
|
+
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `fetchBlockPrivateHosts` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. Set `false`/`0` to disable. |
|
|
138
159
|
|
|
139
160
|
### Credentials and retries
|
|
140
161
|
|
|
141
|
-
| Env variable | Default | Description |
|
|
142
|
-
| --- | --- | --- |
|
|
143
|
-
| `DEEPSEEK_API_KEY` | required | DeepSeek API key, read from the Pi process environment. |
|
|
144
|
-
| `DEEPSEEK_MAX_RETRIES` | `
|
|
145
|
-
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
162
|
+
| Env variable | Config file | Default | Description |
|
|
163
|
+
| --- | --- | --- | --- |
|
|
164
|
+
| `DEEPSEEK_API_KEY` | — | required | DeepSeek API key, read from the Pi process environment. |
|
|
165
|
+
| `DEEPSEEK_MAX_RETRIES` | `maxRetries` | `2` | Retries for 408, 425, 429, and 5xx responses, 0–5. |
|
|
166
|
+
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `retryBaseDelayMs` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
146
167
|
|
|
147
168
|
Invalid values fall back to the shared default.
|
|
148
169
|
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Configuration layering design
|
|
2
|
+
|
|
3
|
+
Design note for the shared configuration base layer across the three shipped adapters (MCP
|
|
4
|
+
server, OpenCode plugin, Pi extension). It records the parameter taxonomy, the precedence
|
|
5
|
+
model, and the per-adapter composition so the design survives between conversations. Host
|
|
6
|
+
capability facts live in [control-matrix.md](../research/control-matrix.md); the config
|
|
7
|
+
surface inventory was verified against the code on 2026-10-23.
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
The state this design replaced — recorded here as history, not as the present. The option
|
|
12
|
+
pipeline was already single-sourced (names, defaults, clamping in
|
|
13
|
+
`src/core/constants.ts` → `src/core/env.ts` → `src/core/options.ts`), but the *channels*
|
|
14
|
+
that fed it were fragmented per host, and a multi-host user configured the same intent in
|
|
15
|
+
up to three ways:
|
|
16
|
+
|
|
17
|
+
- **Pi** — extension runs in-process; `DEEPSEEK_*` shell variables just worked.
|
|
18
|
+
- **Codex** — stdio children do not inherit the parent environment, and the installer's
|
|
19
|
+
`env_vars` entry forwarded **only** `DEEPSEEK_API_KEY`; every other knob set in the
|
|
20
|
+
shell never reached the server unless the user hand-edited `config.toml` to add each
|
|
21
|
+
variable name. (The entry now forwards every `DEEPSEEK_*` name — see the Codex
|
|
22
|
+
consequence in [ADR-0002](../adr/0002-shared-config-base-layer.md).)
|
|
23
|
+
- **OpenCode** — the plugin resolved **only** `ctx.options` (opencode.json plugin
|
|
24
|
+
options, camelCase); `DEEPSEEK_*` variables configured nothing there, so the same
|
|
25
|
+
knob had a second, differently-named vocabulary. (The plugin now composes
|
|
26
|
+
file < environment < `ctx.options` — see the per-adapter composition below.)
|
|
27
|
+
|
|
28
|
+
One intent ("20 results, block pinterest.com"), three configuration acts, two
|
|
29
|
+
vocabularies, one silent-failure trap. The isolation was accidental, not chosen.
|
|
30
|
+
|
|
31
|
+
## Parameter taxonomy
|
|
32
|
+
|
|
33
|
+
Isolation versus unification is decided per class, not globally:
|
|
34
|
+
|
|
35
|
+
| Class | Parameters | Policy |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| **API behavior** — describes the user↔DeepSeek relationship, host-independent | `count`, `maxResults`, `minRerank`, `minAuthority`, `allowUnknownAuthority`, `blockedDomains`, `includeDomains`, `language`, `searchLocalization`, `maxRetries`, `retryBaseDelayMs` | Shared base; identical everywhere unless a host layer overrides |
|
|
38
|
+
| **Host-sensitive** — interacts with host output caps / deadlines (OpenCode 2,000 lines / 50 KiB; Pi MCP 20 KB + 60 s; Pi extension uncapped; Claude Code 25k tokens) | `searchTimeoutMs`, `fetchTimeoutMs`, `fetchMaxChars`, `maxSummaryChars` | Shared base gives the safe default; **per-host override in the host-native layer is the recommended place** to raise them |
|
|
39
|
+
| **Host integration** — describes the host's tool landscape, not the API | `searchEnabled`, `fetchEnabled`, `setDefaultWebsearch`, `fetchOverrideWebfetch`, `fetchRegisterTool`, `apiKeySource` | **Deliberately isolated.** Installer-written, host-native config only; the shared file rejects them |
|
|
40
|
+
|
|
41
|
+
Security-shaped knobs (`fetchAllowedDomains`, `fetchBlockedDomains`, `fetchBlockPrivateHosts`)
|
|
42
|
+
are classed as API behavior: they are deployment policy about the DeepSeek call itself, and a
|
|
43
|
+
shared base strengthens rather than weakens them (one policy instead of three drifting ones).
|
|
44
|
+
|
|
45
|
+
## The layering model
|
|
46
|
+
|
|
47
|
+
Precedence, low → high, identical semantics in every adapter:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
built-in defaults < shared config file < DEEPSEEK_* environment < host-native config
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **Host-native config** means: OpenCode `ctx.options` (opencode.json plugin entry), Pi's
|
|
54
|
+
`deepseekWebRetrieval` settings namespace (the two switches), and — for MCP hosts — the
|
|
55
|
+
per-server `env` block in the host's MCP registration (that block is *how* an environment
|
|
56
|
+
variable arrives, not a fifth layer).
|
|
57
|
+
- Host-native layers keep outranking the base: installer-written intent (capability tiers)
|
|
58
|
+
and explicit per-host overrides always win, so the blast radius of a bad shared value is
|
|
59
|
+
bounded by whatever the host layer pins.
|
|
60
|
+
- The two vocabularies stay as they are — `DEEPSEEK_*` snake-case names for the environment,
|
|
61
|
+
camelCase `PluginOptions` keys for the file and OpenCode options — both generated from the
|
|
62
|
+
same single source and documented side by side.
|
|
63
|
+
|
|
64
|
+
## The shared config file
|
|
65
|
+
|
|
66
|
+
- **Path:** `$XDG_CONFIG_HOME/deepseek-web-retrieval/config.json`, defaulting to
|
|
67
|
+
`~/.config/deepseek-web-retrieval/config.json`. On win32 an explicit, non-empty
|
|
68
|
+
`XDG_CONFIG_HOME` still wins; otherwise the conventional Roaming root applies —
|
|
69
|
+
`%APPDATA%\deepseek-web-retrieval\config.json`, falling back to
|
|
70
|
+
`<home>\AppData\Roaming\deepseek-web-retrieval\config.json` when `%APPDATA%` is
|
|
71
|
+
unset. User scope, one file. A project-scope file
|
|
72
|
+
is a confirmed non-goal for this iteration (open question below).
|
|
73
|
+
- **Format:** JSON object; keys are the camelCase `PluginOptions` vocabulary (class 1 and 2
|
|
74
|
+
only). Example:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"count": 20,
|
|
79
|
+
"blockedDomains": ["pinterest.com"],
|
|
80
|
+
"language": "zh",
|
|
81
|
+
"searchLocalization": "203.0.113.7"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- **Validation:** the file's parsed object feeds the existing `resolvePluginOptions` —
|
|
86
|
+
clamps, IP validation, and domain normalization all come along for free. Unknown keys and
|
|
87
|
+
class-3 (host-integration) keys are **rejected with a one-line stderr warning** and
|
|
88
|
+
otherwise ignored; a missing or unparseable file contributes nothing (a warning line for
|
|
89
|
+
the unparseable case), mirroring the Pi settings reader's conventions.
|
|
90
|
+
- **The API key is deliberately absent.** Auth keeps its existing channels
|
|
91
|
+
(`DEEPSEEK_API_KEY`, OpenCode's auth store, Pi's env) — a config file is liable to end up
|
|
92
|
+
synced through dotfiles, and widening key storage is a security-surface decision this
|
|
93
|
+
design does not make.
|
|
94
|
+
|
|
95
|
+
## Per-adapter composition
|
|
96
|
+
|
|
97
|
+
- **MCP server** (`src/mcp/serve.ts`): `resolveEnvOptions(env)` becomes
|
|
98
|
+
`resolveEnvOptions(env, readFileOptions())` — file keys under environment keys. The server
|
|
99
|
+
reads the file itself, so **the Codex `env_vars` trap disappears** regardless of what the
|
|
100
|
+
host forwards.
|
|
101
|
+
- **Pi extension** (`src/pi/extension.ts`): `resolveExtensionOptions` inserts the file
|
|
102
|
+
between defaults and the environment; the settings namespace stays on top, unchanged.
|
|
103
|
+
- **OpenCode plugin** (`src/opencode/plugin.ts`): `resolvePluginOptions(ctx.options)` becomes
|
|
104
|
+
`resolvePluginOptions({ ...fileOptions(), ...pluginOptionsFromEnv(process.env), ...ctx.options })`
|
|
105
|
+
— file, then environment, then the host layer. Additive only: existing opencode.json
|
|
106
|
+
options keep winning exactly as before; the change is that the file and environment now
|
|
107
|
+
work on this host too.
|
|
108
|
+
|
|
109
|
+
## Installer changes
|
|
110
|
+
|
|
111
|
+
- **Codex `env_vars`:** enumerate **every** `DEEPSEEK_*` name (generated from
|
|
112
|
+
`src/core/constants.ts`, the single source) instead of only `DEEPSEEK_API_KEY`, so
|
|
113
|
+
environment overrides work on Codex without hand-editing `config.toml`. The note the
|
|
114
|
+
installer prints is updated to match.
|
|
115
|
+
- No other host artifacts change: the installer never writes the shared file (it is a user
|
|
116
|
+
authoring surface, like a shell profile), and capability tiers stay where they are.
|
|
117
|
+
|
|
118
|
+
## Visibility
|
|
119
|
+
|
|
120
|
+
A bad shared value now fails everywhere at once, so effective configuration must be visible:
|
|
121
|
+
|
|
122
|
+
- The MCP server's startup stderr line (already printing the client identity and enabled
|
|
123
|
+
tools) additionally prints **deviations from defaults only** — e.g.
|
|
124
|
+
`config: count=20 blockedDomains=1 language=zh` — keeping the line short while showing
|
|
125
|
+
every non-default knob a multi-layer resolution produced.
|
|
126
|
+
- The OpenCode plugin and Pi extension print the same deviation summary once, at
|
|
127
|
+
registration time, through their host's logging channel (implementer picks the least
|
|
128
|
+
noisy channel per host; the content contract is "non-default effective values").
|
|
129
|
+
- `deepseek-web-retrieval config` is the user-facing arm: it prints every knob with its
|
|
130
|
+
value and source, replays the file's warnings where a human actually looks, and its
|
|
131
|
+
`--search` variant verifies the whole chain (key, config, network) with one billed
|
|
132
|
+
request.
|
|
133
|
+
|
|
134
|
+
## What this design does not change
|
|
135
|
+
|
|
136
|
+
- `need_content` stays hardcoded `false` ([search-inline-content.md](../research/search-inline-content.md)).
|
|
137
|
+
- `ori_question` remains per-call-only (`original_question` input / Pi session fallback); it
|
|
138
|
+
is not configurable.
|
|
139
|
+
- Auth surfaces, capability tiers, and the installer's plan/confirm flow.
|
|
140
|
+
|
|
141
|
+
## Testing
|
|
142
|
+
|
|
143
|
+
- Unit: file reader (missing / unparseable / unknown-key / class-3-key rejection with
|
|
144
|
+
warning), precedence matrix per adapter (defaults < file < env < host) asserted through
|
|
145
|
+
each adapter's existing resolution entry points.
|
|
146
|
+
- The installer's Codex plan snapshot gains the full `env_vars` list.
|
|
147
|
+
- Existing suites stay green; e2e scenarios unaffected (the file is absent in CI, which is
|
|
148
|
+
itself the empty-layer case).
|
|
149
|
+
|
|
150
|
+
## Rollout
|
|
151
|
+
|
|
152
|
+
Additive and non-breaking: no existing configuration loses effect, no precedence between
|
|
153
|
+
existing layers changes. Documentation updates ship with the code: README gains a
|
|
154
|
+
"Configuration" section with the precedence table and the two-vocabulary table; the host
|
|
155
|
+
guides' option tables gain a shared-file column; the control-matrix note's Pi sentence
|
|
156
|
+
("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.
|
|
158
|
+
|
|
159
|
+
**Amendment, 2026-10-23** — two changes approved after this design was confirmed alter
|
|
160
|
+
the effective behavior of *untouched* configurations, superseding the "no existing
|
|
161
|
+
configuration loses effect" sentence for those two knobs:
|
|
162
|
+
|
|
163
|
+
1. `maxResults` now follows the effective `count` when unset, so `count`-only
|
|
164
|
+
configurations return `count` results instead of silently truncating to the old
|
|
165
|
+
default of 10 (the one-directional asymmetry is documented at the resolution site in
|
|
166
|
+
`src/core/options.ts`).
|
|
167
|
+
2. Transient failures (408/425/429/5xx) retry twice by default instead of zero
|
|
168
|
+
(rationale and the dated vendor-survey correction live in
|
|
169
|
+
`docs/research/search-api-defaults.md`).
|
|
170
|
+
|
|
171
|
+
## Decisions (confirmed 2026-10-23)
|
|
172
|
+
|
|
173
|
+
1. **Project-scope file:** not in this iteration — hosts already own project-scope
|
|
174
|
+
semantics, and the extra precedence row is not yet earned by demand.
|
|
175
|
+
2. **Invalid-key warnings:** one stderr line per bad key at first resolution — the noise
|
|
176
|
+
buys typo detection (`"retries"` vs `"maxRetries"`) in a hand-edited file.
|
|
177
|
+
3. **File naming:** `config.json` inside the `~/.config/deepseek-web-retrieval/`
|
|
178
|
+
directory (win32: `%APPDATA%\deepseek-web-retrieval\`) — room for future siblings.
|
|
179
|
+
4. **ADR:** the layering decision is recorded as
|
|
180
|
+
[ADR 0002](../adr/0002-shared-config-base-layer.md) alongside this design note.
|
|
@@ -198,6 +198,14 @@ into any existing `permissions` array rather than replacing it.
|
|
|
198
198
|
documents a layer above user config, so there is nothing to check there yet.
|
|
199
199
|
- Only a bare `--apply` enables writes; assigning a value such as `--apply=false`
|
|
200
200
|
is a usage error and writes nothing.
|
|
201
|
+
- `--pin` is opt-in version pinning: the ref written into host config gets the
|
|
202
|
+
running CLI's version appended (`name` becomes `name@<version>`; a ref already
|
|
203
|
+
ending in a version keeps it), so a host resolves that exact release instead of
|
|
204
|
+
the latest publish. Without the flag the ref stays unpinned, byte-identical to
|
|
205
|
+
before; re-running `init --pin` from a newer CLI moves the pin. Ref identity —
|
|
206
|
+
orphan, upgrade, and unexcludable-competitor detection — compares package names
|
|
207
|
+
with the `@version` suffix stripped (`samePackageName` in ownership.ts), so a
|
|
208
|
+
pinned ref still matches the lineage an earlier init registered.
|
|
201
209
|
- File verification precedes the install-record commit. A write or verification
|
|
202
210
|
failure restores the pre-apply files and record and checks the restored values.
|
|
203
211
|
`ApplyError.status` is `rolled_back` only after recovery and new-claim cleanup
|
package/docs/integration.md
CHANGED
|
@@ -94,9 +94,12 @@ For an installation managed by `init`:
|
|
|
94
94
|
needed for uninstall. A global install can still claim shared configuration from a
|
|
95
95
|
particular project, so keep the original working directory for upgrades.
|
|
96
96
|
3. Refresh the package in the host and start or reload a session as described in its
|
|
97
|
-
guide. For Pi's extension path, use `pi update --extensions`.
|
|
98
|
-
package version, pass
|
|
99
|
-
|
|
97
|
+
guide. For Pi's extension path, use `pi update --extensions`. To pin the host's
|
|
98
|
+
package to the exact version being run, pass `--pin` to init (it writes
|
|
99
|
+
`deepseek-web-retrieval@X.Y.Z` into the registration); upgrading a pinned install
|
|
100
|
+
means re-running init with the newer CLI, since updating the CLI alone does not
|
|
101
|
+
move an independently pinned host package. `--package` still overrides the ref
|
|
102
|
+
entirely.
|
|
100
103
|
|
|
101
104
|
When upgrading from 0.4.0, Pi's default changes from MCP to the native extension.
|
|
102
105
|
Pass `--path mcp` explicitly to retain MCP, or `--path extension` to migrate; the plan
|