> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://openrouter.ai/docs/llms.txt.
> For full documentation content, see https://openrouter.ai/docs/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://openrouter.ai/docs/_mcp/server.

# Message Formats

## OpenAI Chat Format

### fromChatMessages()

Convert OpenAI chat-style messages to OpenResponses input:

```typescript
import { OpenRouter, fromChatMessages } from '@openrouter/agent';

const openrouter = new OpenRouter({
  apiKey: process.env.OPENROUTER_API_KEY,
});

// OpenAI chat format
const chatMessages = [
  { role: 'system', content: 'You are a helpful assistant.' },
  { role: 'user', content: 'Hello!' },
  { role: 'assistant', content: 'Hi there! How can I help you?' },
  { role: 'user', content: 'What is the weather like?' },
];

const result = openrouter.callModel({
  model: 'openai/gpt-5-nano',
  input: fromChatMessages(chatMessages),
});

const text = await result.getText();
```

### toChatMessage()

Convert an OpenResponses response to chat message format:

```typescript
import { toChatMessage } from '@openrouter/agent';

const result = openrouter.callModel({
  model: 'openai/gpt-5-nano',
  input: 'Hello!',
});

const response = await result.getResponse();
const chatMessage = toChatMessage(response);

// chatMessage is now: { role: 'assistant', content: '...' }
console.log(chatMessage.role);    // 'assistant'
console.log(chatMessage.content); // Response text
```

### Supported Message Types

| Chat Role   | Description            |
| ----------- | ---------------------- |
| `system`    | System instructions    |
| `user`      | User messages          |
| `assistant` | Assistant responses    |
| `developer` | Developer instructions |
| `tool`      | Tool response messages |

### Tool Messages

Tool responses are converted to function call outputs:

```typescript
const chatMessages = [
  { role: 'user', content: 'What is the weather?' },
  {
    role: 'assistant',
    content: null,
    tool_calls: [{
      id: 'call_123',
      type: 'function',
      function: { name: 'get_weather', arguments: '{"location":"Paris"}' },
    }],
  },
  {
    role: 'tool',
    tool_call_id: 'call_123',
    content: '{"temperature": 20}',
  },
];

const input = fromChatMessages(chatMessages);
```

## Anthropic Claude Format

### fromClaudeMessages()

Convert Anthropic Claude-style messages to OpenResponses input:

```typescript
import { OpenRouter, fromClaudeMessages } from '@openrouter/agent';

// Claude format
const claudeMessages = [
  { role: 'user', content: 'Hello!' },
  { role: 'assistant', content: 'Hi there!' },
  { role: 'user', content: 'Tell me about TypeScript.' },
];

const result = openrouter.callModel({
  model: 'anthropic/claude-sonnet-4.5',
  input: fromClaudeMessages(claudeMessages),
});
```

### toClaudeMessage()

Convert an OpenResponses response to Claude message format:

```typescript
import { toClaudeMessage } from '@openrouter/agent';

const result = openrouter.callModel({
  model: 'anthropic/claude-sonnet-4.5',
  input: 'Hello!',
});

const response = await result.getResponse();
const claudeMessage = toClaudeMessage(response);

// Compatible with Anthropic SDK types
```

### Content Blocks

Claude's content block format is supported:

```typescript
const claudeMessages = [
  {
    role: 'user',
    content: [
      { type: 'text', text: 'What is in this image?' },
      {
        type: 'image',
        source: {
          type: 'url',
          url: 'https://example.com/image.jpg',
        },
      },
    ],
  },
];

const input = fromClaudeMessages(claudeMessages);
```

### Tool Use Blocks

Claude's tool use format is converted:

```typescript
const claudeMessages = [
  { role: 'user', content: 'What is the weather?' },
  {
    role: 'assistant',
    content: [
      {
        type: 'tool_use',
        id: 'tool_123',
        name: 'get_weather',
        input: { location: 'Paris' },
      },
    ],
  },
  {
    role: 'user',
    content: [
      {
        type: 'tool_result',
        tool_use_id: 'tool_123',
        content: '{"temperature": 20}',
      },
    ],
  },
];

const input = fromClaudeMessages(claudeMessages);
```

### Base64 Images

Both URL and base64 images are supported:

```typescript
const claudeMessages = [
  {
    role: 'user',
    content: [
      { type: 'text', text: 'Describe this image.' },
      {
        type: 'image',
        source: {
          type: 'base64',
          media_type: 'image/png',
          data: 'iVBORw0KGgo...',
        },
      },
    ],
  },
];
```

### Limitations

Some Claude features are not preserved in conversion.
e.g. `is_error` flag on tool\_result blocks

These features are Claude-specific and not supported by OpenRouter.

## Migration Examples

### From OpenAI SDK

```typescript
// Before: OpenAI SDK
import OpenAI from 'openai';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const completion = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [
    { role: 'system', content: 'You are helpful.' },
    { role: 'user', content: 'Hello!' },
  ],
});

// After: OpenRouter SDK
import { OpenRouter, fromChatMessages } from '@openrouter/agent';

const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const result = openrouter.callModel({
  model: 'openai/gpt-5.2',
  input: fromChatMessages([
    { role: 'system', content: 'You are helpful.' },
    { role: 'user', content: 'Hello!' },
  ]),
});

const text = await result.getText();
```

### From Anthropic SDK

```typescript
// Before: Anthropic SDK
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic();
const message = await anthropic.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: 'Hello!' },
  ],
});

// After: OpenRouter SDK
import { OpenRouter, fromClaudeMessages } from '@openrouter/agent';

const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const result = openrouter.callModel({
  model: 'anthropic/claude-sonnet-4.5',
  input: fromClaudeMessages([
    { role: 'user', content: 'Hello!' },
  ]),
  maxOutputTokens: 1024,
});

const text = await result.getText();
```

## Building Conversations

Accumulate messages across multiple calls:

```typescript
import { fromChatMessages, toChatMessage } from '@openrouter/agent';

// Start with initial message
let messages = [
  { role: 'system', content: 'You are a helpful assistant.' },
  { role: 'user', content: 'Hello!' },
];

// First call
let result = openrouter.callModel({
  model: 'openai/gpt-5-nano',
  input: fromChatMessages(messages),
});

let response = await result.getResponse();
let assistantMessage = toChatMessage(response);

// Add to history
messages.push(assistantMessage);
messages.push({ role: 'user', content: 'What can you help me with?' });

// Continue conversation
result = openrouter.callModel({
  model: 'openai/gpt-5-nano',
  input: fromChatMessages(messages),
});
```

## Next Steps

* **[Text Generation](/docs/sdks/call-model/text-generation)** - Input formats and parameters
* **[Tools](/docs/sdks/call-model/tools)** - Add tool capabilities
* **[Streaming](/docs/sdks/call-model/streaming)** - Stream format-converted responses