deepseek-web-retrieval 0.4.0 → 0.5.1
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 +99 -244
- package/README.md +16 -11
- package/dist/cli.js +1366 -615
- package/docs/agents/codex.md +28 -7
- package/docs/agents/opencode-v2.md +1 -1
- package/docs/agents/pi.md +88 -86
- package/docs/design/installer-design.md +72 -9
- package/docs/hosts.jsonc +2 -2
- package/docs/integration.md +14 -9
- package/docs/research/control-matrix.md +48 -13
- package/docs/research/mcp-compatibility.md +9 -4
- package/examples/pi.settings.jsonc +17 -0
- package/index.ts +2 -2
- package/package.json +35 -4
- package/src/core/auth.ts +4 -6
- package/src/core/client.ts +65 -53
- package/src/core/constants.ts +24 -24
- package/src/core/descriptions.ts +30 -6
- package/src/core/domains.ts +56 -67
- package/src/core/env.ts +112 -0
- package/src/core/format.ts +53 -50
- package/src/core/index.ts +9 -9
- package/src/core/jsonc.ts +6 -6
- package/src/core/object.ts +4 -0
- package/src/core/options.ts +20 -25
- package/src/core/search.ts +45 -44
- package/src/core/transport.ts +109 -113
- package/src/core/types.ts +47 -47
- package/src/core/url.ts +20 -20
- package/src/installer/apply.ts +256 -81
- package/src/installer/cli.ts +135 -104
- package/src/installer/detect.ts +46 -31
- package/src/installer/formats/index.ts +26 -28
- package/src/installer/formats/json.ts +81 -77
- package/src/installer/formats/rules.ts +55 -28
- package/src/installer/formats/toml.ts +88 -81
- package/src/installer/formats/value.ts +34 -30
- package/src/installer/hosts/codex.ts +100 -54
- package/src/installer/hosts/index.ts +126 -41
- package/src/installer/hosts/opencode.ts +70 -51
- package/src/installer/hosts/pi.ts +269 -75
- package/src/installer/hosts/shared.ts +19 -14
- package/src/installer/operation-lock.ts +54 -0
- package/src/installer/ownership.ts +129 -0
- package/src/installer/paths.ts +7 -5
- package/src/installer/persistence.ts +66 -0
- package/src/installer/render.ts +29 -29
- package/src/installer/revert.ts +33 -29
- package/src/installer/rulesContent.ts +24 -13
- package/src/installer/state.ts +116 -31
- package/src/installer/types.ts +74 -56
- package/src/installer/uninstall.ts +40 -17
- package/src/mcp/auth.ts +7 -8
- package/src/mcp/cli.ts +38 -20
- package/src/mcp/client.ts +35 -0
- package/src/mcp/server.ts +68 -97
- package/src/opencode/auth.ts +24 -26
- package/src/opencode/plugin.ts +99 -87
- package/src/pi/extension.ts +164 -0
- package/src/pi/settings.ts +49 -0
- package/src/mcp/config.ts +0 -112
package/docs/agents/codex.md
CHANGED
|
@@ -16,6 +16,12 @@ The tools appear in Codex as `mcp__deepseek__deepseek_web_search` and
|
|
|
16
16
|
`mcp__deepseek__deepseek_fetch`. Codex's built-in `web_search` tool is not replaced; see
|
|
17
17
|
[Control tiers](#control-tiers) for routing it away.
|
|
18
18
|
|
|
19
|
+
The server recognizes Codex's MCP client identity (`codex-mcp-client`, declared in the
|
|
20
|
+
initialize handshake) and returns text-only tool results: Codex replaces the content
|
|
21
|
+
blocks with the serialized `structuredContent` JSON when it is present, so for Codex the
|
|
22
|
+
structured mirror is omitted and the model reads clean Markdown. Other clients receive
|
|
23
|
+
both the text and `structuredContent`.
|
|
24
|
+
|
|
19
25
|
For shared search/fetch limits, retries, and privacy behavior, see
|
|
20
26
|
[General behavior](../../README.md#general-behavior).
|
|
21
27
|
|
|
@@ -40,7 +46,13 @@ It prints the full plan — every file, old value → new value, and notes about
|
|
|
40
46
|
MCP servers — and writes nothing until you pass `--apply`. `uninstall` restores exactly
|
|
41
47
|
what the plan applied (snapshots, merged entries, created files). Codex's config lives in
|
|
42
48
|
`~/.codex/config.toml` at the user level only, so the server registration and kill switch
|
|
43
|
-
are written there even for `--scope project`; the rules file follows the scope.
|
|
49
|
+
are written there even for `--scope project`; the rules file follows the scope. An `off`
|
|
50
|
+
capability is written as the tool's name in the server entry's `disabled_tools` array —
|
|
51
|
+
Codex's own mechanism — merging with any entries you put there yourself. When `codex` is
|
|
52
|
+
on PATH, `init` also probes `codex --version` and adds a plan note when the installed
|
|
53
|
+
release differs from the tested lock (see
|
|
54
|
+
[hosts.jsonc](../hosts.jsonc)) — version-anchored behavior such as the kill switch may
|
|
55
|
+
have drifted between the two.
|
|
44
56
|
|
|
45
57
|
### Manual install
|
|
46
58
|
|
|
@@ -59,13 +71,22 @@ env_vars = ["DEEPSEEK_API_KEY"]
|
|
|
59
71
|
> forwarded explicitly and set in the shell that launches Codex. Literal values can go
|
|
60
72
|
> in an `env` table instead if you prefer them in the file.
|
|
61
73
|
|
|
62
|
-
To disable one capability,
|
|
74
|
+
To disable one capability, add its raw tool name to the server's `disabled_tools` —
|
|
75
|
+
Codex removes the tool from the model's context while the server keeps running:
|
|
63
76
|
|
|
64
77
|
```toml
|
|
65
|
-
[mcp_servers.deepseek
|
|
66
|
-
|
|
78
|
+
[mcp_servers.deepseek]
|
|
79
|
+
command = "npx"
|
|
80
|
+
args = ["-y", "deepseek-web-retrieval"]
|
|
81
|
+
env_vars = ["DEEPSEEK_API_KEY"]
|
|
82
|
+
disabled_tools = ["deepseek_web_search"] # or deepseek_fetch; at least one must stay on
|
|
67
83
|
```
|
|
68
84
|
|
|
85
|
+
The names match verbatim what the server declares (`deepseek_web_search`,
|
|
86
|
+
`deepseek_fetch`). The server also honors `DEEPSEEK_ENABLE_SEARCH`/`DEEPSEEK_ENABLE_FETCH`
|
|
87
|
+
in the `env` table if you prefer switching the tools off at the source; the installer uses
|
|
88
|
+
`disabled_tools`.
|
|
89
|
+
|
|
69
90
|
### Local checkout
|
|
70
91
|
|
|
71
92
|
```bash
|
|
@@ -111,7 +132,7 @@ Ask naturally:
|
|
|
111
132
|
|
|
112
133
|
```text
|
|
113
134
|
Search the web for the latest Codex MCP config changes and cite the sources.
|
|
114
|
-
Fetch https://
|
|
135
|
+
Fetch https://learn.chatgpt.com/docs/extend/mcp and summarize the config keys.
|
|
115
136
|
```
|
|
116
137
|
|
|
117
138
|
The model calls `mcp__deepseek__deepseek_web_search` or `mcp__deepseek__deepseek_fetch`.
|
|
@@ -163,8 +184,8 @@ defaults and clamping match the other adapters. `DEEPSEEK_API_KEY` goes in `env_
|
|
|
163
184
|
| Server fails to start or `HTTP 401` from the tools | `DEEPSEEK_API_KEY` must be set in the shell that launches Codex and forwarded via `env_vars`; stdio children do not inherit the environment. |
|
|
164
185
|
| Both tools missing after startup | At least one of `DEEPSEEK_ENABLE_SEARCH`/`DEEPSEEK_ENABLE_FETCH` must stay enabled; the server exits when both are false. |
|
|
165
186
|
| Search still uses the built-in tool under the forced tier | The kill switch is the top-level `web_search = "disabled"` key; the `[tools] web_search` form is a no-op at 0.163.0. |
|
|
166
|
-
| Tool results look like raw JSON |
|
|
167
|
-
| Tools time out
|
|
187
|
+
| Tool results look like raw JSON | The server omits `structuredContent` for Codex's `codex-mcp-client` client identity so the model reads Markdown; if JSON still appears, a newer Codex renamed the identity — report it. |
|
|
188
|
+
| Tools time out before the configured DeepSeek timeout | Codex's per-server `tool_timeout_sec` defaults to 300 s — above the 120 s `DEEPSEEK_*_TIMEOUT_MS` maximum — so this only happens if you lowered it; raise it back above the DeepSeek timeout. |
|
|
168
189
|
| Routing not exclusive | Other `[mcp_servers.*]` entries stay registered and are noted in the plan. Under a forced tier, an entry that looks web-capable makes `init` refuse — Codex has no per-server kill switch, so remove the server or restrict its tools via `disabled_tools` by hand. |
|
|
169
190
|
| `HTTP 402`, `HTTP 429` | Top up the DeepSeek account; wait, reduce concurrency, or set `DEEPSEEK_MAX_RETRIES`. |
|
|
170
191
|
| Fetch fails on localhost or an internal URL | Use a local fetch tool; DeepSeek cannot reach private networks. |
|
|
@@ -174,7 +174,7 @@ Set these in the plugin's `options` object.
|
|
|
174
174
|
| `searchEnabled` | `true` | Register the DeepSeek search provider at all. Only an explicit `false` disables it. |
|
|
175
175
|
| `count` | `10` | Results requested from DeepSeek, 1–50. Billing is per request, not per result. |
|
|
176
176
|
| `maxResults` | `10` | Results returned to the model after filtering, 0–50. `0` returns no results. |
|
|
177
|
-
| `minRerank` | `0` | Drop results below this relevance score. DeepSeek scores are 0–3. |
|
|
177
|
+
| `minRerank` | `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. |
|
|
178
178
|
| `minAuthority` | `0` | Drop known authorities below this tier. Authority is 0–4. |
|
|
179
179
|
| `allowUnknownAuthority` | `true` | Keep results whose authority is missing or unknown. Only an explicit `false` disables it. |
|
|
180
180
|
| `blockedDomains` | `[]` | Add `-site:` operators to the search query. |
|
package/docs/agents/pi.md
CHANGED
|
@@ -2,29 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
Pi adapter for [DeepSeek Web Retrieval](../../README.md).
|
|
4
4
|
|
|
5
|
-
Integration mechanism:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
[
|
|
5
|
+
Integration mechanism: Pi's native extension API — the package's `pi` manifest names
|
|
6
|
+
`src/pi/extension.ts`, and Pi loads it in-process (via jiti, TypeScript directly) at session
|
|
7
|
+
start. The same build also ships an MCP server over stdio as the fallback path
|
|
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's codemode trap does not exist here).
|
|
12
|
+
- Results bypass Pi's MCP layer entirely: no 20 KB middle truncation and no 60 s
|
|
13
|
+
per-request timeout; the adapter's own output cap is the only limit.
|
|
14
|
+
- The key is read from the Pi process environment — no `env` forwarding, no `${VAR}`
|
|
15
|
+
indirection in any config file.
|
|
16
|
+
|
|
17
|
+
When loaded, it adds:
|
|
11
18
|
|
|
12
19
|
- A `deepseek_web_search` tool backed by DeepSeek Search
|
|
13
20
|
- A `deepseek_fetch` tool backed by DeepSeek Fetch
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
For shared search/fetch limits, retries, and privacy behavior, see
|
|
22
|
+
Pi 1.3.0 ships no built-in web tool, so the registered tools are the only web path. For
|
|
23
|
+
shared search/fetch limits, retries, and privacy behavior, see
|
|
19
24
|
[General behavior](../../README.md#general-behavior).
|
|
20
25
|
|
|
21
26
|
## Requirements
|
|
22
27
|
|
|
23
28
|
- Pi 1.3.0 or newer
|
|
24
|
-
- Node.js 20 or newer (`npx` runs the server)
|
|
25
29
|
- A DeepSeek account with access to `/v1/tools/search` and `/v1/tools/fetch`
|
|
26
30
|
- A funded DeepSeek account; Search and Fetch are billed per successful request
|
|
27
|
-
- `DEEPSEEK_API_KEY` set in the
|
|
31
|
+
- `DEEPSEEK_API_KEY` set in the shell that launches Pi
|
|
28
32
|
|
|
29
33
|
## Install
|
|
30
34
|
|
|
@@ -36,79 +40,49 @@ npx deepseek-web-retrieval init --host pi --scope <project|global> \
|
|
|
36
40
|
```
|
|
37
41
|
|
|
38
42
|
It prints the full plan — every file, old value → new value, and notes about existing
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
packages and MCP servers — and writes nothing until you pass `--apply`. The default path is
|
|
44
|
+
the extension: the plan appends `npm:deepseek-web-retrieval` to the `packages` array in
|
|
45
|
+
`~/.pi/agent/settings.json` (global) or `.pi/settings.json` (project), and Pi resolves the
|
|
46
|
+
source at the next session start (the first launch fetches the package from npm;
|
|
47
|
+
`pi update --extensions` refreshes it later). An off capability is written into the
|
|
48
|
+
`deepseekWebRetrieval` settings namespace the extension reads at load. Pass `--path mcp`
|
|
49
|
+
to install the [MCP fallback path](#the-mcp-fallback-path) instead. `uninstall` restores
|
|
50
|
+
exactly what the plan applied.
|
|
47
51
|
|
|
48
52
|
### Manual install
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```jsonc
|
|
53
|
-
{
|
|
54
|
-
"mcpServers": {
|
|
55
|
-
"deepseek": {
|
|
56
|
-
"command": "npx",
|
|
57
|
-
"args": ["-y", "deepseek-web-retrieval"],
|
|
58
|
-
"env": { "DEEPSEEK_API_KEY": "${DEEPSEEK_API_KEY}" },
|
|
59
|
-
"exposure": "direct"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`${DEEPSEEK_API_KEY}` expands from the shell that launches Pi, so the key itself stays out
|
|
66
|
-
of the config file. Set it in your shell profile:
|
|
54
|
+
Use Pi's own installer:
|
|
67
55
|
|
|
68
56
|
```bash
|
|
69
|
-
|
|
57
|
+
pi install npm:deepseek-web-retrieval # ~/.pi/agent/settings.json (user)
|
|
58
|
+
pi install --local npm:deepseek-web-retrieval # .pi/settings.json (project)
|
|
70
59
|
```
|
|
71
60
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
> them to the model. `"exposure": "direct"` registers the two tools like built-ins so the
|
|
75
|
-
> model can call them. Without it the server connects but the tools are never used.
|
|
76
|
-
|
|
77
|
-
Verify the registration with `pi mcp list` (or the `/mcp` panel inside a session); Pi
|
|
78
|
-
shows the server's tools when the handshake succeeds. Config changes load with `/reload`
|
|
79
|
-
or a new session.
|
|
61
|
+
Pi reads the package's `pi` manifest and loads `src/pi/extension.ts` at session start. No
|
|
62
|
+
build step and no config entry beyond the `packages` source are needed.
|
|
80
63
|
|
|
81
64
|
### Local checkout
|
|
82
65
|
|
|
83
|
-
To run the server from a checkout instead of the published package (for
|
|
84
|
-
development):
|
|
85
|
-
|
|
86
66
|
```bash
|
|
87
67
|
git clone https://github.com/gwokhou/deepseek-web-retrieval.git
|
|
88
|
-
cd deepseek-web-retrieval
|
|
89
|
-
bun install && bun run build
|
|
90
68
|
```
|
|
91
69
|
|
|
92
|
-
Then point Pi at the
|
|
70
|
+
Then point Pi at the checkout (it is itself a valid package):
|
|
93
71
|
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
"mcpServers": {
|
|
97
|
-
"deepseek": {
|
|
98
|
-
"command": "node",
|
|
99
|
-
"args": ["/absolute/path/to/deepseek-web-retrieval/dist/cli.js"],
|
|
100
|
-
"env": { "DEEPSEEK_API_KEY": "${DEEPSEEK_API_KEY}" },
|
|
101
|
-
"exposure": "direct"
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
72
|
+
```bash
|
|
73
|
+
pi install /absolute/path/to/deepseek-web-retrieval
|
|
105
74
|
```
|
|
106
75
|
|
|
76
|
+
The extension entry imports only host-supplied modules (`@earendil-works/pi-coding-agent`,
|
|
77
|
+
`@earendil-works/pi-ai`) and the package's own `src/core/`, so a plain clone works.
|
|
78
|
+
|
|
107
79
|
## Authentication
|
|
108
80
|
|
|
109
|
-
`DEEPSEEK_API_KEY` is the only source
|
|
110
|
-
|
|
111
|
-
|
|
81
|
+
`DEEPSEEK_API_KEY` is the only source: the extension runs inside the Pi process and reads
|
|
82
|
+
the environment directly, so the key must be set in the shell that launches Pi (MCP's env
|
|
83
|
+
forwarding does not apply). It is read per request and sent only to `api.deepseek.com` as a
|
|
84
|
+
Bearer token. It is not written to tool output or logs. Without it, the first tool call
|
|
85
|
+
returns an error naming the missing variable.
|
|
112
86
|
|
|
113
87
|
## Usage
|
|
114
88
|
|
|
@@ -119,12 +93,15 @@ Search the web for the latest Pi extension API changes and cite the sources.
|
|
|
119
93
|
Fetch https://pi.dev/docs/latest/extensions and summarize the extension lifecycle.
|
|
120
94
|
```
|
|
121
95
|
|
|
122
|
-
The model calls `
|
|
96
|
+
The model calls `deepseek_web_search` or `deepseek_fetch` — the same names over both paths;
|
|
97
|
+
only the MCP fallback prefixes them with `mcp__deepseek__`.
|
|
123
98
|
|
|
124
99
|
## Configuration
|
|
125
100
|
|
|
126
|
-
|
|
127
|
-
defaults and clamping
|
|
101
|
+
The runtime config surface is the same `DEEPSEEK_*` environment the MCP server reads
|
|
102
|
+
(identical defaults and clamping), set in the shell that launches Pi, plus the
|
|
103
|
+
`deepseekWebRetrieval` settings namespace for the off switches (written by the installer;
|
|
104
|
+
it outranks the environment and is preserved by Pi's own settings rewrites).
|
|
128
105
|
|
|
129
106
|
### Search
|
|
130
107
|
|
|
@@ -140,15 +117,15 @@ defaults and clamping match the OpenCode adapter.
|
|
|
140
117
|
| `DEEPSEEK_SEARCH_INCLUDE_DOMAINS` | unset | Comma-separated; restricts results with `site:` operators. |
|
|
141
118
|
| `DEEPSEEK_SEARCH_LANGUAGE` | unset | Adds a `lang:` operator, for example `zh,en`. |
|
|
142
119
|
| `DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS` | `1200` | Per-result summary cap, 0–1,000,000. |
|
|
143
|
-
| `DEEPSEEK_SEARCH_TIMEOUT_MS` | `30000` | Search timeout, 1,000–120,000 ms. |
|
|
120
|
+
| `DEEPSEEK_SEARCH_TIMEOUT_MS` | `30000` | Search timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
144
121
|
|
|
145
122
|
### Fetch
|
|
146
123
|
|
|
147
124
|
| Env variable | Default | Description |
|
|
148
|
-
| --- | --- |
|
|
125
|
+
| --- | --- | --- |
|
|
149
126
|
| `DEEPSEEK_ENABLE_FETCH` | `true` | Register the fetch tool. Same false-only semantics as `DEEPSEEK_ENABLE_SEARCH`. |
|
|
150
|
-
| `DEEPSEEK_FETCH_MAX_CHARS` | `16000` | Maximum characters returned, including the title, 0–1,000,000. |
|
|
151
|
-
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. |
|
|
127
|
+
| `DEEPSEEK_FETCH_MAX_CHARS` | `16000` | Maximum characters returned, including the title, 0–1,000,000. The only output cap on this path. |
|
|
128
|
+
| `DEEPSEEK_FETCH_TIMEOUT_MS` | `30000` | Fetch timeout, 1,000–120,000 ms. No host-side cap applies on the extension path. |
|
|
152
129
|
| `DEEPSEEK_FETCH_ALLOWED_DOMAINS` | unset | If set, only these hosts and subdomains may be fetched. |
|
|
153
130
|
| `DEEPSEEK_FETCH_BLOCKED_DOMAINS` | unset | Always block these hosts and subdomains. Blocked wins over allowed. |
|
|
154
131
|
| `DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS` | `true` | Reject localhost, private IPs, `.local`, `.internal`, and similar hosts. Set `false`/`0` to disable. |
|
|
@@ -157,7 +134,7 @@ defaults and clamping match the OpenCode adapter.
|
|
|
157
134
|
|
|
158
135
|
| Env variable | Default | Description |
|
|
159
136
|
| --- | --- | --- |
|
|
160
|
-
| `DEEPSEEK_API_KEY` | required | DeepSeek API key
|
|
137
|
+
| `DEEPSEEK_API_KEY` | required | DeepSeek API key, read from the Pi process environment. |
|
|
161
138
|
| `DEEPSEEK_MAX_RETRIES` | `0` | Retries for 408, 425, 429, and 5xx responses, 0–5. |
|
|
162
139
|
| `DEEPSEEK_RETRY_BASE_DELAY_MS` | `250` | Base delay for exponential backoff. `Retry-After` is honored up to 10 seconds. |
|
|
163
140
|
|
|
@@ -167,30 +144,28 @@ Invalid values fall back to the shared default.
|
|
|
167
144
|
|
|
168
145
|
| Error or symptom | What to do |
|
|
169
146
|
| --- | --- |
|
|
170
|
-
|
|
|
171
|
-
|
|
|
147
|
+
| `Failed to load extension ... at least one must stay enabled` | Both capabilities are off (env or the `deepseekWebRetrieval` namespace); keep at least one on. |
|
|
148
|
+
| Tools never appear | Check that the `packages` entry is present (`pi list`) and that the first launch after install could reach npm; `pi update --extensions` re-fetches. |
|
|
149
|
+
| First tool call errors on the key | `DEEPSEEK_API_KEY` must be set in the shell that launches Pi; the extension reads only the process environment. |
|
|
172
150
|
| `HTTP 401, invalid API key` | Check the key and its access to the tools endpoints. |
|
|
173
151
|
| `HTTP 402, insufficient balance` | Top up the DeepSeek account. |
|
|
174
152
|
| `HTTP 429, rate limited` | Wait, reduce concurrency, or set `DEEPSEEK_MAX_RETRIES`. |
|
|
175
153
|
| Search query too long | Shorten the query or reduce configured domain/language operators. |
|
|
176
154
|
| Fetch fails on localhost or an internal URL | Use a local fetch tool; DeepSeek cannot reach private networks. |
|
|
177
|
-
|
|
|
178
|
-
| Request fails around 60 seconds | Pi's per-request default timeout is 60 s; raise the server's `timeout` if you raise `DEEPSEEK_*_TIMEOUT_MS` beyond it. |
|
|
179
|
-
| Config change does not take effect | Run `/reload` in the session or start a new one. |
|
|
155
|
+
| Project-scope install does not load | Pi gates project-local files behind project trust; approve the project when prompted (or launch with `--approve`). |
|
|
180
156
|
|
|
181
157
|
## Compatibility
|
|
182
158
|
|
|
183
159
|
| Component | Version |
|
|
184
160
|
| --- | --- |
|
|
185
161
|
| Pi | locked in [`docs/hosts.jsonc`](../hosts.jsonc) |
|
|
186
|
-
|
|
|
187
|
-
|
|
|
188
|
-
| Runtime | Node.js 20+ (stdio) |
|
|
162
|
+
| Extension entry | `src/pi/extension.ts` via the package's `pi` manifest (jiti, no build step) |
|
|
163
|
+
| Runtime | Inside the Pi process (Node, host-provided) |
|
|
189
164
|
| DeepSeek API | `/v1/tools/search`, `/v1/tools/fetch` |
|
|
190
165
|
|
|
191
|
-
Pi 1.3.0
|
|
192
|
-
|
|
193
|
-
|
|
166
|
+
Tested with Pi 1.3.0 on Linux. The extension API is version-locked research surface: the
|
|
167
|
+
`ToolDefinition` shape and the settings `packages` key are verified at the locked version
|
|
168
|
+
(see [the per-host reference](../research/control-matrix.md#pi)).
|
|
194
169
|
|
|
195
170
|
## Uninstall
|
|
196
171
|
|
|
@@ -200,10 +175,37 @@ With the installer CLI:
|
|
|
200
175
|
npx deepseek-web-retrieval uninstall --host pi --scope <project|global>
|
|
201
176
|
```
|
|
202
177
|
|
|
203
|
-
Or remove the
|
|
178
|
+
Or remove the source with Pi itself:
|
|
204
179
|
|
|
205
180
|
```bash
|
|
206
|
-
pi
|
|
181
|
+
pi remove npm:deepseek-web-retrieval
|
|
207
182
|
```
|
|
208
183
|
|
|
209
184
|
For a local-checkout install, also delete the cloned directory.
|
|
185
|
+
|
|
186
|
+
## The MCP fallback path
|
|
187
|
+
|
|
188
|
+
The same package ships a stdio MCP server (`npx deepseek-web-retrieval`). It works on Pi
|
|
189
|
+
through `~/.pi/agent/mcp.json` or `.pi/mcp.json`:
|
|
190
|
+
|
|
191
|
+
```jsonc
|
|
192
|
+
{
|
|
193
|
+
"mcpServers": {
|
|
194
|
+
"deepseek": {
|
|
195
|
+
"command": "npx",
|
|
196
|
+
"args": ["-y", "deepseek-web-retrieval"],
|
|
197
|
+
"env": { "DEEPSEEK_API_KEY": "${DEEPSEEK_API_KEY}" },
|
|
198
|
+
"exposure": "direct"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The tools appear as `mcp__deepseek__deepseek_web_search` and `mcp__deepseek__deepseek_fetch`,
|
|
205
|
+
and the MCP layer's limits apply instead: text results over 20 KB are middle-truncated with
|
|
206
|
+
the full text saved to a file (keep `DEEPSEEK_FETCH_MAX_CHARS` at or below 20000 to truncate
|
|
207
|
+
deterministically), and the per-request default timeout is 60 s (raise the entry's `timeout`
|
|
208
|
+
if you raise `DEEPSEEK_*_TIMEOUT_MS` beyond it). `pi mcp list` verifies the handshake, and
|
|
209
|
+
config changes load with `/reload` or a new session. `npx deepseek-web-retrieval init
|
|
210
|
+
--host pi --path mcp ...` installs this shape with plan-then-apply semantics; see
|
|
211
|
+
[`examples/pi.mcp.jsonc`](../../examples/pi.mcp.jsonc).
|
|
@@ -116,6 +116,21 @@ scope choice would overlap the other scope's record — Codex's project-scope fa
|
|
|
116
116
|
onto `~/.codex/config.toml` beside a global install — the plan refuses with guidance,
|
|
117
117
|
and uninstall runs the same check defensively before touching anything.
|
|
118
118
|
|
|
119
|
+
Shared config files also carry an owner-only sidecar beside the actual file
|
|
120
|
+
(`.config.toml.deepseek-web-retrieval.codex.owner.json` for Codex). It points to the
|
|
121
|
+
owning install record and project directory, so two different project directories
|
|
122
|
+
cannot both claim the same global config, even with different `XDG_CONFIG_HOME`
|
|
123
|
+
values. Planning reports this metadata write; apply acquires the claim before
|
|
124
|
+
writing config and rechecks ownership, and uninstall releases it. A failed first
|
|
125
|
+
apply releases its new claim; a failed re-init retains the previous owner's claim.
|
|
126
|
+
Project-local configs and shared rules blocks do not need these sidecars.
|
|
127
|
+
|
|
128
|
+
For installs created before this ownership metadata existed, re-run init from the
|
|
129
|
+
original project and scope to establish the claim. An installer-style registration
|
|
130
|
+
without a record at the requested location is refused rather than adopted as a new
|
|
131
|
+
snapshot. If an identical registration was created manually, remove it before init.
|
|
132
|
+
Do not delete an ownership sidecar while its install is still active.
|
|
133
|
+
|
|
119
134
|
## Rollback
|
|
120
135
|
|
|
121
136
|
Uninstall reverses exactly what the plan applied: overwritten values restore their
|
|
@@ -127,14 +142,17 @@ pointing at the removed plugin, and the user must clean up by hand.
|
|
|
127
142
|
|
|
128
143
|
## Tier-to-artifact mapping
|
|
129
144
|
|
|
145
|
+
Pi has two integration paths (`--path extension` by default, `--path mcp` as the fallback);
|
|
146
|
+
the artifacts below name the path where they differ.
|
|
147
|
+
|
|
130
148
|
| Choice | Artifacts |
|
|
131
149
|
| --- | --- |
|
|
132
|
-
| Optional | Host config registering the
|
|
133
|
-
| 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)) |
|
|
150
|
+
| 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) |
|
|
151
|
+
| 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) |
|
|
134
152
|
| Forced (replacement) | OpenCode plugin options (`setDefaultWebsearch` / `fetchOverrideWebfetch`) |
|
|
135
|
-
| Forced (exclusion) | The built-in competitor's kill switch (per-host keys in the per-host reference), plus the exclusion of any other web-capable MCP servers the detect phase found — Pi sets their `enabled` key to `false`; Codex, lacking a per-server kill switch, refuses the tier instead |
|
|
153
|
+
| Forced (exclusion) | The built-in competitor's kill switch (per-host keys in the per-host reference), plus the exclusion of any other web-capable MCP servers the detect phase found — Pi sets their `enabled` key to `false`; Codex, lacking a per-server kill switch, refuses the tier instead; Pi's extension path additionally refuses when a web-capable `packages`/`extensions` source is listed in settings.json (no per-package kill switch exists) |
|
|
136
154
|
| Forced (de-facto) | Nothing beyond the Optional artifacts — no competitor exists |
|
|
137
|
-
| Off |
|
|
155
|
+
| Off | Codex writes the capability's raw tool name into the server entry's `disabled_tools` (host-native: the tool leaves the model's context; the user's own entries in that array are kept); the other MCP entry writes the capability's false-only server-side switch instead (`DEEPSEEK_ENABLE_SEARCH` / `DEEPSEEK_ENABLE_FETCH`); Pi's extension path writes the same switches into the `deepseekWebRetrieval` settings namespace the extension reads at load; both capabilities off refuses to install |
|
|
138
156
|
|
|
139
157
|
OpenCode additionally appends `permissions` allow entries for exactly the tools it
|
|
140
158
|
registers (`websearch`, `deepseek_fetch`, and `webfetch` when fetch is forced), merged
|
|
@@ -146,10 +164,13 @@ into any existing `permissions` array rather than replacing it.
|
|
|
146
164
|
request; deterministic routing removes both the model's discretion and its restraint as
|
|
147
165
|
a cost brake. Every forced-tier plan carries a note naming the README's "Privacy and
|
|
148
166
|
cost" section.
|
|
149
|
-
- **Rules content.** Name the full tool ids (`mcp__deepseek__deepseek_web_search`
|
|
150
|
-
|
|
151
|
-
(localhost/private-network URLs go to local
|
|
152
|
-
default).
|
|
167
|
+
- **Rules content.** Name the full tool ids the host will see (`mcp__deepseek__deepseek_web_search`
|
|
168
|
+
over MCP, `deepseek_web_search` over Pi's extension), state trigger conditions rather than
|
|
169
|
+
unconditional preference, and list exclusions (localhost/private-network URLs go to local
|
|
170
|
+
fetch tools; the server blocks them by default). Emit routing guidance only for the
|
|
171
|
+
capability selected as preferred; an optional capability stays optional even when the
|
|
172
|
+
other capability is preferred. Missing, reversed, or duplicate block markers refuse
|
|
173
|
+
planning, apply, and uninstall without deleting the ambiguous surrounding text.
|
|
153
174
|
|
|
154
175
|
## Implementation notes
|
|
155
176
|
|
|
@@ -162,11 +183,22 @@ into any existing `permissions` array rather than replacing it.
|
|
|
162
183
|
records snapshots, appended entries, created files, and created path prefixes — never
|
|
163
184
|
full file contents, so other servers' secrets stay out of the state file.
|
|
164
185
|
- Re-applying over a previous init inherits the original snapshots instead of recording
|
|
165
|
-
the installer's own output as the "previous" value.
|
|
186
|
+
the installer's own output as the "previous" value. Pi forced re-inits keep their
|
|
187
|
+
competitor-disable ops even when those servers are already disabled, so orphan
|
|
188
|
+
reverts cannot re-enable a still-excluded competitor.
|
|
166
189
|
- Verify is file-level: after apply it re-reads each written file and asserts every op
|
|
167
190
|
holds (set values in place, appended entries present, rules block present). Higher
|
|
168
191
|
layers would be a plan-time detect concern, and none of the three shipped hosts
|
|
169
192
|
documents a layer above user config, so there is nothing to check there yet.
|
|
193
|
+
- Only a bare `--apply` enables writes; assigning a value such as `--apply=false`
|
|
194
|
+
is a usage error and writes nothing.
|
|
195
|
+
- File verification precedes the install-record commit. A write or verification
|
|
196
|
+
failure restores the pre-apply files and record and checks the restored values.
|
|
197
|
+
`ApplyError.status` is `rolled_back` only after recovery and new-claim cleanup
|
|
198
|
+
succeed. Otherwise it is `recovery_required`, with the original cause and a
|
|
199
|
+
recovery report; new claims remain while file or record recovery is incomplete.
|
|
200
|
+
Obsolete claims are released after commit. If that cleanup fails, the verified
|
|
201
|
+
install and new record are retained and reported explicitly for recovery.
|
|
170
202
|
|
|
171
203
|
## Server-side gap (resolved)
|
|
172
204
|
|
|
@@ -182,3 +214,34 @@ Claude Code, Cursor, Devin, GitHub Copilot, and Cline still have no
|
|
|
182
214
|
host module; their artifacts (from the tier-to-artifact mapping) remain hand-edited
|
|
183
215
|
config until a module lands here. OpenCode's `opencode plugin add` remains available but
|
|
184
216
|
cannot pass options or manage snapshots; `init` supersedes it for tiered installs.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
### Persistence and concurrent operations
|
|
220
|
+
|
|
221
|
+
Install records distinguish absent files from invalid or unreadable files. The
|
|
222
|
+
reader validates version, host/scope identity, tiers, file metadata, and recorded
|
|
223
|
+
operations before an install or uninstall can use undo state. `list` reports a
|
|
224
|
+
bad record instead of silently omitting it. Restore the record from backup or
|
|
225
|
+
repair access before retrying; deleting it can discard the original snapshots.
|
|
226
|
+
|
|
227
|
+
Config and record writes use private temporary files in the target directory,
|
|
228
|
+
verify the temporary contents, flush the file, then rename and flush the directory
|
|
229
|
+
(on POSIX). Existing config permissions and valid symbolic links are preserved;
|
|
230
|
+
records are always mode 0600. A failed write before rename leaves the old file
|
|
231
|
+
intact. This makes each file replacement atomic, not the entire multi-file install.
|
|
232
|
+
The apply rollback remains responsible for caught errors; power-loss recovery is
|
|
233
|
+
not an automatic transaction replay.
|
|
234
|
+
|
|
235
|
+
Apply and uninstall acquire a record operation lock before reading undo state,
|
|
236
|
+
then locks for every config/rules path they may mutate, including orphan reverts.
|
|
237
|
+
Locks follow canonical paths, so another project or symlink alias cannot bypass a
|
|
238
|
+
shared-file lock. A plan whose prior record changed is refused, even if its only
|
|
239
|
+
edits append arrays. Preview generation is read-only and does not reserve locks.
|
|
240
|
+
|
|
241
|
+
Operation locks are directories ending in `.deepseek-web-retrieval.lock`, with
|
|
242
|
+
owner PID and start time inside. Ordinary success or failure releases them. A
|
|
243
|
+
killed process may leave a lock: after confirming no installer is running, inspect
|
|
244
|
+
config, install record, and persistent ownership claims, restore any inconsistent
|
|
245
|
+
state, then remove the reported lock directory and generate a new plan. Locks are
|
|
246
|
+
never stolen based only on age or PID. Persistent `.owner.json` claims remain a
|
|
247
|
+
separate safeguard against two installations owning one shared config.
|
package/docs/hosts.jsonc
CHANGED
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
"npm": "@earendil-works/pi-coding-agent",
|
|
83
83
|
"nativeSearchProvider": false,
|
|
84
84
|
"nativeFetchOverride": false,
|
|
85
|
-
"paths": ["
|
|
85
|
+
"paths": ["extension", "mcp"],
|
|
86
86
|
"status": "supported",
|
|
87
87
|
"control": {
|
|
88
88
|
"search": { "optional": "yes", "preferred": "yes", "forced": "de-facto", "key": "no built-in web tool at 1.3.0 (source-verified)" },
|
|
89
89
|
"fetch": { "optional": "yes", "preferred": "yes", "forced": "de-facto", "key": "no built-in web tool at 1.3.0 (source-verified)" }
|
|
90
90
|
},
|
|
91
|
-
"adapter": "src/
|
|
91
|
+
"adapter": "src/pi",
|
|
92
92
|
"installer": "src/installer/hosts/pi",
|
|
93
93
|
"guide": "docs/agents/pi.md",
|
|
94
94
|
"e2eScenario": "pi"
|
package/docs/integration.md
CHANGED
|
@@ -16,8 +16,8 @@ ship built-in web tools. MCP tools can add equivalent tools, but do not replace
|
|
|
16
16
|
| Native websearch provider | Yes | No | Host plugin API | OpenCode v2 adapter |
|
|
17
17
|
| Native tool / fetch override | No | Yes | Host tool API | OpenCode v2 adapter |
|
|
18
18
|
| Custom tool plugin | Yes | Yes | Host plugin API | Cline CLI/SDK; no adapter yet |
|
|
19
|
-
| Extension API | Yes | Yes | Host extension API | Pi
|
|
20
|
-
| MCP server | Yes | Yes | Host MCP client | Shipped (`src/mcp/`; Pi
|
|
19
|
+
| Extension API | Yes | Yes | Host extension API | Pi adapter (`src/pi/`) |
|
|
20
|
+
| MCP server | Yes | Yes | Host MCP client | Shipped (`src/mcp/`; Pi and Codex guides) |
|
|
21
21
|
| CLI/HTTP wrapper | Yes | Yes | Host can call external tools | Not shipped |
|
|
22
22
|
|
|
23
23
|
MCP is a protocol, not an agent. It is one possible transport for hosts that support MCP
|
|
@@ -34,7 +34,7 @@ Rows are sorted with open-source hosts first, then by host name alphabetically.
|
|
|
34
34
|
| Cline | 0.0.13 | Yes (Apache-2.0) | No | No | MCP server or custom tool plugin | No adapter yet |
|
|
35
35
|
| Codex | 0.163.0 | Yes (Apache-2.0) | No | No | MCP server | Supported |
|
|
36
36
|
| OpenCode | 2.0.32 | Yes (MIT) | Yes | Yes | native websearch provider or native tool/fetch override | Supported |
|
|
37
|
-
| Pi | 1.3.0 | Yes (MIT) | No | No |
|
|
37
|
+
| Pi | 1.3.0 | Yes (MIT) | No | No | extension API or MCP server | Supported |
|
|
38
38
|
| Claude Code | 2.1.303 | No | No | No | MCP server | No adapter yet |
|
|
39
39
|
| Cursor | 2026.10.08 | No | No | No | MCP server | No adapter yet |
|
|
40
40
|
| Devin | 3000.11.92 | No | No | No | MCP server | No adapter yet |
|
|
@@ -78,14 +78,18 @@ the details: built-in web tools and their kill switches, MCP registration, and r
|
|
|
78
78
|
[Cline](research/control-matrix.md#cline).
|
|
79
79
|
- **Devin** — Ships built-in `web_search` and `webfetch` tools. See
|
|
80
80
|
[Devin](research/control-matrix.md#devin).
|
|
81
|
-
- **Pi** — No built-in web tools;
|
|
82
|
-
the
|
|
81
|
+
- **Pi** — No built-in web tools; a TypeScript extension API plus MCP. Supported through
|
|
82
|
+
the native extension adapter (the recommended path), with the MCP server as the fallback;
|
|
83
|
+
see [Pi](agents/pi.md) and [Pi in the per-host reference](research/control-matrix.md#pi).
|
|
83
84
|
|
|
84
85
|
## Roadmap
|
|
85
86
|
|
|
86
|
-
- **MCP server** — shipped in `src/mcp/`
|
|
87
|
-
|
|
87
|
+
- **MCP server** — shipped in `src/mcp/` (the fallback path in the [Pi](agents/pi.md) guide
|
|
88
|
+
and the path in the [Codex](agents/codex.md) guide); the broadest route for hosts that
|
|
89
|
+
support MCP tools. Protocol compatibility across these hosts is researched in
|
|
88
90
|
[mcp-compatibility.md](research/mcp-compatibility.md).
|
|
91
|
+
- **Native extension adapters** — the Pi extension adapter ships in `src/pi/`; a host whose
|
|
92
|
+
extension point can register tools directly gets a native path alongside MCP.
|
|
89
93
|
- **Host-specific guides** — added as requests and testing land; the server itself is
|
|
90
94
|
host-agnostic.
|
|
91
95
|
|
|
@@ -94,8 +98,9 @@ the details: built-in web tools and their kill switches, MCP registration, and r
|
|
|
94
98
|
- OpenCode: [plugin API](https://opencode.ai/v2/docs/build/plugins)
|
|
95
99
|
- Claude Code: [MCP](https://code.claude.com/docs/en/mcp),
|
|
96
100
|
[tools reference](https://code.claude.com/docs/en/tools-reference)
|
|
97
|
-
- Codex: [MCP](https://
|
|
98
|
-
[CLI](https://
|
|
101
|
+
- Codex: [MCP](https://learn.chatgpt.com/docs/extend/mcp),
|
|
102
|
+
[CLI](https://learn.chatgpt.com/docs/codex/cli),
|
|
103
|
+
[config reference](https://learn.chatgpt.com/docs/config-file/config-reference)
|
|
99
104
|
- Cursor: [MCP](https://cursor.com/docs/mcp),
|
|
100
105
|
[CLI changelog](https://cursor.com/docs/cli/changelog)
|
|
101
106
|
- Copilot CLI: [repository](https://github.com/github/copilot-cli),
|