flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/services/models/src/openai.test.ts

174 lines7,200 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { StreamTranslator, carryId, errorFromChat, fromChat, toChat, uncarryId } from "./openai.ts";
5
6test("a conversation with tool calls becomes a chat completion", () => {
7 const body = toChat(
8 {
9 system: [{ type: "text", text: "You are a coding agent." }],
10 max_tokens: 4096,
11 temperature: 0.2,
12 stream: true,
13 tools: [
14 { name: "Bash", description: "Run a command", input_schema: { type: "object", properties: { command: { type: "string" } } } },
15 { name: "web_search", type: "web_search_20250305" },
16 ],
17 messages: [
18 { role: "user", content: "Fix the test." },
19 {
20 role: "assistant",
21 content: [
22 { type: "text", text: "Running it." },
23 { type: "tool_use", id: "toolu_1", name: "Bash", input: { command: "cargo test" } },
24 ],
25 },
26 {
27 role: "user",
28 content: [
29 { type: "tool_result", tool_use_id: "toolu_1", content: [{ type: "text", text: "1 failed" }] },
30 { type: "text", text: "Keep going." },
31 ],
32 },
33 ],
34 },
35 "gpt-5",
36 { official: true },
37 );
38 assert.deepEqual(body.messages, [
39 { role: "system", content: "You are a coding agent." },
40 { role: "user", content: "Fix the test." },
41 {
42 role: "assistant",
43 content: "Running it.",
44 tool_calls: [{ id: "toolu_1", type: "function", function: { name: "Bash", arguments: '{"command":"cargo test"}' } }],
45 },
46 { role: "tool", tool_call_id: "toolu_1", content: "1 failed" },
47 { role: "user", content: "Keep going." },
48 ]);
49 assert.equal(body.model, "gpt-5");
50 assert.equal(body.max_completion_tokens, 4096);
51 assert.equal(body.temperature, undefined);
52 assert.deepEqual(body.stream_options, { include_usage: true });
53 // Only functions cross over; Anthropic's server tools do not.
54 assert.equal((body.tools as unknown[]).length, 1);
55});
56
57test("a compatible endpoint gets max_tokens and temperature", () => {
58 const body = toChat({ messages: [{ role: "user", content: "hi" }], max_tokens: 10, temperature: 0.5 }, "llama", { official: false });
59 assert.equal(body.max_tokens, 10);
60 assert.equal(body.temperature, 0.5);
61});
62
63test("a completion comes back as an Anthropic message", () => {
64 const message = fromChat(
65 {
66 id: "chatcmpl-1",
67 choices: [
68 {
69 finish_reason: "tool_calls",
70 message: {
71 content: "Let me look.",
72 tool_calls: [{ id: "call_1", type: "function", function: { name: "Read", arguments: '{"file_path":"a.rs"}' } }],
73 },
74 },
75 ],
76 usage: { prompt_tokens: 10, completion_tokens: 5 },
77 },
78 "gpt-5",
79 );
80 assert.deepEqual(message.content, [
81 { type: "text", text: "Let me look." },
82 { type: "tool_use", id: "call_1", name: "Read", input: { file_path: "a.rs" } },
83 ]);
84 assert.equal(message.stop_reason, "tool_use");
85 assert.deepEqual(message.usage, { input_tokens: 10, output_tokens: 5 });
86});
87
88function events(sse: string): { type: string; [key: string]: unknown }[] {
89 return sse
90 .split("\n\n")
91 .filter(Boolean)
92 .map((block) => JSON.parse(block.split("\n")[1].slice(6)));
93}
94
95test("a streamed answer becomes Anthropic's stream, text then a tool call", () => {
96 const translator = new StreamTranslator("gpt-5");
97 const chunks = [
98 { id: "c1", choices: [{ delta: { role: "assistant", content: "On it" } }] },
99 { id: "c1", choices: [{ delta: { content: "." } }] },
100 { id: "c1", choices: [{ delta: { tool_calls: [{ index: 0, id: "call_9", function: { name: "Bash", arguments: '{"comm' } }] } }] },
101 { id: "c1", choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: 'and":"ls"}' } }] } }] },
102 { id: "c1", choices: [{ delta: {}, finish_reason: "tool_calls" }] },
103 { id: "c1", choices: [], usage: { prompt_tokens: 12, completion_tokens: 7 } },
104 ];
105 // Delivered in awkward pieces, as networks do.
106 const raw = chunks.map((c) => `data: ${JSON.stringify(c)}\n\n`).join("") + "data: [DONE]\n\n";
107 let out = "";
108 for (let at = 0; at < raw.length; at += 17) out += translator.push(raw.slice(at, at + 17));
109 out += translator.finish();
110 const seen = events(out);
111 assert.deepEqual(
112 seen.map((e) => e.type),
113 [
114 "message_start",
115 "content_block_start",
116 "content_block_delta",
117 "content_block_delta",
118 "content_block_stop",
119 "content_block_start",
120 "content_block_delta",
121 "content_block_delta",
122 "content_block_stop",
123 "message_delta",
124 "message_stop",
125 ],
126 );
127 assert.deepEqual(seen[5].content_block, { type: "tool_use", id: "call_9", name: "Bash", input: {} });
128 const json = seen
129 .filter((e) => (e.delta as { type?: string } | undefined)?.type === "input_json_delta")
130 .map((e) => (e.delta as { partial_json: string }).partial_json)
131 .join("");
132 assert.deepEqual(JSON.parse(json), { command: "ls" });
133 assert.deepEqual(seen[9].delta, { stop_reason: "tool_use", stop_sequence: null });
134 assert.deepEqual(seen[9].usage, { input_tokens: 12, output_tokens: 7 });
135});
136
137test("a provider's error keeps its status and says what it said", () => {
138 const error = errorFromChat(429, JSON.stringify({ error: { message: "Rate limit reached" } }));
139 assert.deepEqual(error, { type: "error", error: { type: "rate_limit_error", message: "The provider said: Rate limit reached" } });
140});
141
142test("each provider's quirks are met", () => {
143 const ask = { messages: [{ role: "user" as const, content: "hi" }], max_tokens: 32000, stream: true, tool_choice: { type: "any" as const }, tools: [{ name: "Bash", input_schema: { type: "object" } }] };
144 const deepseek = toChat(ask, "deepseek-chat", { official: false, provider: "deepseek" });
145 assert.equal(deepseek.max_tokens, 8192);
146 assert.equal(deepseek.tool_choice, "required");
147 const mistral = toChat(ask, "mistral-large-latest", { official: false, provider: "mistral" });
148 assert.equal(mistral.tool_choice, "any");
149 assert.equal(mistral.stream_options, undefined);
150});
151
152test("what a provider attaches to a tool call comes back with it", () => {
153 const signature = { google: { thought_signature: "c2lnbmF0dXJl+/==" } };
154 const id = carryId("call_1", signature);
155 assert.match(id, /^call_1__g1t_[A-Za-z0-9_-]+$/);
156 assert.deepEqual(uncarryId(id), { id: "call_1", extra: signature });
157 assert.deepEqual(uncarryId("toolu_plain"), { id: "toolu_plain", extra: undefined });
158
159 const body = toChat(
160 {
161 messages: [
162 { role: "user", content: "go" },
163 { role: "assistant", content: [{ type: "tool_use", id, name: "Bash", input: {} }] },
164 { role: "user", content: [{ type: "tool_result", tool_use_id: id, content: "ok" }] },
165 ],
166 },
167 "gemini-3-pro",
168 { official: false, provider: "gemini" },
169 );
170 const messages = body.messages as Record<string, unknown>[];
171 assert.deepEqual((messages[1].tool_calls as Record<string, unknown>[])[0].extra_content, signature);
172 assert.equal((messages[1].tool_calls as Record<string, unknown>[])[0].id, "call_1");
173 assert.equal(messages[2].tool_call_id, "call_1");
174});