mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-13 00:03:57 +00:00
* fix: preserve ai reasoning content * fix: avoid text-only reasoning replay * feat: add deepseek ai eval models
118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import type {
|
|
ChatCompletionChunk,
|
|
ChatCompletionMessageFunctionToolCall,
|
|
ChatCompletionMessageParam
|
|
} from 'openai/resources/index.mjs'
|
|
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
buildAssistantTextMessage,
|
|
buildAssistantToolCallMessage,
|
|
getReasoningContentDelta
|
|
} from './chat/openaiReasoning'
|
|
import { getDefaultChatTemperature, modelDisallowsSamplingParams } from './modelConfig'
|
|
|
|
type AssistantMessageWithReasoning = ChatCompletionMessageParam & {
|
|
role: 'assistant'
|
|
content?: string
|
|
reasoning_content?: string
|
|
tool_calls?: ChatCompletionMessageFunctionToolCall[]
|
|
}
|
|
|
|
describe('modelConfig', () => {
|
|
it('flags Opus 4.7 model IDs via includes matching', () => {
|
|
expect(modelDisallowsSamplingParams('claude-opus-4-7')).toBe(true)
|
|
expect(modelDisallowsSamplingParams('claude-opus-4-7@20260416')).toBe(true)
|
|
expect(modelDisallowsSamplingParams('claude-opus-4-7/thinking')).toBe(true)
|
|
expect(modelDisallowsSamplingParams('anthropic/claude-opus-4-7')).toBe(true)
|
|
})
|
|
|
|
it('omits deterministic temperature for Anthropic Opus 4.7 chat requests', () => {
|
|
expect(
|
|
getDefaultChatTemperature({ provider: 'anthropic', model: 'claude-opus-4-7' })
|
|
).toBeUndefined()
|
|
})
|
|
|
|
it('omits deterministic temperature for non-anthropic providers carrying Opus 4.7 models', () => {
|
|
expect(
|
|
getDefaultChatTemperature({ provider: 'openrouter', model: 'anthropic/claude-opus-4-7' })
|
|
).toBeUndefined()
|
|
})
|
|
|
|
it('keeps deterministic temperature for older Anthropic models', () => {
|
|
expect(getDefaultChatTemperature({ provider: 'anthropic', model: 'claude-sonnet-4-6' })).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('openaiReasoning', () => {
|
|
it('reads provider-specific reasoning_content deltas', () => {
|
|
expect(
|
|
getReasoningContentDelta({
|
|
reasoning_content: 'thinking'
|
|
} as ChatCompletionChunk.Choice.Delta & { reasoning_content: string })
|
|
).toBe('thinking')
|
|
})
|
|
|
|
it('preserves DeepSeek reasoning_content on assistant tool-call messages', () => {
|
|
const toolCalls: ChatCompletionMessageFunctionToolCall[] = [
|
|
{
|
|
id: 'call_1',
|
|
type: 'function',
|
|
function: {
|
|
name: 'lookup',
|
|
arguments: '{"query":"docs"}'
|
|
}
|
|
}
|
|
]
|
|
|
|
const assistantMessage = buildAssistantToolCallMessage({
|
|
content: 'I will look that up.',
|
|
reasoning: {
|
|
hasReasoningContent: true,
|
|
reasoningContent: 'First, I need a lookup.'
|
|
},
|
|
toolCalls
|
|
}) as AssistantMessageWithReasoning
|
|
|
|
expect(assistantMessage).toMatchObject({
|
|
role: 'assistant',
|
|
content: 'I will look that up.',
|
|
reasoning_content: 'First, I need a lookup.',
|
|
tool_calls: [
|
|
{
|
|
id: 'call_1',
|
|
type: 'function',
|
|
function: {
|
|
name: 'lookup',
|
|
arguments: '{"query":"docs"}'
|
|
}
|
|
}
|
|
]
|
|
})
|
|
})
|
|
|
|
it('does not preserve reasoning_content on text-only assistant messages', () => {
|
|
expect(buildAssistantTextMessage('done')).toEqual({
|
|
role: 'assistant',
|
|
content: 'done'
|
|
})
|
|
})
|
|
|
|
it('keeps empty reasoning_content when the provider emitted the field', () => {
|
|
const assistantMessage = buildAssistantToolCallMessage({
|
|
content: '',
|
|
reasoning: {
|
|
hasReasoningContent: true,
|
|
reasoningContent: ''
|
|
},
|
|
toolCalls: []
|
|
}) as AssistantMessageWithReasoning
|
|
|
|
expect(assistantMessage).toMatchObject({
|
|
role: 'assistant',
|
|
content: '',
|
|
reasoning_content: '',
|
|
tool_calls: []
|
|
})
|
|
})
|
|
})
|