Skip to content

feat: add extended thinking (reasoning) support for Anthropic models#55

Draft
masudahiroto wants to merge 12 commits intomainfrom
masudahiroto/extended-thinking-support-v2
Draft

feat: add extended thinking (reasoning) support for Anthropic models#55
masudahiroto wants to merge 12 commits intomainfrom
masudahiroto/extended-thinking-support-v2

Conversation

@masudahiroto
Copy link
Copy Markdown
Contributor

@masudahiroto masudahiroto commented Apr 6, 2026

Add support for Anthropic's extended thinking feature across the full stack. When enabled, the server streams reasoning events to the client, which renders them in a collapsible Reasoning component with shimmer animation.

Server: AISDKAgent emits REASONING_START/REASONING_DELTA/REASONING_END events, converts reasoning parts between AI SDK and Anthropic message formats, and preserves reasoning signatures across multi-turn conversations. MockReasoningModel added under agents/testing/ for dev/test usage.

Client: New Reasoning component handles streaming and completed reasoning display. useServerEvents manages REASONING_* event lifecycle. Reasoning parts are persisted in chat history. mergeAssistantMessages updated to consolidate reasoning parts.

Core: REASONING_START, REASONING_DELTA, REASONING_END added to AG-UI event types.

E2E tests cover single-turn, multi-turn, and multi-step reasoning scenarios.

Note: This PR is branched from #54. #54 has to be merged first.

deer-agent and others added 12 commits April 2, 2026 22:47
When a multi-step agent run produces multiple steps each with text AND
tool calls, the conversation context was losing per-step boundaries.
After page reload, all tool calls were merged into one assistant message
and all text was concatenated into a separate message, causing the LLM
to misunderstand previous turns.

Server: Move hasEmittedTextStart/messageId to StepContext so
TEXT_MESSAGE_START/END is emitted per step instead of per run.
Client: Add STEP_FINISHED handler to flush per-step messages while
maintaining backward compatibility with servers without step events.
useServerEvents: Fix extractTurnMessages to preserve assistant content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… flash

Two UI issues with per-step TEXT_MESSAGE emission:

1. Streaming text cleared at TEXT_MESSAGE_END caused flash between steps.
   Fix: accumulate text across steps via runTextRef, only clear at
   RUN_FINISHED.

2. Intermediate assistant messages with text+toolCalls displayed as
   separate bubbles. Fix: hide all assistant messages with toolCalls
   from display, combine all step text into the final saved message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Assistant messages now render with transparent background and minimal
padding for a cleaner, less cluttered chat appearance. User messages
retain the existing bubble style.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
saveAIResponse was using runTextRef (accumulated text from all steps)
instead of client.currentMessageContent (last step only). Since
intermediate steps' text is already preserved in turnMessages via
extractTurnMessages, the final message duplicated that text.

Use client.currentMessageContent for the saved message content.
runTextRef continues to be used for streaming UI display only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ntation

Tests were re-implementing extractTurnMessages locally, so bugs in the
real function would not be caught. Export extractTurnMessages from
useServerEvents.ts and import it in tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests were re-implementing transformMessagesToClientFormat locally.
Export from useChatManagement.ts and import in both persistence test
files so bugs in the real function are caught by tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per-step messages are preserved for correct LLM context, but the UI
now combines consecutive assistant messages within each turn into a
single bubble. Intermediate assistant messages (with toolCalls) have
their text merged with the final text-only message using paragraph
separators.

Add mergeAssistantMessagesForDisplay utility with 8 unit tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 5 scattered test files (~1850 lines) with 2 focused test files
(~350 lines) that directly verify the core bug fix: per-step text+tool
association is preserved in conversation context sent to LLM on 2nd run.

- client.multiStepContext.test.ts: integration test covering message
  assembly, 2nd run_agent context correctness, and text deduplication
- AISDKAgent.perStepEvents.test.ts: server unit test for per-step
  TEXT_MESSAGE_START/END emission and event ordering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sages tests

- Replace runTextRef (accumulated string never read) with
  hasTextFromPriorStepRef boolean for step separator logic
- Add unit tests for mergeAssistantMessagesForDisplay (7 cases:
  simple exchange, multi-step merge, tool filtering, tool-only step,
  multiple turns, property preservation, ContentPart arrays)
- Strengthen extractTurnMessages assertions in integration test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ests

Replace Date.now() with constituent message IDs to produce stable React
keys. Update stale JSDoc in extractTurnMessages to reflect STEP_FINISHED
flushing. Add tests for empty input, trailing pending text, and ID
determinism.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add support for Anthropic's extended thinking feature across the full
stack. When enabled, the server streams reasoning events to the client,
which renders them in a collapsible Reasoning component.

Server:
- AISDKAgent emits REASONING_START/REASONING_DELTA/REASONING_END events
- Convert reasoning parts between AI SDK and Anthropic message formats
- Preserve reasoning signatures across multi-turn conversations
- Add MockReasoningModel under agents/testing/ for dev/test usage

Client:
- New Reasoning component with shimmer animation during streaming
- useServerEvents handles REASONING_* event lifecycle
- Reasoning parts persisted in chat history (reasoningParts on messages)
- mergeAssistantMessages updated to consolidate reasoning parts

Core:
- Add REASONING_START, REASONING_DELTA, REASONING_END to AG-UI event types

E2E:
- Extended thinking tests covering single-turn, multi-turn, and
  multi-step reasoning scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant