/** * Native Ollama `/api/chat` transport. * * Why this exists: Codeep normally talks to Ollama through its OpenAI-compatible * `/v1/chat/completions` shim, which silently IGNORES Ollama-native options like * `num_ctx` (context window) and `keep_alive` (model residency). The shim also * defaults to a small context (~2-4k) regardless of the model's real window, so * long sessions get silently truncated server-side. * * The native `/api/chat` endpoint accepts those options and streams * newline-delimited JSON (NOT SSE). Each line is a full JSON object: * {"message":{"role":"assistant","content":"…"},"done":false} * … * {"message":{"content":""},"done":true,"prompt_eval_count":N,"eval_count":M} * * This module keeps the line-parsing as PURE functions so they can be unit * tested without a live server. The networking wrapper lives at the bottom. */ /** A tool call as Ollama's native /api/chat returns it: `function.arguments` * is a JSON OBJECT (unlike OpenAI's JSON-string form). */ export interface OllamaToolCall { name: string; arguments: Record; } export interface OllamaStreamDelta { /** Text chunk from this line (may be empty). */ content: string; /** True on the terminating line. */ done: boolean; /** Tool calls present on this line (Ollama emits them on one message). */ toolCalls?: OllamaToolCall[]; /** Prompt (input) tokens — only present on the final line. */ promptTokens?: number; /** Completion (output) tokens — only present on the final line. */ completionTokens?: number; } /** Extract + normalize `message.tool_calls` from a parsed message. Returns * undefined when none. Tolerates missing/malformed entries (never throws). */ export declare function extractOllamaToolCalls(msg: unknown): OllamaToolCall[] | undefined; /** * Parse a single newline-delimited JSON line from `/api/chat`. Returns null for * blank lines or unparseable keepalives (never throws). Tolerates both the * streaming shape (`message.content`) and the non-stream shape. */ export declare function parseOllamaChatLine(line: string): OllamaStreamDelta | null; export interface OllamaAccumulator { text: string; toolCalls: OllamaToolCall[]; promptTokens?: number; completionTokens?: number; done: boolean; } /** * Fold a parsed delta into a running accumulator. Pure — no I/O. The caller * feeds each line's parse result here and reads `text` / token counts at the end. */ export declare function foldOllamaDelta(acc: OllamaAccumulator, delta: OllamaStreamDelta | null): OllamaAccumulator; /** * Split a buffer into complete lines + a trailing remainder. Pure helper so the * stream reader can carry partial lines across chunk boundaries correctly. * Returns { lines, rest } where `rest` is the unfinished tail (no newline yet). */ export declare function splitOllamaLines(buffer: string): { lines: string[]; rest: string; }; export declare const initialOllamaAccumulator: () => OllamaAccumulator; /** * Pull the real context_length out of an `/api/show` response's `model_info`. * The key is architecture-prefixed (e.g. `llama.context_length`, * `qwen2.context_length`), so we scan for any key ending in `.context_length` * (or the bare `context_length`). Pure + tolerant — returns null when absent. */ export declare function extractContextLength(showResponse: unknown): number | null; /** * Fetch a model's real maximum context window via `/api/show`. Cached per model; * returns null on any error (caller falls back to its default). Never throws. */ export declare function getOllamaContextLength(model: string, ollamaBaseUrl: string): Promise; /** Test seam — reset the per-model context cache. */ export declare function _clearOllamaContextCache(): void; export interface OllamaChatOptions { /** Ollama base URL (without /v1), e.g. http://localhost:11434 */ baseUrl: string; model: string; /** Messages in OpenAI shape {role, content} — Ollama /api/chat accepts these. */ messages: { role: string; content: string; }[]; /** num_ctx — the context window to allocate. 0/undefined = let Ollama decide. */ numCtx?: number; /** keep_alive — how long to keep the model resident, e.g. "30m". */ keepAlive?: string; temperature?: number; timeoutMs?: number; /** Stops the request when it fires (Stop / cancel). The promise then * rejects with an error named 'AbortError', as fetch does. */ signal?: AbortSignal; onChunk?: (text: string) => void; /** Tool definitions in OpenAI function format. Ollama's /api/chat accepts the * same `{type:'function',function:{...}}` shape and returns `tool_calls`. */ tools?: unknown[]; /** Pass-through for non-string message parts (tool results carry tool_call_id * etc.). When set, used verbatim instead of `messages`. */ rawMessages?: unknown[]; } export interface OllamaChatResult { text: string; toolCalls: OllamaToolCall[]; promptTokens?: number; completionTokens?: number; } /** * Stream a chat completion from Ollama's native `/api/chat`. Uses node:http to * sidestep undici's connection pooling (which throws AggregateError against * localhost Ollama on Node 24). Parses the newline-JSON stream via the pure * helpers above. Resolves with the full text + token usage. */ export declare function streamOllamaNativeChat(opts: OllamaChatOptions): Promise;