style: 格式化 packages/@ant/ 下所有文件以通过 biome ci

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-code-best
2026-05-01 21:55:51 +08:00
parent c32f26cf21
commit 9ea9859dce
92 changed files with 5903 additions and 5188 deletions

View File

@@ -131,7 +131,13 @@ describe('anthropicMessagesToOpenAI', () => {
],
[] as any,
)
expect(result).toEqual([{ role: 'assistant', content: 'visible response', reasoning_content: 'internal thoughts...' }] as any)
expect(result).toEqual([
{
role: 'assistant',
content: 'visible response',
reasoning_content: 'internal thoughts...',
},
] as any)
})
test('handles full conversation with tools', () => {
@@ -487,10 +493,19 @@ describe('DeepSeek thinking mode (enableThinking)', () => {
[
makeUserMsg('run ls'),
makeAssistantMsg([
{ type: 'tool_use' as const, id: 'toolu_1', name: 'bash', input: { command: 'ls' } },
{
type: 'tool_use' as const,
id: 'toolu_1',
name: 'bash',
input: { command: 'ls' },
},
]),
makeUserMsg([
{ type: 'tool_result' as const, tool_use_id: 'toolu_1', content: 'file.txt' },
{
type: 'tool_result' as const,
tool_use_id: 'toolu_1',
content: 'file.txt',
},
{ type: 'text' as const, text: 'looks good' },
]),
],
@@ -499,7 +514,10 @@ describe('DeepSeek thinking mode (enableThinking)', () => {
// Find the tool message and the user text message
const toolIdx = result.findIndex(m => m.role === 'tool')
const userTextIdx = result.findIndex(
m => m.role === 'user' && typeof m.content === 'string' && m.content.includes('looks good'),
m =>
m.role === 'user' &&
typeof m.content === 'string' &&
m.content.includes('looks good'),
)
expect(toolIdx).toBeGreaterThanOrEqual(0)
expect(userTextIdx).toBeGreaterThanOrEqual(0)
@@ -512,15 +530,26 @@ describe('DeepSeek thinking mode (enableThinking)', () => {
[
makeUserMsg('do something'),
makeAssistantMsg([
{ type: 'tool_use' as const, id: 'toolu_2', name: 'bash', input: { command: 'pwd' } },
{
type: 'tool_use' as const,
id: 'toolu_2',
name: 'bash',
input: { command: 'pwd' },
},
]),
makeUserMsg([
{ type: 'tool_result' as const, tool_use_id: 'toolu_2', content: '/home/user' },
{
type: 'tool_result' as const,
tool_use_id: 'toolu_2',
content: '/home/user',
},
]),
],
[] as any,
)
const assistantIdx = result.findIndex(m => m.role === 'assistant' && (m as any).tool_calls)
const assistantIdx = result.findIndex(
m => m.role === 'assistant' && (m as any).tool_calls,
)
const toolIdx = result.findIndex(m => m.role === 'tool')
expect(assistantIdx).toBeGreaterThanOrEqual(0)
expect(toolIdx).toBe(assistantIdx + 1)

View File

@@ -1,5 +1,8 @@
import { describe, expect, test } from 'bun:test'
import { anthropicToolsToOpenAI, anthropicToolChoiceToOpenAI } from '../openaiConvertTools.js'
import {
anthropicToolsToOpenAI,
anthropicToolChoiceToOpenAI,
} from '../openaiConvertTools.js'
describe('anthropicToolsToOpenAI', () => {
test('converts basic tool', () => {

View File

@@ -3,7 +3,9 @@ import type { ChatCompletionChunk } from 'openai/resources/chat/completions/comp
import { adaptOpenAIStreamToAnthropic } from '../openaiStreamAdapter.js'
/** Helper to create a mock async iterable from chunk array */
function mockStream(chunks: ChatCompletionChunk[]): AsyncIterable<ChatCompletionChunk> {
function mockStream(
chunks: ChatCompletionChunk[],
): AsyncIterable<ChatCompletionChunk> {
return {
[Symbol.asyncIterator]() {
let i = 0
@@ -18,7 +20,9 @@ function mockStream(chunks: ChatCompletionChunk[]): AsyncIterable<ChatCompletion
}
/** Create a minimal ChatCompletionChunk */
function makeChunk(overrides: Partial<ChatCompletionChunk> & any = {}): ChatCompletionChunk {
function makeChunk(
overrides: Partial<ChatCompletionChunk> & any = {},
): ChatCompletionChunk {
return {
id: 'chatcmpl-test',
object: 'chat.completion.chunk',
@@ -32,7 +36,10 @@ function makeChunk(overrides: Partial<ChatCompletionChunk> & any = {}): ChatComp
/** Collect all emitted Anthropic events from the stream adapter for assertion */
async function collectEvents(chunks: ChatCompletionChunk[]) {
const events: any[] = []
for await (const event of adaptOpenAIStreamToAnthropic(mockStream(chunks), 'gpt-4o')) {
for await (const event of adaptOpenAIStreamToAnthropic(
mockStream(chunks),
'gpt-4o',
)) {
events.push(event)
}
return events
@@ -42,25 +49,31 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('emits message_start on first chunk', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { role: 'assistant', content: '' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { role: 'assistant', content: '' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: { content: 'hello' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { content: 'hello' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: {},
finish_reason: 'stop',
}],
choices: [
{
index: 0,
delta: {},
finish_reason: 'stop',
},
],
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
}),
])
@@ -73,10 +86,14 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('converts text content stream', async () => {
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'Hello' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'Hello' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: { content: ' world' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: ' world' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
@@ -91,7 +108,9 @@ describe('adaptOpenAIStreamToAnthropic', () => {
expect(types).toContain('message_delta')
expect(types).toContain('message_stop')
const textDeltas = events.filter(e => e.type === 'content_block_delta') as any[]
const textDeltas = events.filter(
e => e.type === 'content_block_delta',
) as any[]
expect(textDeltas[0].delta.text).toBe('Hello')
expect(textDeltas[1].delta.text).toBe(' world')
})
@@ -99,42 +118,54 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('converts tool_calls stream', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{
index: 0,
id: 'call_abc',
type: 'function',
function: { name: 'bash', arguments: '' },
}],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_abc',
type: 'function',
function: { name: 'bash', arguments: '' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{
index: 0,
function: { arguments: '{"comm' },
}],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
function: { arguments: '{"comm' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{
index: 0,
function: { arguments: 'and":"ls"}' },
}],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
function: { arguments: 'and":"ls"}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
@@ -146,7 +177,8 @@ describe('adaptOpenAIStreamToAnthropic', () => {
expect(blockStart.content_block.name).toBe('bash')
const jsonDeltas = events.filter(
e => e.type === 'content_block_delta' && e.delta.type === 'input_json_delta',
e =>
e.type === 'content_block_delta' && e.delta.type === 'input_json_delta',
) as any[]
const fullArgs = jsonDeltas.map(d => d.delta.partial_json).join('')
expect(fullArgs).toBe('{"command":"ls"}')
@@ -171,13 +203,21 @@ describe('adaptOpenAIStreamToAnthropic', () => {
// return finish_reason "stop" when they actually made tool calls.
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{ index: 0, id: 'call_1', function: { name: 'bash', arguments: '{"cmd":"ls"}' } }],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_1',
function: { name: 'bash', arguments: '{"cmd":"ls"}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
@@ -191,13 +231,21 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('maps finish_reason tool_calls to tool_use', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{ index: 0, id: 'call_1', function: { name: 'bash', arguments: '{}' } }],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_1',
function: { name: 'bash', arguments: '{}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
@@ -211,7 +259,9 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('maps finish_reason length to max_tokens', async () => {
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'truncated' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'truncated' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'length' }],
@@ -225,23 +275,35 @@ describe('adaptOpenAIStreamToAnthropic', () => {
test('handles mixed text and tool_calls', async () => {
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'Thinking...' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'Thinking...' }, finish_reason: null },
],
}),
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{ index: 0, id: 'call_1', function: { name: 'grep', arguments: '{"p":"test"}' } }],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_1',
function: { name: 'grep', arguments: '{"p":"test"}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
}),
])
const blockStarts = events.filter(e => e.type === 'content_block_start') as any[]
const blockStarts = events.filter(
e => e.type === 'content_block_start',
) as any[]
expect(blockStarts.length).toBe(2)
expect(blockStarts[0].content_block.type).toBe('text')
expect(blockStarts[1].content_block.type).toBe('tool_use')
@@ -252,18 +314,22 @@ describe('thinking support (reasoning_content)', () => {
test('converts reasoning_content to thinking block', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { reasoning_content: 'Let me analyze this...' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { reasoning_content: 'Let me analyze this...' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: { reasoning_content: ' step by step.' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { reasoning_content: ' step by step.' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
@@ -277,7 +343,8 @@ describe('thinking support (reasoning_content)', () => {
// Should have thinking_delta events
const thinkingDeltas = events.filter(
e => e.type === 'content_block_delta' && e.delta.type === 'thinking_delta',
e =>
e.type === 'content_block_delta' && e.delta.type === 'thinking_delta',
) as any[]
expect(thinkingDeltas.length).toBe(2)
expect(thinkingDeltas[0].delta.thinking).toBe('Let me analyze this...')
@@ -287,18 +354,22 @@ describe('thinking support (reasoning_content)', () => {
test('converts reasoning then content (DeepSeek-style)', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { reasoning_content: 'Thinking about the answer...' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { reasoning_content: 'Thinking about the answer...' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: { content: 'Here is my answer.' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { content: 'Here is my answer.' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
@@ -306,13 +377,17 @@ describe('thinking support (reasoning_content)', () => {
])
// Should have two content blocks: thinking + text
const blockStarts = events.filter(e => e.type === 'content_block_start') as any[]
const blockStarts = events.filter(
e => e.type === 'content_block_start',
) as any[]
expect(blockStarts.length).toBe(2)
expect(blockStarts[0].content_block.type).toBe('thinking')
expect(blockStarts[1].content_block.type).toBe('text')
// Thinking block should be closed before text block starts
const blockStops = events.filter(e => e.type === 'content_block_stop') as any[]
const blockStops = events.filter(
e => e.type === 'content_block_stop',
) as any[]
expect(blockStops[0].index).toBe(0) // thinking block closed at index 0
expect(blockStarts[1].index).toBe(1) // text block starts at index 1
@@ -326,27 +401,39 @@ describe('thinking support (reasoning_content)', () => {
test('handles reasoning then tool_calls', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { reasoning_content: 'I need to run a command.' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { reasoning_content: 'I need to run a command.' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{ index: 0, id: 'call_1', function: { name: 'bash', arguments: '{"c":"ls"}' } }],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_1',
function: { name: 'bash', arguments: '{"c":"ls"}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
}),
])
const blockStarts = events.filter(e => e.type === 'content_block_start') as any[]
const blockStarts = events.filter(
e => e.type === 'content_block_start',
) as any[]
expect(blockStarts.length).toBe(2)
expect(blockStarts[0].content_block.type).toBe('thinking')
expect(blockStarts[1].content_block.type).toBe('tool_use')
@@ -355,25 +442,31 @@ describe('thinking support (reasoning_content)', () => {
test('thinking block index is 0, text block index is 1', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { reasoning_content: 'reason' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { reasoning_content: 'reason' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{
index: 0,
delta: { content: 'answer' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { content: 'answer' },
finish_reason: null,
},
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
}),
])
const blockStarts = events.filter(e => e.type === 'content_block_start') as any[]
const blockStarts = events.filter(
e => e.type === 'content_block_start',
) as any[]
expect(blockStarts[0].index).toBe(0)
expect(blockStarts[1].index).toBe(1)
})
@@ -383,11 +476,13 @@ describe('prompt caching support', () => {
test('maps cached_tokens to cache_read_input_tokens', async () => {
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: { content: 'hi' },
finish_reason: null,
}],
choices: [
{
index: 0,
delta: { content: 'hi' },
finish_reason: null,
},
],
usage: {
prompt_tokens: 1000,
completion_tokens: 0,
@@ -463,7 +558,9 @@ describe('prompt caching support', () => {
// emitted before the trailing chunk and always has input_tokens=0.
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'hello' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'hello' }, finish_reason: null },
],
}),
// finish_reason chunk — usage not yet available
makeChunk({
@@ -493,14 +590,20 @@ describe('prompt caching support', () => {
// the autocompact threshold (~33k), so compaction never fires.
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'answer' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'answer' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
}),
makeChunk({
choices: [],
usage: { prompt_tokens: 800, completion_tokens: 200, total_tokens: 1000 },
usage: {
prompt_tokens: 800,
completion_tokens: 200,
total_tokens: 1000,
},
}),
])
@@ -514,13 +617,21 @@ describe('prompt caching support', () => {
// when the model made tool calls and usage arrives in a trailing chunk.
const events = await collectEvents([
makeChunk({
choices: [{
index: 0,
delta: {
tool_calls: [{ index: 0, id: 'call_x', function: { name: 'bash', arguments: '{"cmd":"ls"}' } }],
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: 'call_x',
function: { name: 'bash', arguments: '{"cmd":"ls"}' },
},
],
},
finish_reason: null,
},
finish_reason: null,
}],
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
@@ -540,9 +651,14 @@ describe('prompt caching support', () => {
test('message_delta always comes before message_stop', async () => {
// Verifies event ordering is preserved after deferring to post-loop emission.
const events = await collectEvents([
makeChunk({ choices: [{ index: 0, delta: { content: 'x' }, finish_reason: null }] }),
makeChunk({
choices: [{ index: 0, delta: { content: 'x' }, finish_reason: null }],
}),
makeChunk({ choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] }),
makeChunk({ choices: [], usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 } }),
makeChunk({
choices: [],
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
}),
])
const types = events.map(e => e.type)
@@ -561,7 +677,9 @@ describe('prompt caching support', () => {
// queryModelOpenAI's spread — even though cachedTokens was captured internally.
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'answer' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'answer' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
@@ -638,7 +756,9 @@ describe('prompt caching support', () => {
// Some endpoints send usage in the finish_reason chunk instead of a trailing chunk.
const events = await collectEvents([
makeChunk({
choices: [{ index: 0, delta: { content: 'result' }, finish_reason: null }],
choices: [
{ index: 0, delta: { content: 'result' }, finish_reason: null },
],
}),
makeChunk({
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],