feat(web): add Moonshot and Kimi native search - #5686
Conversation
Signed-off-by: hexin <372726039@qq.com>
Signed-off-by: hexin <372726039@qq.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Rebased this PR onto current
Verification on the rebased head: Rebased head (original authors and Signed-off-by preserved): Blocker for updating this PR's head: the branch lives in the Pinvou fork and the Hmbown/hunterbown credentials on this machine have |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abb9978056
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| matches!( | ||
| inner.api_provider, | ||
| ApiProvider::Openai | ApiProvider::Anthropic | ApiProvider::Xai | ||
| ApiProvider::Openai | ApiProvider::Anthropic | ApiProvider::Xai | ApiProvider::Moonshot |
There was a problem hiding this comment.
Route Moonshot domain filters to the configured fallback
When web_search includes any domains on a newly enabled Moonshot/Kimi route, this provider falls through maximum_domain_count() to Some(0); ProviderNativeSearchBackend::search converts that into InvalidInput, and run_backend_chain treats that error as fail-closed, so the configured or DuckDuckGo fallback is never attempted. Every domain-constrained search on these routes therefore fails instead of preserving the constraint through fallback.
Useful? React with 👍 / 👎.
| fn is_kimi_code_route(base_url: &str) -> bool { | ||
| base_url | ||
| .trim() | ||
| .trim_end_matches('/') | ||
| .eq_ignore_ascii_case(DEFAULT_KIMI_CODE_BASE_URL) |
There was a problem hiding this comment.
Reuse the path-sensitive Kimi Code route classifier
When a configured endpoint differs only in path casing, such as https://api.kimi.com/Coding/v1, this case-insensitive comparison classifies it as the official membership route and sends /search to that neighboring path. URL paths are case-sensitive, and the existing codewhale_config::provider::is_exact_kimi_code_route deliberately accepts case-insensitive scheme/host but requires the exact coding/v1 path; reuse that predicate here and in capability resolution so custom paths remain fail-closed.
AGENTS.md reference: AGENTS.md:L11-L14
Useful? React with 👍 / 👎.
| .eq_ignore_ascii_case(MOONSHOT_KIMI_K3_MODEL) | ||
| { | ||
| search_formula(client, request).await |
There was a problem hiding this comment.
Reserve the K3 Formula stage's provider timeout
When the new kimi-k3 route takes the Formula path, its discovery/chat/fiber sequence runs under the generic search-chain slice: web_search defaults to 15 seconds, caps callers at 60 seconds, and run_backend_chain divides that time among all configured fallbacks. Thus K3 normally receives only about 5 seconds and can never receive its required 180-second native-stage budget, so otherwise valid Formula searches are cancelled before completion; reserve the provider stage independently and leave the caller-requested timeout available for configured/local fallback.
Useful? React with 👍 / 👎.
| let end = tail | ||
| .char_indices() | ||
| .find_map(|(index, ch)| { | ||
| (index > 0 | ||
| && (ch.is_whitespace() | ||
| || matches!(ch, ')' | ']' | '}' | '>' | '"' | '\'' | '`'))) | ||
| .then_some(index) |
There was a problem hiding this comment.
Preserve balanced parentheses in extracted citation URLs
When a K2.6 or K3 final answer cites a valid URL containing parentheses, such as https://en.wikipedia.org/wiki/Foo_(bar), this scanner treats the first ) as an unconditional delimiter and records https://en.wikipedia.org/wiki/Foo_(bar instead. The malformed-but-still-parseable URL survives citation registration and is returned to the user as a broken source, so extraction needs to distinguish balanced URL parentheses from the closing delimiter of a Markdown link.
Useful? React with 👍 / 👎.
The contribution gate leaves an unlisted contributor's workflow runs at `action_required`, so their CI never starts and the PR sits looking stalled through no fault of theirs. whp233's #5714 and #5716 had SEVEN workflows each parked that way; I approved those runs by hand, but the allowlist is the actual fix. Added (all five have landed or open work): whp233 open PRs #5714, #5716 — the runs that were parked musichen merged #5689 (DeepSeek configured-view picker) M-Maciej merged #5591 (goal continuation cadence) serephus merged #5669 (nixpkgs update) Pinvou fork owner behind #5686 (Moonshot/Kimi native search) Entries use `all:` to match the existing convention for active contributors. No-Issue: contribution-gate hygiene; no issue tracks it Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Every rule here is something that actually went wrong on the 2026-08-29 night shift, written down so the next agent does not rediscover it. Landing other people's work: - A contributor's branch goes stale because WE land things. #5686 was CONFLICTING purely from Route Contract Phase 1 plus that same contributor's own earlier PRs merging into the same files. A maintainer resolves that. - Conflicts that split mid-function do not resolve by keeping both sides — the markers landed inside two function bodies and the naive resolution failed to compile with 'unclosed delimiter'. Take one side whole, re-insert the other's additions at their anchor. - maintainerCanModify did not grant push access to the fork (403), so the resolved merge went to integration/moonshot-kimi-5686-20260829 instead. That integration-branch path is now the documented default for conflicted work. - whp233's #5714 and #5716 each had SEVEN workflows parked at action_required because the author was not on .github/APPROVED_CONTRIBUTORS. The PRs looked stalled; nobody had looked. Five contributors have since been added. - Credit is mechanical: AUTHOR_MAP and .mailmap are project conventions and GitHub reads neither for the contribution graph. Merging under a gate: - #5698 merged while ACCEPTANCE_MATRIX.md still said FAIL and 37 minutes after a review confirming five findings were unchanged. Five real bugs reached main. A gate is its artifact, and check rollups are not the review thread. Claiming a test passed: - cargo test with a non-matching filter exits 0 having run ZERO tests; that was briefly mistaken for a pass here. - A harness scored 72 PASS of which 12 were never evaluated: 'ok = ok and X or True' parses as '(ok and X) or True'. CLAUDE.md already imports this file, so no second entrypoint was created. No-Issue: process documentation from the night shift Signed-off-by: CodeWhale Bot <bot@codewhale.net>
feat(web): Moonshot and Kimi native search (rescue of #5686, review findings fixed)
… native search Rescue merge of abb9978 (Pinvou feat/moonshot-kimi-provider-native-search, PR Hmbown#5686) onto current main (142 ahead). Contributor head preserved verbatim as the second parent; conflicts resolved following the landed native-search adapter pattern (Hmbown#5682/Hmbown#5683/Hmbown#5690/Hmbown#5691/Hmbown#5693): main's Mimo/Zai/ModelStudio/ DeepSeek adapters and the post-fallback domain-constraint/budget plumbing stay, the Kimi module + Moonshot dispatch and capability wiring join them. Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…losed Moonshot/Kimi (and the other contracts without a domain filter field) report maximum_domain_count() == Some(0), so a domain-filtered query hit the shared InvalidInput branch and killed the whole backend chain instead of reaching the configured provider or DuckDuckGo. Decline with NotAvailable for that case so the chain falls back; keep InvalidInput for genuinely over-limit counts on providers that do honor domains (Hmbown#5686 review). Signed-off-by: CodeWhale Bot <bot@codewhale.net>
The local case-insensitive whole-URL comparison let differently-cased paths (https://API.KIMI.COM/CODING/V1) inherit the official membership /search service. Reuse config's exact matcher (scheme/authority case-insensitive, path exact) for both the kimi.rs dispatch and the capability gate, matching the is_exact_kimi_code_route discipline everywhere else (Hmbown#5686 review). Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Wikipedia-style URLs such as .../wiki/Foo_(bar) lost their balanced closing paren to the terminator scan. Track paren depth while scanning so balanced pairs stay part of the URL and an unmatched closer still ends it (Hmbown#5686 review). Signed-off-by: CodeWhale Bot <bot@codewhale.net>
|
Merged — thank you @h3c-hexin. Your Moonshot/Kimi native search landed on Your two commits are in
On top of them #5720 resolved the conflict with current With this slice the #5681 umbrella is complete. Much appreciated — the K3 Formula tool/fiber mock in particular made this straightforward to verify. |
Summary
$web_search, and Kimi Code membership/search.Refs #5681 (partial).
No-Issue: partial delivery tracked by #5681; this slice must not close the umbrella issue.
Depends on #5682 for the exact K3 180-second native-stage budget and independent configured/local fallback timeout.
Testing
cargo fmt --all -- --checkcargo test -p codewhale-config moonshot_native_search_requires_exact_product_model_pair -- --nocapturecargo test -p codewhale-config moonshot_route_fact_is_exact_to_product_and_model -- --nocapturecargo test -p codewhale-tui client::provider_native_search::kimi::tests -- --nocapture— 4 passedcargo test -p codewhale-tui client::provider_native_search::tests -- --nocapture— 7 passedcargo check -p codewhale-config -p codewhale-tuigit diff --checkThe K3 HTTP mock covers authenticated tool discovery, a chat tool call with
max_completion_tokens: 4096, fiber execution, encrypted-result replay, and final citation extraction.Safety boundary
Honesty boundary
This exact upstream commit was verified with deterministic mocks, not a new funded live Moonshot request. The earlier downstream implementation completed a live Kimi Code provider-native search, but that is not presented as verification of this commit or of K3 Formula. No credentials, release, tag, deployment, or publication action is part of this PR.