/** * Grammar-leak recovery — adapted in place from monotykamary/pi-tool-repair * (MIT), `src/grammar-repair.ts`. The grammar-family parsers, candidate * selection, code-fence awareness, and `removeRanges` are kept close to * upstream; the driver (`recoverGrammarLeaks`) is rewritten to integrate this * extension's settings, model gate, and telemetry, and to add a stopReason gate * upstream lacks. * * What it does: some models print a tool call as literal text (10 grammar * families — DSML, Qwen/GLM XML, Kimi/Mistral/Llama/MiniMax sentinels, etc.) * instead of emitting a real tool call. On the `message_end` hook this detects * those leaked blocks, strips them from the assistant text, and — in `recover` * mode — promotes the parsed calls to real toolCalls that execute the same turn. * * The one deliberate improvement over upstream: promotion happens ONLY when the * original message's `stopReason` is `"stop"` (see `recoverGrammarLeaks`). * Upstream promotes regardless and overwrites `stopReason: "length"`, defeating * pi's protection that fails all tool calls on truncated output * (docs/research.md Claim 7). Stripping leaked text is permitted on any * stopReason; only promotion is gated. */ export declare const GRAMMAR_NAMES: readonly ["dsml", "invoke", "qwen", "kimi", "mistral", "llama", "glm", "granite", "minimax-text", "olmo"]; export type GrammarName = (typeof GRAMMAR_NAMES)[number]; export type GrammarRecoveryMode = "off" | "observe" | "strip" | "recover"; export interface RecoveredToolCall { name: string; arguments: Record; grammar: GrammarName; } interface MinimalTextContent { type: "text"; text: string; [key: string]: unknown; } interface MinimalThinkingContent { type: "thinking"; thinking: string; [key: string]: unknown; } interface MinimalToolCallContent { type: "toolCall"; id: string; name: string; arguments: Record; [key: string]: unknown; } type MinimalAssistantContent = MinimalTextContent | MinimalThinkingContent | MinimalToolCallContent | Record; export interface MinimalAssistantMessage { role: string; content: MinimalAssistantContent[]; stopReason?: string; [key: string]: unknown; } /** * Open-model families known to print tool-call grammar as text. Grammar * recovery runs only when the current model matches one of these — a heuristic * gate that keeps the parsers off frontier models (Claude/GPT/Gemini) that emit * native tool calls and may legitimately quote grammar in prose. The real * safety is the known-tool / empty-args / stopReason gates; this list is the * cheap first filter and can be loosened as telemetry warrants. */ export declare const GRAMMAR_RECOVERY_MODELS: readonly RegExp[]; /** Whether grammar recovery's model gate matches the given model id. */ export declare function modelLeaksGrammar(modelId: string | undefined): boolean; export interface GrammarRecoveryOptions { mode: GrammarRecoveryMode; /** Active/allowed tool names; a leaked call is only promoted if its name is here. */ knownTools: Set; /** Which grammar families to detect. Default: all. */ grammars?: readonly GrammarName[]; /** Require the recovered tool name to be in `knownTools`. Default: true. */ requireKnownTool?: boolean; /** Unknown/disallowed calls are preserved unless explicitly set to strip. */ unknownToolText?: "preserve" | "strip"; } export interface GrammarRecoveryResult { /** Whether the message was modified (text stripped and/or calls promoted). */ changed: boolean; /** Calls promoted to real toolCalls (empty unless a promotion happened). */ recoveredCalls: RecoveredToolCall[]; /** Distinct grammar families whose leaked text was stripped. */ strippedGrammars: GrammarName[]; /** Number of leaked ranges removed from text. */ strippedRanges: number; /** True when calls were promoted and stopReason was set to "toolUse". */ promoted: boolean; /** Recognized leak metadata, populated even when observe mode preserves text. */ observed: boolean; detectedGrammars: GrammarName[]; detectedRanges: number; /** IDs assigned to promoted calls, in recoveredCalls order. */ promotedCallIds: string[]; /** The replacement message (same object when unchanged). */ message: MinimalAssistantMessage; } /** * Detect leaked tool-call grammar in an assistant message, strip it from the * text, and (in `recover` mode, on a `stopReason: "stop"` message with no * existing toolCalls) promote the parsed calls to real toolCalls. */ export declare function recoverGrammarLeaks(message: MinimalAssistantMessage, options: GrammarRecoveryOptions): GrammarRecoveryResult; /** Pure parse: leaked tool calls in text (no stripping, no gates). For tests. */ export declare function parseToolGrammarLeaks(text: string, grammars?: Iterable): RecoveredToolCall[]; export {}; //# sourceMappingURL=grammar-recovery.d.ts.map