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
|
@@ -43,8 +43,9 @@ already exists, and the installer uses three phases:
|
|
|
43
43
|
1. **Detect.** Read the host config, the rules files, and the registered MCP servers.
|
|
44
44
|
Report the conflict surface: existing rules steering toward another web tool; other
|
|
45
45
|
web-capable MCP servers already on the field; array-valued keys the plan must merge
|
|
46
|
-
into rather than replace (`disabledTools`, `permissions.deny`,
|
|
47
|
-
`exclude
|
|
46
|
+
into rather than replace (Cline's `disabledTools`, Claude Code's `permissions.deny`,
|
|
47
|
+
permissions `exclude` arrays, Codex's and Devin's `disabled_tools`); and higher
|
|
48
|
+
layers (Claude Code managed policy — its
|
|
48
49
|
existence is checked by the claude-code module; Devin enterprise team settings) that
|
|
49
50
|
would outrank what the installer writes.
|
|
50
51
|
2. **Merge or snapshot.** Array keys merge with existing entries, recording exactly
|
|
@@ -69,22 +70,24 @@ already exists, and the installer uses three phases:
|
|
|
69
70
|
conditions; it does not resolve them.
|
|
70
71
|
- **Forced is conditional**: the exclusion kill switches remove the built-in
|
|
71
72
|
competitor, not third-party web MCP servers — those must be excluded too (the
|
|
72
|
-
per-host keys cover them), or routing is not actually forced.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
explicit user choices (OpenCode's
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
per-host keys cover them), or routing is not actually forced.
|
|
74
|
+
- Per-host exclusion of detected web-capable MCP servers: Pi's per-server
|
|
75
|
+
`enabled` key lets the plan disable them (each prior value snapshotted for
|
|
76
|
+
uninstall); Claude Code excludes them the same way via server-level
|
|
77
|
+
`mcp__<server>` deny rules appended to `permissions.deny`; Codex has no
|
|
78
|
+
per-server kill switch, so a detected web-capable competitor makes the plan
|
|
79
|
+
refuse the tier instead of promising non-exclusive routing; OpenCode's forced
|
|
80
|
+
is replacement, which no third-party server overrides.
|
|
81
|
+
- Detection classifies a server web-capable from its name plus its
|
|
82
|
+
command/args/url — a heuristic the plan always discloses.
|
|
83
|
+
- Blast radius: forced also overrides explicit user choices (OpenCode's
|
|
84
|
+
`websearch.provider`), and its deny rules affect workflows beyond this
|
|
85
|
+
project (a Claude Code deny cannot be carved out by allow rules), so the plan
|
|
86
|
+
must state the blast radius before the user approves it.
|
|
85
87
|
- **Forced is not universally available**: where hosts.jsonc records `forced: "none"`
|
|
86
88
|
(Cursor's search today), the wizard does not offer the tier — the tier-level analogue
|
|
87
|
-
of the scope rule
|
|
89
|
+
of the scope rule below (honor or report, never silently downgrade: never offer what
|
|
90
|
+
cannot be delivered). Some kill
|
|
88
91
|
switches are session-scoped (Copilot fetch's `--deny-tool`/`--excluded-tools` flags);
|
|
89
92
|
an installer cannot persist them, so the plan reports that the exclusion evaporates on
|
|
90
93
|
restart and offers what persistence exists.
|
|
@@ -158,9 +161,33 @@ the artifacts below name the path where they differ.
|
|
|
158
161
|
| Optional | Host config registering the integration: Pi's extension path appends an `npm:<package>` source to `packages` in settings.json; the MCP paths register the server (Pi's MCP entry needs `"exposure": "direct"`; the extension path needs nothing — extension tools are `direct` by Pi's own default) |
|
|
159
162
|
| Preferred | The above plus a rules file for the host (file names per host in the [per-host reference](../research/control-matrix.md#per-host-reference)); the rules name the path's tool ids (`deepseek_web_search` for the extension, `mcp__deepseek__deepseek_web_search` for MCP) |
|
|
160
163
|
| Forced (replacement) | OpenCode plugin options (`setDefaultWebsearch` / `fetchOverrideWebfetch`) |
|
|
161
|
-
| Forced (exclusion) | The built-in competitor's kill switch (per-host keys in the per-host reference), plus
|
|
164
|
+
| Forced (exclusion) | The built-in competitor's kill switch (per-host keys in the per-host reference), plus exclusion of any other web-capable MCP servers the detect phase found — host by host below |
|
|
162
165
|
| Forced (de-facto) | Nothing beyond the Optional artifacts — no competitor exists |
|
|
163
|
-
| Off |
|
|
166
|
+
| Off | A host-native removal of the capability's tool — host by host below |
|
|
167
|
+
|
|
168
|
+
Forced (exclusion), host by host:
|
|
169
|
+
|
|
170
|
+
- **Pi** sets each detected web-capable server's `enabled` key to `false`.
|
|
171
|
+
- **Claude Code** appends server-level `mcp__<server>` deny rules to
|
|
172
|
+
`permissions.deny`, merging with the user's own entries.
|
|
173
|
+
- **Codex**, lacking a per-server kill switch, refuses the tier instead.
|
|
174
|
+
- **Pi's extension path** additionally refuses when a web-capable
|
|
175
|
+
`packages`/`extensions` source is listed in settings.json (no per-package kill
|
|
176
|
+
switch exists).
|
|
177
|
+
|
|
178
|
+
Off, host by host:
|
|
179
|
+
|
|
180
|
+
- **Codex** writes the capability's raw tool name into the server entry's
|
|
181
|
+
`disabled_tools` (host-native: the tool leaves the model's context; the user's
|
|
182
|
+
own entries in that array are kept).
|
|
183
|
+
- **Claude Code** appends the capability's full tool id (`mcp__deepseek__*`) to
|
|
184
|
+
`permissions.deny` — the same host-native removal.
|
|
185
|
+
- **The remaining MCP entry** (Pi's fallback) writes the capability's false-only
|
|
186
|
+
server-side switch instead (`DEEPSEEK_ENABLE_SEARCH` / `DEEPSEEK_ENABLE_FETCH`).
|
|
187
|
+
- **Pi's extension path** writes the same switches into the
|
|
188
|
+
`deepseekWebRetrieval` settings namespace the extension reads at load.
|
|
189
|
+
|
|
190
|
+
Both capabilities off refuses to install.
|
|
164
191
|
|
|
165
192
|
OpenCode additionally appends `permissions` allow entries for exactly the tools it
|
|
166
193
|
registers (`websearch`, `deepseek_fetch`, and `webfetch` when fetch is forced), merged
|
|
@@ -186,10 +213,10 @@ into any existing `permissions` array rather than replacing it.
|
|
|
186
213
|
comments and formatting in `opencode.jsonc` and Pi's `mcp.json` survive apply and
|
|
187
214
|
uninstall; TOML edits go through `smol-toml` and drop comments, which the plan reports
|
|
188
215
|
as a note. The hand-written JSONC stripper that predated this lived in `scripts/jsonc.ts`.
|
|
189
|
-
- Install
|
|
190
|
-
`~/.config/deepseek-web-retrieval/`, project under `.deepseek-web-retrieval/`);
|
|
191
|
-
|
|
192
|
-
full file contents, so other servers' secrets stay out of the
|
|
216
|
+
- Install records live per host and scope (global under
|
|
217
|
+
`~/.config/deepseek-web-retrieval/`, project under `.deepseek-web-retrieval/`); they
|
|
218
|
+
record snapshots, appended entries, created files, and created path prefixes — never
|
|
219
|
+
full file contents, so other servers' secrets stay out of the install record.
|
|
193
220
|
- Re-applying over a previous init inherits the original snapshots instead of recording
|
|
194
221
|
the installer's own output as the "previous" value. Pi forced re-inits keep their
|
|
195
222
|
competitor-disable ops even when those servers are already disabled, so orphan
|
|
@@ -256,8 +283,13 @@ edits append arrays. Preview generation is read-only and does not reserve locks.
|
|
|
256
283
|
|
|
257
284
|
Operation locks are directories ending in `.deepseek-web-retrieval.lock`, with
|
|
258
285
|
owner PID and start time inside. Ordinary success or failure releases them. A
|
|
259
|
-
killed process may leave a lock
|
|
260
|
-
|
|
261
|
-
|
|
286
|
+
killed process may leave a lock; to recover from one:
|
|
287
|
+
|
|
288
|
+
1. Confirm no installer is currently running.
|
|
289
|
+
2. Inspect the config, install record, and persistent ownership claims.
|
|
290
|
+
3. Restore any inconsistent state.
|
|
291
|
+
4. Remove the reported lock directory and generate a new plan.
|
|
292
|
+
|
|
293
|
+
Locks are
|
|
262
294
|
never stolen based only on age or PID. Persistent `.owner.json` claims remain a
|
|
263
295
|
separate safeguard against two installations owning one shared config.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Search content design
|
|
2
|
+
|
|
3
|
+
Design note for `need_content` — DeepSeek's inline-content search flag — across the two
|
|
4
|
+
model-facing adapters (the MCP server and the Pi extension). It records the parameter
|
|
5
|
+
split (who decides what), the envelope arithmetic that sets the defaults, the rendering
|
|
6
|
+
contract, and the per-adapter composition, so the design survives between conversations.
|
|
7
|
+
The facts it builds on are in [search-inline-content.md](../research/search-inline-content.md)
|
|
8
|
+
(baseline 2026-10-23); the decision record is
|
|
9
|
+
[ADR-0003](../adr/0003-need-content-per-call-boolean.md). This note was verified against
|
|
10
|
+
the code on 2026-10-24.
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
The wire parameter is a boolean the repo hardcoded `false`: search results carried a
|
|
15
|
+
summary digest (`summary` falling back to `snippet`) and never a page body. An agent
|
|
16
|
+
needing bodies had to guess which URLs to fetch from the digests — a wrong guess is a
|
|
17
|
+
silent miss. Turning the flag on naively is not safe either: DeepSeek documents **no**
|
|
18
|
+
size bound for the returned `content`, host output caps run as tight as Pi's 20 KB
|
|
19
|
+
MCP-path truncation (middle truncation — whole results vanish), and the 30 s default
|
|
20
|
+
search timeout does not budget for the server-side page crawl the flag triggers.
|
|
21
|
+
|
|
22
|
+
## The parameter split
|
|
23
|
+
|
|
24
|
+
Two axes, two owners:
|
|
25
|
+
|
|
26
|
+
- **The agent owns the boolean.** `need_content` is a per-call, optional tool parameter
|
|
27
|
+
on every surface where this package defines the search tool's inputs (the MCP server
|
|
28
|
+
and the Pi extension), defaulting to `false`. It rides `SearchRequest.needContent`
|
|
29
|
+
(the `oriQuestion` pattern), not the resolved options — it changes nothing in option
|
|
30
|
+
state, only what that one call sends. Task type is the biggest determinant of whether
|
|
31
|
+
content helps, and only the model knows the task; the repo's other per-call parameters
|
|
32
|
+
(`count`, fetch `maxChars`) are the precedent: always exposed, never mode-gated.
|
|
33
|
+
- **The deployment owns the envelope.** Two deployment-level knobs — never tool
|
|
34
|
+
parameters — apply whenever content flows: `searchContentMaxChars` (per-result body
|
|
35
|
+
budget) and `searchContentTimeoutMs` (the timeout a content call runs on, replacing
|
|
36
|
+
`searchTimeoutMs` for that call; the per-call `timeoutMs` cap still wins if shorter).
|
|
37
|
+
The model cannot see which host caps its output, so it cannot own a budget.
|
|
38
|
+
|
|
39
|
+
## The envelope
|
|
40
|
+
|
|
41
|
+
Defaults from the host-cap arithmetic in the research note:
|
|
42
|
+
|
|
43
|
+
- `searchContentMaxChars` defaults to **1,500**. At the default `count=10`, bodies plus
|
|
44
|
+
the ~1k chars of per-result metadata land near 16 KB — under the tightest published
|
|
45
|
+
cap (Pi's 20 KB MCP-path truncation) for Latin-script pages. CJK-heavy responses
|
|
46
|
+
measure 3 bytes per character toward that cap, so a CJK-focused deployment on a
|
|
47
|
+
20 KB host should lower the budget or the count (at 1,500 chars/result, count ≈ 13 is
|
|
48
|
+
the 20 KB ceiling even for Latin text). The native Pi extension bypasses the MCP
|
|
49
|
+
layer entirely — neither its 20 KB truncation nor its 60 s timeout applies — so that
|
|
50
|
+
deployment can afford a larger budget.
|
|
51
|
+
- `searchContentTimeoutMs` defaults to **60,000** — between the 30 s search default the
|
|
52
|
+
digest path keeps and the 300 s ceiling Codex allows, because the API must fetch
|
|
53
|
+
every result page server-side before responding and documents no latency statement.
|
|
54
|
+
|
|
55
|
+
The total a response can carry is budget × count plus metadata. That product is the
|
|
56
|
+
deployment's arithmetic to run when tuning either knob; the core does not narrow any
|
|
57
|
+
parameter's range at runtime (see Decisions).
|
|
58
|
+
|
|
59
|
+
## Per-adapter composition
|
|
60
|
+
|
|
61
|
+
- **MCP server**: `need_content` in the zod input schema, forwarded as
|
|
62
|
+
`needContent: need_content === true`.
|
|
63
|
+
- **Pi extension**: the same parameter in the TypeBox schema (`SEARCH_PARAMETERS` stays
|
|
64
|
+
a module-level constant on both surfaces — the schema is unconditional), forwarded the
|
|
65
|
+
same way.
|
|
66
|
+
- **OpenCode**: no change. The host fixes the `websearch` provider input to `query`
|
|
67
|
+
(the upstream gap that already blocks per-call `count`), so the provider stays
|
|
68
|
+
summary-only; the envelope knobs resolve through the shared pipeline and are dormant
|
|
69
|
+
there. Documented next to the count gap in
|
|
70
|
+
[opencode-v2.md](../agents/opencode-v2.md).
|
|
71
|
+
- **Installer**: no artifacts change. The knob defaults are global and the deviation
|
|
72
|
+
lines on every adapter already report non-default values through the config
|
|
73
|
+
vocabulary.
|
|
74
|
+
|
|
75
|
+
## Processing and rendering
|
|
76
|
+
|
|
77
|
+
`processResults` is mode-agnostic: a present, non-empty `content` **replaces** the
|
|
78
|
+
digest (the summary is a proxy for the body it compresses), clamped to
|
|
79
|
+
`searchContentMaxChars` with an ellipsis marker when shortened; an empty, whitespace,
|
|
80
|
+
or missing body — the API documents per-result absence, and `need_content: false`
|
|
81
|
+
responses carry an empty string — falls back to the digest path. `searchContentMaxChars:
|
|
82
|
+
0` treats the body as absent. Each result carries `contentKind: "page" | "digest"` so
|
|
83
|
+
the renderer knows the source: page bodies render as Markdown indented into the list
|
|
84
|
+
item (heading and list structure survive); digests stay compacted to one line, as
|
|
85
|
+
summaries always were. The `structuredContent` mirror carries the same `content`
|
|
86
|
+
string on hosts that read it.
|
|
87
|
+
|
|
88
|
+
## What this design does not change
|
|
89
|
+
|
|
90
|
+
- Billing behavior: Search bills per successful request; `need_content` is not a price
|
|
91
|
+
modifier, so a content call costs the same as a digest call (and can replace fetch
|
|
92
|
+
calls at the same per-request price).
|
|
93
|
+
- The fetch tool, its `maxChars` parameter, and the two-tool architecture — a content
|
|
94
|
+
call replaces *some* fetches, not the deep-read path.
|
|
95
|
+
- `maxSummaryChars`, thresholds, dedup, query composition, and degradation.
|
|
96
|
+
- `MAX_RESPONSE_BYTES` (5 MiB) — still the outer guard, still erroring rather than
|
|
97
|
+
truncating; the per-result budget keeps responses far below it.
|
|
98
|
+
|
|
99
|
+
## Testing
|
|
100
|
+
|
|
101
|
+
Wire assertions on both model-facing adapters (`need_content: true` reaching the wire;
|
|
102
|
+
`false` by default), client tests for the flag and the timeout selection
|
|
103
|
+
(`contentTimeoutMs` used only when the call asks for content), `processResults` tests
|
|
104
|
+
for the body-over-digest precedence, the budget clamp and marker, the empty-body
|
|
105
|
+
fallback, and the zero-budget drop, and format tests for the two rendering shapes.
|
|
106
|
+
|
|
107
|
+
## Rollout
|
|
108
|
+
|
|
109
|
+
Shipped behind default-`false` behavior: with no configuration and no parameter use,
|
|
110
|
+
every surface behaves exactly as before (the wire still says `need_content: false`).
|
|
111
|
+
Deployments opt in per call by the model, per host by the two envelope knobs. No
|
|
112
|
+
installer or shared-file migration; the knobs join the config vocabulary and the
|
|
113
|
+
generated knob table.
|
|
114
|
+
|
|
115
|
+
## Decisions (confirmed 2026-10-24)
|
|
116
|
+
|
|
117
|
+
1. The boolean is a per-call tool parameter, always exposed on the MCP server and the
|
|
118
|
+
Pi extension; no config mode gates it.
|
|
119
|
+
2. The envelope is deployment-only: `searchContentMaxChars` (1,500) and
|
|
120
|
+
`searchContentTimeoutMs` (60,000), never tool parameters.
|
|
121
|
+
3. A page body replaces the digest; empty bodies fall back to it.
|
|
122
|
+
4. `need_content` does not control other parameters — neither their availability nor
|
|
123
|
+
their value ranges. Effects may be conditional (the envelope knobs apply only when
|
|
124
|
+
content flows); domains are static. No surveyed vendor couples a content flag to
|
|
125
|
+
another parameter's range ([search-inline-content.md](../research/search-inline-content.md)),
|
|
126
|
+
and a silent runtime narrowing (say, of `count`) would be a decision the model
|
|
127
|
+
cannot see. The budget × count arithmetic is the deployment's to run.
|
|
128
|
+
5. OpenCode stays summary-only until the upstream provider input widens.
|
|
129
|
+
6. The descriptions state facts — mechanics, latency, price, magnitude, the fetch
|
|
130
|
+
alternative — and no usage policy. When content is worth it is the model's per-call
|
|
131
|
+
judgment (or a user's rules file per deployment), not the tool author's; if usage
|
|
132
|
+
data later shows the parameter systematically ignored or overused, that is the point
|
|
133
|
+
to add minimal steering, decided by evidence.
|
package/docs/integration.md
CHANGED
|
@@ -7,7 +7,8 @@ use it depends on that agent's extension points.
|
|
|
7
7
|
CLI/terminal agents only; IDE and editor extension surfaces are out of scope. Versions are
|
|
8
8
|
the latest stable CLI release checked at that baseline unless noted otherwise. `No` means no
|
|
9
9
|
documented native provider or override was found in the checked version; several hosts still
|
|
10
|
-
ship built-in web tools. MCP tools can add equivalent tools, but
|
|
10
|
+
ship built-in web tools. MCP (Model Context Protocol) tools can add equivalent tools, but
|
|
11
|
+
do not replace built-ins.
|
|
11
12
|
|
|
12
13
|
## Mechanisms
|
|
13
14
|
|
|
@@ -20,8 +21,12 @@ ship built-in web tools. MCP tools can add equivalent tools, but do not replace
|
|
|
20
21
|
| MCP server | Yes | Yes | Host MCP client | Shipped (`src/mcp/`; Pi, Codex, and Claude Code guides) |
|
|
21
22
|
| CLI/HTTP wrapper | Yes | Yes | Host can call external tools | Not shipped |
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
Why the mechanism distinction matters: some agents expose a native websearch provider,
|
|
25
|
+
some only let you add tools, and some only support MCP. A "yes" for one mechanism does
|
|
26
|
+
not mean the others are supported — the adapter code and docs need to match the
|
|
27
|
+
mechanism the host actually provides. MCP is a protocol, not an agent: one possible
|
|
28
|
+
transport for hosts that support MCP tools, never a host itself. `Custom tool plugin`
|
|
29
|
+
means adding tools; it does not replace a host's built-ins.
|
|
25
30
|
|
|
26
31
|
## Host support
|
|
27
32
|
|
|
@@ -96,12 +101,13 @@ For an installation managed by `init`:
|
|
|
96
101
|
needed for uninstall. A global install can still claim shared configuration from a
|
|
97
102
|
particular project, so keep the original working directory for upgrades.
|
|
98
103
|
3. Refresh the package in the host and start or reload a session as described in its
|
|
99
|
-
guide
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
guide (for Pi's extension path, `pi update --extensions`).
|
|
105
|
+
|
|
106
|
+
Two init flags change what gets registered. `--pin` pins the host's package to the exact
|
|
107
|
+
version being run (`deepseek-web-retrieval@X.Y.Z` in the registration); upgrading a
|
|
108
|
+
pinned install therefore means re-running init with the newer CLI, since updating the
|
|
109
|
+
CLI alone does not move an independently pinned host package. `--package` overrides the
|
|
110
|
+
ref entirely.
|
|
105
111
|
|
|
106
112
|
When upgrading from 0.4.0, Pi's default changes from MCP to the native extension.
|
|
107
113
|
Pass `--path mcp` explicitly to retain MCP, or `--path extension` to migrate; the plan
|
|
@@ -109,12 +115,15 @@ shows the old path's removals and retains the original uninstall snapshots. Open
|
|
|
109
115
|
native plugin and Codex's MCP path remain the same. Standalone MCP installs no longer
|
|
110
116
|
require OpenCode or Pi SDKs; native adapters use the SDKs provided by their hosts.
|
|
111
117
|
|
|
112
|
-
Keep install records and ownership sidecars
|
|
118
|
+
Keep install records and ownership sidecars (the `.owner.json` claim files the installer
|
|
119
|
+
writes beside shared config files): deleting them loses recovery information
|
|
113
120
|
and can cause a later init to refuse an existing registration. If an operation was
|
|
114
121
|
interrupted, follow the [recovery guidance](design/installer-design.md#persistence-and-concurrent-operations)
|
|
115
122
|
before retrying. For manual installations, update the package reference or checkout and
|
|
116
123
|
follow the host guide rather than adopting the config through init.
|
|
117
124
|
|
|
125
|
+
### Breaking changes for library consumers
|
|
126
|
+
|
|
118
127
|
Code importing the core's removed `formatFetchContent` helper must migrate to
|
|
119
128
|
`formatFetchedContent`, which returns both `content` and `truncated`.
|
|
120
129
|
|
|
@@ -178,12 +187,6 @@ the README Usage section only after the adapter ships. To request evaluation for
|
|
|
178
187
|
host, [open an issue](https://github.com/gwokhou/deepseek-web-retrieval/issues) with links
|
|
179
188
|
to its plugin, tool, or MCP documentation.
|
|
180
189
|
|
|
181
|
-
## Why the distinction matters
|
|
182
|
-
|
|
183
|
-
Some agents expose a native websearch provider, some only let you add tools, and some only
|
|
184
|
-
support MCP. A "yes" for one mechanism does not mean the others are supported. The adapter
|
|
185
|
-
code and docs need to match the mechanism the host actually provides.
|
|
186
|
-
|
|
187
190
|
## Adding an adapter
|
|
188
191
|
|
|
189
192
|
- Register the host and its version lock in [hosts.jsonc](hosts.jsonc), then regenerate
|
|
@@ -113,30 +113,31 @@ scopes; keys locked to a single scope are enumerated in the
|
|
|
113
113
|
`web_search = "disabled"` in `~/.codex/config.toml`. Trap: the `[tools] web_search =
|
|
114
114
|
<bool>` form parses but discards the value at 0.163.0 — a silent no-op
|
|
115
115
|
([config source at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/config_toml.rs)).
|
|
116
|
-
- **MCP registration** — `~/.codex/config.toml` `[mcp_servers.<name>]`:
|
|
117
|
-
`command`/`args`/`env`/`env_vars`;
|
|
118
|
-
(300 s) defaults —
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
116
|
+
- **MCP registration** — `~/.codex/config.toml` `[mcp_servers.<name>]`:
|
|
117
|
+
- **Entry keys:** stdio `command`/`args`/`env`/`env_vars`; per-tool approval modes.
|
|
118
|
+
- **Timeouts:** `startup_timeout_sec` (30 s) and `tool_timeout_sec` (300 s) defaults —
|
|
119
|
+
the `DEFAULT_STARTUP_TIMEOUT`/`DEFAULT_TOOL_TIMEOUT` constants
|
|
120
|
+
([rmcp_client.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/rmcp_client.rs)).
|
|
121
|
+
- **Tool filtering:** `enabled_tools`/`disabled_tools` — verbatim raw tool-name match,
|
|
122
|
+
filtered before registration so the model never sees a disabled tool; an empty
|
|
123
|
+
`enabled_tools` allow-list exposes nothing.
|
|
124
|
+
- **Output limits:** MCP tool output can be capped per tool via `output_token_limit`
|
|
125
|
+
("Token budget for one MCP tool's output, before the standard 20% serialization
|
|
126
|
+
allowance"; the default cap is not published there)
|
|
127
|
+
([mcp_types.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/mcp_types.rs)).
|
|
128
|
+
- **Environment:** stdio children do not inherit the parent environment (only `HOME`,
|
|
129
|
+
`PATH`, and explicit `env`), so `DEEPSEEK_API_KEY` must be passed explicitly.
|
|
130
|
+
- **Result shape and identity:** when a tool result has `structuredContent`, Codex
|
|
131
|
+
replaces the content blocks with the serialized JSON. No SSE. Codex identifies itself
|
|
132
|
+
in the initialize handshake as clientInfo name `codex-mcp-client` with title `Codex`
|
|
133
|
+
([rmcp_client.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/rmcp_client.rs)).
|
|
134
|
+
- **Docs drift:** the official docs moved to learn.chatgpt.com
|
|
135
|
+
([MCP](https://learn.chatgpt.com/docs/extend/mcp),
|
|
136
|
+
[config reference](https://learn.chatgpt.com/docs/config-file/config-reference); the
|
|
137
|
+
old developers.openai.com URLs 308-redirect there) and now document every key above —
|
|
138
|
+
but state 10 s/60 s timeout defaults, which describe an older release line; the
|
|
139
|
+
30 s/300 s constants above are the facts at the locked 0.163.0 (docs discrepancy
|
|
140
|
+
re-verified 2026-10-21).
|
|
140
141
|
- **Rules** — `~/.codex/AGENTS.md` (with `AGENTS.override.md` preferred) at user scope;
|
|
141
142
|
every `AGENTS.md` from the project root down to the cwd, concatenated root→cwd.
|
|
142
143
|
Extensible via `project_doc_fallback_filenames` and `developer_instructions`
|
|
@@ -184,8 +185,10 @@ scopes; keys locked to a single scope are enumerated in the
|
|
|
184
185
|
channel: the runtime config surface is the `DEEPSEEK_*` environment (the same pipeline as
|
|
185
186
|
the MCP server), the shared config file
|
|
186
187
|
(`~/.config/deepseek-web-retrieval/config.json`, layered under the environment), plus a
|
|
187
|
-
`deepseekWebRetrieval` settings namespace the installer writes for
|
|
188
|
-
|
|
188
|
+
`deepseekWebRetrieval` settings namespace the installer writes for the `off` tier (a
|
|
189
|
+
capability switched off — the [tier-to-artifact
|
|
190
|
+
mapping](../design/installer-design.md#tier-to-artifact-mapping) defines it) — Pi
|
|
191
|
+
preserves unknown settings keys on read and on its own rewrites
|
|
189
192
|
(`pi install`), verified at 1.3.0. Action methods such as `getSettings()` cannot be
|
|
190
193
|
called during extension loading, so the adapter reads the settings files itself.
|
|
191
194
|
- **MCP registration** — `~/.pi/agent/mcp.json` or `.pi/mcp.json`: stdio
|
|
@@ -320,11 +323,13 @@ scopes; keys locked to a single scope are enumerated in the
|
|
|
320
323
|
`toolPolicies`). Codex's docs location and Copilot's `GEMINI.md` dating were re-verified
|
|
321
324
|
2026-10-21 and are settled in their sections above. Protocol-revision evidence for every
|
|
322
325
|
host lives in [mcp-compatibility.md](mcp-compatibility.md).
|
|
323
|
-
- **Claude Code forward-compat anchors (checked at the 2.1.303 lock)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
326
|
+
- **Claude Code forward-compat anchors (checked at the 2.1.303 lock)** — three facts a
|
|
327
|
+
baseline bump should re-verify against the then-current docs:
|
|
328
|
+
1. The headless docs pre-announce `--bare` becoming the default for `-p`, and bare mode
|
|
329
|
+
never reads `.mcp.json` — the billed `claude-code` e2e scenario in this repo's test
|
|
330
|
+
suite and the project-scope install story both need re-checking when that lands.
|
|
331
|
+
2. `${VAR}` expansion in the `env` block of a user-scope `~/.claude.json` entry is
|
|
332
|
+
supported but only indirectly documented (the docs spell out `.mcp.json` and
|
|
333
|
+
`command`/`args`).
|
|
334
|
+
3. The same e2e scenario's `hasCompletedOnboarding` flag and the redundant
|
|
335
|
+
`enableAllProjectMcpServers` belt-and-suspenders are undocumented.
|
|
@@ -127,7 +127,9 @@ differences:
|
|
|
127
127
|
spec says clients SHOULD support it whenever possible. Legacy SSE is never required —
|
|
128
128
|
Codex and Pi reject it anyway.
|
|
129
129
|
3. **Build on the official SDK v2 dual-era serving.** One build then serves the full range:
|
|
130
|
-
the `2024-11-05` floor set by Cline (v2 legacy support spans `2024-10-07`–`2025-11-25
|
|
130
|
+
the `2024-11-05` floor set by Cline (v2 legacy support spans `2024-10-07`–`2025-11-25`;
|
|
131
|
+
`2024-10-07` is the pre-1.0 draft version string the SDK accepts for legacy
|
|
132
|
+
compatibility — it predates the spec's initial `2024-11-05` revision)
|
|
131
133
|
up to the `2026-07-28` negotiators (Claude Code 2.1.274+, Devin 3000.11.92, Copilot CLI
|
|
132
134
|
1.0.81+). A v1.x-built server still works today — modern clients fall back to the legacy
|
|
133
135
|
handshake — but it can never offer the stateless era; v2 serves both from one entry
|
|
@@ -54,7 +54,7 @@ MCP never carries conversation context to a server. The facts, per revision:
|
|
|
54
54
|
human-reviewed
|
|
55
55
|
([sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling)). A server
|
|
56
56
|
could only ask a model to *guess* intent — not obtain the user's question.
|
|
57
|
-
- **
|
|
57
|
+
- **Elicitation is interactive, not derivation.** `elicitation/create` asks the user a form/choice
|
|
58
58
|
question and waits ([2025-06-18+](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation));
|
|
59
59
|
it requires client capability (only Codex in this matrix has it, per
|
|
60
60
|
[mcp-compatibility.md](mcp-compatibility.md)) and an explicit round trip.
|
|
@@ -170,26 +170,25 @@ tag (commit `843a6c5`); the `opencode-ai/opencode` repository's tags stop at `v0
|
|
|
170
170
|
only heuristic correlation via the session hooks (which fire per model request with the
|
|
171
171
|
sessionID, but no API contract binds a provider call to a session).
|
|
172
172
|
|
|
173
|
+
Post-baseline drift check (2026-10-24): the interface is unchanged at 2.1.4, the latest npm
|
|
174
|
+
release on that date (unpkg dist of `@opencode/schema`/`@opencode/plugin` 2.1.4:
|
|
175
|
+
`ProviderInput = Pick<Input, "query">`, provider context `{ signal }`). Upstream requests
|
|
176
|
+
filed the same day to widen this surface:
|
|
177
|
+
[anomalyco/opencode#58635](https://github.com/anomalyco/opencode/issues/58635) (session
|
|
178
|
+
linkage in the provider execute context) and
|
|
179
|
+
[#58636](https://github.com/anomalyco/opencode/issues/58636) (optional per-call `count`
|
|
180
|
+
passthrough) — re-check both when the baseline or the OpenCode lock bumps.
|
|
181
|
+
|
|
173
182
|
Verdict: **tool path (`deepseek_fetch` / the `webfetch` override): A feasible (validated against
|
|
174
183
|
the declared schema; raw JSON Schema forwarded verbatim) and B feasible
|
|
175
184
|
(`ctx.session.context`). Websearch provider path (the search replacement this repo ships): neither
|
|
176
185
|
— the input schema is host-fixed to `query`, and the provider context has no session handle.**
|
|
177
186
|
|
|
178
|
-
### Cline 0.0.13
|
|
179
|
-
|
|
180
|
-
Closed source; the platform binary
|
|
181
|
-
([@cline/cli-linux-x64 0.0.13](https://registry.npmjs.org/@cline/cli-linux-x64/0.0.13), ~119 MB)
|
|
182
|
-
yielded the protocol facts already recorded — custom client negotiating `2024-11-05`,
|
|
183
|
-
text-content-only results ([mcp-compatibility.md](mcp-compatibility.md)). No primary source
|
|
184
|
-
documents whether the client validates tool arguments against `inputSchema` or mangles schemas;
|
|
185
|
-
strings cannot prove a runtime behavior either way, so this is **undeterminable at the lock**. The
|
|
186
|
-
2024-11-05 revision itself puts no validation obligation on clients and defines `arguments` as a
|
|
187
|
-
free-form object, so there is no protocol-level obstacle to channel A — merely no evidence for or
|
|
188
|
-
against host behavior. Channel B: none (MCP only, `paths` in hosts.jsonc).
|
|
189
|
-
|
|
190
187
|
## Proprietary hosts
|
|
191
188
|
|
|
192
|
-
|
|
189
|
+
Closed-source hosts, from binary analysis (Cline) and official docs/changelogs (the
|
|
190
|
+
rest). No proprietary host documents a context
|
|
191
|
+
channel; the question is whether anything documents
|
|
193
192
|
input-schema handling that would break an optional parameter.
|
|
194
193
|
|
|
195
194
|
- **Claude Code 2.1.303.** The [MCP docs](https://code.claude.com/docs/en/mcp) say nothing about
|
|
@@ -203,6 +202,16 @@ input-schema handling that would break an optional parameter.
|
|
|
203
202
|
preventing calling MCP tools that have nested references in their input schemas". Together these
|
|
204
203
|
show the server's `inputSchema` is what the model provider sees and that arguments follow it;
|
|
205
204
|
no host-side validation is ever mentioned. **A feasible by this evidence; B none.**
|
|
205
|
+
- **Cline 0.0.13.** Closed source; the platform binary
|
|
206
|
+
([@cline/cli-linux-x64 0.0.13](https://registry.npmjs.org/@cline/cli-linux-x64/0.0.13), ~119 MB)
|
|
207
|
+
yielded the protocol facts already recorded — custom client negotiating `2024-11-05`,
|
|
208
|
+
text-content-only results ([mcp-compatibility.md](mcp-compatibility.md)). No primary
|
|
209
|
+
source documents whether the client validates tool arguments against `inputSchema` or
|
|
210
|
+
mangles schemas; strings cannot prove a runtime behavior either way, so this is
|
|
211
|
+
**undeterminable at the lock**. The 2024-11-05 revision itself puts no validation
|
|
212
|
+
obligation on clients and defines `arguments` as a free-form object, so there is no
|
|
213
|
+
protocol-level obstacle to channel A — merely no evidence for or against host behavior.
|
|
214
|
+
Channel B: none (MCP only, `paths` in hosts.jsonc).
|
|
206
215
|
- **Cursor 2026.10.08.** The [MCP docs](https://cursor.com/docs/mcp) describe tools only as
|
|
207
216
|
"Functions for the AI model to execute" and say nothing about input schemas, validation, or
|
|
208
217
|
context — and the protocol revision itself is unpinnable from primary sources
|
|
@@ -256,7 +265,9 @@ negotiated revision in the matrix.
|
|
|
256
265
|
`ctx.session.context({ sessionID })` — user messages with their `text` — at call time, so
|
|
257
266
|
channel B exists here without touching schemas. The `websearch` provider replacement — the path
|
|
258
267
|
this repo uses for search — has neither channel at 2.0.32: its model-facing input schema is
|
|
259
|
-
fixed in host source to `query`, and its provider context is `{ signal }` only
|
|
268
|
+
fixed in host source to `query`, and its provider context is `{ signal }` only (upstream
|
|
269
|
+
requests: [#58635](https://github.com/anomalyco/opencode/issues/58635),
|
|
270
|
+
[#58636](https://github.com/anomalyco/opencode/issues/58636)). Note also that
|
|
260
271
|
`FETCH_INPUT` sets `additionalProperties: false`, which matters if a parameter is ever added on
|
|
261
272
|
channel A: an undeclared field would be rejected by OpenCode's runtime validation with a
|
|
262
273
|
retryable error.
|
|
@@ -282,7 +293,7 @@ negotiated revision in the matrix.
|
|
|
282
293
|
[2025-11-25 tasks (experimental)](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks)
|
|
283
294
|
- [2026-07-28 overview (`_meta`, statelessness)](https://modelcontextprotocol.io/specification/2026-07-28/basic/index)
|
|
284
295
|
|
|
285
|
-
### Open-source
|
|
296
|
+
### Open-source host sources
|
|
286
297
|
|
|
287
298
|
- Codex: [rust-v0.163.0 tag](https://github.com/openai/codex/tree/rust-v0.163.0) —
|
|
288
299
|
[mcp_tool_call.rs (argument parsing, no validation)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/core/src/mcp_tool_call.rs),
|
|
@@ -313,15 +324,15 @@ negotiated revision in the matrix.
|
|
|
313
324
|
(Tool.Context, WebSearch.ProviderInput),
|
|
314
325
|
[@opencode/client](https://registry.npmjs.org/@opencode/client/2.0.32)
|
|
315
326
|
(session.context → SessionMessageInfo[], SessionMessageUser.text)
|
|
316
|
-
- Cline: [@cline/cli-linux-x64 0.0.13](https://registry.npmjs.org/@cline/cli-linux-x64/0.0.13)
|
|
317
|
-
(manifest only; behavior undeterminable) and prior binary analysis recorded in
|
|
318
|
-
[mcp-compatibility.md](mcp-compatibility.md)
|
|
319
327
|
|
|
320
|
-
### Proprietary
|
|
328
|
+
### Proprietary host sources
|
|
321
329
|
|
|
322
330
|
- Claude Code: [changelog](https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md)
|
|
323
331
|
(entries 2.0.50, 2.1.30, 2.1.246, 2.1.300 — all ≤ the 2.1.303 lock),
|
|
324
332
|
[MCP docs](https://code.claude.com/docs/en/mcp)
|
|
333
|
+
- Cline: [@cline/cli-linux-x64 0.0.13](https://registry.npmjs.org/@cline/cli-linux-x64/0.0.13)
|
|
334
|
+
(manifest only; behavior undeterminable) and prior binary analysis recorded in
|
|
335
|
+
[mcp-compatibility.md](mcp-compatibility.md)
|
|
325
336
|
- Cursor: [MCP docs](https://cursor.com/docs/mcp) (silent on the question)
|
|
326
337
|
- Devin: [MCP overview](https://docs.devin.ai/cli/extensibility/mcp/overview),
|
|
327
338
|
[changelog](https://docs.devin.ai/cli/changelog) (silent on the question)
|
|
@@ -5,8 +5,8 @@ This note answers one question: through which channel can DeepSeek's per-result
|
|
|
5
5
|
(string|null) — reach the **model** (not the human UI) on each host at its locked version? The
|
|
6
6
|
repo filters on the first two in `src/core/search.ts` (thresholds default to off); at the
|
|
7
7
|
research baseline it dropped all three before returning — the adapters now pass them through
|
|
8
|
-
as a text marker plus a structured mirror (
|
|
9
|
-
`formatQualityMarker`).
|
|
8
|
+
as a text marker plus a structured mirror (the text marker of *What this means for this
|
|
9
|
+
repo*, item 1, is implemented as `formatQualityMarker`).
|
|
10
10
|
Related: [ori-question-sourcing.md](ori-question-sourcing.md) (input side),
|
|
11
11
|
[search-inline-content.md](search-inline-content.md) (content volume).
|
|
12
12
|
|
|
@@ -47,7 +47,8 @@ The server-side validator (`@modelcontextprotocol/server` 2.3.1,
|
|
|
47
47
|
`Output validation error: Tool <name> has an output schema but no structured content was
|
|
48
48
|
provided` (JSON-RPC `InvalidParams`). Text-only results are not allowed for schema'd tools.
|
|
49
49
|
- `structuredContent` is then validated against the schema; a mismatch is rejected the same way.
|
|
50
|
-
- The v2 codec's SEP-2106 §4.3 auto-append (
|
|
50
|
+
- The v2 codec's SEP-2106 §4.3 auto-append (so named in the installed SDK's own source;
|
|
51
|
+
implemented as `appendTextFallbackForNonObject`) adds a
|
|
51
52
|
`JSON.stringify(structuredContent)` TextContent block **only when `structuredContent` is a
|
|
52
53
|
non-object** (primitive/array/null) and no text block exists. Object-shaped
|
|
53
54
|
`structuredContent` gets **no** automatic text mirror — the server must mirror it itself to
|
|
@@ -108,7 +109,8 @@ From the official repo at tag `v2.0.32` (github.com/anomalyco/opencode, where `@
|
|
|
108
109
|
- Every tool result then passes through `ToolOutput.truncate`:
|
|
109
110
|
**`MAX_LINES = 2000`, `MAX_BYTES = 50 KiB`** (full output retained to a `tool-output/`
|
|
110
111
|
file for 7 days) — [`packages/core/src/tool-output.ts`](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool-output.ts).
|
|
111
|
-
These caps
|
|
112
|
+
These caps are also recorded in [control-matrix.md](control-matrix.md#opencode)'s
|
|
113
|
+
OpenCode section.
|
|
112
114
|
|
|
113
115
|
## What this means for this repo
|
|
114
116
|
|
|
@@ -128,9 +130,9 @@ From the official repo at tag `v2.0.32` (github.com/anomalyco/opencode, where `@
|
|
|
128
130
|
The Pi adapter's extension `outputSchema` is safe as-is — Pi re-declares but does not
|
|
129
131
|
validate it, and its `structuredContent` is event data.
|
|
130
132
|
4. **New cap facts for the design margin:** OpenCode plugin results truncate at 2000 lines /
|
|
131
|
-
50 KiB
|
|
132
|
-
|
|
133
|
-
bind at search-result volumes; they matter if [inline content](search-inline-content.md) is
|
|
133
|
+
50 KiB, Pi extension tools bypass the MCP 20 KB truncation, Claude Code caps output at
|
|
134
|
+
25k tokens, and Codex applies its per-tool `output_token_limit` (default unpublished).
|
|
135
|
+
None of these bind at search-result volumes; they matter if [inline content](search-inline-content.md) is
|
|
134
136
|
ever enabled.
|
|
135
137
|
|
|
136
138
|
## Sources
|
|
@@ -159,7 +159,8 @@ the current official docs** (checked 2026-10-21), nor in the November 2025 snaps
|
|
|
159
159
|
page on the Internet Archive; the published truncation mechanism is the token-based
|
|
160
160
|
`max_content_tokens` parameter above, with no published default.
|
|
161
161
|
|
|
162
|
-
SDK layer (official repos, default branch
|
|
162
|
+
SDK layer (official repos, default branch at the 2026-10-21 check — moving heads, unlike
|
|
163
|
+
the pinned firecrawl 4.50.0 above; re-pin to a tag before citing these constants later):
|
|
163
164
|
|
|
164
165
|
| SDK | Default timeout | Default max retries | Source |
|
|
165
166
|
| --- | --- | --- | --- |
|
|
@@ -180,7 +181,8 @@ From the official guide
|
|
|
180
181
|
|
|
181
182
|
No relevance/authority score or filter is exposed on any web-search surface.
|
|
182
183
|
|
|
183
|
-
SDK layer (official repos, default branch
|
|
184
|
+
SDK layer (official repos, default branch at the 2026-10-21 check — same moving-head
|
|
185
|
+
caveat as the Anthropic SDK table above):
|
|
184
186
|
|
|
185
187
|
| SDK | Default timeout | Default max retries | Source |
|
|
186
188
|
| --- | --- | --- | --- |
|