Skip to content

fix(executors): backfill missing tool message names for Kimi K3 and strict BYOK providers - #9005

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
Zenlyte:fix/kimi-tool-name-fixup
Aug 6, 2026
Merged

fix(executors): backfill missing tool message names for Kimi K3 and strict BYOK providers#9005
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
Zenlyte:fix/kimi-tool-name-fixup

Conversation

@Zenlyte

@Zenlyte Zenlyte commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Problem

Kimi K3 (Moonshot) enforces a stricter tool-message contract than most OpenAI-compatible APIs: every role:"tool" message must carry a name field matching the function that issued the tool_call_id. When requests arrive through combo routing or format translation, the name field is frequently stripped, causing a 400 error.

This also affects other strict BYOK openai-compatible-* providers that validate tool message structure.

Fix

Adds a shared open-sse/executors/kimiToolNames.ts module with ensureToolMessageNames() that:

  1. Builds a tool_call_id → function.name lookup from assistant messages
  2. Backfills missing name fields on role:"tool" messages

Wired into both:

  • KimiExecutor.transformRequest() — fixes Kimi K3 specifically
  • DefaultExecutor.transformRequest() — fixes all openai-compatible-* BYOK providers

Changes

File Change
open-sse/executors/kimiToolNames.ts New shared module
open-sse/executors/kimi.ts Import + call ensureToolMessageNames before normalization
open-sse/executors/default.ts Import + call ensureToolMessageNames in transformRequest

Testing

  • All existing lint/ESLint/Prettier/docs-sync checks pass
  • Manual testing confirms tool calls work through Kimi K3 after fix

Upgrade Path

If Moonshot relaxes this requirement in the future, ensureToolMessageNames() becomes a no-op (returns the record unchanged when no tool messages lack names).

…trict BYOK providers

Kimi K3 (Moonshot) enforces a stricter tool-message contract: every
role:"tool" message must carry a `name` field matching the function
that issued the tool_call_id. When requests arrive through combo
routing or format translation, the `name` field is frequently stripped,
causing a 400 error.

Add shared kimiToolNames.ts with ensureToolMessageNames() that builds
a tool_call_id → function.name lookup from assistant tool_calls and
backfills missing names on tool messages.

Wire into both KimiExecutor.transformRequest and
DefaultExecutor.transformRequest so BYOK openai-compatible providers
also get the fixup.
@Zenlyte
Zenlyte requested a review from diegosouzapw as a code owner July 30, 2026 18:59
@diegosouzapw
diegosouzapw changed the base branch from main to release/v3.8.50 August 4, 2026 06:51
@diegosouzapw
diegosouzapw merged commit 1a8f10b into diegosouzapw:release/v3.8.50 Aug 6, 2026
3 checks passed
diegosouzapw added a commit that referenced this pull request Aug 6, 2026
…as in CI

The base kept moving during the reconcile cycle: #9184 grew
src/sse/handlers/chat.ts 1857->1877 and #9005 grew
open-sse/executors/default.ts 1027->1042. Re-measured on the merged
tree; gate back to 0 violations.
diegosouzapw added a commit that referenced this pull request Aug 6, 2026
…9554)

* fix(quality): reconcile inherited file-size drift on the release tip

13 files sit above their frozen LOC on the clean tip 8180b49
(measured by the gate itself). The PR-mode base-relative check (#8522)
correctly lets innocent PRs pass, but per-PR rebaselines were lost
across successive conflict resolutions of this hot file during the
08-05/06 merge batch — so the absolute mode (nightly, local runs) is
permanently red and stops distinguishing real growth from inherited
drift.

Frozen values updated to the measured tip, each annotated with the
merged PR that grew the file (#9024 #9324 #9329 #9193 #9332 #9228
#9236 #9314 #9260 #8934 #9196 #9163); executors default.ts and kiro.ts
(above the 1000 cap with no frozen entry) join the frozen set.

* fix(quality): prune orphaned ESLint suppressions and clear the 5 unsuppressed errors

The 'No new ESLint warnings' job reds the whole queue with exit 2:
'There are suppressions left that do not occur anymore' — the 08-05
merge batch removed code whose violations were frozen in
eslint-suppressions.json, leaving orphaned entries (673->670 files,
4338->4333 violations after eslint --prune-suppressions).

The full-tree run also surfaced 5 real unsuppressed errors merged with
the batch, fixed here instead of suppressed (new violations must be
fixed, per policy): 4x no-explicit-any in
tests/unit/catalog-order-contract.test.ts ((conn as any).id -> typed
cast) and 1x react/no-unescaped-entities in the agent-bridge
SetupWizard (#9095).

Also restores the _comment policy header the successive hot-file
conflict resolutions had dropped (TS7 debt freeze provenance + prune
policy).

* fix(quality): absorb the two file-size growths merged while this PR was in CI

The base kept moving during the reconcile cycle: #9184 grew
src/sse/handlers/chat.ts 1857->1877 and #9005 grew
open-sse/executors/default.ts 1027->1042. Re-measured on the merged
tree; gate back to 0 violations.

* fix(tests): move the orphaned RTL ratchet test to a collected path as node:test

#8828 added tests/unit/scripts/check-rtl-ratchet.test.ts — a path no
runner collects (the node:test globs enumerate an explicit subdir list
without scripts/, and vitest.config.ts never included it), so the file
NEVER ran and the test-discovery orphan gate reds the queue. Moved to
tests/unit/ (collected by node:test) and converted from vitest
describe/it/expect to node:test+assert to match the runner and the
sibling check-*.test.ts files. 5/5 green under the real runner.

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
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.

2 participants