# How aisuite Handles Provider-Specific Thinking/Reasoning Content Extraction

> Learn how aisuite extracts provider-specific thinking and reasoning content using XML tags, separating it into dedicated fields for cleaner analysis.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: internals
- Published: 2026-08-03

---

**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`](https://github.com/andrewyng/aisuite/blob/main/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`](https://github.com/andrewyng/aisuite/blob/main/aisuite/client.py):

```python

# 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`](https://github.com/andrewyng/aisuite/blob/main/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)

```python
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:

```python
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:

```python
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`](https://github.com/andrewyng/aisuite/blob/main/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`](https://github.com/andrewyng/aisuite/blob/main/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`](https://github.com/andrewyng/aisuite/blob/main/aisuite/framework/message.py) provides dedicated `reasoning_tokens` tracking
- Unit tests in [`tests/client/test_client.py`](https://github.com/andrewyng/aisuite/blob/main/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.