import { chat, rawSSE, save, MODELS, short } from "./lib.ts"; const tools = [ { type: "function", function: { name: "get_weather", description: "Get the current weather for a city", parameters: { type: "object", properties: { city: { type: "string", description: "City name" } }, required: ["city"], additionalProperties: false }, }, }, ]; const out: Record = {}; for (const model of MODELS) { const messages: any[] = [{ role: "user", content: "What's the weather in Montreal right now? Use the tool." }]; const s = await rawSSE("/chat/completions", { model, messages, tools, tool_choice: "auto", max_completion_tokens: 200, stream: true, stream_options: { include_usage: true } }); const tcEvents = s.events.filter((e) => e.data !== "[DONE]" && e.data?.choices?.[0]?.delta?.tool_calls); const finishes = s.events.filter((e) => e.data !== "[DONE]" && e.data?.choices?.[0]?.finish_reason).map((e) => e.data.choices[0].finish_reason); // accumulate const acc: Record = {}; for (const e of tcEvents) { for (const tc of e.data.choices[0].delta.tool_calls) { const i = tc.index ?? 0; acc[i] ??= { args: "" }; if (tc.id) acc[i].id = tc.id; if (tc.type) acc[i].type = tc.type; if (tc.function?.name) acc[i].name = tc.function.name; if (tc.function?.arguments) acc[i].args += tc.function.arguments; } } console.log(model, "stream tools:", s.status, "events", s.events.length, "toolCallChunks", tcEvents.length, "finishes", finishes, "\n accumulated:", JSON.stringify(acc), "\n tc deltas:", short(tcEvents.map((e) => e.data.choices[0].delta), 800), s.error ? "\n ERROR " + short(s.error) : ""); out[`${model}:stream`] = { status: s.status, nEvents: s.events.length, toolCallChunkCount: tcEvents.length, finishes, accumulated: acc, toolCallDeltas: tcEvents.map((e) => e.data.choices[0].delta), usageEvent: s.events.find((e) => e.data !== "[DONE]" && e.data?.usage)?.data, error: s.error }; // round trip (non-stream round 2) const first = Object.values(acc)[0]; if (first?.id) { messages.push({ role: "assistant", content: null, tool_calls: [{ id: first.id, type: "function", function: { name: first.name, arguments: first.args } }] }); messages.push({ role: "tool", tool_call_id: first.id, content: JSON.stringify({ city: "Montreal", temp_c: 21, sky: "sunny" }) }); const r2 = await chat({ model, messages, tools, max_completion_tokens: 150 }); const b: any = r2.body; out[`${model}:round2`] = { status: r2.status, body: b }; console.log(model, "round2:", r2.status, short(b?.choices?.[0]?.message?.content ?? b, 200), "finish", b?.choices?.[0]?.finish_reason); } else { // non-stream tool call for comparison const r1 = await chat({ model, messages, tools, tool_choice: "required", max_completion_tokens: 200 }); out[`${model}:nonstream-required`] = r1; console.log(model, "nonstream required:", r1.status, short((r1.body as any)?.choices?.[0]?.message ?? r1.body, 400)); } } save("03-tools-stream.json", out);