test(llm): cover OpenAI-compatible Chat parity

This commit is contained in:
Kit Langton
2026-04-26 11:48:20 -04:00
parent 3a2cb7f8ac
commit 6a7735e14c
3 changed files with 100 additions and 0 deletions
@@ -0,0 +1 @@
{"version":1,"interactions":[{"request":{"method":"POST","url":"https://api.deepseek.com/v1/chat/completions","headers":{"content-type":"application/json"},"body":"{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"system\",\"content\":\"You are concise.\"},{\"role\":\"user\",\"content\":\"Reply with exactly: Hello!\"}],\"stream\":true,\"max_tokens\":20,\"temperature\":0}"},"response":{"status":200,"headers":{"content-type":"text/event-stream; charset=utf-8"},"body":"data: {\"id\":\"37be8034-f5e7-41e4-8ee7-39e0b5c613a2\",\"object\":\"chat.completion.chunk\",\"created\":1777218434,\"model\":\"deepseek-v4-flash\",\"system_fingerprint\":\"fp_058df29938_prod0820_fp8_kvcache_20260402\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\"},\"logprobs\":null,\"finish_reason\":null}]}\n\ndata: {\"id\":\"37be8034-f5e7-41e4-8ee7-39e0b5c613a2\",\"object\":\"chat.completion.chunk\",\"created\":1777218434,\"model\":\"deepseek-v4-flash\",\"system_fingerprint\":\"fp_058df29938_prod0820_fp8_kvcache_20260402\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"Hello\"},\"logprobs\":null,\"finish_reason\":null}]}\n\ndata: {\"id\":\"37be8034-f5e7-41e4-8ee7-39e0b5c613a2\",\"object\":\"chat.completion.chunk\",\"created\":1777218434,\"model\":\"deepseek-v4-flash\",\"system_fingerprint\":\"fp_058df29938_prod0820_fp8_kvcache_20260402\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"!\"},\"logprobs\":null,\"finish_reason\":null}]}\n\ndata: {\"id\":\"37be8034-f5e7-41e4-8ee7-39e0b5c613a2\",\"object\":\"chat.completion.chunk\",\"created\":1777218434,\"model\":\"deepseek-v4-flash\",\"system_fingerprint\":\"fp_058df29938_prod0820_fp8_kvcache_20260402\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"\"},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":14,\"completion_tokens\":2,\"total_tokens\":16,\"prompt_tokens_details\":{\"cached_tokens\":0},\"prompt_cache_hit_tokens\":0,\"prompt_cache_miss_tokens\":14}}\n\ndata: [DONE]\n\n"}}]}
@@ -0,0 +1,33 @@
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { LLM } from "../../src"
import { client } from "../../src/adapter"
import { OpenAICompatibleChat } from "../../src/provider/openai-compatible-chat"
import { recordedTests } from "../recorded-test"
const deepseekModel = OpenAICompatibleChat.deepseek({
id: "deepseek-chat",
apiKey: process.env.DEEPSEEK_API_KEY ?? "fixture",
})
const deepseekRequest = LLM.request({
id: "recorded_deepseek_text",
model: deepseekModel,
system: "You are concise.",
prompt: "Reply with exactly: Hello!",
generation: { maxTokens: 20, temperature: 0 },
})
const recorded = recordedTests({ prefix: "openai-compatible-chat" })
const llm = client({ adapters: [OpenAICompatibleChat.adapter] })
describe("OpenAI-compatible Chat recorded", () => {
recorded.effect.with("deepseek streams text", { requires: ["DEEPSEEK_API_KEY"] }, () =>
Effect.gen(function* () {
const response = yield* llm.generate(deepseekRequest)
expect(LLM.outputText(response)).toMatch(/^Hello!?$/)
expect(response.events.at(-1)).toMatchObject({ type: "request-finish", reason: "stop" })
}),
)
})
@@ -124,6 +124,72 @@ describe("OpenAI-compatible Chat adapter", () => {
}),
)
it.effect("matches AI SDK compatible basic request body fixture", () =>
Effect.gen(function* () {
const prepared = yield* client({ adapters: [OpenAICompatibleChat.adapter] }).prepare(request)
expect(prepared.target).toEqual({
model: "deepseek-chat",
messages: [
{ role: "system", content: "You are concise." },
{ role: "user", content: "Say hello." },
],
stream: true,
max_tokens: 20,
temperature: 0,
})
}),
)
it.effect("matches AI SDK compatible tool request body fixture", () =>
Effect.gen(function* () {
const prepared = yield* client({ adapters: [OpenAICompatibleChat.adapter] }).prepare(
LLM.request({
id: "req_tool_parity",
model,
tools: [{
name: "lookup",
description: "Lookup data",
inputSchema: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
}],
toolChoice: "lookup",
messages: [
LLM.user("What is the weather?"),
LLM.assistant([LLM.toolCall({ id: "call_1", name: "lookup", input: { query: "weather" } })]),
LLM.toolMessage({ id: "call_1", name: "lookup", result: { forecast: "sunny" } }),
],
}),
)
expect(prepared.target).toEqual({
model: "deepseek-chat",
messages: [
{ role: "user", content: "What is the weather?" },
{
role: "assistant",
content: null,
tool_calls: [{
id: "call_1",
type: "function",
function: { name: "lookup", arguments: '{"query":"weather"}' },
}],
},
{ role: "tool", tool_call_id: "call_1", content: '{"forecast":"sunny"}' },
],
tools: [{
type: "function",
function: {
name: "lookup",
description: "Lookup data",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
},
}],
tool_choice: { type: "function", function: { name: "lookup" } },
stream: true,
})
}),
)
it.effect("posts to the configured compatible endpoint and parses text usage", () =>
Effect.gen(function* () {
const response = yield* client({