Repository navigation
Conversation
b8d90c9 to
1d9b74b
Compare
|
Rebased onto the current #131 head ( The single K3.1 commit was replayed onto Also retargeted this PR's base from |
|
Pushed the overseas-endpoint follow-up for the review P2 (
Sequencing note for the parent pin: once this and the #131 stack land on |
asto18089
left a comment
There was a problem hiding this comment.
Fresh multi-lane review (7 lanes + 2 verification lanes: gate semantics, shared-matcher consumer audit, Kimi-family sweep, other-vendor sweep incl. all pinvoy-agent#825 families, mutation testing at both heads, smuggle/CI classification, claim verification). All findings verified at head 5e4545615. Verdict: the fix is real, root-caused, and well-scoped; requesting changes on three items before merge.
Verified-good
- Root cause confirmed:
build_chat_messages_with_reasoningemitsreasoning_contenton the replayed tool-call assistant message only whenshould_replay_reasoning_content_for_provider_on_routereturns true (chat.rs:2885,2918-2920); pre-PR the gate only learned bare K3 via the exact matchers. The new arm is catalog-independent, effort-immune (consistent with the always-reasoning contract), and correctly ordered (no shadowing with the K3 arms — spelling sets are disjoint, all matchers exact-compare). - Dedicated arm (vs extending the shared matchers) is justified: ~23 production consumers of
is_exact_direct_moonshot_k3_route/is_exact_kimi_code_k3_routegate K3-only contracts (effort dialects, route shapes, picker ladders, output limits, search timeout floor, two display labels); teaching the shared matchers K3.1 would have flipped all of them at once. PR body claim verified factually accurate. - Commit 2's
.aigate arm is exactly as strict as the.comarm (is_exact_https_routereuse), with negative neighbors (case/path/scheme/port/query) inprovider.rs:2226-2253. Loose-helper over-match safety verified (host+path pinned, no substring matching). - Smuggle: clean — 4 files, every hunk serves the disclosed purpose; no deps/submodule/workflow changes. Both commits DCO-signed, conventional subjects.
- Mutations at
5e4545615: arm deletion, Kimi-Code URL,.aiURL, and 3 of 4 spellings all go red when removed. fmt rc=0; applicable clippy gates rc=0; kimi/replay suites 125/75 green; ubuntu CI passed the full suite with the PR applied.
Must fix
- M1 — doc-comment hijack (
chat.rs:3485-3504): the helperis_kimi_k31_model_spellingwas inserted between the gate fn's doc block and the gate fn, so the entire "Route-aware reasoning replay policy." block now rustdoc-attaches to the 4-line spelling helper; the gate fn is left undocumented; "see the arm inside" (3494) points backwards; sentences 3492-3494 vs 3495-3496 duplicate each other. The inherited sentence "only Kimi Code's exact membership-plan endpoint has this replay contract" (3489-3490) is contradicted by the direct-platform K3 arm (3513) and the new arm itself (3533-3534) as the block now stands. Compiles clean, so CI cannot catch it. - M2 — commit 2 is incomplete on the config side (split-brain): the TUI exact gate and the TUI copy of the loose fallback learned
api.kimi.ai/coding/v1, but the config-crate twins did not:moonshot_base_url_uses_kimi_code(crates/config/src/lib.rs:4619-4624, still.com-only) andprovider_base_url_is_official(Moonshot, …)(lib.rs:4874-4882, delegates to it). Verified consequence: a Moonshot route onapi.kimi.ai/coding/v1with no model resolves the default tokimi-k2.7-code(the config-crate fallback misses), whichvalidate_kimi_code_api_model_idthen hard-rejects as a direct-platform id on the membership endpoint — a config-resolution failure on exactly the route commit 2 exists to support (the same config works onapi.kimi.com/coding/v1).provider_base_url_is_officialreturning false also contradicts its own "so route canonicalization and credential scoping cannot disagree" doctrine (lib.rs:4852-4856); consumers includeclient/responses.rs:905, clilib.rs:3117, app-serverchat_completions.rs:153/255. - M3 — required
linkgate red ×3, PR-caused: the body has no line-startCloses #N/No-Issue:anchor (checkedpr-issue-link.yml's regex; the mid-sentence "pinvoy-agent#825" mentions don't satisfy it). Will add the line in the fix wave.
Minors (will fix in the fix wave unless noted)
m— PR body overstates the pre-PR bug: the twokimi-k3.1-pro[-highspeed]spellings already replayed at default effort via thekimi-prefix heuristic (models.rs:447); the actual pre-PR failures were (a) barek3.1-pro[-highspeed]on Kimi Code never replaying and (b) all four spellings stripped at stored effort=off. Will recalibrate the body wording.m— "the host catalog registers api.kimi.ai" (provider.rs:517-518,client.rs:9386-9387, commit 2 body): no host catalog in this repo registers it (docs still documentapi.kimi.comonly); name the app-side catalog explicitly or updatedocs/PROVIDERS.md/docs/CONFIGURATION.md.m— typo "pinjou-agent#825" ×3 in code (provider.rs:518,client.rs:9328,client.rs:9387) + commit 2 body.m— stale adjacent strings: the membership-rejection error still names onlyapi.kimi.com/coding/v1(config.rs:10227); Moonshot guidance suggests only the.comURL (config.rs:7075).m— test-strength (mutation-verified): unpinned — the direct-platform matcher (masked by the generickimi-prefix; an effort=off direct leg would pin it), theprovider == Moonshotroute restriction (no custom-gateway negative), case/trim normalization (no variant input), and the 4th spellingkimi-k3.1-pro-highspeed. Sibling K3 tests (chat.rs:5166-5191,6228-6282) set the negative-test norm.m— commit 2's.aiwidening legitimately extends K3 effort shaping / sampling / route shape / billing / pickers to the overseas endpoint, but only the gate + replay legs are tested on.ai.
Follow-ups disclosed (not for this PR)
- OpenRouter
moonshotai/kimi-k3.1-pro(a codewhale-hq#825 row): not deterministically covered — theprovider == Moonshotrestriction is faithful to the aggregator precedent, but the generic heuristics miss themoonshotai/prefix (only k2.x org ids enumerated,models.rs:473-476), so replay depends on the runtime models.dev cache (fails offline/fresh installs); the same id on Volcengine replays via the bare-kimi-prefix — a pure prefix artifact. Cheap fix: add the org-prefixed spellings to the recognition list. - MiniMax M3.1-Flash (codewhale-hq#825-served, always-thinking):
minimax-m3.1-flashis in no recognition list → no replay, no stream classification. Different vendor contract; genuine follow-up. - Other codewhale-hq#825-family recognition staleness (pre-existing):
zai-org/GLM-5.3on SiliconFlow,minimax/minimax-m3.1-flashandanthropic/claude-opus-5.5org-prefixes on OpenRouter,Qwen/Qwen3.8-27B, mimo v2.6 ids,gemini-4thought-signature matcher,kimi-k2.5preserve_thinking verification, and the app-side bridge-arm gap for Mistral/Together/Meta/Groq (belongs on pinvoy-agent#825, not here). - CI reds other than
linkare base/environmental (verified against base0583e19cb): Lint = pre-existingclippy::collapsible_ifatturn_loop.rs:5611(untouched file); cargo-audit/cargo-deny = RUSTSEC-2026-0430 in the untouched lockfile; Lint & Type Check = release-data drift; Version drift / Integrations / Test-windows = unrelated subsystems (the PR's own test passed on Windows). - Upstream-first note: the gate is foundation code; fork-policy letter prefers upstream-first for all-embedder fixes — worth an upstream PR once the stack lands.
- Known pre-existing flake observed during verification:
forkguard_model_operation_auxiliary_retry_keys(operation_tests.rs:379) is order-dependent, passes in isolation, unrelated to this PR.
Fix wave incoming for M1-M3 + the minors; follow-ups stay disclosed.
|
Fix wave pushed as fd0aef4 + e11b90e (head M1 — doc-comment hijack (e11b90e): the spelling helper now carries its own doc line; the gate's "Route-aware reasoning replay policy." block is restored directly above M2 — config-crate M3 — Minors: route-gate comment premise reworded to "the app's model catalog registers api.kimi.ai" (provider.rs); membership-rejection and plan-key guidance strings now name both hosts; remaining Test-strength (e11b90e): the K3.1 regression test now pins all four spellings across both hosts, plus — each verified red under its targeted mutation before revert —
Erratum to the review comment: the Local gates: Disclosed, not fixed here (follow-ups): OpenRouter |
Jensen's review 5779604267 (P2): after the rebase onto main 78dcc1c the PR's child is the public maintenance head 11cba403d, whose exact-route exceptions only recognize k3/k3-256k - a tool turn on the bare k3.1-pro ids omits the required assistant reasoning_content and the Kimi Code gateway answers 400. Defer the two bare rows from the Kimi Coding Plan group (en/ja keys follow; the row-scoped FE imageCapable annotation goes with them) until the pinned child carries the upstream replay repair (Pinvou/CodeWhale#137). The prefixed platform rows ride the kimi-k3 fallback and stay; the custom row still permits manual ids. Test expectations flipped to the deferred semantics with the restore condition documented. Signed-off-by: asto <asto18089@126.com>
Jensen's review 5779604267 (P2): after the rebase onto main 78dcc1c the PR's child is the public maintenance head 11cba403d, whose exact-route exceptions only recognize k3/k3-256k - a tool turn on the bare k3.1-pro ids omits the required assistant reasoning_content and the Kimi Code gateway answers 400. Defer the two bare rows from the Kimi Coding Plan group (en/ja keys follow; the row-scoped FE imageCapable annotation goes with them) until the pinned child carries the upstream replay repair (Pinvou/CodeWhale#137). The prefixed platform rows ride the kimi-k3 fallback and stay; the custom row still permits manual ids. Test expectations flipped to the deferred semantics with the restore condition documented. Signed-off-by: asto <asto18089@126.com>
The Moonshot chat path prefixes a digit-led registry tool name with `_` to satisfy Kimi's documented `name` pattern, but the loop only ran outbound: the response decoder deliberately keeps the wire spelling, no layer mapped `_3d_render` back to `3d_render`, and every model call for such a tool died at dispatch with "tool not available" — the tools array kept advertising the name, so the model would retry the same spelling until the turn ended. Two halves now close the loop: - Engine dispatch: after every exact and alias lookup misses, `resolve_tool_definition` falls back to the unprefixed name for the exact `_<digit>` shape the prefix produces. A genuinely underscore-led name is never stripped, and a registry holding both spellings still resolves exactly (the fallback only fires after the exact lookups missed), so approval and policy gates see the canonical registry name. - Replay: assistant tool_calls persist the registry spelling, so the Moonshot message builder re-applies the wire prefix on replayed `tool_calls` (shared `prefix_digit_led_function_name` helper with the tools-array pass). The history now matches the tools array and stays inside the documented pattern; pre-fixture histories that already carry `_` pass through untouched. Also pins the hand-copied sampling-route matcher to the config-crate reference on the shared host (the twin covers the overseas host until PR #137 widens the shared matcher; that assertion is what flips when it lands), and restores the doc comment that `sanitize_moonshot_chat_tools` had lost when the prefix function was inserted between the comment and its function. No-Issue: completes the digit-led fix in this PR's own series; the repository has issues disabled. Signed-off-by: asto <asto18089@126.com>
Jensen's review 5779604267 (P2): after the rebase onto main 78dcc1c the PR's child is the public maintenance head 11cba403d, whose exact-route exceptions only recognize k3/k3-256k - a tool turn on the bare k3.1-pro ids omits the required assistant reasoning_content and the Kimi Code gateway answers 400. Defer the two bare rows from the Kimi Coding Plan group (en/ja keys follow; the row-scoped FE imageCapable annotation goes with them) until the pinned child carries the upstream replay repair (Pinvou/CodeWhale#137). The prefixed platform rows ride the kimi-k3 fallback and stay; the custom row still permits manual ids. Test expectations flipped to the deferred semantics with the restore condition documented. Signed-off-by: asto <asto18089@126.com>
Jensen's review 5779604267 (P2): after the rebase onto main 78dcc1c the PR's child is the public maintenance head 11cba403d, whose exact-route exceptions only recognize k3/k3-256k - a tool turn on the bare k3.1-pro ids omits the required assistant reasoning_content and the Kimi Code gateway answers 400. Defer the two bare rows from the Kimi Coding Plan group (en/ja keys follow; the row-scoped FE imageCapable annotation goes with them) until the pinned child carries the upstream replay repair (Pinvou/CodeWhale#137). The prefixed platform rows ride the kimi-k3 fallback and stay; the custom row still permits manual ids. Test expectations flipped to the deferred semantics with the restore condition documented. Signed-off-by: asto <asto18089@126.com>
The K3.1 spellings (kimi-k3.1-pro[-highspeed] on the direct platform, k3.1-pro[-highspeed] on Kimi Code) inherit the K3 contract verbatim, including the replay rule: the API requires the assistant reasoning_content on later tool turns and answers HTTP 400 when a replayed tool-call message misses it (Kimi Code error reference, missing-reasoning-content-field). The reasoning-replay gate only learned the bare k3 ids through the exact-K3 matchers, so a K3.1 tool round fell through to the generic heuristics and stripped the required field. The gate carries its own K3.1 arm on the vendor's two official routes; it is deliberately narrower than extending the shared matchers, whose other consumers (effort shaping, route validation, pickers) carry different K3-only contracts. Regression pins both routes with a tool-call round. Signed-off-by: asto18089 <asto18089@126.com>
The host catalog registers https://api.kimi.ai/coding/v1 as an official alias of the Kimi Code membership plan and saved settings keep it verbatim, but the exact route gate only learned api.kimi.com — so on the overseas route the K3.1 tool-turn replay contract (and the default model fallback, credential guidance, and billing presentation) still missed. Teach both the exact and the loose Kimi Code route gates the .ai host, keeping neighboring paths, lookalike hosts, and custom gateways outside the membership semantics. The K3.1 regression now pins both bare ids on the overseas route. Review: pinjou-agent#825 5765736266 / 5765853804 Signed-off-by: asto <asto18089@126.com>
Commit 2 taught the TUI-side loose fallback about api.kimi.ai/coding/v1 but left the config-crate twin and provider_base_url_is_official behind, so the two layers disagreed about the official endpoint family: a model-less Moonshot route on the overseas host resolved the default direct-platform id and then hard-failed membership validation on exactly the route the commit exists to support. Widen the loose membership recognition to both hosts, document the exact-gate subset doctrine it must keep, and pin the relation (and the lookalike/neighbor negatives) with tests. Also fixes the route-gate comment premise (the overseas alias is registered by the app-side model catalog, pinvoy-agent#825) and its pinjou typo. Signed-off-by: asto <asto18089@126.com>
The K3.1 helper was inserted between the replay gate and its doc block, so the whole route-aware replay policy comment rustdoc- attaches to the 4-line spelling matcher while the gate itself is left undocumented, with a duplicated sentence pair and a backwards "see the arm inside" pointer. Give the helper its own doc line and restore the gate's policy doc with an accurate K3.1 paragraph. The regression test now pins what the arm actually promises: all four spellings across both vendor hosts, the stale-effort-off always-replay case (which is what the direct-platform matcher is for — the generic kimi- prefix masks it at default effort), the case/padding normalization on the bare Kimi Code ids, and the custom-gateway / non-Moonshot dialect boundary as negatives. Also aligns the membership-rejection and plan-key guidance strings with both membership hosts and fixes the remaining pinjou typo in the overseas test comment. Signed-off-by: asto <asto18089@126.com>
e11b90e to
2602208
Compare
asto18089
left a comment
There was a problem hiding this comment.
Fresh multi-lane review (6 lanes: claims audit incl. live vendor-doc verification, deep gate semantics, smuggling + #138 overlap + commit hygiene, stream-side completeness, build/test/fmt/clippy + 10-leg mutation testing, elegance/engineering). Rebased first: the parent #131 merged as squash e2a0e14fd, so the stack was re-cut onto pinvou3-clean 6f7a3a748 — zero conflicts, patch content identical (hunk offsets only), no kimi-related drift on the touched files between the old cut point and the new base (0583e19cb..6f7a3a748 touched only 78804c83e, error-source, unrelated). New head 2602208af, pushed; base retargeted feat/host-armed-guardrail-prompts → pinvou3-clean (MERGEABLE). DCO intact on all 4 commits.
Verdict up front: the replay fix itself is real, root-caused, and strongly pinned — but I'm requesting changes (posted as a comment; GitHub refuses request-changes on the author's own PR) on the undisclosed stream-side gap and two truthfulness minors.
Verified-good
- Root cause confirmed at base: the gate learned only bare K3 via
is_exact_direct_moonshot_k3_route(kimi-k3, direct) /is_exact_kimi_code_k3_route(k3/k3-256k, membership); barek3.1-pro[-highspeed]fell through every static heuristic (DeepSeek-onlyrequires_reasoning_content, exact-id-only catalog, nokimi-prefix) → stripped;kimi-k3.1-pro[-highspeed]replayed at default effort via thekimi-prefix but died at the effort=off early-return. Body claims 1-4 match code exactly. - The arm is correctly placed and equivalent: precedes the effort check like bare K3 (mutation M10 — moving it after — goes RED at exactly the effort-off leg); case/trim semantics proved equivalent to the sibling
eq_ignore_ascii_casearms; no shadowing (spelling sets disjoint, full-string compares);moonshot_base_url_is_exact_direct_platformcovers both.cnand.aidirect hosts. is_exact_https_routeadversarial sweep clean: scheme/host case-fold, path case-sensitive, rejectshttp,:443, query, fragment, userinfo,//host, double trailing slash — the.aiarm mirrors the.comarm exactly.- Split-brain sweep clean: every production membership-semantics site is
.ai-aware via the two canonical gates (default-model fallback, official-host scoping, billing, web-search capability, credential help, replay/billing delegators). Remaining.com-only sites are comments/test fixtures only (see follow-ups). - The
.aiwidening ofis_exact_kimi_code_routeis the right move, not the lazy one: a narrower K3.1-only overseas predicate would leave bare K3 itself broken onapi.kimi.ai/coding/v1(no effort dialect, no replay). Live Kimi Code docs confirm.aias the official overseas endpoint. The final state's exact⊆loose doctrine is documented and tested (kimi_code_loose_route_recognition_covers_both_membership_hosts). - Dedicated-arm justification verified, not overstated: ~23 production consumers of the shared K3 matchers gate K3-only contracts (max_completion_tokens, nested
thinking.effortdialect, temperature/top_p strip, output ceiling, RouteShape, pickers ×3, effort normalization, timeout floor, labels, stream class). Extending them would have flipped all at once. - Claims audit: models-overview always-reasoning contract TRUE (live
platform.kimi.com/docs/api/models-overview.md: "K3 始终进行推理思考…"; K3.1 rows subject to the K3-series column; verbatim 「参数约束也与 kimi-k3 完全一致」 present in the codewhale-hq#825 record); HTTP 400 substance TRUE (live Kimi Code error reference documents "thinking is enabled but reasoning_content is missing in assistant tool call message" → 400);api.kimi.ai/coding/v1registration TRUE (local appmodel-catalog.js:366-372endpointAlias +prefs/model.rsverbatim); codewhale-hq#825 consumption real (merged 2026-11-06; its fork pins were deliberately reverted, dependency direction documented — "pin the second request once this lands" is accurate). - Smuggle: CLEAN — all 17 hunks across the 6 files serve the disclosed claims or the disclosed prior-round fixes; no deps/lockfile/workflow/submodule/i18n/version changes; no #138 debris.
- Gates:
cargo check0 warnings; tuikimi125/0,kimi_code46/0, config lib 645/0/1-ignored, both new tests green on the restored tree;fmt --checkclean; clippy at the CI profile (ci.yml:359) — 0 PR-introduced lints (2 pre-existingcollapsible_ifatturn_loop.rs:5662,subagent/mod.rs:8058, byte-identical on base). - Mutations 10/10 RED (each reverted, tree clean after): arm deletion, provider conjunct, case-sensitize, trim removal,
.aiexact line, config-crate.ailoose lines, direct-platform leg, kimi-code leg, highspeed spellings, and the ordering survivor check — no survivors; the test genuinely pins arm-before-effort-check.
Must fix
- M1 — stream-side classification gap, undisclosed (
chat.rs:3617-3659):is_reasoning_model_for_stream_on_routedid not learn K3.1. Matrix (Moonshot provider, head):kimi-k3.1-pro[-highspeed]stream-classify via the generickimi-prefix on all routes; the two bare membership spellingsk3.1-pro[-highspeed]— the heart of this PR — getReasoningStreamStyle::Noneon every route, because arm 1 is bare-K3-only andmodel_supports_reasoninghas no bundled k3.1 row and no matching prefix. Consequence: on Kimi Code +k3.1-pro+ streaming, every turn streams the CoT as answer text (parse_sse_chunk_with_reasoning_style→push_text_delta) and the trace re-sent on later tool turns as assistantcontent— context pollution of the tool loop, on the same route where barek3gets Thinking cells (pinned bybare_k3_reasoning_semantics_are_scoped_to_exact_kimi_code_route). Non-stream is safe (parse_chat_message_for_routepromotesreasoning_contentunconditionally), and the sanitizer placeholder path incidentally starts working for K3.1 via the widened replay gate — but that behavior is unpinned here. The closing comment on duplicate #138 shows the author knew exactly this; the body does not disclose it. Fix is a ~7-line mirror arm + a stream pin mirroring the replay test — in this PR or an immediately-pushed companion, with body disclosure either way. Not grading BLOCKER only because no hard failure occurs (placeholder keeps requests valid). - M2 — commit-message truthfulness:
2602208af's body claims it "fixes the remaining pinjou typo in the overseas test comment" — it is still there (client.rs:9450pinjou-agent#825), and the round's earlier "fix" replaced pinjou with a different misspelling atprovider.rs:518(pinvoy-agent#825); the PR body's No-Issue line carriespinvoy-agent#825too (line 14 is correct). Three residual misspellings + one false fix claim. Trivial to fix, but a fix-wave commit must not claim a fix it doesn't make.
Minors
- m1 — effort shaping sends a vendor-rejected payload to K3.1 at stored effort=off: bare K3 on the membership route gets
{thinking:{enabled,effort:low}}(Off→Low,chat.rs:195-216); K3.1 falls to the generic arm (client.rs:4095-4099) and gets{thinking:{type:disabled}}— the payloadchat.rs:222-224itself calls "not truthful" for the always-thinking family, and live docs state K3.1 Pro rejects disabled-thinking requests (400). The#3024premise ("Kimi models accept thinking enable/disable") predates K3.1. Pre-existing generic behavior, not worsened here — but this PR is what makes K3.1 on these routes its advertised purpose, so disclose it (or teach the shaping layer the K3.1 spellings / extend the defensive Off→Low) in the same follow-up as M1's seam closure. - m2 — newly codified exact⊆loose invariant breaks on whitespace-padded input: the exact gate trims (
is_exact_https_routedoesbase_url.trim()), both loose copies onlytrim_end_matches('/')(config/lib.rs:4625, tuiconfig.rs:9943), so" https://api.kimi.com/coding/v1"is exact-true/loose-false (andprovider_base_url_is_officialpasses the raw string through). Inherited asymmetry, but the PR makes the invariant load-bearing doc + test — trim in the loose copies or scope the doc claim. - m3 — commit slicing: commits 2+3 leave a broken intermediate (after
cf8a27b4cthe config-crate exact gate knows.aibut the loose gate andprovider_base_url_is_officialdon't — the exact⊄loose state commit 3's own body admits; a model-less.airoute hard-fails between them) → bisect hazard; squash 2+3. Commit 4 also mixes commit 1's doc-attachment repair with unrelated copy changes. History is being rewritten anyway with the rebase push — cheap to fix now. - m4 — test legs shielded by the generic heuristic: the two direct-platform default-effort legs (
kimi-k3.1-*) pass via thekimi-prefix even with the arm dead (test docstring acknowledges this); the uniquely pinning legs are the effort-off leg and the bare membership ids, both present and mutation-proven. Keep or re-comment — no action strictly required. - m5 — "missing-reasoning-content-field" cited as if a documented code: the live error reference documents the 400 by message text; that literal anchor appears nowhere on the page. Substance true, citation label imprecise — same precision bar as the sibling URL+date citations.
Nits
- fn-doc K3.1 paragraph (
chat.rs:3494-3502) and the arm comment (3520-3531) substantially repeat each other. - Citations lack the URL + verification-date form siblings use (
chat.rs:927pattern). - Doc maps spellings→routes (
kimi-k3.1-*direct /k3.1-*membership) but the arm accepts the union —kimi-k3.1-proon the membership route replays too. Harmless (same vendor family), doc-vs-code precision only. - No effort=off leg on the Kimi Code route (only direct platform has one); same code path, low incremental value.
k31vs the repo'sk3_1m/K3_256Kunderscore abbreviation;cf8a27b4cisfix(tui)while touchingcrates/config/src/provider.rs.
Disclosed follow-ups (not this PR)
- Stream/effort seam closure should promote the four spellings to one shared constant (the roster doctrine's anti-drift rationale activates at the second consumer — that consumer now exists).
- K3.1 roster/picker staleness:
KIMI_CODE_MEMBERSHIP_MODELS(4 ids) andMOONSHOT_DIRECT_PLATFORM_MODELS(3 ids) lack k3.1 — validation passes through (fail-open by design), but the pickers won't offer the codewhale-hq#825 presets. - OpenRouter
moonshotai/kimi-k3.1-pro(no org-prefix recognition; replay there depends on the runtime models.dev cache); MiniMax M3.1-Flash recognition;.com-only comment/fixtures atagent/src/lib.rs:785,provider_native_search/kimi.rs:376-390,route_billing.rstests; sanitizer placeholder pin for K3.1; upstream-first contribution of the gate change per fork policy; models.dev runtime-cache caveat on the body's "never matched" framing (static heuristics — a runtime-refreshed exact k3.1 catalog row could replay pre-PR).
Environmental (base-verified, not chargeable)
event_handoff_replays_and_dedupes_interaction_prompts_without_a_gapstack-overflows on this arm64 host in the PR tree and identically at base — replay suite run with--skipfor it (74/0 otherwise).- The 2 clippy errors above; base CI reds unrelated (audit RUSTSEC in untouched lockfile etc.).
Fix wave on offer for M1/M2 + minors; the stream arm and the typo sweep are mechanical.
Summary
Teaches the reasoning-replay gate the K3.1 family spellings so a K3.1 tool round replays
reasoning_contentlike bare K3 does.The replay gate only learned the bare k3 ids through
is_exact_direct_moonshot_k3_route/is_exact_kimi_code_k3_route. Thek3.1-pro[-highspeed]Kimi Code membership spellings fell through to the generic heuristics, which never matched, so the sender omitted the assistant tool-call message'sreasoning_contenton the follow-up request — the Kimi Code error reference documents that missing field as HTTP 400. Thekimi-k3.1-pro[-highspeed]direct-platform spellings did replay at default effort via the generickimi-prefix heuristic, but were still stripped whenever a stored effort ofoffwas present; the review-round arm (2026-11-04) makes all four spellings replay catalog-independently and effort-immune on both vendor routes, including the overseasapi.kimi.ai/coding/v1endpoint.Contract
reasoning_content.Scope
Deliberately narrow: the gate gains its own K3.1 arm on the vendor's two official routes instead of extending the shared exact-K3 matchers, whose other consumers (effort shaping, route validation, pickers) carry different K3-only contracts. Regression pins both routes with a tool-call round (assistant thinking + tool use → tool result → assert
reasoning_contentreplays).Context
Surfaced by the pinvou-agent#825 review round 3 (the app's model-catalog refresh adds these presets); the consumer's wire-body harness is ready to pin the second request once this lands.
No-Issue: follow-up to the pinvoy-agent#825 model-catalog review; this repository has issues disabled.