mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-09 22:25:02 +03:00
81 lines
3.3 KiB
TypeScript
81 lines
3.3 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import { Schema } from "effect"
|
|
import { ai, type LLMRequest, Message, ToolCallPart, ToolDefinition } from "../src/effect.js"
|
|
import { OpenAIChat } from "../src/protocols.js"
|
|
import { Auth } from "../src/route.js"
|
|
import { sanitizeSurrogates } from "../src/utils/sanitize.js"
|
|
|
|
const model = OpenAIChat.route
|
|
.with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") })
|
|
.model({ id: "gpt-4o-mini" })
|
|
|
|
const tool = new ToolDefinition({
|
|
name: "lookup",
|
|
description: "Look something up",
|
|
inputSchema: { type: "object", properties: { query: { type: "string" } } },
|
|
})
|
|
|
|
// Mirrors request preparation: sanitize everything but the model, then normalize the copies back into classes.
|
|
const sanitizeRequest = (request: LLMRequest) =>
|
|
ai.request({ ...request, ...sanitizeSurrogates({ ...request, model: undefined }), model: request.model })
|
|
|
|
describe("sanitizeSurrogates", () => {
|
|
test("replaces lone surrogates in nested message text, tool input, and tool output", () => {
|
|
const sanitized = sanitizeRequest(
|
|
ai.request({
|
|
model,
|
|
system: "system \uD800",
|
|
tools: [tool],
|
|
messages: [
|
|
Message.user("user \uDC00 \u{1F600}"),
|
|
Message.assistant([
|
|
ToolCallPart.make({ id: "call_1", name: "lookup", input: { "q\uD800": "input \uDC00" } }),
|
|
]),
|
|
Message.tool({ id: "call_1", name: "lookup", result: { output: ["result \uD800", "valid"] } }),
|
|
],
|
|
}),
|
|
)
|
|
|
|
expect(sanitized.messages.every((message) => Schema.is(Message)(message))).toBe(true)
|
|
expect(sanitized.tools[0]).toBe(tool)
|
|
expect(sanitized.system).toEqual([{ type: "text", text: "system \uFFFD" }])
|
|
expect(sanitized.messages).toEqual([
|
|
Message.user("user \uFFFD \u{1F600}"),
|
|
Message.assistant([ToolCallPart.make({ id: "call_1", name: "lookup", input: { "q\uFFFD": "input \uFFFD" } })]),
|
|
Message.tool({ id: "call_1", name: "lookup", result: { output: ["result \uFFFD", "valid"] } }),
|
|
])
|
|
})
|
|
|
|
test("keeps clean requests equal and shares unchanged nested values", () => {
|
|
const messages = [Message.user("hello \u{1F600}"), Message.assistant("hi")]
|
|
const request = ai.request({
|
|
model,
|
|
system: "system",
|
|
tools: [tool],
|
|
messages: [...messages, Message.user("bad \uD800")],
|
|
maxTokens: 10,
|
|
providerOptions: { nested: { list: ["a", "b"] } },
|
|
})
|
|
const sanitized = sanitizeRequest(request)
|
|
|
|
expect(sanitized.messages.slice(0, 2)).toEqual(request.messages.slice(0, 2))
|
|
expect(sanitized.messages[0]).toBe(request.messages[0])
|
|
expect(sanitized.messages[1]).toBe(request.messages[1])
|
|
expect(sanitized.messages[2]).not.toBe(request.messages[2])
|
|
expect(sanitized.messages[2]).toEqual(Message.user("bad \uFFFD"))
|
|
expect(sanitized.tools[0]).toBe(request.tools[0])
|
|
expect(sanitized.maxTokens).toBe(10)
|
|
|
|
const input = request
|
|
const output = sanitizeSurrogates(input)
|
|
expect(output.system).toBe(input.system)
|
|
expect(output.tools).toBe(input.tools)
|
|
expect(output.providerOptions).toBe(input.providerOptions)
|
|
expect(output.messages).not.toBe(input.messages)
|
|
|
|
const clean = ai.request({ model, system: "system", tools: [tool], messages })
|
|
expect(sanitizeRequest(clean)).toEqual(clean)
|
|
expect(sanitizeSurrogates(clean).messages).toBe(clean.messages)
|
|
})
|
|
})
|