Files
OmniRoute/tests/unit
initguru 8deea62daf fix(sse): guard empty tool_calls[] and strip tool_choice without tools (#12901)
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>
2026-09-17 02:31:19 -03:00
..