Skip to content

[Feature] Auto-strip <think> reasoning tags in OpenAI adapter #45

@best

Description

@best

Problem

Many reasoning models (MiniMax-M2.5, DeepSeek R1, QwQ, etc.) return <think>...</think> blocks in their content field when called via OpenAI-compatible API. This causes:

  1. Structured output failuregenerateObject tries to JSON.parse response text that starts with <think>, fails every retry, times out
  2. Tool calling failure — Agent ReAct loop may not parse tool results correctly
  3. Dirty output — Users see raw thinking process mixed with the actual response

Example raw response from MiniMax-M2.5:

{
  "content": "<think>\nThe user wants me to...\n</think>\n\nActual response here"
}

Solution

In the OpenAI adapter layer (openai-adapter.ts), auto-detect and strip <think>...</think> tags from response content.

Requirements

  • Strip <think>...</think> from response.text in both generate() and generateWithTools()
  • Preserve the thinking content in a separate field (e.g., response.reasoning) for observability
  • Handle streaming mode: buffer and strip thinking tokens from the stream
  • Handle edge cases: multiple think blocks, unclosed tags, nested tags
  • Regex pattern: /^<think>[\s\S]*?<\/think>\s*/ (greedy match from start)

Affected code

  • packages/ai/src/adapters/openai-adapter.ts — core parsing logic
  • packages/ai/src/stream.ts — streaming mode handling

Acceptance Criteria

  • response.text is clean (no <think> tags) for all generate methods
  • Thinking content preserved in response.reasoning (optional field)
  • Streaming mode correctly strips thinking tokens
  • generateObject (structured output) works with reasoning models
  • Tool calling works with reasoning models
  • Existing unit tests pass (no regression)
  • New tests for think-tag stripping added

Priority

P1 — Blocks real API validation of examples and E2E tests

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions