| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Sorry, something went wrong.
…se#1751 arity _extract_streamed_openai_response now returns a 5-tuple (adds service_tier, upstream langfuse#1751) instead of 4. Update this test's unpack to match; the bug assertions (model/completion/metadata content) are unchanged.
|
Refreshed this branch onto current main at 60a746dc. The fix remains relevant: current upstream still reproduces TypeError: unsupported operand type(s) for +=: 'NoneType' and 'str' when a legacy streamed function_call begins with arguments=None and a later chunk appends string arguments. Validation on the refreshed branch:
The targeted regression test was also run red-before and green-after. Ready for maintainer review. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
What does this PR do?
_extract_streamed_openai_response (langfuse/openai.py) merges the deprecated function_call
streaming delta with a bare +=:
getattr(obj, "arguments", "") only returns the "" default when the attribute is absent. Some
OpenAI-compatible proxies send a first delta with function_call.arguments explicitly set to
None (not missing) — a real payload shape, not a hypothetical one. In that case
curr["arguments"] is None, and None += str raises TypeError, killing the merge for the
whole streamed completion. The TypeError is currently swallowed by a bare except Exception: pass further up the call stack, so today this fails silently: the generation ends with no output
and no error a caller would notice.
This is the same crash class PR #1339 already fixed for the newer tool_calls array — but that
fix only touched the tool_calls branch a few lines below; the sibling legacy function_call
branch was never patched. The tool_calls branch already guards the accumulator side and skips
None increments:
The fix brings the same protection to the legacy branch, adopting that branch's
(... or "") + ... accumulator guard and coalescing the incoming delta inline so a None (or
missing) arguments on either side can't break the concatenation:
This guards both sides: the accumulator being None, and the incoming delta's arguments being
None or missing. When both sides are normal strings it is equivalent to the original += — no
behavior change on the happy path. Two-line functional change to a single merge branch; does not
touch the tool_calls branch or any other streaming path.
No existing issue or open PR describes this legacy-function_call-branch crash (see the search
under Verification below); happy to open a tracking issue first if that's preferred for bug-fix PRs.
Type of change
Verification
List the main commands you ran:
Test added: test_streaming_chat_completion_handles_legacy_function_call_none_arguments, mirroring
the existing test_streaming_chat_completion_preserves_tool_calls_after_content pattern but for
the legacy branch, with a first delta carrying function_call.arguments=None.
Checklist
behavior changed; two-line internal guard.)
regeneration path.
Greptile Summary
This PR fixes a silent TypeError crash in the deprecated function_call streaming-merge branch of _extract_streamed_openai_response when an OpenAI-compatible proxy sends a delta with arguments explicitly set to None. The fix mirrors the identical guard already applied to the tool_calls branch in PR #1339 that was never extended to this legacy sibling branch.
Confidence Score: 5/5
Safe to merge — the change is a two-line targeted guard that cannot regress the happy path (string + string produces the same result as before), and the new test directly validates the failing case.
The fix is a minimal null-coalescing guard that mirrors an already-proven pattern from the tool_calls branch. The initialization path at line 807 could still store None for arguments on a single-delta stream, but that pre-existing edge produces None output rather than a crash and is out of scope for this PR. No other correctness issues found.
No files require special attention.
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Proxy as OpenAI-compatible Proxy participant Extract as _extract_streamed_openai_response participant Accum as function_call accumulator Proxy->>Extract: "chunk 1: function_call.arguments = None" Extract->>Accum: "if not curr → initialize {name, arguments: None}" Proxy->>Extract: "chunk 2: function_call.arguments = '{"city":"Berlin"}'" Note over Extract,Accum: BEFORE fix: None += str → TypeError (swallowed silently) Note over Extract,Accum: AFTER fix: (None or "") + (str or "") → '{"city":"Berlin"}' Extract->>Accum: "curr["arguments"] = "" + '{"city":"Berlin"}'" Accum-->>Extract: "{name: "get_weather", arguments: '{"city":"Berlin"}'}"%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Proxy as OpenAI-compatible Proxy participant Extract as _extract_streamed_openai_response participant Accum as function_call accumulator Proxy->>Extract: "chunk 1: function_call.arguments = None" Extract->>Accum: "if not curr → initialize {name, arguments: None}" Proxy->>Extract: "chunk 2: function_call.arguments = '{"city":"Berlin"}'" Note over Extract,Accum: BEFORE fix: None += str → TypeError (swallowed silently) Note over Extract,Accum: AFTER fix: (None or "") + (str or "") → '{"city":"Berlin"}' Extract->>Accum: "curr["arguments"] = "" + '{"city":"Berlin"}'" Accum-->>Extract: "{name: "get_weather", arguments: '{"city":"Berlin"}'}"Reviews (1): Last reviewed commit: "test(openai): rebase legacy function_cal..." | Re-trigger Greptile