Message Formats

The OpenRouter SDK provides helper functions to convert between popular message formats. This makes it easy to migrate existing code or integrate with different APIs.

OpenAI Chat Format

fromChatMessages()

Convert OpenAI chat-style messages to OpenResponses input:

1import { OpenRouter, fromChatMessages } from '@openrouter/sdk';
2
3const openrouter = new OpenRouter({
4 apiKey: process.env.OPENROUTER_API_KEY,
5});
6
7// OpenAI chat format
8const chatMessages = [
9 { role: 'system', content: 'You are a helpful assistant.' },
10 { role: 'user', content: 'Hello!' },
11 { role: 'assistant', content: 'Hi there! How can I help you?' },
12 { role: 'user', content: 'What is the weather like?' },
13];
14
15const result = openrouter.callModel({
16 model: 'openai/gpt-5-nano',
17 input: fromChatMessages(chatMessages),
18});
19
20const text = await result.getText();

toChatMessage()

Convert an OpenResponses response to chat message format:

1import { toChatMessage } from '@openrouter/sdk';
2
3const result = openrouter.callModel({
4 model: 'openai/gpt-5-nano',
5 input: 'Hello!',
6});
7
8const response = await result.getResponse();
9const chatMessage = toChatMessage(response);
10
11// chatMessage is now: { role: 'assistant', content: '...' }
12console.log(chatMessage.role); // 'assistant'
13console.log(chatMessage.content); // Response text

Supported Message Types

Chat RoleDescription
systemSystem instructions
userUser messages
assistantAssistant responses
developerDeveloper instructions
toolTool response messages

Tool Messages

Tool responses are converted to function call outputs:

1const chatMessages = [
2 { role: 'user', content: 'What is the weather?' },
3 {
4 role: 'assistant',
5 content: null,
6 tool_calls: [{
7 id: 'call_123',
8 type: 'function',
9 function: { name: 'get_weather', arguments: '{"location":"Paris"}' },
10 }],
11 },
12 {
13 role: 'tool',
14 tool_call_id: 'call_123',
15 content: '{"temperature": 20}',
16 },
17];
18
19const input = fromChatMessages(chatMessages);

Anthropic Claude Format

fromClaudeMessages()

Convert Anthropic Claude-style messages to OpenResponses input:

1import { OpenRouter, fromClaudeMessages } from '@openrouter/sdk';
2
3// Claude format
4const claudeMessages = [
5 { role: 'user', content: 'Hello!' },
6 { role: 'assistant', content: 'Hi there!' },
7 { role: 'user', content: 'Tell me about TypeScript.' },
8];
9
10const result = openrouter.callModel({
11 model: 'anthropic/claude-sonnet-4.5',
12 input: fromClaudeMessages(claudeMessages),
13});

toClaudeMessage()

Convert an OpenResponses response to Claude message format:

1import { toClaudeMessage } from '@openrouter/sdk';
2
3const result = openrouter.callModel({
4 model: 'anthropic/claude-sonnet-4.5',
5 input: 'Hello!',
6});
7
8const response = await result.getResponse();
9const claudeMessage = toClaudeMessage(response);
10
11// Compatible with Anthropic SDK types

Content Blocks

Claude’s content block format is supported:

1const claudeMessages = [
2 {
3 role: 'user',
4 content: [
5 { type: 'text', text: 'What is in this image?' },
6 {
7 type: 'image',
8 source: {
9 type: 'url',
10 url: 'https://example.com/image.jpg',
11 },
12 },
13 ],
14 },
15];
16
17const input = fromClaudeMessages(claudeMessages);

Tool Use Blocks

Claude’s tool use format is converted:

1const claudeMessages = [
2 { role: 'user', content: 'What is the weather?' },
3 {
4 role: 'assistant',
5 content: [
6 {
7 type: 'tool_use',
8 id: 'tool_123',
9 name: 'get_weather',
10 input: { location: 'Paris' },
11 },
12 ],
13 },
14 {
15 role: 'user',
16 content: [
17 {
18 type: 'tool_result',
19 tool_use_id: 'tool_123',
20 content: '{"temperature": 20}',
21 },
22 ],
23 },
24];
25
26const input = fromClaudeMessages(claudeMessages);

Base64 Images

Both URL and base64 images are supported:

1const claudeMessages = [
2 {
3 role: 'user',
4 content: [
5 { type: 'text', text: 'Describe this image.' },
6 {
7 type: 'image',
8 source: {
9 type: 'base64',
10 media_type: 'image/png',
11 data: 'iVBORw0KGgo...',
12 },
13 },
14 ],
15 },
16];

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

1// Before: OpenAI SDK
2import OpenAI from 'openai';
3
4const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
5const completion = await openai.chat.completions.create({
6 model: 'gpt-4',
7 messages: [
8 { role: 'system', content: 'You are helpful.' },
9 { role: 'user', content: 'Hello!' },
10 ],
11});
12
13// After: OpenRouter SDK
14import { OpenRouter, fromChatMessages } from '@openrouter/sdk';
15
16const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
17const result = openrouter.callModel({
18 model: 'openai/gpt-5.2',
19 input: fromChatMessages([
20 { role: 'system', content: 'You are helpful.' },
21 { role: 'user', content: 'Hello!' },
22 ]),
23});
24
25const text = await result.getText();

From Anthropic SDK

1// Before: Anthropic SDK
2import Anthropic from '@anthropic-ai/sdk';
3
4const anthropic = new Anthropic();
5const message = await anthropic.messages.create({
6 model: 'claude-sonnet-4-20250514',
7 max_tokens: 1024,
8 messages: [
9 { role: 'user', content: 'Hello!' },
10 ],
11});
12
13// After: OpenRouter SDK
14import { OpenRouter, fromClaudeMessages } from '@openrouter/sdk';
15
16const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
17const result = openrouter.callModel({
18 model: 'anthropic/claude-sonnet-4.5',
19 input: fromClaudeMessages([
20 { role: 'user', content: 'Hello!' },
21 ]),
22 maxOutputTokens: 1024,
23});
24
25const text = await result.getText();

Building Conversations

Accumulate messages across multiple calls:

1import { fromChatMessages, toChatMessage } from '@openrouter/sdk';
2
3// Start with initial message
4let messages = [
5 { role: 'system', content: 'You are a helpful assistant.' },
6 { role: 'user', content: 'Hello!' },
7];
8
9// First call
10let result = openrouter.callModel({
11 model: 'openai/gpt-5-nano',
12 input: fromChatMessages(messages),
13});
14
15let response = await result.getResponse();
16let assistantMessage = toChatMessage(response);
17
18// Add to history
19messages.push(assistantMessage);
20messages.push({ role: 'user', content: 'What can you help me with?' });
21
22// Continue conversation
23result = openrouter.callModel({
24 model: 'openai/gpt-5-nano',
25 input: fromChatMessages(messages),
26});

Next Steps