// Probe (d): function-call round trip with streaming; record tool_calls delta shape. import { CHAT_MODELS, client, rawSSE, save, short } from "./lib.ts"; const tools: any = [ { type: "function", function: { name: "get_weather", description: "Get current weather for a city", parameters: { type: "object", properties: { city: { type: "string" }, unit: { type: "string", enum: ["c", "f"] } }, required: ["city"], }, }, }, ]; const results: Record = {}; for (const model of CHAT_MODELS) { const r: any = {}; const messages: any[] = [{ role: "user", content: "What's the weather in Montreal right now? Use the tool." }]; // round 1 streaming (raw) to capture delta shape const s = await rawSSE("/chat/completions", { model, messages, tools, tool_choice: "auto", stream: true, stream_options: { include_usage: true }, max_completion_tokens: 300 }); if ((s as any).error) { r.round1 = { status: s.status, error: (s as any).error }; console.log(model, "round1 ERR", s.status, short((s as any).error)); results[model] = r; continue; } const tcChunks = s.events.filter((e) => e.data?.choices?.[0]?.delta?.tool_calls); r.round1 = { nChunks: s.events.length, toolCallChunks: tcChunks.map((e) => e.data), finishReasons: [...new Set(s.events.map((e) => e.data?.choices?.[0]?.finish_reason).filter(Boolean))], usage: s.events.find((e) => e.data?.usage)?.data?.usage, }; console.log(model, "round1 toolCallChunks", tcChunks.length, "finish", r.round1.finishReasons, short(tcChunks[0]?.data?.choices[0].delta, 300)); // assemble tool call const acc: Record = {}; for (const e of tcChunks) for (const tc of e.data.choices[0].delta.tool_calls) { const a = (acc[tc.index ?? 0] ??= { id: "", name: "", args: "" }); if (tc.id) a.id = tc.id; if (tc.function?.name) a.name += tc.function.name; if (tc.function?.arguments) a.args += tc.function.arguments; } const calls = Object.values(acc); if (!calls.length) { results[model] = r; continue; } messages.push({ role: "assistant", content: null, tool_calls: calls.map((c) => ({ id: c.id, type: "function", function: { name: c.name, arguments: c.args } })) }); for (const c of calls) messages.push({ role: "tool", tool_call_id: c.id, content: JSON.stringify({ temp_c: 21, condition: "sunny" }) }); // round 2 via SDK, non-stream try { const res = await client.chat.completions.create({ model, messages, tools, max_completion_tokens: 200 }); r.round2 = { content: res.choices[0].message.content, finish: res.choices[0].finish_reason, usage: res.usage }; console.log(model, "round2", short(res.choices[0].message.content, 120)); } catch (e: any) { r.round2 = { error: e.status, body: e.error ?? e.message }; console.log(model, "round2 ERR", e.status, short(e.error ?? e.message)); } results[model] = r; } save("03-tools-stream.json", results);