F5: web search/fetch on the Kimi services (kimi-cli parity)

web_search now speaks the Kimi search service (kimi-cli tools/web/search.py,
wire-verified against api.kimi.com):
- POST {coding_base}/search with {text_query, limit 1-20 (default 5),
  enable_page_crawling, timeout_seconds: 30}, OAuth bearer +
  X-Msh-Tool-Call-Id; results render in kimi-cli's Title/Date/URL/Summary
  schema with result URLs as citations.
- The old implementation called the xAI Responses API with a search model;
  that client is fully replaced and the entire model-based config surface
  is excised root-and-branch: web_search_model config keys/env/CLI plumbing,
  resolve_web_search_sampling_config, toolset web_search SamplerConfig,
  RemoteSettings.web_search_model, default_web_search_model.
- Enablement is now purely structural: the service exists only on the Kimi
  Code subscription channel, so OAuth sessions get Enabled and API-key-only
  sessions get Disabled (tool absent) — per PRD F5.

web_fetch gains the Kimi fetch service as its primary path (kimi-cli
tools/web/fetch.py): POST {coding_base}/fetch with {url}, Accept:
text/markdown, OAuth bearer + X-Msh-Tool-Call-Id; the 200 body is the
extracted markdown (still overflow-budgeted). Any service failure falls
back to the existing local pipeline (SSRF guards, cache, extraction).
The tool gate defaults ON now (kimi-cli always offers FetchURL) and the
egress User-Agent no longer claims grok-agent/x.ai.

Verified end-to-end against the scripted mock service: a headless session
drove web_search (limit/crawling/call-id observed on the wire) then
web_fetch (Accept + call-id observed) to completion.
This commit is contained in:
2026-07-17 19:33:19 -04:00
parent 78cd94a751
commit 74b210535e
34 changed files with 659 additions and 1209 deletions
@@ -32,7 +32,6 @@ auto_update = true # check for updates on launch
[models]
default = "grok-build" # model used for new sessions
web_search = "grok-4.20-multi-agent" # model used by the web_search tool
# Defaults applied to every model; a per-model [model.<id>] value always wins.
# See "Custom Models" for the per-model overrides and full details.
@@ -277,34 +277,6 @@ When you set `models_base_url`, Grok uses API key auth (`Authorization: Bearer`)
---
## Web Search Model
The `web_search` tool uses a separate model. Configure it with:
```toml
[models]
web_search = "grok-4.20-multi-agent"
```
Or via environment variable:
```bash
export KIGI_WEB_SEARCH_MODEL="grok-4.20-multi-agent"
```
If you point web search at a custom model, you also need a `[model.*]` entry so Grok can reach it. Server-side ("backend") web search runs only when the model sets `supports_backend_search = true` (and the build enables backend search); it does not depend on `api_backend`:
```toml
[models]
web_search = "my-custom-model"
[model.my-custom-model]
model = "my-custom-model"
supports_backend_search = true
```
---
## Using Custom Models
```bash
-1
View File
@@ -159,7 +159,6 @@ pub async fn connect(cancel: &CancellationToken, flags: ConnectFlags) -> Result<
cwd: None,
is_headless: false,
cli_subagents: Some(flags.subagents),
cli_web_search_model: None,
cli_session_summary_model: None,
cli_experimental_memory: flags.experimental_memory,
cli_no_memory: flags.no_memory,
@@ -1730,9 +1730,9 @@ pub(in crate::app::dispatch) fn clear_fork_secondary_model(app: &mut AppView) ->
}]
}
// `web_search_model`, `session_summary_model`, and
// `default_reasoning_effort` setters were removed alongside their
// registry entries. Mirror fields and TOML schema stay for compat.
// `session_summary_model` and `default_reasoning_effort` setters were
// removed alongside their registry entries. Mirror fields and TOML
// schema stay for compat.
// ---------------------------------------------------------------------------
// max_thoughts_width — Int-valued setting. Registry surface is `i64`;
@@ -5668,9 +5668,8 @@ mod tests {
"plan_mode",
// SHELL-owned default_model (Models category).
"default_model",
// Models category. `default_reasoning_effort`,
// `web_search_model`, and `session_summary_model` are
// not exposed in the modal.
// Models category. `default_reasoning_effort` and
// `session_summary_model` are not exposed in the modal.
"fork_secondary_model",
// `auto_compact_threshold_percent` (Session category) is
// not exposed in the modal.