react-headless: built-in stream adapters drop reasoning/thinking output instead of emitting `REASONING_*` events

Open
#1,413 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
30/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
react, typescript
Domain
api, frontend

Research direction

Start in packages/react-headless/src/stream/adapters/ and read how each built-in adapter maps its provider stream to AG-UI events, beginning with the OpenAI Responses and Chat Completions adapters. Check the REASONING_MESSAGE_* event types in @ag-ui/[email protected]. Before writing code, get maintainer answers to the three open questions in the issue, since they decide the event scope and whether reasoning is opt-in. Done means each targeted adapter emits the reasoning events, with a per-adapter fixture test and a patch changeset.

Written by the indexing model from the issue text.

Description

Is your feature request related to a problem? Please describe.

#414 covers consuming AG-UI reasoning events in processStreamedMessage and rendering them in react-ui (in progress in #594). But the built-in stream adapters in @openuidev/react-headless never produce those events. Each one drops reasoning before it reaches processStreamedMessage:

Adapter Reasoning on the wire What happens today
openAIResponsesAdapter response.reasoning_summary_text.delta / .done, response.reasoning_text.delta / .done No matching case, ignored
openAIAdapter (Chat Completions) and openAIReadableStreamAdapter delta.reasoning_content (DeepSeek, Qwen, vLLM and other OpenAI-compatible servers), delta.reasoning (OpenRouter) Only delta.content and delta.tool_calls are read
vercelAIAdapter reasoning-start / reasoning-delta / reasoning-end UI stream parts No matching case, ignored
langGraphAdapter reasoning / thinking content blocks on AI message chunks Content blocks are filtered to type === "text"

So even once #594 lands, only backends that speak AG-UI natively will show reasoning. Anyone using the OpenAI, DeepSeek, OpenRouter, Vercel AI SDK or LangGraph adapters will still see nothing.

Describe the solution you'd like

Map each provider's reasoning stream to the AG-UI events @ag-ui/[email protected] already defines:

  • REASONING_MESSAGE_START when reasoning begins
  • REASONING_MESSAGE_CONTENT for each delta
  • REASONING_MESSAGE_END when reasoning finishes or the first text/tool call arrives

Scope:

  • Adapter changes only, in packages/react-headless/src/stream/adapters/. No changes to processStreamedMessage, message types or UI, so this does not overlap with #594.
  • Until #594 (or another consumer) lands, processStreamedMessage ignores these events, so this is a no-op for existing users.
  • Unit tests per adapter with hand-crafted stream fixtures, matching the existing adapter tests.
  • A changeset for @openuidev/react-headless (patch).

I'd suggest starting with the OpenAI Responses and Chat Completions adapters, then Vercel AI SDK and LangGraph, either in the same PR or as follow-ups, whichever you prefer.

Describe alternatives you've considered

  • Each app writes its own adapter wrapper to translate reasoning. This duplicates provider-specific parsing that the built-in adapters already own.
  • Handling provider formats inside processStreamedMessage. This would break the current split, where adapters normalise to AG-UI and processStreamedMessage consumes AG-UI only.

Additional context

Questions for maintainers:

  1. Should adapters also emit the outer REASONING_START / REASONING_END pair, or only the REASONING_MESSAGE_* events?
  2. Is reasoning wanted by default, or behind an adapter option (e.g. openAIAdapter({ reasoning: true })) so existing apps don't receive new events unexpectedly?
  3. One PR for all four adapters, or OpenAI first?

I'd be happy to implement this once the direction is confirmed.

Dominant language
TypeScript
Stars
10k
Forks
698
Avg merge
1d 3h
Merged PRs (30d)
133

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from thesysdev/openui

All issues in thesysdev/openui

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.