Skip to content

fix(providers): unindexed streamed tool-call ids dedupe; parsed stream detection (Eve2-F7/F8) - #615

Merged
LinuxDevil merged 2 commits into
mainfrom
fix/eve2-f78-providerfetch
Oct 12, 2026
Merged

LinuxDevil merged 2 commits into
mainfrom
fix/eve2-f78-providerfetch

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

Two runtime fixes in src/providers/providerFetch.ts from the eve2 audit (audit/eve2/FINDINGS-runtime-tools.md §7–§8), each with a regression test in providerFetchWatch.test.ts and a CHANGELOG line.

F7 — uniqueToolCallIds fragmented a streamed call whose deltas repeat id without index

ToolCallIds.assign() only recognized a repeated streamed id when it could key it by ${choice.index}:${call.index}. Deltas that repeat id but omit index — exactly the quirky OpenAI-compatible / Gemini-proxy servers this rewrite exists for — each minted a fresh suffix: one logical call became call_1, call_1_2, call_1_3, … with the arguments JSON split across phantom calls.

Fix: a delta call's slot in tool_calls stands in for the missing index in the dedupe key, so a repeated raw id at the same position maps back to its first assignment. Distinct ids still get distinct ids; indexed behavior is unchanged.

Repro audit/eve2/repro/streamToolCallIdRewrite.ts: before [ 'call_1', 'call_1_2', 'call_1_3' ] → after [ 'call_1', 'call_1', 'call_1' ] (indexed control unchanged).

F8 — isStreamingRequest regexed the raw body

isStreamingRequest() matched /"stream"\s*:\s*true/ against the entire serialized request body, so any nested flag (providerOptions.gateway.stream: true, tool arguments, gateway metadata) made a non-streamed call look streamed — and watchedResponse() rewrote its JSON reply into SSE events the consumer cannot parse.

Fix: parse the body once and read the top-level stream field; a malformed body is not a stream.

Repro audit/eve2/repro/streamRegexFalsePositive.ts: before — JSON completion rewritten to data: … SSE with content-type: text/event-stream → after — JSON preserved.

Verification

  • Both audit repro scripts now print OK (run against this worktree via npx tsx).
  • npx tsc --noEmit -p tsconfig.json — clean.
  • npm run lint — clean.
  • npx vitest run src/providers — 608 passed, 4 skipped (live tests); the two dist-dependent files needed npm run build in the fresh worktree, which also passed.
  • npm run api:check — all 20 reports up to date (no public API change).

…eat it without `index` (Eve2-F7)

The tool-call id rewrite keys a repeated streamed id by ${choice.index}:${call.index};
deltas that repeat id but omit index (the OpenAI-compatible / Gemini-proxy servers the
rewrite exists for) minted call_1_2, call_1_3, ... - one logical call became N phantom
calls with fragmented arguments. A delta's slot in tool_calls now stands in for the
missing index, so a repeated raw id maps back to its first assignment; distinct ids
still get distinct ids and indexed behavior is unchanged.
…tream` field (Eve2-F8)

isStreamingRequest() regexed the raw request body for /"stream"\s*:\s*true/, so a
nested field like providerOptions.gateway.stream:true made a non-streamed call look
streamed and watchedResponse() rewrote its JSON reply into SSE the consumer cannot
parse. The check now JSON.parses the body once and reads the top-level stream field;
a malformed body is not a stream.
@LinuxDevil
LinuxDevil merged commit 249ff5a into main Oct 12, 2026
7 checks passed
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