# How aisuite Handles Message Format Conversion Between Diverse LLM Providers

> Learn how aisuite simplifies LLM message format conversion. It unifies formats using an internal Message model and provider-specific converters for seamless integration.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-07-27

---

**aisuite normalizes message format conversion by using a unified internal `Message` model and provider-specific converter classes that translate requests and responses between OpenAI-compatible schemas and vendor-specific formats like Anthropic's content blocks or Google's Vertex AI `Content` objects.**

aisuite is an open-source Python library developed by Andrew Ng's team to simplify integration with multiple large language model providers. The framework's architecture centers on **message format conversion** logic that abstracts away API differences, allowing developers to use a single internal representation while the library handles provider-specific payload transformations.

## Message Format Conversion Architecture

The foundation of aisuite's interoperability lies in its two-layer conversion system defined in `aisuite.framework.message.Message` and implemented across provider-specific modules.

### The Base Converter Pattern

At the core is `OpenAICompliantMessageConverter` located in [`aisuite/providers/message_converter.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/message_converter.py). This base class provides OpenAI-compatible defaults for tool-result handling, usage extraction, and response shaping. Each provider extends this base:

- **Anthropic**: `AnthropicMessageConverter` in [`aisuite/providers/anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/anthropic_provider.py)
- **Google**: `GoogleMessageConverter` in [`aisuite/providers/google_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/google_provider.py)
- **Groq**: `GroqMessageConverter` in [`aisuite/providers/groq_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/groq_provider.py) (inherits base directly)

Provider classes like `OpenaiProvider` or `AnthropicProvider` instantiate these converters and delegate all message-format work to them:

```python

# Simplified flow from OpenaiProvider

transformed = self.transformer.convert_request(messages)
response = self.client.chat.completions.create(model=model, messages=transformed, **kwargs)

```

## Request-Side Conversion

When sending messages to an LLM, `convert_request` performs two critical transformations: normalization and role mapping.

### Message Normalization and Role Mapping

The conversion pipeline first ensures every message element is a plain dictionary via `model_dump(mode="json")`. Then it maps roles according to provider requirements:

- **OpenAI-compatible providers** (OpenAI, Groq): Preserve native roles (`user`, `assistant`, `tool`)
- **Anthropic**: Maps `user` → `user`, `assistant` → `assistant`, but converts `tool` role to `user` with a special `"tool_result"` content block
- **Google Vertex AI**: Constructs `Content` objects with `role="user"` or `role="model"`, creating `Part` objects with `function_call` fields for tool interactions

### Tool-Result Handling

For tool results (role=`tool`), the base `OpenAICompliantMessageConverter` supports `tool_results_as_strings=True` to coerce content to strings. Provider-specific converters like Anthropic's embed these in vendor-specific structures such as `"tool_result"` blocks, while Google wraps them in `function_call` parts.

## Response-Side Normalization

Each converter implements `convert_response` to transform vendor-specific outputs into aisuite's unified `ChatCompletionResponse`.

### Building the Standardized Response

The method creates a fresh `ChatCompletionResponse` matching OpenAI's schema structure:

1. Copies assistant text into `choices[0].message.content`
2. Detects tool calls and builds `ChatCompletionMessageToolCall` objects
3. Extracts token usage into `CompletionUsage` objects

Provider-specific detection logic varies:

- **OpenAI**: Passes through unchanged (native format)
- **Anthropic**: Inspects content blocks for `tool_use` types and constructs OpenAI-style tool call dictionaries
- **Google**: Examines the first `Part` of the candidate for `function_call` presence

## Streaming Support

For streaming implementations, converters provide `convert_stream_event` methods that translate vendor-specific streaming events into `ChatCompletionChunk` objects with unified `ChoiceDelta` structures. This allows downstream code to consume streaming tokens, tool-call deltas, and partial transcriptions without provider-specific parsing logic.

## Practical Usage Example

The following demonstrates how the same internal `Message` list works across different providers without format modification:

```python
from aisuite import aisuite
from aisuite.providers import AnthropicProvider, OpenaiProvider

# Build chat history using the internal Message model

messages = [
    aisuite.framework.message.Message(role="user", content="What's the weather in Paris?"),
]

# Anthropic provider auto-converts the request

anthropic = AnthropicProvider(api_key="…")
anthropic_response = anthropic.chat_completions_create(
    model="claude-3-5-sonnet-20240620", messages=messages
)
print(anthropic_response.choices[0].message.content)

# Switch to OpenAI with identical message format

openai = OpenaiProvider(api_key="…")
openai_response = openai.chat_completions_create(
    model="gpt-4o-mini", messages=messages
)
print(openai_response.choices[0].message.content)

```

## Key Implementation Files

The message format conversion system spans these critical files in the `andrewyng/aisuite` repository:

- [`aisuite/providers/message_converter.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/message_converter.py) — Base `OpenAICompliantMessageConverter` class
- [`aisuite/providers/anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/anthropic_provider.py) — `AnthropicMessageConverter` implementation
- [`aisuite/providers/google_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/google_provider.py) — `GoogleMessageConverter` with Vertex AI support
- [`aisuite/providers/groq_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/groq_provider.py) — `GroqMessageConverter` (OpenAI-compliant inheritance)
- [`aisuite/providers/openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/openai_provider.py) — Direct base converter usage
- [`aisuite/framework/message.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/framework/message.py) — Internal `Message` model definition
- [`aisuite/framework/chat_completion_response.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/framework/chat_completion_response.py) — Unified response schema

## Summary

- aisuite uses a **unified internal `Message` model** to abstract provider differences
- **Provider-specific converters** (e.g., `AnthropicMessageConverter`, `GoogleMessageConverter`) handle translation in `aisuite/providers/`
- **Request conversion** includes role mapping (Anthropic tool→user, Google Content objects) and message normalization via `convert_request`
- **Response normalization** produces OpenAI-compatible `ChatCompletionResponse` objects regardless of source API
- **Streaming support** is achieved through `convert_stream_event` methods that yield standardized `ChatCompletionChunk` objects

## Frequently Asked Questions

### How does aisuite handle different role naming conventions between providers?

aisuite's converter classes map internal roles to provider-specific strings during request transformation. For example, `AnthropicMessageConverter` maps the internal `tool` role to `user` with a `"tool_result"` content type, while `GoogleMessageConverter` translates roles to `"user"` or `"model"` for Vertex AI. OpenAI-compatible providers use the internal roles directly without modification.

### Can I use the same message history with multiple providers in aisuite?

Yes. By instantiating different providers (e.g., `AnthropicProvider`, `OpenaiProvider`) with the same `messages` list built from `aisuite.framework.message.Message` objects, aisuite automatically handles the format conversion. Each provider's `convert_request` method transforms the unified model into the vendor-specific payload required by that API.

### What happens to tool calls in responses from non-OpenAI providers?

Converters inspect provider-specific response structures and normalize them into OpenAI-compatible `ChatCompletionMessageToolCall` objects. Anthropic's converter checks for `tool_use` content blocks, while Google's converter looks for `function_call` in response parts. Both return a standardized `ChatCompletionResponse` with `tool_calls` populated in the expected format.

### How does aisuite manage streaming responses across different APIs?

Each provider implements a `convert_stream_event` method that translates vendor-specific streaming events (SSE chunks, Vertex AI streaming objects, etc.) into `ChatCompletionChunk` objects containing `ChoiceDelta` data. This ensures that consuming code can process streaming tokens, tool-call deltas, and completion events through a single interface regardless of the underlying LLM provider.