#15117: feat: add Kimi (Moonshot AI) as web_search provider
agents
stale
size: M
Cluster:
Web Search Provider Enhancements
## Summary
Adds **Kimi** (by [Moonshot AI](https://platform.moonshot.ai/)) as a fourth `web_search` provider, alongside Brave, Perplexity, and Grok.
Kimi's API includes a **native built-in `$web_search` tool** — the model performs real-time web searches server-side and synthesizes answers with citations, similar to how the Grok provider works. This means users who already have a Kimi/Moonshot API key get web search for free, without needing a separate Brave Search API key.
## How it works
Kimi's `$web_search` uses a **two-turn conversation flow** (unlike Grok's single-shot):
1. **Turn 1**: Send the query with `tools: [{type: "builtin_function", function: {name: "$web_search"}}]`
- Kimi performs the search server-side and returns `finish_reason: "tool_calls"` with a `search_id`
2. **Turn 2**: Echo back the assistant message (with `reasoning_content` — required by Kimi's reasoning mode) and the tool result
- Kimi synthesizes a final answer from the search results and returns `content` with citations
If Kimi answers directly without searching (e.g., for simple queries), the implementation handles that too — it checks `finish_reason` and returns immediately.
### API compatibility note
Kimi has two API endpoints:
- `https://api.moonshot.cn/v1` — Standard Moonshot API (uses `MOONSHOT_API_KEY`)
- `https://api.kimi.com/coding/v1` — Kimi for Coding API (uses `KIMI_API_KEY` / `sk-kimi-*` keys)
Both support `$web_search`. The default `baseUrl` is `api.moonshot.cn/v1`, but users with Kimi for Coding keys can override via `tools.web.search.kimi.baseUrl`.
## Configuration
```json5
{
tools: {
web: {
search: {
provider: "kimi",
kimi: {
apiKey: "your-kimi-or-moonshot-api-key", // or set KIMI_API_KEY / MOONSHOT_API_KEY env
baseUrl: "https://api.moonshot.cn/v1", // optional, default shown
model: "moonshot-v1-128k", // optional, default shown
},
},
},
},
}
```
Environment variable fallback chain: config `apiKey` → `KIMI_API_KEY` → `MOONSHOT_API_KEY`
## Changes
- **`src/config/types.tools.ts`** — Added `"kimi"` to the provider union type and `kimi` config block
- **`src/agents/tools/web-search.ts`** — Full provider implementation following existing patterns:
- `resolveKimiConfig`, `resolveKimiApiKey`, `resolveKimiModel`, `resolveKimiBaseUrl`
- `runKimiSearch` with two-turn `$web_search` flow
- Cache key, description, API key resolution, and dispatch integrated into `createWebSearchTool`
- **`src/agents/tools/web-search.test.ts`** — 9 new tests for config resolution (API key fallback chain, model defaults, baseUrl defaults)
## Test plan
- [x] All 34 unit tests pass (`pnpm vitest run src/agents/tools/web-search.test.ts`)
- [x] TypeScript compiles with zero errors (`tsc --noEmit`)
- [x] Lint passes (`oxlint --type-aware`)
- [x] Live-tested against Kimi API — confirmed two-turn $web_search flow produces real search results
- [ ] Verify with `provider: "kimi"` in a running Gateway session
## AI-assisted PR
- Built with Claude Opus 4.6
- Fully tested (unit + live API integration)
- Author understands the code and verified the implementation against Kimi's API behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a new `web_search` provider (`kimi`) alongside Brave, Perplexity, and Grok by extending the provider union/config types and wiring a new `runKimiSearch` implementation into `createWebSearchTool` dispatch.
Implementation-wise, Kimi is modeled as a 2-turn tool-calling flow against a `/chat/completions` endpoint using a builtin `$web_search` tool, with config resolution for apiKey/model/baseUrl and caching integrated into the existing web-search cache.
<h3>Confidence Score: 3/5</h3>
- This PR is close to mergeable, but the Kimi 2-turn tool-calling flow likely won’t work as implemented.
- Most changes are additive and follow existing patterns (provider selection, config typing, cache integration, unit tests for config resolution). However, the Kimi second-turn request appears to send tool-call arguments instead of tool results, which would break the intended web-search synthesis behavior.
- src/agents/tools/web-search.ts
<sub>Last reviewed commit: f2e5652</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#6960: feat: Add kimi-coding provider support
by YYW0228 · 2026-02-02
80.9%
#13386: feat(web-search): add Nimble Web Search API provider
by ilchemla · 2026-02-10
77.7%
#13370: Tools: rewrite Grok parser, add Tavily provider, multi-provider con...
by a-anand-91119 · 2026-02-10
75.5%
#21911: Enable `reasoning: true` for Kimi models
by ighostych · 2026-02-20
74.8%
#13075: [Feature]: Add Gemini (Google Search grounding) as web_search provider
by akoscz · 2026-02-10
74.3%
#17632: feat(web-search): add per-call provider override
by cog-bernthiddema · 2026-02-16
73.9%
#13814: feat(web-search): add ZAI Search (zsearch) provider
by strelov1 · 2026-02-11
73.6%
#22505: Feature/clean grok search base url
by vacuityv · 2026-02-21
73.2%
#8715: fix(web-search): safer provider resolution & Perplexity auto-detection
by abhijeet117 · 2026-02-04
72.8%
#4459: fix: enable image input for Kimi K2.5 and refresh stale config mode...
by manikv12 · 2026-01-30
72.8%