zz_

app/agent/chatBackend.ts

zzmq.dev@gmail.com/zz / app / agent / chatBackend.ts @ 94a4d2db Download
Ladder Summary
  • file The file defines the public contract between the generic tool‑calling loop and any underlying LLM provider by exporting the **ChatMessage** type (the shape of messages, including tool call metadata) and the **ChatBackend** interface (which any backend must implement with a `name` string and a `chat(messages, tools, onPartial?)` method that returns a `Promise<ChatMessage>`). These exported types are the only symbols other code imports to interact with a local Ollama model, Gemini API, or future providers.
 // The one seam between the generic tool-calling loop (agent/loop.ts)
 // and whichever model actually answers -- a local Ollama model or a
 // remote API (Gemini today). The loop only ever talks to this
 // interface, never to a provider's own wire format directly, so it
 // doesn't care which one is running underneath.
 import type { ToolDef } from "./tools.js";
 
 export interface ChatMessage {
  role: "system" | "user" | "assistant" | "tool";
  content: string;
  tool_calls?: {
  function: { name: string; arguments: Record<string, unknown> };
  /**
  * A backend's own opaque per-call metadata, round-tripped back to
  * that same backend unchanged on the next turn -- needed for
  * Gemini specifically, whose API rejects a reconstructed
  * functionCall that's missing the `thoughtSignature` it returned
  * the first time (confirmed directly: a real 400 "Function call is
  * missing a thought_signature" error). Other backends (Ollama)
  * never set or read this.
  */
  raw?: unknown;
  }[];
  /** Which tool this result is for, on a "tool"-role message -- Ollama doesn't need it (matches by array order), Gemini's functionResponse does (matches by name). */
  name?: string;
 }
 
 export interface ChatBackend {
  name: string;
  /**
  * One turn: given the full message history and the tools available,
  * returns the model's reply (content and/or tool_calls). `onPartial`,
  * if the backend supports streaming, is called repeatedly with the
  * accumulated text-so-far.
  */
  chat(messages: ChatMessage[], tools: ToolDef[], onPartial?: (textSoFar: string) => void): Promise<ChatMessage>;
 }