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.7 KB · 46 lines typescript
Raw Blame History
1import { rawPost, rawSSE, save, short } from "./lib.ts";23const model = process.argv[2] ?? "kimi-k3";4const tools = [{ type: "builtin_function", function: { name: "$web_search" } }];5const messages: any[] = [{ role: "user", content: "What was the closing value of the S&P 500 yesterday? Search the web and cite the source URL." }];67// step 1 streamed8const s = await rawSSE("/chat/completions", { model, messages, tools, max_tokens: 6000, stream_options: { include_usage: true }, ...(model === "kimi-k3" ? { reasoning_effort: "low" } : {}) });9const acc: any = { role: "assistant", content: "", reasoning_content: "", tool_calls: [] as any[] };10let finish: string | null = null; let usage: any = null; const tcChunks: any[] = [];11for (const c of s.chunks) {12  if (c === "[DONE]") continue;13  if (c.usage) usage = c.usage;14  for (const ch of c.choices ?? []) {15    const d = ch.delta ?? {};16    if (d.content) acc.content += d.content;17    if (d.reasoning_content) acc.reasoning_content += d.reasoning_content;18    if (d.tool_calls) { tcChunks.push(d.tool_calls); for (const tc of d.tool_calls) { const i = tc.index ?? 0; acc.tool_calls[i] ??= { id: "", type: "", function: { name: "", arguments: "" } }; if (tc.id) acc.tool_calls[i].id = tc.id; if (tc.type) acc.tool_calls[i].type = tc.type; if (tc.function?.name) acc.tool_calls[i].function.name += tc.function.name; if (tc.function?.arguments) acc.tool_calls[i].function.arguments += tc.function.arguments; } }19    if (ch.finish_reason) finish = ch.finish_reason;20  }21}22console.log(`[${model}] step1 ${s.status} finish=${finish} tcChunks=${tcChunks.length} usage=${JSON.stringify(usage)} error=${short(s.error, 300)}`);23console.log("  first tool_calls chunk:", short(tcChunks[0], 500));24console.log("  accumulated tool_calls:", short(acc.tool_calls, 800));25console.log("  content:", short(acc.content, 200), "reasoning len:", acc.reasoning_content.length);26const out: any = { step1: { status: s.status, finish, usage, tcChunks, acc, error: s.error } };2728if (acc.tool_calls.length) {29  // step 2: return arguments verbatim30  const toolMsgs = acc.tool_calls.map((tc: any) => ({ role: "tool", tool_call_id: tc.id, name: tc.function.name, content: tc.function.arguments }));31  const r2 = await rawPost("/chat/completions", { model, messages: [...messages, { role: "assistant", content: acc.content || null, reasoning_content: acc.reasoning_content, tool_calls: acc.tool_calls }, ...toolMsgs], tools, max_tokens: 6000, ...(model === "kimi-k3" ? { reasoning_effort: "low" } : {}) });32  const m = (r2.body as any)?.choices?.[0]?.message;33  console.log(`  step2 ${r2.status} finish=${(r2.body as any)?.choices?.[0]?.finish_reason} keys=${Object.keys(m ?? {})} usage=${JSON.stringify((r2.body as any)?.usage)}`);34  console.log("  step2 content:", short(m?.content ?? r2.body, 1200));35  console.log("  step2 top-level keys:", Object.keys((r2.body as any) ?? {}));36  console.log("  step2 choice keys:", Object.keys((r2.body as any)?.choices?.[0] ?? {}));37  out.step2 = r2;38  // if it called search again, do a 3rd round39  if (m?.tool_calls?.length) {40    const r3 = await rawPost("/chat/completions", { model, messages: [...messages, { role: "assistant", content: acc.content || null, reasoning_content: acc.reasoning_content, tool_calls: acc.tool_calls }, ...toolMsgs, m, ...m.tool_calls.map((tc: any) => ({ role: "tool", tool_call_id: tc.id, name: tc.function.name, content: tc.function.arguments }))], tools, max_tokens: 6000, ...(model === "kimi-k3" ? { reasoning_effort: "low" } : {}) });41    console.log(`  step3 ${r3.status} finish=${(r3.body as any)?.choices?.[0]?.finish_reason}`, short((r3.body as any)?.choices?.[0]?.message?.content ?? r3.body, 1200), JSON.stringify((r3.body as any)?.usage));42    out.step3 = r3;43  }44}45save(`06-websearch-${model}`, out);46