Skip to main content

OpenAI Chat Format

fromChatMessages()

Convert OpenAI chat-style messages to OpenResponses input:
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:
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 RoleDescription
systemSystem instructions
userUser messages
assistantAssistant responses
developerDeveloper instructions
toolTool response messages

Tool Messages

Tool responses are converted to function call outputs:
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:
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:
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:
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:
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:
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

// 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

// 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:
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