Skip to content

fix(merge): reorder branches so streaming deltas always concatenate - #436

Draft
cpsievert wants to merge 2 commits into
mainfrom
fix/merge-dicts-equal-delta
Draft

cpsievert wants to merge 2 commits into
mainfrom
fix/merge-dicts-equal-delta

Conversation

@cpsievert

Copy link
Copy Markdown
Collaborator

Closes #435

Summary

merge_dicts() had an equality check (left_v == right_v → continue) before the str/dict/list branches. When a streamed text delta happened to equal the full accumulation so far (e.g. "\n" + "\n"), the second delta was silently dropped — both at the string-leaf level and at the container level (an equal dict skipped recursion entirely).

The fix reorders the branches to match langchain's original ordering (from which this code was adapted). Strings always concatenate, containers always recurse, and the equality check now only applies to remaining scalar types (int, float, bool).

All providers that stream via merge_dicts() are affected: ChatOllama(), ChatGroq(), ChatDeepSeek(), ChatOpenRouter(), ChatDatabricks(), ChatGoogle(), and ChatOpenAICompletions().

Verification

from openai.types.chat import ChatCompletionChunk
from chatlas._provider_openai_completions import OpenAICompletionsProvider

provider = OpenAICompletionsProvider(api_key="unused", model="gpt-4o-mini")

def chunk(text, last=False):
    return ChatCompletionChunk.model_validate({
        "id": "chatcmpl-1", "object": "chat.completion.chunk", "created": 1,
        "model": "gpt-4o-mini",
        "choices": [{"index": 0, "delta": {"role": "assistant", "content": text},
                     "finish_reason": "stop" if last else None}],
    })

deltas = ["\n", "\n", "Here is the answer."]

completion = None
for i, d in enumerate(deltas):
    completion = provider.stream_merge_chunks(
        completion, chunk(d, last=i == len(deltas) - 1)
    )
turn = provider.stream_turn(completion, has_data_model=False)

# Before: '\nHere is the answer.'
# After:  '\n\nHere is the answer.'
assert turn.text == "\n\nHere is the answer."

cpsievert and others added 2 commits September 14, 2026 11:58
`merge_dicts()` had an equality check (`left_v == right_v → continue`)
before the str/dict/list branches. When a streamed text delta happened
to equal the full accumulation so far (e.g. "\n" + "\n"), the second
delta was silently dropped — both at the string-leaf level and at the
container level (an equal dict skipped recursion entirely).

Move the str/dict/list branches before the equality check, matching
langchain's original ordering. Strings always concatenate, containers
always recurse, and the equality check now only applies to remaining
scalar types (int, float, bool).

Closes #435

This branch has not been deployed

No deployments
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.

A streaming text delta that repeats everything streamed so far is missing from the recorded turn

1 participant