import type { TemplateContext } from "../templating.js"; import type { VerboseLevel } from "../thinking.js"; import type { GetReplyOptions, ReplyPayload } from "../types.js"; import type { FollowupRun } from "./queue.js"; import type { TypingSignaler } from "./typing-mode.js"; import { runEmbeddedPiKoi } from "../../koi/pi-embedded.js"; import { type SessionEntry } from "../../config/sessions.js"; import { type BlockReplyPipeline } from "./block-reply-pipeline.js"; export type KoiRunLoopResult = { kind: "success"; runResult: Awaited>; fallbackProvider?: string; fallbackModel?: string; didLogHeartbeatStrip: boolean; autoCompactionCompleted: boolean; /** Payload keys sent directly (not via pipeline) during tool flush. */ directlySentBlockKeys?: Set; /** Number of tool calls made during this run (tracked via koi events). */ heartbeatToolCallCount?: number; } | { kind: "final"; payload: ReplyPayload; }; /** * Runs the koi LLM turn with automatic model fallback on context overflow * or compaction failure. Retries with a fresh session when necessary. * * Tracks tool-call counts for heartbeat productivity enforcement and streams * block replies through the pipeline when block-streaming is enabled. * * @returns Either a `"success"` result with the raw run output and metadata, * or a `"final"` result with a pre-built error payload (no further processing needed). */ export declare function runKoiTurnWithFallback(params: { commandBody: string; followupRun: FollowupRun; sessionCtx: TemplateContext; opts?: GetReplyOptions; typingSignals: TypingSignaler; blockReplyPipeline: BlockReplyPipeline | null; blockStreamingEnabled: boolean; blockReplyChunking?: { minChars: number; maxChars: number; breakPreference: "paragraph" | "newline" | "sentence"; flushOnParagraph?: boolean; }; resolvedBlockStreamingBreak: "text_end" | "message_end"; applyReplyToMode: (payload: ReplyPayload) => ReplyPayload; shouldEmitToolResult: () => boolean; shouldEmitToolOutput: () => boolean; pendingToolTasks: Set>; resetSessionAfterCompactionFailure: (reason: string) => Promise; resetSessionAfterRoleOrderingConflict: (reason: string) => Promise; isHeartbeat: boolean; sessionKey?: string; getActiveSessionEntry: () => SessionEntry | undefined; activeSessionStore?: Record; storePath?: string; resolvedVerboseLevel: VerboseLevel; }): Promise;