Skip to content

fix(route): replay k3.1 reasoning on tool turns - #138

Closed
asto18089 wants to merge 1 commit into
pinvou3-cleanfrom
fix/kimi-code-k31-replay
Closed

asto18089 wants to merge 1 commit into
pinvou3-cleanfrom
fix/kimi-code-k31-replay

Conversation

@asto18089

Copy link
Copy Markdown
Collaborator

背景

父仓 pinjou-agent PR codewhale-hq#825 的模型目录新增 Kimi Code K3.1 旗舰预设(k3.1-pro、k3.1-pro-highspeed)。两者是 always-reasoning 模型:供应商要求工具续轮请求必须回放 assistant reasoning_content。但 should_replay_reasoning_content_for_provider_on_route(chat.rs)的精确路由臂只认裸 k3/k3-256k(与直连平台的 kimi-k3),两个 K3.1 裸 ID 在 model_supports_reasoning 兜底里也不命中(目录无条目、无 kimi- 前缀)→ 续轮丢字段 → 供应商拒绝(pinvou-agent#825 review 5764334265 / 5764497649 P2)。

变更

  • config/models.rs:新增 KIMI_CODE_K3_1_MODEL / KIMI_CODE_K3_1_HIGHSPEED_MODEL 常量(注释钉明 always-reasoning 契约与「仅 replay/stream 消费」边界)。
  • config.rs:新增 is_exact_kimi_code_k31_route —— 刻意不并入 is_exact_kimi_code_k3_route(那两扇门还 gate 嵌套 thinking.effort 整形、固定采样、输出天花板等 K3 专属方言;K3.1 明确拒绝 thinking 参数,扩错会复活 thinking:{enabled} 线)。
  • client/chat.rs:仅在两个决策点挂入——should_replay_reasoning_content_for_provider_on_route(replay 主决策)与 is_reasoning_model_for_stream_on_route(流式推理分类,防裸 ID 的 reasoning delta 被内联进正文)。发送面(apply_reasoning_effort)不动:K3.1 的 effort 由父侧省略,引擎 None 早退即充分。

验证

  • 新增 kimi_code_k31_replays_reasoning_across_the_tool_loop:评审点名的「工具调用 → 工具结果 → 检查第二次请求」形状,两裸 ID × effort None/Some("high") × 大小写变体全部保留 reasoning_content 且工具调用绑定完好;负臂=同 ID 在直连平台 endpoint 不继承 Kimi Code replay。
  • 新增 kimi_code_k31_sanitizer_injects_placeholder_when_trace_was_dropped:推理字段被上游丢弃时 sanitizer 注入回放占位符;负臂=平台 endpoint 不触碰。
  • 新增 kimi_code_k31_route_predicate_is_exact_and_disjoint_from_k3(config/tests.rs):新谓词精确命中两裸 ID(大小写不敏感)、与全部 K3 谓词互斥、端点隔离(平台拼写/直连平台 endpoint 不命中)。
  • 负验证:摘除 replay 钩点 → kimi_code_k31_replays... 红;恢复 → 绿。kimi 全族 127 通过 / 0 失败。cargo fmt --check -p codewhale-tui 净。
  • 已知预存:本地 clippy(较新版本)在 context_report.rs / core/engine.rs / turn_loop.rs 报 6 处既有错误,本 PR 未触碰这些文件。

Kimi Code K3.1 flagship ids (k3.1-pro, k3.1-pro-highspeed) are
always-reasoning: the vendor requires the assistant reasoning_content
on the follow-up request after a tool call. The exact replay predicate
only learned the bare k3 ids, so the K3.1 presets from the host catalog
dropped the field and the follow-up request was rejected. Add a
separate exact predicate for the two K3.1 wire ids and hook it into the
replay decision and the stream reasoning classification only — the K3
route shapers (nested thinking.effort, fixed sampling, output ceilings)
stay K3-only because K3.1 rejects the thinking parameter.

Reported-by: JensenChen28 <jensenchen28@users.noreply.github.com>
Reported-by: zhuowp <zhuowp@users.noreply.github.com>
Signed-off-by: asto <asto18089@126.com>
@asto18089

Copy link
Copy Markdown
Collaborator Author

Closing as a duplicate: #137 lands the same K3.1 replay fix (four spellings across both vendor routes) and is already the vehicle for the pinjou-agent#825 consumption. One FYI for whoever reviews #137: it hooks only the replay gate (should_replay_reasoning_content_for_provider_on_route) — the stream-side mirror is_reasoning_model_for_stream_on_route still learns only the bare k3 ids, so on the bare k3.1-pro ids the reasoning delta decoding falls to None and gets inlined into content. Outside both review scopes, purely informational.

@asto18089 asto18089 closed this Nov 4, 2026
@asto18089
asto18089 deleted the fix/kimi-code-k31-replay branch November 4, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant