How aisuite Handles Provider-Specific Thinking/Reasoning Content Extraction

aisuite extracts provider-specific thinking content by parsing <thinking> XML tags from model responses, automatically separating reasoning from final answers into dedicated reasoning_content and reasoning_tokens fields.

The aisuite library provides a unified interface for multiple LLM providers while preserving access to each model's internal reasoning process. This article examines how the framework implements provider-agnostic thinking content extraction based on the source code in andrewyng/aisuite.

The <thinking> Tag Convention

aisuite adopts a simple XML-style tagging convention that providers can use to delineate reasoning from final output. When a model returns content wrapped in <thinking>...</thinking> tags, the framework automatically extracts this content.

The extraction logic lives in aisuite/client.py within the _extract_thinking_content method.

Step-by-Step Extraction Process

The extraction follows four sequential operations:

  1. Detection – Verify the message content begins with <thinking>
  2. Validation – Confirm a matching </thinking> closing tag exists
  3. Extraction – Capture the substring between tags and assign to message.reasoning_content
  4. Cleanup – Remove the tags and surrounding whitespace from message.content, leaving only the final answer

Here's the implementation pattern from aisuite/client.py:


# Pseudocode representing the extraction logic

def _extract_thinking_content(self, message):
    content = message.content
    if not content.startswith("<thinking>"):
        return
    
    end_tag = "</thinking>"
    end_pos = content.find(end_tag)
    if end_pos == -1:
        return  # Malformed: no closing tag

    
    # Extract reasoning

    reasoning = content[len("<thinking>"):end_pos].strip()
    message.reasoning_content = reasoning
    
    # Cleanup main content

    final_content = content[end_pos + len(end_tag):].strip()
    message.content = final_content

The Message Model Structure

The Message class in aisuite/framework/message.py provides dedicated fields for reasoning metadata:

  • reasoning_content – The extracted thinking text
  • reasoning_tokens – Token count for the reasoning portion (populated when available from the provider)
from aisuite.framework import Message

# After extraction, message has both fields populated

message.content           # Final answer only

message.reasoning_content # Reasoning/thinking content

message.reasoning_tokens  # Optional token count

Practical Usage Example

Consider a provider that returns combined content like this:

raw_response = """
<thinking>
First, preheat the oven to 350°F. Then mix the dry ingredients separately from the wet ingredients. Fold together gently to avoid over-mixing.
</thinking>

Here is the final recipe.
"""

After aisuite processing:

import aisuite

client = aisuite.Client()
resp = client.chat.completions.create(
    model="provider:model",
    messages=[{"role": "user", "content": "Give me a cake recipe"}]
)

print(resp.choices[0].message.content)

# Output: "Here is the final recipe."

print(resp.choices[0].message.reasoning_content)

# Output: "First, preheat the oven to 350°F. Then mix the dry ingredients..."

Token Usage Handling

When available, aisuite also extracts reasoning_tokens from provider responses. This enables accurate cost tracking and performance analysis, separating reasoning overhead from final answer generation.

The token extraction occurs in the same response processing pipeline, with providers optionally populating this field based on their native API capabilities.

Testing and Validation

The extraction behavior is validated in tests/client/test_client.py, which confirms:

  • Proper parsing of well-formed <thinking> blocks
  • Graceful handling of missing or malformed tags
  • Correct whitespace trimming in both extracted and remaining content
  • Preservation of original content when no thinking tags are present

Provider Integration Notes

Providers implementing thinking support should:

  • Wrap reasoning content in <thinking>...</thinking> XML tags
  • Place tags at the very beginning of the response content
  • Include the final answer after the closing tag

This convention maintains compatibility with the unified extraction logic while requiring no provider-specific code paths in the client.

Summary

  • aisuite implements provider-agnostic thinking extraction through XML tag parsing in aisuite/client.py
  • The _extract_thinking_content method handles detection, validation, extraction, and cleanup in four sequential steps
  • Extracted reasoning populates message.reasoning_content while the cleaned answer remains in message.content
  • The Message model in aisuite/framework/message.py provides dedicated reasoning_tokens tracking
  • Unit tests in tests/client/test_client.py validate extraction correctness across edge cases

Frequently Asked Questions

Which LLM providers support thinking content extraction in aisuite?

Any provider can support thinking extraction by returning content wrapped in <thinking> tags. The framework itself is provider-agnostic—extraction depends entirely on whether the underlying model and provider implementation use this tagging convention in their responses.

What happens if thinking tags are malformed or missing?

If the content lacks <thinking> tags or has malformed XML (missing closing tag), the _extract_thinking_content method returns early without modification. The original content remains intact in message.content, and reasoning_content stays empty.

How does aisuite count tokens for reasoning versus final answers?

Token usage depends on provider API support. When available, reasoning_tokens is populated from the provider's response metadata. The framework separates this from standard usage fields to enable distinct tracking of reasoning overhead.

Can I disable thinking extraction for specific requests?

Thinking extraction is automatic when tags are present and cannot be disabled per-request in the current implementation. To prevent extraction, providers must omit <thinking> tags from their responses entirely.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →