Skip to content

fix(rust): make ChatCompletionChunk a transparent Value passthrough#65

Merged
AnthonyRonning merged 1 commit intomasterfrom
fix/streaming-tool-call-passthrough
Feb 21, 2026
Merged

fix(rust): make ChatCompletionChunk a transparent Value passthrough#65
AnthonyRonning merged 1 commit intomasterfrom
fix/streaming-tool-call-passthrough

Conversation

@AnthonyRonning
Copy link
Contributor

@AnthonyRonning AnthonyRonning commented Feb 21, 2026

Problem

Streaming chat completions with multiple tool calls fail with:

Failed to parse chunk: invalid type: null, expected a string at line 1 column 230

The OpenAI streaming spec sends null for id, type, and function.name in subsequent tool_call delta chunks after the first. The SDK's ToolCall struct had these as required String fields, causing deserialization failures.

Fix

Replace the typed streaming structs (ChatCompletionChunk, ChatChoiceDelta, ChatMessageDelta) with a single transparent serde_json::Value wrapper:

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ChatCompletionChunk(pub Value);

This makes the streaming path a full JSON passthrough -- any valid JSON from the backend flows through without the SDK ever failing on null, absent, or new fields.

Also

  • Fixes kimi-k2-thinking -> kimi-k2-5 model name in tests (old model no longer available)
  • Adds test_streaming_multi_tool_calls integration test that verifies parallel tool call streaming works end-to-end

Testing

Verified against the dev instance (enclave.secretgpt.ai) with glm-5 model via maple-proxy:

  • Non-streaming tool calls: pass
  • Streaming single tool call: pass
  • Streaming multi-tool calls (previously broken): pass
  • All existing SDK unit tests: pass

Open with Devin

Summary by CodeRabbit

  • New Features

    • Function and Tool types are now publicly available and can be imported directly.
    • Streaming responses with multiple tool calls are now supported.
  • Refactor

    • Streaming response structure has been updated to a unified wrapper format.

Streaming tool_call deltas from LLMs (e.g. GLM-5 via vLLM) send null for
id, type, and function.name fields in subsequent chunks after the first.
The previous typed structs required these as non-Optional Strings, causing
deserialization failures on multi-tool streaming responses.

Replace ChatCompletionChunk, ChatChoiceDelta, and ChatMessageDelta with a
single transparent serde_json::Value wrapper. This makes the streaming path
a full JSON passthrough, avoiding failures on null/absent fields and
future-proofing against new fields from the backend.

Also fixes kimi-k2-thinking -> kimi-k2-5 model name in tests and adds a
new test_streaming_multi_tool_calls integration test.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

The pull request replaces three fixed streaming delta types (ChatCompletionChunk, ChatChoiceDelta, ChatMessageDelta) with a single transparent wrapper ChatCompletionChunk that encapsulates a generic Value. This enables passthrough of raw backend JSON without deserialization constraints. Tests are updated to access chunk data via JSON navigation rather than structured field access, and a new streaming test for multiple tool calls is added.

Changes

Cohort / File(s) Summary
Type Definitions
rust/src/types.rs
Removed three structured streaming delta types; added transparent ChatCompletionChunk(pub Value) wrapper to allow direct JSON passthrough and accommodate evolving backend fields.
Integration Tests
rust/tests/ai_integration.rs
Updated imports to export Function and Tool; refactored chunk field access throughout tests from structured paths (e.g., chunk.choices[0].delta.content) to JSON value paths (e.g., chunk.0["choices"][0]["delta"]["content"]); added new test_streaming_multi_tool_calls test for verifying multiple tool calls in streaming responses.
API Integration Tests
rust/tests/api_keys.rs
Updated streaming response parsing to extract content via JSON value traversal (chunk.0["choices"].as_array()...["delta"]["content"]) instead of structured field access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Whiskers twitching with delight,
Types shed their rigid chains so tight,
A transparent wrapper born to be free,
JSON streams through—wild and carefree!
No more fretting over unknown fields,
Our schema's heart forever yields!

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: converting ChatCompletionChunk to a transparent Value wrapper for JSON passthrough.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/streaming-tool-call-passthrough

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

Deploying opensecret-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9354c31
Status: ✅  Deploy successful!
Preview URL: https://fd6a5007.opensecret-sdk.pages.dev
Branch Preview URL: https://fix-streaming-tool-call-pass.opensecret-sdk.pages.dev

View logs

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@AnthonyRonning AnthonyRonning merged commit aa672f3 into master Feb 21, 2026
8 checks passed
@AnthonyRonning AnthonyRonning deleted the fix/streaming-tool-call-passthrough branch February 21, 2026 19:02
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.

1 participant