deepseek-web-retrieval 0.5.1 → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/README.md +167 -45
  3. package/dist/cli.js +2303 -1836
  4. package/docs/adr/0002-shared-config-base-layer.md +43 -0
  5. package/docs/agents/codex.md +60 -32
  6. package/docs/agents/opencode-v2.md +69 -39
  7. package/docs/agents/pi.md +60 -31
  8. package/docs/design/config-layering-design.md +180 -0
  9. package/docs/design/installer-design.md +33 -20
  10. package/docs/integration.md +41 -7
  11. package/docs/research/control-matrix.md +17 -4
  12. package/docs/research/mcp-compatibility.md +9 -2
  13. package/docs/research/ori-question-sourcing.md +336 -0
  14. package/docs/research/result-quality-passthrough.md +159 -0
  15. package/docs/research/search-api-defaults.md +18 -2
  16. package/docs/research/search-inline-content.md +244 -0
  17. package/examples/opencode.global.jsonc +3 -2
  18. package/package.json +2 -1
  19. package/src/core/auth.ts +3 -0
  20. package/src/core/client.ts +26 -4
  21. package/src/core/config-file.ts +168 -0
  22. package/src/core/config-summary.ts +82 -0
  23. package/src/core/constants.ts +15 -1
  24. package/src/core/descriptions.ts +6 -2
  25. package/src/core/env.ts +99 -32
  26. package/src/core/format.ts +19 -1
  27. package/src/core/options.ts +22 -2
  28. package/src/core/search.ts +6 -0
  29. package/src/core/types.ts +11 -0
  30. package/src/installer/apply.ts +5 -3
  31. package/src/installer/cli.ts +92 -25
  32. package/src/installer/config-command.ts +116 -0
  33. package/src/installer/hosts/codex.ts +5 -3
  34. package/src/installer/hosts/opencode.ts +9 -5
  35. package/src/installer/hosts/pi.ts +10 -6
  36. package/src/installer/ownership.ts +54 -1
  37. package/src/installer/paths.ts +7 -1
  38. package/src/installer/state.ts +73 -19
  39. package/src/installer/types.ts +12 -0
  40. package/src/mcp/auth.ts +2 -3
  41. package/src/mcp/cli.ts +9 -51
  42. package/src/mcp/serve.ts +60 -0
  43. package/src/mcp/server.ts +7 -2
  44. package/src/opencode/plugin.ts +22 -2
  45. package/src/pi/extension.ts +78 -9
  46. package/src/version.ts +12 -0
@@ -0,0 +1,336 @@
1
+ # Sourcing `ori_question` across hosts
2
+
3
+ This note answers one question: through what channel could each host in the
4
+ [support matrix](../integration.md) supply a value for the DeepSeek Search API's optional
5
+ `ori_question` request parameter — "触发搜索的用户原始问题,1~128 个字符,有助于更好地理解搜索意图" (the
6
+ user's original question that triggered the search;
7
+ [API guide](https://api-docs.deepseek.com/guides/search), parameter table reproduced in
8
+ [search-api-defaults.md](search-api-defaults.md))? Two candidate channels are examined per host:
9
+ **(A)** a model-filled optional tool input parameter (e.g. an optional `original_question` string in
10
+ the tool's input schema), and **(B)** the adapter itself reading the surrounding session/task
11
+ context at tool-call time. At the research baseline the repo never sent the parameter; it is
12
+ now sent on the MCP path (channel A) and the Pi path (A plus B as a blank-input fallback),
13
+ while OpenCode's websearch provider path has no channel at 2.0.32 (below).
14
+
15
+ **Research baseline:** 2026-10-23, using the same version locks as
16
+ [hosts.jsonc](../hosts.jsonc) (baseline 2026-10-19): Cline 0.0.13, Codex 0.163.0
17
+ (rust-v0.163.0, rmcp 3.5.1), OpenCode 2.0.32, Pi 1.3.0, Claude Code 2.1.303, Cursor 2026.10.08,
18
+ Devin 3000.11.92, GitHub Copilot 1.0.98. Claims are cited to primary sources only: the MCP
19
+ specification, host source code at exact git tags, npm tarballs at the locked versions, and
20
+ official docs/changelogs. Where no primary source pins a fact, that is stated rather than guessed.
21
+ Protocol-revision facts per host are inherited from
22
+ [mcp-compatibility.md](mcp-compatibility.md) and not re-derived.
23
+
24
+ ## What the protocol offers
25
+
26
+ MCP never carries conversation context to a server. The facts, per revision:
27
+
28
+ - **`tools/call` params are `name` + `arguments` (+ `_meta`).** The 2025-06-18 schema defines the
29
+ params as `name` (required, string) and `arguments` (optional, free-form object with
30
+ `additionalProperties: {}`) — the concrete `CallToolRequest` does not even enumerate `_meta`
31
+ ([schema.json](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-06-18/schema.json));
32
+ the same shape holds in 2024-11-05 and 2025-11-25
33
+ ([tools pages](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)). 2025-11-25
34
+ adds an optional `task` field (task augmentation) and 2026-07-28 adds `inputResponses` /
35
+ `requestState` for multi round-trip retries plus required per-request `_meta` protocol fields
36
+ ([2026-07-28 tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools),
37
+ [_meta](https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta)) — none of
38
+ these carry user or conversation data.
39
+ - **The spec assigns input validation to servers, not clients.** "Servers **MUST**: Validate all
40
+ tool inputs"; the client-side SHOULDs cover validating *results* and showing inputs to the user —
41
+ no revision obliges (or forbids) a client to validate model arguments against `inputSchema`
42
+ ([security considerations](https://modelcontextprotocol.io/specification/2025-06-18/server/tools),
43
+ all revisions). `inputSchema` is "JSON Schema defining expected parameters", defaulting to the
44
+ 2020-12 dialect from 2025-11-25 on. This makes an optional declared property the spec-sanctioned
45
+ way for a model to convey extra intent.
46
+ - **"MCP has no protocol-level session."** The 2026-07-28 spec says it directly: "a server cannot
47
+ rely on implicit per-connection state to relate one tool call to the next"
48
+ ([Stateful Tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools#stateful-tools)),
49
+ and the statelessness rules forbid inferring context from prior requests
50
+ ([Statelessness](https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness)).
51
+ - **Sampling cannot be abused to obtain the context.** `sampling/createMessage` is
52
+ server-initiated with server-authored `messages`; `includeContext: "thisServer"/"allServers"`
53
+ (soft-deprecated) includes *MCP-server* context, not the host conversation, and requests are
54
+ human-reviewed
55
+ ([sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling)). A server
56
+ could only ask a model to *guess* intent — not obtain the user's question.
57
+ - **Elicititation is interactive, not derivation.** `elicitation/create` asks the user a form/choice
58
+ question and waits ([2025-06-18+](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation));
59
+ it requires client capability (only Codex in this matrix has it, per
60
+ [mcp-compatibility.md](mcp-compatibility.md)) and an explicit round trip.
61
+ - **Tasks are state machines, not context.** The experimental 2025-11-25 `Task` object is
62
+ `taskId`/`status`/timestamps/`ttl`/`pollInterval` — no user data
63
+ ([tasks](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks)).
64
+ - **`_meta` has no context convention.** Reserved keys are enumerated; vendors may add prefixed
65
+ keys, but no host documents sending conversation context there
66
+ ([_meta](https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta)). Codex is the
67
+ one host observed adding its own key — `openai/entitlementContext`, carrying entitlement status
68
+ for zero-argument read-only plugin tools
69
+ ([trusted_access.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/trusted_access.rs))
70
+ — not user context.
71
+
72
+ Conclusion: **for an MCP-connected host, channel A (the tool's input schema) is the only spec-borne
73
+ channel; channel B does not exist at the protocol layer.** Whether A works in practice depends on
74
+ each host's client, below.
75
+
76
+ ## Open-source hosts, from source at the lock
77
+
78
+ ### Codex 0.163.0 (rust-v0.163.0)
79
+
80
+ - **No client-side argument validation.** The model's `arguments` string is parsed as JSON (empty
81
+ allowed; invalid JSON becomes an error result) and the resulting `serde_json::Value` flows
82
+ unchanged to rmcp's `call_tool`
83
+ ([mcp_tool_call.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/core/src/mcp_tool_call.rs),
84
+ [connection_manager.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/connection_manager.rs)).
85
+ No JSON-Schema validator exists in the tree (only `schemars`, used to *generate* schemas for
86
+ built-in tools; codex-rs/Cargo.toml at the tag).
87
+ - **Input schemas reach the model essentially verbatim.** `mcp_tool_to_responses_api_tool` forwards
88
+ the server's `inputSchema` as the tool's `parameters`
89
+ ([responses_api.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/responses_api.rs));
90
+ the only transformations are inserting an empty `properties` object when missing, sanitizing
91
+ boolean schemas, and a default 5,000-byte budget: over-budget schemas are progressively
92
+ compacted (strip descriptions → drop definitions → collapse deep objects → prune compositions)
93
+ ([mcp_tool.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/mcp_tool.rs),
94
+ [json_schema.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/json_schema.rs),
95
+ [compaction.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/json_schema/compaction.rs)).
96
+ A small schema with one optional string property stays intact.
97
+ - **Channel B: none.** Codex's third-party integration surface at this tag is MCP servers; there is
98
+ no session/context API a server can call.
99
+
100
+ Verdict: **A feasible (nothing validates or strips arguments; schema forwarded), B impossible.**
101
+
102
+ ### Pi 1.3.0 (v1.3.0)
103
+
104
+ - **The agent loop validates arguments against the tool's parameter schema before `execute`.**
105
+ `validateToolArguments` clones the arguments, normalizes `null` for optional properties, coerces
106
+ types (`Value.Convert`, plus JSON-Schema coercion for plain JSON-Schema tools), then runs a
107
+ TypeBox `Check`; failures come back to the model as `Validation failed for tool …` error results
108
+ ([validation.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/ai/src/utils/validation.ts),
109
+ [agent-loop.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/agent/src/agent-loop.ts)).
110
+ A *declared optional* property therefore passes and reaches the tool; undeclared fields pass only
111
+ when the schema itself permits them.
112
+ - **MCP tools: schema forwarded, params passed through.** The adapter spreads the server's
113
+ `inputSchema` into the model-facing parameters (adding only `type: "object"` and an empty
114
+ `properties` when missing) and passes the validated `params` to the client's `callTool`, which
115
+ sends `{ name, arguments }` verbatim (a `_meta.progressToken` is added only when progress
116
+ reporting is on)
117
+ ([tools.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/extensions/mcp/tools.ts),
118
+ [client.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/mcp/src/client.ts)).
119
+ - **Extension tools receive session access as a fifth `execute` argument.** At v1.3.0 the signature
120
+ is `execute(toolCallId, params, signal, onUpdate, ctx: ExtensionToolContext)`
121
+ ([types.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/core/extensions/types.ts)).
122
+ `ExtensionToolContext` extends `ExtensionContext`, whose `sessionManager` is a
123
+ `ReadonlySessionManager` exposing `buildSessionProjection()` — returning the model-visible
124
+ `messages: AgentMessage[]` (user messages included), plus `getEntries`/`getTree`/`getBranch`
125
+ ([session-manager.ts](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/core/session-manager.ts)).
126
+ The extension docs at the tag document `ctx` for tools (`ctx.executeTool`, `ctx.sessionManager`)
127
+ ([extensions.md](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/docs/extensions.md)).
128
+ The `ExtensionAPI` event surface (`input`, `message_end`, `tool_execution_*`) additionally lets an
129
+ extension track the user prompt as it arrives.
130
+
131
+ Verdict: **A feasible on both paths (declared optional TypeBox property; validated, then passed
132
+ through). B feasible on the extension path via the fifth `execute` argument — the handler can read
133
+ the session's user messages at call time. B impossible via MCP** (separate process, no session
134
+ API).
135
+
136
+ ### OpenCode 2.0.32
137
+
138
+ Repo provenance first: `@opencode/cli@2.0.32`'s manifest points at
139
+ [github.com/anomalyco/opencode](https://github.com/anomalyco/opencode), which has the `v2.0.32`
140
+ tag (commit `843a6c5`); the `opencode-ai/opencode` repository's tags stop at `v0.0.x` and hold no
141
+ 2.x tag. Facts below are from the tag plus the npm tarballs at 2.0.32
142
+ (`@opencode/plugin`, `@opencode/schema`, `@opencode/client`).
143
+
144
+ - **The tool runtime validates arguments against the tool's declared input schema before
145
+ `execute`.** `Tool.runtime.execute` decodes the model's input first: raw JSON-Schema inputs are
146
+ converted to an Effect codec and validated; failures return `Invalid arguments for tool "…":
147
+ … Update the arguments and call the tool again.`
148
+ ([runtime.ts](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/runtime.ts)).
149
+ A plugin tool's plain JSON Schema `input` is forwarded to the model **as-is** (`inputJsonSchema`
150
+ returns it unchanged), so a declared optional parameter is both model-visible and validated.
151
+ - **`ToolContext` carries IDs only**: `sessionID`, `agent`, `messageID`, call `id`, `signal`,
152
+ `progress` ([tool.d.ts in @opencode/schema 2.0.32](https://registry.npmjs.org/@opencode/schema/2.0.32);
153
+ [tool.d.ts in @opencode/plugin 2.0.32](https://registry.npmjs.org/@opencode/plugin/2.0.32)).
154
+ - **But the plugin `Context.session` domain can read the conversation.** The picked `SessionDomain`
155
+ includes `context({ sessionID }) → SessionMessageInfo[]`, and `SessionMessageUser` has
156
+ `text: string` — the user's prompt text — plus attachments
157
+ ([session.d.ts](https://registry.npmjs.org/@opencode/plugin/2.0.32),
158
+ [client types](https://registry.npmjs.org/@opencode/client/2.0.32)). Session hooks round it out:
159
+ `"prompt"` fires with the prompt itself, `"generate"`/`"context"` with `messages: Array<Message>`
160
+ ([session.d.ts at 2.0.32](https://registry.npmjs.org/@opencode/plugin/2.0.32)). So a tool's
161
+ `execute` can call `ctx.session.context({ sessionID: context.sessionID })` at call time.
162
+ - **The native websearch provider interface carries only the query.**
163
+ `WebSearch.ProviderInput = Pick<Input, "query">`, the provider context is `{ signal }`, and core
164
+ invokes providers as `.execute({ query: input.query })`
165
+ ([websearch.ts](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/websearch.ts),
166
+ [websearch.d.ts](https://registry.npmjs.org/@opencode/schema/2.0.32)). The model-facing
167
+ `websearch` tool's input schema is fixed in host source to `query` alone
168
+ ([tool/plugin/websearch.ts](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/plugin/websearch.ts)).
169
+ A provider gets no sessionID, so session auto-derivation on this path is not directly possible —
170
+ only heuristic correlation via the session hooks (which fire per model request with the
171
+ sessionID, but no API contract binds a provider call to a session).
172
+
173
+ Verdict: **tool path (`deepseek_fetch` / the `webfetch` override): A feasible (validated against
174
+ the declared schema; raw JSON Schema forwarded verbatim) and B feasible
175
+ (`ctx.session.context`). Websearch provider path (the search replacement this repo ships): neither
176
+ — the input schema is host-fixed to `query`, and the provider context has no session handle.**
177
+
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
+ ## Proprietary hosts
191
+
192
+ No proprietary host documents a context channel; the question is whether anything documents
193
+ input-schema handling that would break an optional parameter.
194
+
195
+ - **Claude Code 2.1.303.** The [MCP docs](https://code.claude.com/docs/en/mcp) say nothing about
196
+ input schemas or argument validation. The
197
+ [changelog](https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md) documents
198
+ the mechanics indirectly, all at or before the lock: 2.1.300 — "Fixed a conversation failing on
199
+ every turn with a 400 error when the API rejected an MCP tool's input schema; Claude Code now
200
+ sends that tool without parameters for the rest of the conversation"; 2.1.246 — "Fixed MCP tool
201
+ arguments being sent as JSON strings when the parameter's schema is empty (`{}`)"; 2.1.30 —
202
+ prompt-cache invalidation "when tool descriptions or input schemas changed"; 2.0.50 — "bug
203
+ preventing calling MCP tools that have nested references in their input schemas". Together these
204
+ show the server's `inputSchema` is what the model provider sees and that arguments follow it;
205
+ no host-side validation is ever mentioned. **A feasible by this evidence; B none.**
206
+ - **Cursor 2026.10.08.** The [MCP docs](https://cursor.com/docs/mcp) describe tools only as
207
+ "Functions for the AI model to execute" and say nothing about input schemas, validation, or
208
+ context — and the protocol revision itself is unpinnable from primary sources
209
+ ([mcp-compatibility.md](mcp-compatibility.md)). **No primary source either way for A; B none.**
210
+ - **Devin 3000.11.92.** The [MCP docs](https://docs.devin.ai/cli/extensibility/mcp/overview) and
211
+ [changelog](https://docs.devin.ai/cli/changelog) cover transport, OAuth, permissions, and
212
+ tool-level gating (`disabled_tools`, `mcp__server__tool` patterns) but nothing on input schemas
213
+ or argument validation; the nearest mechanisms (`PostToolUse` hooks, positional prompt arguments)
214
+ are not tool-input channels. **No primary source either way for A; B none.**
215
+ - **GitHub Copilot 1.0.98.** The
216
+ [MCP docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers)
217
+ document per-server `tools` filtering only. The
218
+ [changelog](https://raw.githubusercontent.com/github/copilot-cli/main/changelog.md) shows MCP tool
219
+ schemas are forwarded to model providers verbatim enough that *provider-side* schema validation
220
+ fires, at or before the lock: 1.0.89 — "Gemini models no longer fail every request with 400
221
+ invalid request body when an MCP server exposes a tool whose schema puts a type or properties
222
+ beside anyOf"; 1.0.85 — "MCP tools with boolean property or array-item schemas work with Gemini
223
+ instead of causing a 400 error"; 1.0.61 — "Gemini models work correctly with MCP tools that use
224
+ nullable schema types". No host-side argument validation is mentioned. **A feasible by this
225
+ evidence; B none.**
226
+
227
+ ## Verdicts at a glance
228
+
229
+ | Host | (A) model-filled optional param | (B) session auto-derivation | Load-bearing fact |
230
+ | --- | --- | --- | --- |
231
+ | Codex | Yes | No | No argument validation anywhere in the tool-call path; schema forwarded (compaction only above 5 KB) |
232
+ | Pi | Yes (extension and MCP paths) | Yes — extension path only | 5th `execute` arg exposes `sessionManager.buildSessionProjection()`; MCP path validated against the server's own schema |
233
+ | OpenCode | Yes — tool path; **no** — websearch provider | Yes — tool path; not directly — provider | Runtime validates against the declared schema and forwards raw JSON Schemas verbatim; `ctx.session.context` reads user text; provider input is host-fixed to `query` |
234
+ | Cline | Undeterminable (no primary source) | No | 2024-11-05 client; behavior not documented |
235
+ | Claude Code | Yes (changelog evidence) | No | Input schemas demonstrably reach the model API |
236
+ | Cursor | No primary source | No | Docs silent |
237
+ | Devin | No primary source | No | Docs/changelog silent |
238
+ | Copilot | Yes (changelog evidence) | No | Provider-side 400s driven by MCP schema shapes prove forwarding |
239
+
240
+ For every MCP-only host, channel A is the only candidate; where no primary source pins the
241
+ behavior (Cline, Cursor, Devin), an optional declared parameter is still spec-conformant on every
242
+ negotiated revision in the matrix.
243
+
244
+ ## What this means for this repo
245
+
246
+ - **MCP server (`src/mcp/server.ts`).** The tool `inputSchema` is the only channel any MCP host
247
+ offers. The server declares its inputs as zod objects (`z.object({ query, original_question })`,
248
+ `z.object({ url })`) through SDK v2's `registerTool`; zod's default behavior strips undeclared
249
+ keys server-side, so a host-side pre-filled undeclared field would be dropped — whatever a host
250
+ sends must be *declared* in the schema to arrive in the handler. The declared optional string
251
+ surfaces in the JSON Schema every host in this note forwards (Codex and Pi verbatim-small,
252
+ OpenCode verbatim, Claude Code and Copilot per changelog evidence; Cline, Cursor, Devin
253
+ unproven but spec-conformant) — exactly the channel the shipped `original_question` rides.
254
+ - **OpenCode plugin (`src/opencode/plugin.ts`).** The fetch tools' `execute` receives a
255
+ `ToolContext` with `sessionID`, and the plugin `Context` can read
256
+ `ctx.session.context({ sessionID })` — user messages with their `text` — at call time, so
257
+ channel B exists here without touching schemas. The `websearch` provider replacement — the path
258
+ 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. Note also that
260
+ `FETCH_INPUT` sets `additionalProperties: false`, which matters if a parameter is ever added on
261
+ channel A: an undeclared field would be rejected by OpenCode's runtime validation with a
262
+ retryable error.
263
+ - **Pi extension (`src/pi/extension.ts`).** The search handler reads the fifth `execute`
264
+ argument (`ExtensionToolContext`), whose `sessionManager.buildSessionProjection()` returns the
265
+ model-visible messages, user prompts included — readable synchronously at call time, so channel
266
+ B exists on this path; the shipped adapter uses it as the blank-input fallback. Channel A is
267
+ equally open: the TypeBox `parameters` are what the agent loop validates against, and
268
+ `Type.Optional(Type.String(...))` properties pass validation when the model fills them. The
269
+ extension runs in-process, so B does not pay the MCP detour.
270
+
271
+ ## Sources
272
+
273
+ ### Specification
274
+
275
+ - MCP tools: [2024-11-05](https://modelcontextprotocol.io/specification/2024-11-05/server/tools) ·
276
+ [2025-06-18](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) ·
277
+ [2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) ·
278
+ [2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)
279
+ (Stateful Tools, MRTR retry params, `x-mcp-header`)
280
+ - [2025-06-18 schema.json (CallToolRequest)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-06-18/schema.json)
281
+ - [2025-11-25 sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling) ·
282
+ [2025-11-25 tasks (experimental)](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks)
283
+ - [2026-07-28 overview (`_meta`, statelessness)](https://modelcontextprotocol.io/specification/2026-07-28/basic/index)
284
+
285
+ ### Open-source hosts
286
+
287
+ - Codex: [rust-v0.163.0 tag](https://github.com/openai/codex/tree/rust-v0.163.0) —
288
+ [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),
289
+ [connection_manager.rs (call_tool passthrough)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/connection_manager.rs),
290
+ [responses_api.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/responses_api.rs),
291
+ [mcp_tool.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/mcp_tool.rs),
292
+ [json_schema.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/json_schema.rs),
293
+ [compaction.rs (5 KB default budget)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/tools/src/json_schema/compaction.rs),
294
+ [trusted_access.rs (openai/entitlementContext)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/trusted_access.rs)
295
+ - Pi: [v1.3.0 tag](https://github.com/earendil-works/pi/tree/v1.3.0) —
296
+ [extensions/mcp/tools.ts (toParameters, execute passthrough)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/extensions/mcp/tools.ts),
297
+ [agent-loop.ts (prepare/validate/execute)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/agent/src/agent-loop.ts),
298
+ [validation.ts (validateToolArguments)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/ai/src/utils/validation.ts),
299
+ [mcp/client.ts (callTool)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/mcp/src/client.ts),
300
+ [extensions/types.ts (ToolDefinition.execute 5th arg, ExtensionAPI)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/core/extensions/types.ts),
301
+ [session-manager.ts (ReadonlySessionManager)](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/core/session-manager.ts),
302
+ [extensions.md at the tag](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/docs/extensions.md)
303
+ - OpenCode: [anomalyco/opencode v2.0.32 tag](https://github.com/anomalyco/opencode/tree/v2.0.32)
304
+ (repository URL from
305
+ [@opencode/cli 2.0.32](https://registry.npmjs.org/@opencode/cli/2.0.32)) —
306
+ [tool/runtime.ts (input validation, schema forwarding)](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/runtime.ts),
307
+ [websearch.ts (ProviderInput, execute({query}))](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/websearch.ts),
308
+ [tool/plugin/websearch.ts (fixed query schema)](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/plugin/websearch.ts);
309
+ npm tarballs at 2.0.32:
310
+ [@opencode/plugin](https://registry.npmjs.org/@opencode/plugin/2.0.32)
311
+ (ToolContext, Context, SessionDomain hooks),
312
+ [@opencode/schema](https://registry.npmjs.org/@opencode/schema/2.0.32)
313
+ (Tool.Context, WebSearch.ProviderInput),
314
+ [@opencode/client](https://registry.npmjs.org/@opencode/client/2.0.32)
315
+ (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
+
320
+ ### Proprietary hosts
321
+
322
+ - Claude Code: [changelog](https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md)
323
+ (entries 2.0.50, 2.1.30, 2.1.246, 2.1.300 — all ≤ the 2.1.303 lock),
324
+ [MCP docs](https://code.claude.com/docs/en/mcp)
325
+ - Cursor: [MCP docs](https://cursor.com/docs/mcp) (silent on the question)
326
+ - Devin: [MCP overview](https://docs.devin.ai/cli/extensibility/mcp/overview),
327
+ [changelog](https://docs.devin.ai/cli/changelog) (silent on the question)
328
+ - GitHub Copilot: [changelog](https://raw.githubusercontent.com/github/copilot-cli/main/changelog.md)
329
+ (entries 1.0.61, 1.0.85, 1.0.89 — all ≤ the 1.0.98 lock),
330
+ [MCP docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers)
331
+
332
+ ### DeepSeek API
333
+
334
+ - [Search & Fetch guide](https://api-docs.deepseek.com/guides/search) (`ori_question` optional,
335
+ 1–128 chars; parameter table transcribed in
336
+ [search-api-defaults.md](search-api-defaults.md))
@@ -0,0 +1,159 @@
1
+ # Passing result quality fields to the model
2
+
3
+ This note answers one question: through which channel can DeepSeek's per-result quality fields —
4
+ `rerank_score` (0–3, "≥1.5 优质"), `authority` (0–4, -1 unknown, "≥3 极权威"), `site_name`
5
+ (string|null) — reach the **model** (not the human UI) on each host at its locked version? The
6
+ repo filters on the first two in `src/core/search.ts` (thresholds default to off); at the
7
+ research baseline it dropped all three before returning — the adapters now pass them through
8
+ as a text marker plus a structured mirror (item 1 below is implemented as
9
+ `formatQualityMarker`).
10
+ Related: [ori-question-sourcing.md](ori-question-sourcing.md) (input side),
11
+ [search-inline-content.md](search-inline-content.md) (content volume).
12
+
13
+ **Research baseline:** 2026-10-23, using the same version locks as
14
+ [hosts.jsonc](../hosts.jsonc) (Cline 0.0.13, Codex 0.163.0, OpenCode 2.0.32, Pi 1.3.0,
15
+ Claude Code 2.1.303, Cursor 2026.10.08, Devin 3000.11.92, GitHub Copilot 1.0.98). Claims are
16
+ cited to primary sources: the MCP specification, the official TypeScript SDK as installed in
17
+ this repo (`@modelcontextprotocol/server` 2.3.1 — the shipped artifact), host source at the
18
+ exact tags or as installed in `node_modules` (the published npm packages are themselves primary
19
+ sources), and official docs/changelogs. Prior findings in
20
+ [mcp-compatibility.md](mcp-compatibility.md) and [control-matrix.md](control-matrix.md) are
21
+ cited rather than re-derived; this note re-verified the load-bearing ones and extends them.
22
+
23
+ ## What the specification says
24
+
25
+ MCP [`2025-06-18` tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
26
+ introduced structured output:
27
+
28
+ - Unstructured content rides in `content` (text/image/audio/resource blocks); structured
29
+ content is "a JSON object in the `structuredContent` field."
30
+ - Backwards compatibility is a server-side SHOULD, verbatim: *"For backwards compatibility, a
31
+ tool that returns structured content **SHOULD** also return the serialized JSON in a
32
+ TextContent block."*
33
+ - With a declared `outputSchema`: *"Servers **MUST** provide structured results that conform to
34
+ this schema. Clients **SHOULD** validate structured results against this schema."*
35
+ - Content blocks carry optional `annotations.audience` (`"user"` / `"assistant"`) — a spec-level
36
+ way to mark a block as model-visible or human-visible. No host in the matrix is documented to
37
+ honor it; treated as unpinned below.
38
+
39
+ The `2024-11-05` revision (Cline's floor) has neither `structuredContent` nor `outputSchema`.
40
+
41
+ ## What the official TypeScript SDK enforces (v2.3.1, as shipped in this repo)
42
+
43
+ The server-side validator (`@modelcontextprotocol/server` 2.3.1,
44
+ `dist/mcp-*.mjs`, `validateToolOutput`) makes the outputSchema obligation concrete:
45
+
46
+ - A tool with an `outputSchema` whose result has no `structuredContent` is **rejected**:
47
+ `Output validation error: Tool <name> has an output schema but no structured content was
48
+ provided` (JSON-RPC `InvalidParams`). Text-only results are not allowed for schema'd tools.
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 (`appendTextFallbackForNonObject`) adds a
51
+ `JSON.stringify(structuredContent)` TextContent block **only when `structuredContent` is a
52
+ non-object** (primitive/array/null) and no text block exists. Object-shaped
53
+ `structuredContent` gets **no** automatic text mirror — the server must mirror it itself to
54
+ satisfy the spec's SHOULD.
55
+
56
+ Consequence for this repo: the shipped server declares no `outputSchema` and emits both a text
57
+ summary and (except for Codex, below) a mirrored `structuredContent` — that combination remains
58
+ the spec- and SDK-safe shape. Declaring an `outputSchema` would obligate every successful call
59
+ to return schema-conforming structured content.
60
+
61
+ ## Per host: what actually reaches the model
62
+
63
+ | Host (lock) | Text `content` reaches model | `structuredContent` reaches model | Output caps at the lock |
64
+ | --- | --- | --- | --- |
65
+ | Codex 0.163.0 | Replaced when `structuredContent` present | Yes — content is **replaced** by serialized JSON | Per-tool `output_token_limit` + "standard 20% serialization allowance" ([mcp_types.rs](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/mcp_types.rs)); default value not pinned there |
66
+ | Pi 1.3.0 (MCP path) | Yes (content-first) | Only when no content blocks | 20 KB text middle-truncate, full text saved to file; 60 s per-request ([control-matrix](control-matrix.md#pi)) |
67
+ | Pi 1.3.0 (extension path) | Yes — **the only model channel** | **No** — event-layer only (below) | Extension tools bypass the MCP 20 KB truncation ([control-matrix](control-matrix.md#pi)) |
68
+ | OpenCode 2.0.32 (plugin path) | Yes (content wins) | **No** — serialized `output` is a fallback only (below) | 2000 lines / 50 KiB tool-output truncation, full output retained to file for 7 days |
69
+ | Claude Code 2.1.303 | Yes | Spec-level yes (2026-07-28 + TS SDK 2.0 runtime); client-side rendering not pinned by a primary source | 25k tokens default (`MAX_MCP_OUTPUT_TOKENS`), oversized saved to file ([control-matrix](control-matrix.md#claude-code)) |
70
+ | Cline 0.0.13 | Yes | **No** — `2024-11-05` has no `structuredContent` | None documented |
71
+ | Devin 3000.11.92 / Copilot 1.0.98 | Yes | Spec-level yes (both negotiate 2026-07-28); rendering not pinned | Not pinned |
72
+ | Cursor 2026.10.08 | Yes | Revision unpinnable (docs show ≥2025-06-18 features, so the field exists); rendering not pinned | Not pinned |
73
+
74
+ Codex's replacement behavior and Cline's text-only floor were established at these locks in
75
+ [mcp-compatibility.md](mcp-compatibility.md#what-each-host-supports) and re-checked; the two
76
+ native-adapter findings below are new.
77
+
78
+ ### Pi 1.3.0: the extension `structuredContent` never reaches the model
79
+
80
+ From the installed `@earendil-works/pi-coding-agent` 1.3.0 (the shipped artifact):
81
+
82
+ - An extension tool's `execute` returns `{ content, structuredContent?, details? }`. The
83
+ `structuredContent` field exists only on the extension **event** layer, documented as
84
+ *"Machine-readable result for tools that declare an `outputSchema`"*
85
+ (`dist/core/extensions/types.d.ts`, `ToolResultEventBase`) — consumers are other extensions
86
+ (hooks, nested tool calls), not the model.
87
+ - The model-facing message type (`@earendil-works/pi-ai` `ToolResultMessage`,
88
+ `dist/types.d.ts`) carries `content` blocks, `isError`, ids — no `structuredContent`, and
89
+ `details` is session-record only. The Anthropic serializer sends exactly
90
+ `tool_use_id` + content blocks + `is_error`
91
+ (`dist/api/anthropic-messages.js`, `convertToolResult`).
92
+ - So this repo's Pi adapter already does the right thing by putting the full result in the text
93
+ block; its `structuredContent` payload is event-layer data for machine consumers.
94
+
95
+ ### OpenCode 2.0.32: text `content` wins; typed `output` is a JSON-stringified fallback; `metadata` is not model-facing
96
+
97
+ From the official repo at tag `v2.0.32` (github.com/anomalyco/opencode, where `@opencode/cli`
98
+ 2.0.32's npm manifest points) and the installed `@opencode/schema`/`@opencode/plugin`:
99
+
100
+ - `Tool.Result` is `{ output?, content?, metadata? }` — `output` typed by an optional declared
101
+ output schema, `content` a string or text/file blocks, `metadata` a free record
102
+ (`@opencode/schema/dist/tool.d.ts`).
103
+ - The model channel is decided by
104
+ [`normalizeContent(content, output)`](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/runtime.ts):
105
+ a string or non-empty `content` wins; only when `content` is absent/empty is `output`
106
+ serialized via `JSON.stringify` into a text block. `metadata` never enters this path (it
107
+ feeds `tool.execute.after` hooks and UI).
108
+ - Every tool result then passes through `ToolOutput.truncate`:
109
+ **`MAX_LINES = 2000`, `MAX_BYTES = 50 KiB`** (full output retained to a `tool-output/`
110
+ 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 were not previously recorded in [control-matrix.md](control-matrix.md).
112
+
113
+ ## What this means for this repo
114
+
115
+ 1. **Text is the only channel verified to reach the model on every host.** Codex is the sole
116
+ host where `structuredContent` demonstrably reaches the model (as a *replacement*); on the
117
+ two native adapters it provably does not (Pi: event-layer only; OpenCode: fallback only).
118
+ Quality fields the model should reason about therefore belong **in the text** — e.g. a
119
+ compact per-result marker like `[rerank 2.1 · authority 3]` (plus `site_name` where present).
120
+ At 10 results that is a few hundred characters, negligible against every cap above.
121
+ 2. **Mirroring in `structuredContent` stays worth it** for machine consumers (Pi extension
122
+ events, future hosts, tests) and costs nothing: the shipped dual-emission — text plus
123
+ structured, with the mirror omitted for the detected `codex-mcp-client` identity — already
124
+ matches the spec's SHOULD and Codex's replacement. Adding the new fields to both shapes
125
+ changes no host behavior.
126
+ 3. **Keep `outputSchema` undeclared** on the MCP server unless the team is prepared to guarantee
127
+ schema-conforming `structuredContent` on every successful call (the SDK rejects otherwise).
128
+ The Pi adapter's extension `outputSchema` is safe as-is — Pi re-declares but does not
129
+ validate it, and its `structuredContent` is event data.
130
+ 4. **New cap facts for the design margin:** OpenCode plugin results truncate at 2000 lines /
131
+ 50 KiB (new), Pi extension tools bypass the MCP 20 KB truncation (already known), Claude
132
+ Code 25k tokens, Codex per-tool `output_token_limit` (default unpublished). None of these
133
+ bind at search-result volumes; they matter if [inline content](search-inline-content.md) is
134
+ ever enabled.
135
+
136
+ ## Sources
137
+
138
+ - MCP spec: [2025-06-18 tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
139
+ (structured content, outputSchema MUST/SHOULD, audience annotations); revision table in
140
+ [mcp-compatibility.md](mcp-compatibility.md#protocol-revisions).
141
+ - Official TypeScript SDK, **as installed** (`@modelcontextprotocol/server` 2.3.1,
142
+ `@modelcontextprotocol/client` 2.3.1): `dist/mcp-*.mjs` `validateToolOutput` /
143
+ `validateToolInput`; `dist/src-*.mjs` `appendTextFallbackForNonObject` /
144
+ `projectCallToolResult` (SEP-2106 §4.3).
145
+ - Pi, **as installed** (`@earendil-works/pi-coding-agent` 1.3.0, `@earendil-works/pi-ai`):
146
+ `dist/core/extensions/types.d.ts` (`ToolResultEventBase.structuredContent` doc,
147
+ `ToolDefinition.outputSchema`), `pi-ai/dist/types.d.ts` (`ToolResultMessage`),
148
+ `pi-ai/dist/api/anthropic-messages.js` (`convertToolResult`, `convertMessages`).
149
+ - OpenCode at the lock: [`v2.0.32` tool/runtime.ts (`normalizeContent`)](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool/runtime.ts),
150
+ [`v2.0.32` tool-output.ts (MAX_LINES/MAX_BYTES)](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool-output.ts),
151
+ [`v2.0.32` core/src/tool.ts (execute.after result shape)](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool.ts),
152
+ installed `@opencode/schema/dist/tool.d.ts` and `@opencode/plugin/dist/promise/tool.d.ts`.
153
+ - Codex: [`mcp_types.rs` at rust-v0.163.0 (`output_token_limit`, 20% serialization allowance)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/mcp_types.rs);
154
+ replacement behavior per [mcp-compatibility.md](mcp-compatibility.md#what-each-host-supports).
155
+ - Host caps and protocol facts previously verified at these locks:
156
+ [control-matrix.md](control-matrix.md#per-host-reference) (Pi 20 KB / 60 s, Claude Code
157
+ `MAX_MCP_OUTPUT_TOKENS` 25k, Cline text-only floor),
158
+ [mcp-compatibility.md](mcp-compatibility.md) (per-host negotiated revisions; Cursor
159
+ unpinnable).
@@ -255,9 +255,25 @@ quality filtering**. What they do publish, verbatim
255
255
  - `rerank_score`: "排序分数,0~3 分,综合考虑相关性、权威性、时效性等维度,**大于等于 1.5 分为优质结果**。"
256
256
  - `authority`: "网页权威性,0~4(**-1 表示未知**),**大于等于 3 为极权威结果**。"
257
257
  - Request defaults: `count` "否 / 默认值 10 / 返回条数,1~50"; `need_content` "否 / false";
258
- `localization` "否 / 空"; `ori_question` optional.
258
+ `ori_question` optional ("触发搜索的用户原始问题,1~128 个字符").
259
+ - `localization` (checked 2026-10-23): documented as "用于优先返回本地化搜索结果的 IP
260
+ 地址" — an IP address used to prefer geo-localized results, optional, default empty. The
261
+ docs pin nothing beyond "IP 地址"; this repo accepts exactly what `net.isIP` validates
262
+ (IPv4 or IPv6) and drops anything else at option resolution.
263
+ - Query operators (checked 2026-10-23): the `query` "会原样传递给搜索服务" and supports
264
+ `site:` / `-site:` / `lang:` (e.g. `lang:zh,en`) plus the time filters `after:` ("将结果限制在指定日期之后发布的网页")
265
+ and `before:` ("将结果限制在指定日期之前发布的网页") — each taking a year or a date, with the
266
+ doc examples "DeepSeek after:2025 或 DeepSeek after:2025-01-01" and
267
+ "DeepSeek before:2026 或 DeepSeek before:2026-06-01".
259
268
  - Response sizing: `snippet` "短摘要 … 通常为 100~200 字符"; `summary` "长摘要 … 通常为 600~800 字符".
260
269
 
270
+ Two follow-up notes examine the request parameters this section lists only as defaults:
271
+ [search-inline-content.md](search-inline-content.md) covers `need_content: true` — what
272
+ provably returns, what it costs, how large it can get, and where that collides with
273
+ per-host output caps — and [ori-question-sourcing.md](ori-question-sourcing.md) covers
274
+ `ori_question` — the per-host channels that could supply a value (the MCP and Pi adapters
275
+ now send it; OpenCode's websearch provider path has no input channel at its lock).
276
+
261
277
  ## What this means for this repo's defaults
262
278
 
263
279
  Fact-by-fact alignment of the repo's client-side defaults
@@ -268,7 +284,7 @@ here; the table only lines up what the industry ships.
268
284
  | --- | --- |
269
285
  | API `count=10`, client `maxResults=10` (post-dedup cap; `5` before 2026-10-21) | API-level count defaults: Tavily 10, Exa 10, Perplexity Search API 10, Firecrawl 10, You.com 10 (per section), Brave 20. Post-filter caps are uncommon; a fixed 5 exists at Jina (`s.jina.ai` top 5, not configurable) and Perplexity's `image_search` tool (default 5). Linkup's schema example is 5 but no default is published. OpenAI and Anthropic expose no count at all |
270
286
  | `minRerank=0`, `minAuthority=0`, `allowUnknownAuthority=true` — no client-side filtering (previously `1.5`/`2`/`false`) | **No surveyed product filters search results client-side by relevance score or authority.** The only published thresholds for DeepSeek's own fields are the docs' quality labels (≥1.5 "优质", ≥3 "极权威") — labels, not filters. The closest shipped analogues are domain allow/block lists (Tavily, Exa, Perplexity, You.com, Anthropic, Brave) and You.com's `safesearch: moderate` default, which is content moderation, not authority |
271
- | `maxRetries=0` | Official model-API SDKs: OpenAI 2, Anthropic 2 (both languages). Search-API SDKs: firecrawl-js 3 (502 only), tavily-python 0, Linkup SDK 0 |
287
+ | `maxRetries=2` — changed from `0` on 2026-10-23: this package runs as an agent tool, where a transient failure left un-retried falls to the model re-issuing the whole billed tool call, the failure profile of the model-API SDKs in this row (2, both languages) rather than of the split search-API SDKs; the default followed the model-SDK column | Official model-API SDKs: OpenAI 2, Anthropic 2 (both languages). Search-API SDKs: firecrawl-js 3 (502 only), tavily-python 0, Linkup SDK 0 |
272
288
  | `timeout=30s` (search and fetch, 1–120 s range, covers body read) | Search/scrape API timeouts: Firecrawl 60 s (scrape max 300 s), Tavily SDK search 60 s (cap 120 s) / extract 30 s, You.com `crawl_timeout` 10 s, Linkup SDK no timeout, Jina `x-timeout` unset by default (max 180 s). Model-API SDKs: OpenAI and Anthropic 10 minutes |
273
289
  | Fetch truncation 16,000 chars | Exa: page text **off** by default (`contents.text: false`), opt-in `maxCharacters` with no published default; DeepSeek itself: `need_content: false` by default; Anthropic `web_fetch`: token-based `max_content_tokens`, no published default (example 100000), no char/MiB figure in current docs; You.com highlights budget 8192 tokens; Firecrawl and Jina publish no truncation default |
274
290
  | Summary truncation 1,200 chars | DeepSeek's own field doc says `summary` is "通常为 600~800 字符"; no surveyed vendor ships a client-side summary cap (they return snippets/highlights sized server-side: Exa verbosity `compact`, You.com highlights budget) |