Repository navigation
fix(kimi): repair empty items schemas instead of dropping the tool - #7015
Conversation
Moonshot MFJS validation fails any empty schema node with MissingType,
and sanitize_moonshot_chat_tools answers by silently excluding the whole
tool from the request — the model only sees a tool_search reference it
can never call and keeps emitting the nearest advertised tool instead.
JSON Schema reads an empty items schema as unconstrained items, which is
exactly the MFJS-legal shape with the keyword absent, so the kimi
parameters sanitizer now removes the empty keyword instead of the tool.
Untyped nodes without a semantics-preserving equivalent (empty property
schemas) still fail closed.
Found in the wild: a browser-automation MCP server advertised
`args: {"type": "array", "items": {}}`, so Kimi requests never carried
the tool no matter how often it was activated.
The walker visits children before the node's own items check so a nested
repair can empty the parent (`"items": {"items": {}}` is vacuously true
once the inner keyword is gone, so dropping the outer keyword stays
semantics-preserving), and visits every schema-value position the
validator recurses into: property values, `items`, object-form
`additionalProperties`, `anyOf` branches, and `$defs` entries.
Signed-off-by: asto <asto18089@126.com>
Maintainer follow-ups from the review of three merged contributor PRs from @asto18089. #7014 (Claude 5 sampling gate): the "never send both" assertion sat after the older-model loop, so it checked the first claude-opus-4-8 body, which never carries top_p, and could not catch a regression. It now runs inside the loop for each 4.x model, and a top_p-only request is checked to pass through, as the PR body described. #7015 (Kimi empty `items` repair): once an empty `items` is dropped, a required array with minItems >= 1 still failed mfjs_schema_can_terminate with InvalidSchemaNode, so that tool was still excluded. MFJS allows `items` to be absent, and an unconstrained array can always be satisfied, so absent `items` now counts as terminating. #7017 (era-scoped checkpoint recognition): the docs said an unstamped history "predates stamping". A session that has never been compacted has no stamped carrier either, so a pasted legacy header still reads as a checkpoint at a session's first compaction. SURVIVAL_CONTRACT.md and the history_is_post_provenance doc now state that limit. Refs #7014 Refs #7015 Refs #7017 Verified: scripts/dev-test.sh tui body_drops_sampling schema_sanitize moonshot kimi compaction: 355 run, 355 passed (includes body_drops_sampling_params_for_models_that_reject_them and 141 kimi/moonshot tests). validate_survival_contract.mjs: ok 17 fixtures. cargo fmt --check clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
|
🤖 This reply is from Claude Opus 5.5, an AI agent working on behalf of the Codewhale maintainers. It is posted through @Hmbown's account, but Hunter did not write it. Merged in 7f469f6. Thank you @asto18089. Repairing One follow-up on — Written by Claude Opus 5.5 (AI agent) on behalf of the maintainers. |
Adds [Unreleased] entries for #7014, #7015, #7017, #7018, #7019 and #7020, crediting @asto18089 (and @zhuowp for the fork ports). Each merged without a changelog line. The entry for #7020 names its behavior change: the app-server's legacy [providers.custom] table now refuses a non-Chat wire with provider_wire_format_unsupported instead of forwarding a Chat body. Refs #7014 Refs #7015 Refs #7017 Refs #7018 Refs #7019 Refs #7020 Refs #6997 Verified: sync-changelog --check up to date; web check-facts OK; check-contributor-credit "Every contributor in the window is credited on all three surfaces". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
What
Moonshot's MFJS schema validation fails any empty schema node with
MissingType, andsanitize_moonshot_chat_toolsanswers by silently excluding the whole tool from the request. A tool that ships"items": {}— legal JSON Schema for "items are unconstrained", and the exact shape a browser-automation MCP server in the wild advertised for itsargsarray — therefore never reached Kimi: the model only saw atool_searchreference it could never call and kept emitting the nearest advertised tool instead.The Kimi parameters sanitizer now removes the empty
itemskeyword instead of the tool: an absentitemskeyword already means unconstrained items, so the repair is semantics-preserving. Untyped nodes without a semantics-preserving MFJS equivalent (e.g.{"items": {"description": "..."}}) still fail closed withMissingType.The walker visits children before the node's own
itemscheck, so a nested repair can empty the parent ("items": {"items": {}}is vacuously true once the inner keyword is gone, making the outer drop still semantics-preserving), and it visits every schema-value position the validator recurses into: property values,items, object-formadditionalProperties,anyOfbranches, and$defsentries — including a rootitemskeyword beside$defs.Tests
kimi_parameters_repairs_empty_items_as_unconstrained— the wild-found shape, nested occurrences, and the still-fail-closed described-only node.kimi_parameters_repairs_nested_and_sibling_empty_items— items-in-items, root-items-beside-$defs,additionalPropertiesandanyOfpositions.cargo test -p codewhale-tui --lib schema_sanitize63 passed / 0 failed; clippy-D warningsclean (lib).Found in the wild on a browser-automation MCP catalog; ported from the Pinvou/CodeWhale fork (#101). The fork commit's tool-search eviction-reporting half already landed upstream (#6969) and is not included.
No-Issue: Moonshot dropped any tool whose schema has an empty
items(port of fork PR #101)