mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-18 04:42:30 +03:00
Two related schema-compliance fixes for upstreams that enforce the OpenAI
spec strictly (vLLM self-hosted, Kimi-K2.6):
1. Empty tool_calls[] guard: providers like Kimi-K2.6 attach an empty
tool_calls:[] array to every content delta when tools are defined. An
empty array is truthy, so guarding on 'delta.tool_calls' alone called
closeMessage() after the first content delta, closing the message item
prematurely. Subsequent content deltas arrived on a done item and were
dropped by clients (Codex: 'OutputTextDelta without active item'),
leaving only the first text fragment in the output. Guard both
translation paths on 'delta.tool_calls?.length' so closeMessage runs
only when at least one actual tool call is present:
- open-sse/translator/response/openai-responses.ts (chatCore translate path)
- open-sse/transformer/responsesTransformer.ts (/v1/responses direct path)
2. tool_choice schema guard: auxiliary/internal calls (e.g. WebSearch)
legitimately send tool_choice:'auto' with no tools array, and routing
may drop the tools array after the client sent it. vLLM rejects this
combination with a schema 400 ('When using tool_choice, tools must be
set'). Add stripToolChoiceWithoutTools() to targetRequestSanitizer.ts
that removes a dangling tool_choice lacking a usable tools array at
the common dispatch boundary. The guard is OpenAI-spec compliance, not
provider-specific, so it fires regardless of provider.
TDD: tests reproduce both bugs (Red: 5 fail → Green: 31 pass, 0 fail):
- tests/unit/translator-openai-responses-empty-tool-calls.test.ts (2 tests)
- tests/unit/responses-transformer.test.ts (+2 tests, 21 total pass)
- tests/unit/tool-choice-schema-normalization.test.ts (8 tests)
typecheck:core: 0 errors
Co-authored-by: Jihyun Son <jihyun.son@sk.com>