mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-31 00:10:22 +08:00
test(unified-messages): add unit tests for convertAnthropicToolsToAiSdk and convertAnthropicToAiMessages functions
This commit is contained in:
parent
c877a3c4a5
commit
9c1f538f15
795
src/main/apiServer/services/__tests__/unified-messages.test.ts
Normal file
795
src/main/apiServer/services/__tests__/unified-messages.test.ts
Normal file
@ -0,0 +1,795 @@
|
||||
import type { MessageCreateParams } from '@anthropic-ai/sdk/resources/messages'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { convertAnthropicToAiMessages, convertAnthropicToolsToAiSdk } from '../unified-messages'
|
||||
|
||||
describe('unified-messages', () => {
|
||||
describe('convertAnthropicToolsToAiSdk', () => {
|
||||
it('should return undefined for empty tools array', () => {
|
||||
const result = convertAnthropicToolsToAiSdk([])
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should return undefined for undefined tools', () => {
|
||||
const result = convertAnthropicToolsToAiSdk(undefined)
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should convert simple tool with string schema', () => {
|
||||
const anthropicTools: MessageCreateParams['tools'] = [
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'get_weather',
|
||||
description: 'Get current weather',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: { type: 'string' }
|
||||
},
|
||||
required: ['location']
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const result = convertAnthropicToolsToAiSdk(anthropicTools)
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toHaveProperty('get_weather')
|
||||
expect(result!.get_weather).toHaveProperty('description', 'Get current weather')
|
||||
})
|
||||
|
||||
it('should convert multiple tools', () => {
|
||||
const anthropicTools: MessageCreateParams['tools'] = [
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'tool1',
|
||||
description: 'First tool',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'tool2',
|
||||
description: 'Second tool',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const result = convertAnthropicToolsToAiSdk(anthropicTools)
|
||||
expect(result).toBeDefined()
|
||||
expect(Object.keys(result!)).toHaveLength(2)
|
||||
expect(result).toHaveProperty('tool1')
|
||||
expect(result).toHaveProperty('tool2')
|
||||
})
|
||||
|
||||
it('should convert tool with complex schema', () => {
|
||||
const anthropicTools: MessageCreateParams['tools'] = [
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'search',
|
||||
description: 'Search for information',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
query: { type: 'string', minLength: 1 },
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100 },
|
||||
filters: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
},
|
||||
required: ['query']
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const result = convertAnthropicToolsToAiSdk(anthropicTools)
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toHaveProperty('search')
|
||||
})
|
||||
|
||||
it('should skip bash_20250124 tool type', () => {
|
||||
const anthropicTools: MessageCreateParams['tools'] = [
|
||||
{
|
||||
type: 'bash_20250124',
|
||||
name: 'bash'
|
||||
},
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'regular_tool',
|
||||
description: 'A regular tool',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const result = convertAnthropicToolsToAiSdk(anthropicTools)
|
||||
expect(result).toBeDefined()
|
||||
expect(Object.keys(result!)).toHaveLength(1)
|
||||
expect(result).toHaveProperty('regular_tool')
|
||||
expect(result).not.toHaveProperty('bash')
|
||||
})
|
||||
|
||||
it('should handle tool with no description', () => {
|
||||
const anthropicTools: MessageCreateParams['tools'] = [
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'no_desc_tool',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const result = convertAnthropicToolsToAiSdk(anthropicTools)
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toHaveProperty('no_desc_tool')
|
||||
expect(result!.no_desc_tool).toHaveProperty('description', '')
|
||||
})
|
||||
})
|
||||
|
||||
describe('convertAnthropicToAiMessages', () => {
|
||||
describe('System Messages', () => {
|
||||
it('should convert string system message', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
system: 'You are a helpful assistant.',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[0]).toEqual({
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant.'
|
||||
})
|
||||
})
|
||||
|
||||
it('should convert array system message', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
system: [
|
||||
{ type: 'text', text: 'Instruction 1' },
|
||||
{ type: 'text', text: 'Instruction 2' }
|
||||
],
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result[0]).toEqual({
|
||||
role: 'system',
|
||||
content: 'Instruction 1\nInstruction 2'
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle no system message', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result[0].role).toBe('user')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Text Messages', () => {
|
||||
it('should convert simple string message', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello, world!'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toEqual({
|
||||
role: 'user',
|
||||
content: 'Hello, world!'
|
||||
})
|
||||
})
|
||||
|
||||
it('should convert text block array', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: 'First part' },
|
||||
{ type: 'text', text: 'Second part' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].role).toBe('user')
|
||||
expect(Array.isArray(result[0].content)).toBe(true)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(2)
|
||||
expect(result[0].content[0]).toEqual({ type: 'text', text: 'First part' })
|
||||
expect(result[0].content[1]).toEqual({ type: 'text', text: 'Second part' })
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert assistant message', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello'
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content: 'Hi there!'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[1]).toEqual({
|
||||
role: 'assistant',
|
||||
content: 'Hi there!'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Image Messages', () => {
|
||||
it('should convert base64 image', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'image',
|
||||
source: {
|
||||
type: 'base64',
|
||||
media_type: 'image/png',
|
||||
data: 'iVBORw0KGgo='
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(1)
|
||||
expect(Array.isArray(result[0].content)).toBe(true)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(1)
|
||||
const imagePart = result[0].content[0]
|
||||
if (imagePart.type === 'image') {
|
||||
expect(imagePart.image).toBe('data:image/png;base64,iVBORw0KGgo=')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert URL image', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'image',
|
||||
source: {
|
||||
type: 'url',
|
||||
url: 'https://example.com/image.png'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
const imagePart = result[0].content[0]
|
||||
if (imagePart.type === 'image') {
|
||||
expect(imagePart.image).toBe('https://example.com/image.png')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert mixed text and image content', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: 'Look at this:' },
|
||||
{
|
||||
type: 'image',
|
||||
source: {
|
||||
type: 'url',
|
||||
url: 'https://example.com/pic.jpg'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(2)
|
||||
expect(result[0].content[0].type).toBe('text')
|
||||
expect(result[0].content[1].type).toBe('image')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Tool Messages', () => {
|
||||
it('should convert tool_use block', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'What is the weather?'
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_123',
|
||||
name: 'get_weather',
|
||||
input: { location: 'San Francisco' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(2)
|
||||
const assistantMsg = result[1]
|
||||
expect(assistantMsg.role).toBe('assistant')
|
||||
if (Array.isArray(assistantMsg.content)) {
|
||||
expect(assistantMsg.content).toHaveLength(1)
|
||||
const toolCall = assistantMsg.content[0]
|
||||
if (toolCall.type === 'tool-call') {
|
||||
expect(toolCall.toolName).toBe('get_weather')
|
||||
expect(toolCall.toolCallId).toBe('call_123')
|
||||
expect(toolCall.input).toEqual({ location: 'San Francisco' })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert tool_result with string content', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_123',
|
||||
name: 'get_weather',
|
||||
input: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'call_123',
|
||||
content: 'Temperature is 72°F'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
const toolMsg = result[1]
|
||||
expect(toolMsg.role).toBe('tool')
|
||||
if (Array.isArray(toolMsg.content)) {
|
||||
expect(toolMsg.content).toHaveLength(1)
|
||||
const toolResult = toolMsg.content[0]
|
||||
if (toolResult.type === 'tool-result') {
|
||||
expect(toolResult.toolCallId).toBe('call_123')
|
||||
expect(toolResult.toolName).toBe('get_weather')
|
||||
if (toolResult.output.type === 'text') {
|
||||
expect(toolResult.output.value).toBe('Temperature is 72°F')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert tool_result with array content', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_456',
|
||||
name: 'analyze',
|
||||
input: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'call_456',
|
||||
content: [
|
||||
{ type: 'text', text: 'Result part 1' },
|
||||
{ type: 'text', text: 'Result part 2' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
const toolMsg = result[1]
|
||||
if (Array.isArray(toolMsg.content)) {
|
||||
const toolResult = toolMsg.content[0]
|
||||
if (toolResult.type === 'tool-result' && toolResult.output.type === 'content') {
|
||||
expect(toolResult.output.value).toHaveLength(2)
|
||||
expect(toolResult.output.value[0]).toEqual({ type: 'text', text: 'Result part 1' })
|
||||
expect(toolResult.output.value[1]).toEqual({ type: 'text', text: 'Result part 2' })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert tool_result with image content', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_789',
|
||||
name: 'screenshot',
|
||||
input: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'call_789',
|
||||
content: [
|
||||
{
|
||||
type: 'image',
|
||||
source: {
|
||||
type: 'base64',
|
||||
media_type: 'image/png',
|
||||
data: 'abc123'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
const toolMsg = result[1]
|
||||
if (Array.isArray(toolMsg.content)) {
|
||||
const toolResult = toolMsg.content[0]
|
||||
if (toolResult.type === 'tool-result' && toolResult.output.type === 'content') {
|
||||
expect(toolResult.output.value).toHaveLength(1)
|
||||
const media = toolResult.output.value[0]
|
||||
if (media.type === 'media') {
|
||||
expect(media.data).toBe('abc123')
|
||||
expect(media.mediaType).toBe('image/png')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle multiple tool calls', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_1',
|
||||
name: 'tool1',
|
||||
input: {}
|
||||
},
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_2',
|
||||
name: 'tool2',
|
||||
input: {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(2)
|
||||
expect(result[0].content[0].type).toBe('tool-call')
|
||||
expect(result[0].content[1].type).toBe('tool-call')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Thinking Content', () => {
|
||||
it('should convert thinking block to reasoning', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'thinking',
|
||||
thinking: 'Let me analyze this...',
|
||||
signature: 'sig123'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Here is my answer'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(2)
|
||||
const reasoning = result[0].content[0]
|
||||
if (reasoning.type === 'reasoning') {
|
||||
expect(reasoning.text).toBe('Let me analyze this...')
|
||||
}
|
||||
const text = result[0].content[1]
|
||||
if (text.type === 'text') {
|
||||
expect(text.text).toBe('Here is my answer')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert redacted_thinking to reasoning', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'redacted_thinking',
|
||||
data: '[Redacted]'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
expect(result[0].content).toHaveLength(1)
|
||||
const reasoning = result[0].content[0]
|
||||
if (reasoning.type === 'reasoning') {
|
||||
expect(reasoning.text).toBe('[Redacted]')
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Multi-turn Conversations', () => {
|
||||
it('should handle complete conversation flow', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
system: 'You are a helpful assistant.',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'What is the weather in SF?'
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'weather_call',
|
||||
name: 'get_weather',
|
||||
input: { location: 'SF' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'weather_call',
|
||||
content: '72°F and sunny'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content: 'The weather in San Francisco is 72°F and sunny.'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(5)
|
||||
expect(result[0].role).toBe('system')
|
||||
expect(result[1].role).toBe('user')
|
||||
expect(result[2].role).toBe('assistant')
|
||||
expect(result[3].role).toBe('tool')
|
||||
expect(result[4].role).toBe('assistant')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle empty content array for user', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should handle empty content array for assistant', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should handle tool_result without matching tool_use', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'unknown_call',
|
||||
content: 'Some result'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
expect(result).toHaveLength(1)
|
||||
if (Array.isArray(result[0].content)) {
|
||||
const toolResult = result[0].content[0]
|
||||
if (toolResult.type === 'tool-result') {
|
||||
expect(toolResult.toolName).toBe('unknown')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle tool_result with empty content', () => {
|
||||
const params: MessageCreateParams = {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: 'call_empty',
|
||||
name: 'empty_tool',
|
||||
input: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'call_empty'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const result = convertAnthropicToAiMessages(params)
|
||||
const toolMsg = result[1]
|
||||
if (Array.isArray(toolMsg.content)) {
|
||||
const toolResult = toolMsg.content[0]
|
||||
if (toolResult.type === 'tool-result' && toolResult.output.type === 'text') {
|
||||
expect(toolResult.output.value).toBe('')
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -255,7 +255,9 @@ export function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
}
|
||||
}
|
||||
|
||||
function convertAnthropicToolsToAiSdk(tools: MessageCreateParams['tools']): Record<string, AiSdkTool> | undefined {
|
||||
export function convertAnthropicToolsToAiSdk(
|
||||
tools: MessageCreateParams['tools']
|
||||
): Record<string, AiSdkTool> | undefined {
|
||||
if (!tools || tools.length === 0) return undefined
|
||||
|
||||
const aiSdkTools: Record<string, AiSdkTool> = {}
|
||||
@ -277,7 +279,7 @@ function convertAnthropicToolsToAiSdk(tools: MessageCreateParams['tools']): Reco
|
||||
return Object.keys(aiSdkTools).length > 0 ? aiSdkTools : undefined
|
||||
}
|
||||
|
||||
function convertAnthropicToAiMessages(params: MessageCreateParams): ModelMessage[] {
|
||||
export function convertAnthropicToAiMessages(params: MessageCreateParams): ModelMessage[] {
|
||||
const messages: ModelMessage[] = []
|
||||
|
||||
// System message
|
||||
|
||||
Loading…
Reference in New Issue
Block a user