Skip to content

fix(acl/openai): assign new block index for text interleaved between tool calls - #976

Open
oierxjn wants to merge 3 commits into
cloudwego:mainfrom
oierxjn:fix/agentic-converter-interleaved-text-index
Open

fix(acl/openai): assign new block index for text interleaved between tool calls#976
oierxjn wants to merge 3 commits into
cloudwego:mainfrom
oierxjn:fix/agentic-converter-interleaved-text-index

Conversation

@oierxjn

@oierxjn oierxjn commented Aug 27, 2026

Copy link
Copy Markdown

Fixes #975

Problem

Some providers (observed on Cloudflare Workers AI gateways) emit content chunks between parallel tool-call chunks in one stream:

data: {"choices":[{"delta":{"tool_calls":[{"id":"call_a","index":0,"type":"function",...}]}}]}
data: {"choices":[{"delta":{"content":"\n"}}]}            <-- interleaved text
data: {"choices":[{"delta":{"tool_calls":[{"id":"call_b","index":1,"type":"function",...}]}}]}

chunkConverter.advanceContent only compares block type and source index, ignoring c.inToolCalls. Once tool calls have started, an interleaved text chunk still matches the previous text block's type, so it inherits the tool-call group's StreamingMeta.Index. schema.ConcatAgenticMessages then groups mismatched block types under one index and fails with:

content block type mismatch: expected 'function_tool_call', but got 'assistant_gen_text'

Fix

When inToolCalls is set, advanceContent now always advances to a new block index and resets inToolCalls, so:

  • the interleaved text gets its own index (no collision with the tool-call group)
  • a following tool call also gets a fresh index

Change is confined to (*chunkConverter).advanceContent; streams without interleaved text are unaffected.

Test

Added TestChunkConverter/text_interleaved_between_tool_calls covering the exact frame sequence (text → tool call 0 → interleaved text → tool call 1), asserting each block gets a distinct index and the full sequence passes ConcatAgenticMessages.

go test -gcflags="all=-N -l" ./libs/acl/openai/...   # ok

…tool calls

Some providers (e.g. Cloudflare Workers AI gateways) emit content chunks
between parallel tool-call chunks in one stream. Once tool calls started,
chunkConverter.advanceContent only compared block type and source index,
so an interleaved text chunk inherited the tool-call group's
StreamingMeta.Index. ConcatAgenticMessages then grouped mismatched block
types under one index and failed with:

  content block type mismatch: expected 'function_tool_call', but got
  'assistant_gen_text'

When inToolCalls is set, advanceContent now always starts a new block and
resets inToolCalls so a following tool call also gets a fresh index.

Fixes cloudwego#975
@CLAassistant

CLAassistant commented Aug 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

bug(acl/openai): chunkConverter assigns duplicate StreamingMeta index when text is interleaved between parallel tool calls

2 participants