Reviewed full PR details including description, comments, commits, and changed files.
UnderstandIdentified and read linked issues referenced in the PR.
UnderstandAnalyzed code changes and their impact on tool call argument handling.
UnderstandClarified variable reset behavior and effect on streaming tool results.
VerifyYou are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/pull/917 this looks fishy
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
Let me read the full source file to understand the context:
Let me check for any related tests and look at the parseStreamingJson function to understand its behavior better:
Now let me check if documentation needs updates:
PR: https://github.com/badlogic/pi-mono/pull/917
Changelog:
packages/ai/CHANGELOG.md under [Unreleased]. Required before merge.Good:
response.function_call_arguments.done instead of streaming deltascurrentBlock.partialJson (populated from done event) over item.arguments (which is empty "{}" in this case)currentBlock = null after function_call handling in response.output_item.done, matching the pattern used for reasoning and message types (this was a pre-existing bug)parseStreamingJson function tries JSON.parse first, so using it on complete JSON from the done event is correctBad:
function_call_arguments.done without deltas)parseStreamingJson in the done handler but JSON.parse in the completion handler is inconsistent (both work, but mixing styles)Ugly:
Questions or Assumptions:
Change summary:
response.function_call_arguments.done event that stores complete arguments in currentBlock.partialJsonresponse.output_item.done handler for function_call to prefer pre-parsed arguments from currentBlock.partialJson over potentially empty item.argumentscurrentBlock = null cleanup after function_call completion (bug fix unrelated to the main issue)Tests:
function_call_arguments.done without prior delta events.Verdict: The code looks correct and the fix is sensible, but the contributor needs to:
The "fishy" part you noticed is likely the external contribution process bypass and lack of tests. The actual code change is sound.
are you sure the missing currentBlock = null is a preexisting bug? also, what effect does this have on responses from providers that DO support tool result streaming?
Good questions. Let me re-examine.
On currentBlock = null:
Looking at the code flow more carefully:
response.output_item.added overwrites currentBlock with a new blockdelta, done) all check currentBlock?.type === "toolCall" before actingoutput_item.done, the next item would overwrite currentBlock anyway via output_item.addedSo it's not a "preexisting bug" causing actual problems. It's an inconsistency with how reasoning and message handle completion (they set currentBlock = null). Adding it is defensive programming that would only matter if a malformed stream sent a stray function_call_arguments.delta after output_item.done. I overstated it.
On providers that DO support streaming deltas:
Let me trace through:
output_item.added: currentBlock.partialJson = "" (or item.arguments || "")function_call_arguments.delta: partialJson += event.delta, accumulates to complete JSONoutput_item.done: checks currentBlock?.type === "toolCall" && currentBlock.partialJson
currentBlock.partialJson is truthy (accumulated deltas)JSON.parse(currentBlock.partialJson)item.arguments should equal currentBlock.partialJson for conformant providersThe condition currentBlock.partialJson being truthy is key. For delta-streaming providers, it will be populated. For done-only providers (LM Studio), the new handler populates it.
One edge case worth noting: If a provider sends BOTH deltas AND a done event, the done handler would overwrite partialJson with event.arguments. This should be fine since the done event should have the complete value.
Revised verdict: The code is correct, but my characterization of the currentBlock = null as a "preexisting bug" was wrong. It's a stylistic consistency fix / defensive measure.