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.
- package/CHANGELOG.md +21 -1
- package/README.md +167 -45
- package/dist/cli.js +2303 -1836
- package/docs/adr/0002-shared-config-base-layer.md +43 -0
- package/docs/agents/codex.md +60 -32
- package/docs/agents/opencode-v2.md +69 -39
- package/docs/agents/pi.md +60 -31
- package/docs/design/config-layering-design.md +180 -0
- package/docs/design/installer-design.md +33 -20
- package/docs/integration.md +41 -7
- package/docs/research/control-matrix.md +17 -4
- package/docs/research/mcp-compatibility.md +9 -2
- package/docs/research/ori-question-sourcing.md +336 -0
- package/docs/research/result-quality-passthrough.md +159 -0
- package/docs/research/search-api-defaults.md +18 -2
- package/docs/research/search-inline-content.md +244 -0
- package/examples/opencode.global.jsonc +3 -2
- package/package.json +2 -1
- package/src/core/auth.ts +3 -0
- package/src/core/client.ts +26 -4
- package/src/core/config-file.ts +168 -0
- package/src/core/config-summary.ts +82 -0
- package/src/core/constants.ts +15 -1
- package/src/core/descriptions.ts +6 -2
- package/src/core/env.ts +99 -32
- package/src/core/format.ts +19 -1
- package/src/core/options.ts +22 -2
- package/src/core/search.ts +6 -0
- package/src/core/types.ts +11 -0
- package/src/installer/apply.ts +5 -3
- package/src/installer/cli.ts +92 -25
- package/src/installer/config-command.ts +116 -0
- package/src/installer/hosts/codex.ts +5 -3
- package/src/installer/hosts/opencode.ts +9 -5
- package/src/installer/hosts/pi.ts +10 -6
- package/src/installer/ownership.ts +54 -1
- package/src/installer/paths.ts +7 -1
- package/src/installer/state.ts +73 -19
- package/src/installer/types.ts +12 -0
- package/src/mcp/auth.ts +2 -3
- package/src/mcp/cli.ts +9 -51
- package/src/mcp/serve.ts +60 -0
- package/src/mcp/server.ts +7 -2
- package/src/opencode/plugin.ts +22 -2
- package/src/pi/extension.ts +78 -9
- 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
|
-
`
|
|
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) |
|