Skip to content

OpenRouter SDK 内置多种消息格式转换函数,可将 OpenAI Chat Completions 格式或 Anthropic Claude 格式的消息历史无损转换为 OpenRouter 的 OpenResponses 格式。本文详细介绍 fromChatMessages()toChatMessage()fromClaudeMessages()toClaudeMessage() 四个核心工具函数的用法,涵盖 tool call 消息、图片 content blocks、base64 图片等复杂场景,以及完整的迁移示例。

OpenAI Chat 格式

fromChatMessages()

将 OpenAI Chat Completions 格式的消息数组转换为 OpenResponses 输入:

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

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

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()

将 OpenResponses 响应转换回 Chat Completions 的 assistant 消息格式:

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: { role: 'assistant', content: '...' }
console.log(chatMessage.role);    // 'assistant'
console.log(chatMessage.content); // 响应文本

支持的消息角色

Chat Role说明
system系统指令
user用户消息
assistant助手响应
developer开发者指令
tool工具返回消息

Tool Call 消息

工具调用的 function call + tool result 格式会被正确转换:

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 格式

fromClaudeMessages()

将 Anthropic SDK 风格的消息数组转换为 OpenResponses 输入:

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

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()

将响应转换为与 Anthropic SDK 兼容的 message 格式:

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);
// 与 Anthropic SDK 类型兼容

Content Blocks(多模态)

支持 Claude 的 content block 格式,可包含文字和图片:

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 的 tool_use / tool_result 格式会被自动转换:

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 图片

URL 和 base64 编码的图片都支持:

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

限制说明

部分 Claude 专有特性在转换中会丢失,例如 tool_resultis_error 标志。这些是 Claude API 独有的特性,OpenRouter 格式不支持。

迁移示例

从 OpenAI SDK 迁移

typescript
// 迁移前: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!' },
  ],
});

// 迁移后: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();

从 Anthropic SDK 迁移

typescript
// 迁移前: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!' }],
});

// 迁移后: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();

多轮对话构建

跨多次 API 调用累积消息历史:

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

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

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

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

// 追加到历史
messages.push(assistantMessage);
messages.push({ role: 'user', content: 'What can you help me with?' });

// 第二轮继续对话
result = openrouter.callModel({
  model: 'openai/gpt-5-nano',
  input: fromChatMessages(messages),
});

常见问题

Q: fromChatMessages 和直接传字符串有什么区别?

A: 传字符串是单轮无历史的简单调用;fromChatMessages 适合需要携带完整对话历史的多轮场景,或者从 OpenAI SDK 迁移时保持消息结构不变。

Q: 从 Claude SDK 迁移后,system prompt 怎么处理?

A: fromClaudeMessages 只处理 messages 数组;system prompt 应通过 callModelinstructions 参数传入,不要放进消息数组里。

Q: 转换后的格式能用于 streaming 吗?

A: 可以,转换函数只处理 input 格式,不影响 callModel 的其他配置,streaming 正常使用即可。