import * as readline from 'node:readline/promises'; import type { Message, CrowcoderConfig } from './types.js'; import type { Mode } from './modes.js'; /** * Count how many NON-OVERLAPPING occurrences of the last `windowSize` * characters of `fullText` appear in the full string. Bails as soon as * `threshold` is reached so the cost is O(threshold * windowSize) in * the common stuck-model case rather than O(fullText.length). * * Non-overlapping by stepping the search index by `windowSize` after * each match. Overlapping counts cause false positives on self-similar * text (markdown tables, repeated import lines, ASCII art) — the audit * found that `idx++` made a single copy match 3+ times when there were * only two genuine repeats. * * Exported so the loop-detector behavior can be unit-tested without * driving the full streamChat loop. */ export declare function countTailRepetitions(fullText: string, windowSize: number, threshold: number): number; export interface QueryContext { config: CrowcoderConfig; messages: Message[]; cwd: string; rl: readline.Interface; sessionId: string; mode: Mode; } export interface InputGuard { pause(): void; resume(): void; /** Return whatever the user typed during streaming, then clear the buffer. */ drainQueuedInput(): string; /** * Register a callback invoked when the user presses Ctrl+G (Steer). * The handler is responsible for aborting the active stream / chain * and treating the queued buffer as the next user message. */ onSteer(handler: () => void): void; restore(): void; } export declare function buildStateBlock(messages: Message[]): string | null; export declare function maskOldToolResults(messages: Message[]): Message[]; /** * F5+ DeCRIM 3-stage critique prompts. * * Each prompt is designed to do exactly one job, in sequence: * * decompose — Forces the model to extract requirements from the * ORIGINAL task before judging its own work. This is * the leverage point: the model can't bypass an * implicit requirement if it has to name it. * * critique — Per-item PASS/FAIL with concrete evidence required. * Asking for evidence ("file path", "command output", * "test result") is much harder to fake than the * generic "have you accomplished what was asked?". * * refine — Only the FAIL items get redone, plus any items * whose PASS evidence the model now thinks was weak. * If everything is solid, the model exits naturally. * * The phrasing deliberately includes "be honest" / "the user prefers * honest failures over confident lies" — research on prompted self- * criticism shows this kind of social-cost signaling reduces the * self-confirmation bias that otherwise dominates weak-model * critique. (Reflexion-style "just reflect on your work" prompts * have been shown to degrade weak models — generic self-questioning * without concrete structure produces overconfident revisions.) */ export declare function critiquePromptFor(stage: 'decompose' | 'critique' | 'refine'): string; export declare function dedupFingerprint(toolName: string, rawArgs: string): string; /** * F4 — Rewrite stale duplicate tool-result messages in place. * * Called once per tool-execution batch. For each call whose * fingerprint we've seen before in this chain, find the previous * tool-result message and replace its `content` with a 1-line stub * pointing at the newer message. The new result stays untouched so * the model's next turn reads complete, fresh data. * * NOT called for the FIRST occurrence of a fingerprint — only when * a repeat fires. So a one-time `read` of a file is never touched. * * The map is keyed by fingerprint → array-index of the tool result * in ctx.messages. We update the index to the newest occurrence after * each rewrite, so the NEXT repeat collapses the second one (not the * first, which is already stubbed). */ export declare function dedupRepeatedToolCalls(messages: Message[], toolCalls: { id: string; type: 'function'; function: { name: string; arguments: string; }; }[], toolResults: Message[], dedupMap: Map): void; /** * Main query loop: sends messages to the API, handles tool calls, loops until done. */ export declare function runQuery(ctx: QueryContext): Promise;