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:
- Detection – Verify the message content begins with
<thinking> - Validation – Confirm a matching
</thinking>closing tag exists - Extraction – Capture the substring between tags and assign to
message.reasoning_content - 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 textreasoning_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_contentmethod handles detection, validation, extraction, and cleanup in four sequential steps - Extracted reasoning populates
message.reasoning_contentwhile the cleaned answer remains inmessage.content - The
Messagemodel inaisuite/framework/message.pyprovides dedicatedreasoning_tokenstracking - Unit tests in
tests/client/test_client.pyvalidate 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →