/** * Tool calls that arrive as text instead of as structured `tool_calls`. * * Several local models — Qwen's coder line especially, and anything served through Ollama's * generic chat template — answer a tool-calling request by writing the call out in the content * stream rather than attaching it to the response: * * * * src/main.py * ... * * * * The model is doing exactly what was asked; only the envelope is wrong. Discarding it produced * the worst possible outcome: a run that printed a wall of markup, wrote nothing, and then told * the user their model was "ignoring tool calls" when it plainly was not. * * Only explicitly marked calls are parsed. Bare JSON in a reply is left alone however much it * looks like a call, because a model explaining an API — or writing a file that happens to be * JSON — must never be mistaken for one asking to run something. */ export interface TextToolCall { name: string; /** JSON, matching what the structured field would have carried. */ arguments: string; } export interface TextToolCallResult { calls: TextToolCall[]; /** The reply with the call markup removed, for the transcript. */ cleaned: string; } /** * The declared type of each parameter of a tool, or null if the tool is unknown. * * Needed because the text form carries no types: every value arrives as a string. Guessing by * trying to parse each one as JSON would corrupt the most important case there is — writing a * file whose contents are themselves JSON would turn the text into an object and lose it. */ export type ParamTypes = (toolName: string) => Record | null; /** * Tool calls a model wrote into its reply, and that reply with the markup taken out. * * Returns no calls at all when nothing is explicitly marked, so ordinary prose is untouched. */ export declare function parseTextToolCalls(content: string, paramTypes: ParamTypes): TextToolCallResult; /** Builds the type lookup from the tool list the engine already assembles for the provider. */ export declare function paramTypesFrom(tools: ReadonlyArray<{ function?: { name?: string; parameters?: unknown; }; }>): ParamTypes; /** * Whether a reply has started writing a tool call, cheap enough to run on every streamed chunk. * * Deliberately looser than the parser: the point is to stop putting markup on the screen as soon * as it begins, before enough has arrived to parse. */ export declare function looksLikeTextToolCall(sofar: string): boolean; /** The reply without those tokens, and without the blank space they leave behind. */ export declare function stripTemplateTokens(text: string): string; /** * Whether the reply so far could still turn out to be a bare JSON tool call. * * `looksLikeTextToolCall` needs the whole `{"name"` before it can say so, and a stream does not * deliver it in one piece: the chunks arrive as `{`, then `"`, then `name`. Each was put on screen * as it came, so a local model answering with a bare call printed `{"name` before anything * suppressed the rest. Reported from an Ollama model, and visible in the screenshot as exactly * that fragment sitting above the reply. * * True only while the reply is nothing but a possible opening — six or seven characters, at the * very start. A `{` in the middle of prose is a `{`, and once the text stops being a prefix of one * of these it flows straight through, having lost nothing but a few frames of delay. */ export declare function mightBeginTextToolCall(sofar: string): boolean; /** * Splits streamed text into the part safe to display and a tail that might begin a tool call. * * Suppression can only start once a marker is complete, and a chunk boundary falls wherever the * provider put it — so a reply ended visibly with a bare "; } export type ToolShapes = (name: string) => ToolShape | null; /** Tool names and their parameters, from the same array sent to the provider. */ export declare function toolShapesFrom(tools: ReadonlyArray<{ function?: { name?: string; parameters?: unknown; }; }>): ToolShapes; /** * One line as a call, or null. * * Three shapes, all seen from local models: `read_file package.json`, `read_file("package.json")` * and `read_file(path="package.json")`. Anything needing more than one value is only accepted in * the named form — guessing which of two arguments a bare word belongs to is how a write ends up * with its path and its contents the wrong way round. */ export declare function parseCommandStyleLine(line: string, shapes: ToolShapes, resolveAlias?: (name: string) => string | null): TextToolCall | null; /** * Calls written as commands inside fenced blocks. * * Only fenced blocks, and only fences whose language is one a model reaches for when it thinks it * is issuing a command. A bare line in prose is not read as a call: "you can read_file anything" * is a sentence. */ export declare function parseCommandStyleCalls(content: string, shapes: ToolShapes, resolveAlias?: (name: string) => string | null): TextToolCallResult; //# sourceMappingURL=tool-call-text.d.ts.map