SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%
3.1 KB · 52 lines typescript
Raw Blame History
1import { chat, rawSSE, save, MODELS, short } from "./lib.ts";23const tools = [4  {5    type: "function",6    function: {7      name: "get_weather",8      description: "Get the current weather for a city",9      parameters: { type: "object", properties: { city: { type: "string", description: "City name" } }, required: ["city"], additionalProperties: false },10    },11  },12];1314const out: Record<string, unknown> = {};15for (const model of MODELS) {16  const messages: any[] = [{ role: "user", content: "What's the weather in Montreal right now? Use the tool." }];17  const s = await rawSSE("/chat/completions", { model, messages, tools, tool_choice: "auto", max_completion_tokens: 200, stream: true, stream_options: { include_usage: true } });18  const tcEvents = s.events.filter((e) => e.data !== "[DONE]" && e.data?.choices?.[0]?.delta?.tool_calls);19  const finishes = s.events.filter((e) => e.data !== "[DONE]" && e.data?.choices?.[0]?.finish_reason).map((e) => e.data.choices[0].finish_reason);20  // accumulate21  const acc: Record<number, { id?: string; name?: string; args: string; type?: string }> = {};22  for (const e of tcEvents) {23    for (const tc of e.data.choices[0].delta.tool_calls) {24      const i = tc.index ?? 0;25      acc[i] ??= { args: "" };26      if (tc.id) acc[i].id = tc.id;27      if (tc.type) acc[i].type = tc.type;28      if (tc.function?.name) acc[i].name = tc.function.name;29      if (tc.function?.arguments) acc[i].args += tc.function.arguments;30    }31  }32  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) : "");33  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 };3435  // round trip (non-stream round 2)36  const first = Object.values(acc)[0];37  if (first?.id) {38    messages.push({ role: "assistant", content: null, tool_calls: [{ id: first.id, type: "function", function: { name: first.name, arguments: first.args } }] });39    messages.push({ role: "tool", tool_call_id: first.id, content: JSON.stringify({ city: "Montreal", temp_c: 21, sky: "sunny" }) });40    const r2 = await chat({ model, messages, tools, max_completion_tokens: 150 });41    const b: any = r2.body;42    out[`${model}:round2`] = { status: r2.status, body: b };43    console.log(model, "round2:", r2.status, short(b?.choices?.[0]?.message?.content ?? b, 200), "finish", b?.choices?.[0]?.finish_reason);44  } else {45    // non-stream tool call for comparison46    const r1 = await chat({ model, messages, tools, tool_choice: "required", max_completion_tokens: 200 });47    out[`${model}:nonstream-required`] = r1;48    console.log(model, "nonstream required:", r1.status, short((r1.body as any)?.choices?.[0]?.message ?? r1.body, 400));49  }50}51save("03-tools-stream.json", out);52