Skip to content

feat(ai-gemini): stream structured outputs natively - #971

Open
Missing-Identity wants to merge 2 commits into
TanStack:mainfrom
Missing-Identity:feat/gemini-structured-output-stream
Open

feat(ai-gemini): stream structured outputs natively#971
Missing-Identity wants to merge 2 commits into
TanStack:mainfrom
Missing-Identity:feat/gemini-structured-output-stream

Conversation

@Missing-Identity

@Missing-Identity Missing-Identity commented Jul 21, 2026

Copy link
Copy Markdown

What changed

  • add native structuredOutputStream support to the standard Gemini text adapter
  • add native structured-output streaming to the experimental Gemini Interactions adapter
  • accumulate and parse streamed JSON before emitting structured-output.complete
  • preserve interaction ID and run-finished event ordering
  • add focused adapter coverage, enable Gemini in the structured-output-stream E2E matrix, and add a minor changeset

Closes #570.

Validation

  • focused Gemini adapter tests: 46 passed
  • complete @tanstack/ai-gemini test suite: 239 passed
  • @tanstack/ai-gemini TypeScript check: passed
  • @tanstack/ai-gemini ESLint: no errors; seven pre-existing warnings
  • @tanstack/ai-gemini production build: passed
  • git diff --check: passed

Limitations

The hosted environment could not download Playwright Chromium, so browser E2E execution was not claimed. The existing structured-output-stream E2E matrix was updated to include Gemini.

Summary by CodeRabbit

  • New Features
    • Added native structured-output streaming for Gemini text generation.
    • Added structured-output streaming support for the experimental Gemini Interactions API.
    • Streams now emit parsed JSON results and original text before final completion.
  • Improved Reliability
    • Enhanced handling and reporting for empty, truncated, invalid, or provider-failing streams.
  • Tests
    • Expanded adapter and end-to-end coverage for Gemini structured-output streaming.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8c2d2dd6-a4f3-440f-98f2-91bc0b15ae6b

📥 Commits

Reviewing files that changed from the base of the PR and between d3aa104 and af20c54.

📒 Files selected for processing (6)
  • .changeset/tidy-gemini-streams.md
  • packages/ai-gemini/src/adapters/text.ts
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • packages/ai-gemini/tests/gemini-adapter.test.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts
  • testing/e2e/src/lib/feature-support.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • .changeset/tidy-gemini-streams.md
  • testing/e2e/src/lib/feature-support.ts
  • packages/ai-gemini/tests/gemini-adapter.test.ts
  • packages/ai-gemini/src/adapters/text.ts
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Native structured-output streaming was added to the Gemini text and experimental Gemini Interactions adapters. Both accumulate JSON deltas, emit parsed completion events before terminal events, handle stream failures, and add tests plus E2E feature coverage.

Changes

Gemini structured-output streaming

Layer / File(s) Summary
Gemini text streaming
packages/ai-gemini/src/adapters/text.ts, packages/ai-gemini/tests/gemini-adapter.test.ts
GeminiTextAdapter streams JSON responses, emits incremental content, and produces structured-output.complete before RUN_FINISHED. Standardized error events cover stream failures.
Gemini Interactions streaming
packages/ai-gemini/src/experimental/text-interactions/adapter.ts, packages/ai-gemini/tests/text-interactions-adapter.test.ts
GeminiTextInteractionsAdapter streams schema-constrained responses, preserves interaction IDs, parses accumulated JSON, and validates completion ordering and chaining.
Streaming coverage and release metadata
testing/e2e/src/lib/feature-support.ts, .changeset/tidy-gemini-streams.md
Gemini is added to the structured-output-stream feature matrix, and the package receives a minor changeset.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to af20c

This PR adds native structured-output streaming for Gemini adapters with focused coverage and no actionable merge-blocking risk remaining after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant GeminiAdapter
  participant GeminiAPI
  participant Consumer
  Caller->>GeminiAdapter: structuredOutputStream(options)
  GeminiAdapter->>GeminiAPI: Request JSON schema with streaming enabled
  GeminiAPI-->>GeminiAdapter: JSON text deltas
  GeminiAdapter-->>Consumer: TEXT_MESSAGE_CONTENT chunks
  GeminiAdapter-->>Consumer: structured-output.complete
  GeminiAdapter-->>Consumer: RUN_FINISHED
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 5 files. (1 skipped: 1 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes native structured-output streaming for the Gemini adapter.
Description check ✅ Passed The description covers the implementation, validation, limitations, and changeset, but omits the template checklist and release-impact sections.
Linked Issues check ✅ Passed The changes implement native streaming for both Gemini adapters, add terminal-event and ordering tests, and enable Gemini in the E2E matrix as required by [#570].
Out of Scope Changes check ✅ Passed The changes remain within the linked issue scope and do not add unrelated functionality or modality support.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ai-gemini/src/adapters/text.ts`:
- Around line 229-283: The structuredOutputStream method uses inconsistent run
IDs between stream processing and structured-stream errors. Resolve a single
runId, using the existing override-or-generated fallback behavior, create an
options object containing it, and pass that same object to processStreamChunks
and every structuredStreamError call so all emitted events share the resolved
ID.

In `@packages/ai-gemini/tests/gemini-adapter.test.ts`:
- Line 3: Reorder the named imports from `@tanstack/ai` alphabetically to satisfy
ESLint sort-imports in packages/ai-gemini/tests/gemini-adapter.test.ts:3-3 and
packages/ai-gemini/tests/text-interactions-adapter.test.ts:3-3; update only the
import member ordering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c313a8d4-d80c-4e8d-a85c-1fc5ab15f7ca

📥 Commits

Reviewing files that changed from the base of the PR and between 7c7aa09 and 35b371e.

📒 Files selected for processing (6)
  • .changeset/tidy-gemini-streams.md
  • packages/ai-gemini/src/adapters/text.ts
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • packages/ai-gemini/tests/gemini-adapter.test.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts
  • testing/e2e/src/lib/feature-support.ts

Comment thread packages/ai-gemini/src/adapters/text.ts Outdated
Comment thread packages/ai-gemini/tests/gemini-adapter.test.ts Outdated
@tombeckenham

Copy link
Copy Markdown
Contributor

Thanks for the PR, @Missing-Identity! 🙌 @jherr will take a look.

Automated pre-review checks

  • ✅ CI passing
  • ✅ No merge conflicts
  • ✅ Changeset present
  • ✅ E2E test changes included

Automated triage — a human review follows.

@tombeckenham tombeckenham added the waiting-on: maintainer The ball is in the maintainers’ court label Jul 23, 2026
@tombeckenham
tombeckenham force-pushed the feat/gemini-structured-output-stream branch from 32f4a91 to a259d22 Compare August 10, 2026 09:13
@nx-cloud

nx-cloud Bot commented Aug 10, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit af20c54

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 11s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-22 21:40:14 UTC

@pkg-pr-new

pkg-pr-new Bot commented Aug 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@971

@tanstack/ai-acp

npm i https://pkg.pr.new/@tanstack/ai-acp@971

@tanstack/ai-angular

npm i https://pkg.pr.new/@tanstack/ai-angular@971

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@971

@tanstack/ai-bedrock

npm i https://pkg.pr.new/@tanstack/ai-bedrock@971

@tanstack/ai-byteplus

npm i https://pkg.pr.new/@tanstack/ai-byteplus@971

@tanstack/ai-claude-code

npm i https://pkg.pr.new/@tanstack/ai-claude-code@971

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@971

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@971

@tanstack/ai-code-mode-snippets

npm i https://pkg.pr.new/@tanstack/ai-code-mode-snippets@971

@tanstack/ai-codex

npm i https://pkg.pr.new/@tanstack/ai-codex@971

@tanstack/ai-cohere

npm i https://pkg.pr.new/@tanstack/ai-cohere@971

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@971

@tanstack/ai-durable-stream

npm i https://pkg.pr.new/@tanstack/ai-durable-stream@971

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@971

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@971

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@971

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@971

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@971

@tanstack/ai-grok-build

npm i https://pkg.pr.new/@tanstack/ai-grok-build@971

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@971

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@971

@tanstack/ai-isolate-daytona

npm i https://pkg.pr.new/@tanstack/ai-isolate-daytona@971

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@971

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@971

@tanstack/ai-isolate-quickjs-bun

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs-bun@971

@tanstack/ai-llmgateway

npm i https://pkg.pr.new/@tanstack/ai-llmgateway@971

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@971

@tanstack/ai-memory

npm i https://pkg.pr.new/@tanstack/ai-memory@971

@tanstack/ai-mistral

npm i https://pkg.pr.new/@tanstack/ai-mistral@971

@tanstack/ai-octane

npm i https://pkg.pr.new/@tanstack/ai-octane@971

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@971

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@971

@tanstack/ai-opencode

npm i https://pkg.pr.new/@tanstack/ai-opencode@971

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@971

@tanstack/ai-perplexity

npm i https://pkg.pr.new/@tanstack/ai-perplexity@971

@tanstack/ai-persistence

npm i https://pkg.pr.new/@tanstack/ai-persistence@971

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@971

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@971

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@971

@tanstack/ai-sandbox

npm i https://pkg.pr.new/@tanstack/ai-sandbox@971

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-sandbox-cloudflare@971

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/@tanstack/ai-sandbox-daytona@971

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/@tanstack/ai-sandbox-docker@971

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/@tanstack/ai-sandbox-local-process@971

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/@tanstack/ai-sandbox-sprites@971

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/@tanstack/ai-sandbox-vercel@971

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@971

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@971

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@971

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@971

@tanstack/ai-vercel-gateway

npm i https://pkg.pr.new/@tanstack/ai-vercel-gateway@971

@tanstack/ai-vertex

npm i https://pkg.pr.new/@tanstack/ai-vertex@971

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@971

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@971

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@971

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@971

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@971

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@971

commit: af20c54

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the PR, @Missing-Identity! 🙌 @jherr will take a look.

Automated pre-review checks

  • ✅ CI passing
  • ✅ No merge conflicts
  • ✅ Changeset present
  • ✅ E2E test changes included

Automated triage — a human review follows.

@github-actions github-actions Bot added waiting-on: author Waiting for the author to respond or update and removed waiting-on: maintainer The ball is in the maintainers’ court labels Aug 13, 2026
@tombeckenham
tombeckenham force-pushed the feat/gemini-structured-output-stream branch 2 times, most recently from ecfcce6 to 3f1aa81 Compare August 20, 2026 10:40
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@tombeckenham
tombeckenham force-pushed the feat/gemini-structured-output-stream branch 2 times, most recently from de64b24 to 77ee888 Compare August 21, 2026 21:07
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions github-actions Bot added waiting-on: maintainer The ball is in the maintainers’ court merge-conflicts Conflicts with the base branch — needs a rebase waiting-on: author Waiting for the author to respond or update and removed waiting-on: author Waiting for the author to respond or update waiting-on: maintainer The ball is in the maintainers’ court merge-conflicts Conflicts with the base branch — needs a rebase labels Aug 21, 2026
@github-actions github-actions Bot added merge-conflicts Conflicts with the base branch — needs a rebase waiting-on: author Waiting for the author to respond or update and removed merge-conflicts Conflicts with the base branch — needs a rebase waiting-on: maintainer The ball is in the maintainers’ court labels Aug 22, 2026
@tombeckenham
tombeckenham force-pushed the feat/gemini-structured-output-stream branch from 77ee888 to af20c54 Compare August 22, 2026 21:28
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions github-actions Bot added waiting-on: maintainer The ball is in the maintainers’ court and removed waiting-on: author Waiting for the author to respond or update merge-conflicts Conflicts with the base branch — needs a rebase labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on: maintainer The ball is in the maintainers’ court

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ai-gemini): native structuredOutputStream for geminiText and geminiTextInteractions

3 participants