Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/openai/lib/streaming/_deltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,24 @@
def accumulate_delta(acc: dict[object, object], delta: dict[object, object]) -> dict[object, object]:
for key, delta_value in delta.items():
if key not in acc:
acc[key] = delta_value
continue
if is_list(delta_value):
# Initialize an empty list so that list-merge logic below
# handles duplicate-index entries even on the very first chunk.
acc[key] = []
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fix first list chunk duplicate-index merging

When delta_value is a list for a key that is not yet in acc, this initializes acc_value to an empty list, but the existing list branch treats all(isinstance(... ) for x in acc_value) as true for an empty list and just extends the raw delta. As a result, the exact duplicate-index case this commit is meant to fix still leaves two entries at index 0 for inputs like {'tool_calls': [{'index': 0, ...}, {'index': 0, ...}]} instead of merging them, so later chunks continue from a malformed snapshot.

Useful? React with 👍 / 👎.

else:
acc[key] = delta_value
continue

acc_value = acc[key]
if acc_value is None:
acc[key] = delta_value
continue
if is_list(delta_value):
# Same as above: route list deltas through the merge path
# instead of copying the raw array wholesale.
acc[key] = []
acc_value = acc[key]
else:
acc[key] = delta_value
continue

# the `index` property is used in arrays of objects so it should
# not be accumulated like other values e.g.
Expand All @@ -33,7 +44,7 @@ def accumulate_delta(acc: dict[object, object], delta: dict[object, object]) ->
elif is_list(acc_value) and is_list(delta_value):
# for lists of non-dictionary items we'll only ever get new entries
# in the array, existing entries will never be changed
if all(isinstance(x, (str, int, float)) for x in acc_value):
if acc_value and all(isinstance(x, (str, int, float)) for x in acc_value):
acc_value.extend(delta_value)
continue

Expand Down