import { type Message, type Provider, type ThinkingLevel } from "@kenkaiiii/gg-ai";
import { EventBus } from "./event-bus.js";
import { SlashCommandRegistry } from "./slash-commands.js";
import { type BranchInfo, type KenTurnPayload, type AutopilotMarkerPayload, type AppMarkerPayload } from "./session-manager.js";
import type { BackgroundProcess } from "./process-manager.js";
import { type EnhanceResult } from "../utils/prompt-enhancer.js";
/** A chat attachment (image / video / other file) prepared for the model. The
 *  raw base64 `data` rides native blocks; `path` (when persisted to disk) lets
 *  the agent's tools open the file directly. */
export interface SessionAttachment {
    kind: "image" | "video" | "file";
    mediaType: string;
    data: string;
    name: string;
    path?: string;
}
export interface AgentSessionOptions {
    provider: Provider;
    model: string;
    cwd: string;
    baseUrl?: string;
    systemPrompt?: string;
    sessionId?: string;
    continueRecent?: boolean;
    maxTokens?: number;
    maxTurns?: number;
    thinkingLevel?: ThinkingLevel;
    signal?: AbortSignal;
    /** Prefix used for provider prompt-cache routing keys. */
    promptCacheKeyPrefix?: string;
    /**
     * Explicit prompt-cache routing key. When set, overrides the
     * `${promptCacheKeyPrefix}:${sessionId}` default so spawned sub-agents can
     * inherit a stable parent-scoped key — without this, each sub-agent process
     * generates a fresh sessionId and starts with a cold cache.
     */
    promptCacheKey?: string;
    /**
     * If true, this session does NOT create a `.jsonl` session file or persist
     * any messages. Used by subagent spawns (`--json` mode) so their transcripts
     * don't leak into `ggcoder continue` for the parent project. Subagent runs
     * are one-shot, NDJSON-streamed to the parent over stdout, and have no
     * resumable identity.
     */
    transient?: boolean;
    /**
     * If true, `initialize()` returns WITHOUT waiting for MCP servers to connect —
     * the connection runs in the background and tools are appended when ready.
     * Hosts whose readiness is gated on `initialize()` (the gg-app sidecar, which
     * can't emit its listening handshake until init resolves) set this so a slow
     * or hanging stdio MCP server (e.g. a first-run `npx -y …` download) can't
     * delay the session from becoming usable. Default (false) keeps the CLI's
     * connect-before-ready behavior so MCP tools are present on the first turn.
     */
    backgroundMcpConnect?: boolean;
    /**
     * Plan-mode callbacks. When provided, the `enter_plan`/`exit_plan` tools are
     * registered and the session manages plan-mode restrictions + system-prompt
     * rebuilds. Hosts (e.g. the gg-app sidecar) use these to surface plan-mode
     * UI. Omitted by callers that don't want plan mode (CLI wires its own).
     */
    onEnterPlan?: (reason?: string) => void | Promise<void>;
    onExitPlan?: (planPath: string) => Promise<string>;
    /**
     * If provided, the session's tool set is filtered to ONLY these tool names
     * after `createTools()` runs, and the system prompt's Tools section lists only
     * them. Used by read-only advisory sessions (e.g. the Ken mentor agent) to
     * register a safe subset — excluded mutating tools (write/edit/bash/…) are
     * never registered, so a hallucinated call can't change the repo. Default
     * (undefined) = all tools, preserving every existing caller's behavior.
     */
    allowedTools?: string[];
    /**
     * MCP server names whose tools are allowed in an allow-listed session. Only
     * meaningful alongside `allowedTools`. With it set, the session connects ONLY
     * these named MCP servers (not the full configured set) and every tool they
     * expose (`mcp__<server>__*`) passes the allow-list. The Ken mentor agent uses
     * this to get `kencode-search` for real-code research while still being barred
     * from every mutating tool. Empty/undefined → an allow-listed session skips
     * MCP entirely (its dynamic tool names could never match a fixed allow-list).
     */
    allowedMcpServers?: string[];
    /**
     * Force 1-h prompt-cache TTL + pre-warm regardless of the user's global
     * `speedProfile` setting. Bursty read-only advisory sessions (the Ken
     * mentor + autopilot reviewer) call the same static system prompt on a
     * schedule that routinely exceeds the default 5-min cache window — a
     * dropped cache there resends the whole cached prefix at full price right
     * when it matters most, independent of whatever the user picked for the
     * main build session. Default (undefined) = follow `speedProfile`.
     */
    forceLongCacheRetention?: boolean;
    /** Hidden persistent subagent workers omit the async orchestration tool suite. */
    subagentWorker?: boolean;
}
export interface AgentSessionState {
    provider: Provider;
    model: string;
    cwd: string;
    sessionId: string;
    sessionPath: string;
    messageCount: number;
    planMode: boolean;
    /** accountId from the most recently resolved credentials, if any — lets
     *  callers compute the transport-specific context window (e.g. OpenAI Codex
     *  OAuth) without re-resolving credentials. */
    accountId?: string;
}
export declare class AgentSession {
    readonly eventBus: EventBus;
    readonly slashCommands: SlashCommandRegistry;
    private settingsManager;
    private authStorage;
    private sessionManager;
    private extensionLoader;
    private messages;
    private kenTurns;
    private autopilotMarkers;
    private appMarkers;
    private tools;
    /** Rebuilds the read tool for a new model (video byte cap is baked in at
     *  creation). Called from switchModel so video-capable models get the
     *  read-tool's native-video path after a mid-session model change. */
    private rebuildReadTool;
    private skills;
    private cacheKeyLogged;
    private hookStats;
    private hookText;
    private hookConsecutiveFailures;
    private hookMaxSignatureRepeats;
    private hookMaxSameFileEdits;
    private hookSignatureCounts;
    private hookFileEditCounts;
    private hookToolCalls;
    private idealReviewInjected;
    private loopBreakInjected;
    private regroundingInjected;
    private compactionOccurred;
    private originalRequest;
    private userQueue;
    private processManager?;
    private lspManager?;
    private subAgentManager?;
    private managerAbortSignal?;
    private readonly managerAbortHandler;
    private mcpManager?;
    /** Deferred MCP tools awaiting discovery via tool_search (bench A win). */
    private mcpCatalog?;
    private provider;
    private model;
    private cwd;
    /** accountId from the most recently resolved credentials — cached so sync
     *  callers (e.g. the app-sidecar's context-window footer stat) can reflect
     *  transport-specific windows (e.g. OpenAI Codex OAuth's smaller window)
     *  without re-resolving credentials on every poll. */
    private lastAccountId?;
    private baseUrl?;
    private maxTokens;
    private thinkingLevel?;
    private customSystemPrompt?;
    /** Shared with the tool layer so plan-mode restrictions read live state. */
    private planModeRef;
    /** Path of the approved plan currently being implemented, or undefined. When
     *  set, the system prompt carries the `[DONE:n]` progress contract so the
     *  model emits step-completion markers the UI's plan-progress widget reads. */
    private approvedPlanPath?;
    private sessionId;
    private sessionPath;
    private lastPersistedIndex;
    /** Current leaf entry ID in the session DAG — used to chain parentIds for branching. */
    private currentLeafId;
    private opts;
    constructor(options: AgentSessionOptions);
    /**
     * Derive the output-token cap for a model. Follows the active model's
     * `maxOutputTokens` so a session booted on a large-output model (e.g. Kimi's
     * 256K) doesn't carry that cap to a smaller one (e.g. Opus's 128K) after a
     * model switch — that mismatch surfaces from the provider as
     * `max_tokens: 262144 > 128000, which is the maximum allowed …`. An explicit
     * `maxTokens` override is honored but clamped to the model's ceiling.
     */
    private resolveMaxTokens;
    initialize(): Promise<void>;
    /**
     * Whether a tool name is permitted for this session. With no `allowedTools`
     * everything passes (default behavior). Otherwise a tool is allowed when its
     * name is in `allowedTools`, OR it's an MCP tool (`mcp__<server>__<tool>`)
     * whose `<server>` is in `allowedMcpServers`. The MCP-prefix rule lets a
     * whitelisted research server (e.g. kencode-search) expose all its tools
     * without hard-coding each one, while every other tool stays blocked.
     */
    private isToolAllowed;
    /**
     * Connect all configured MCP servers and append their tools to `this.tools`.
     * Resolves the GLM api key first (Z.AI's bundled servers need it). Never
     * throws — a failed connect is logged and skipped — so it is safe to either
     * `await` (CLI: tools ready before the first turn) or fire-and-forget
     * (sidecar: `backgroundMcpConnect`, so a slow stdio server can't stall
     * startup). Tools are pushed onto the live array the agent loop reads each
     * turn, so background-connected servers become available on the next prompt.
     */
    private connectMcpServers;
    /**
     * Route freshly connected MCP tools: deferred into the tool_search catalog
     * (default — keeps ~8k tokens of schema out of every cache-miss turn, see
     * bench/RESULTS.md bench A) or pushed eagerly when the user opted out.
     * Allow-listed sessions (Ken) always get the eager path — their fixed tool
     * expectations predate the catalog, and tool_search isn't allow-listed.
     * Promotion pushes onto the live `this.tools` array the running agent loop
     * re-reads every turn, so promoted tools are callable on the next step.
     */
    private addMcpTools;
    /**
     * Process user input. Handles slash commands or runs agent loop.
     */
    prompt(content: string): Promise<void>;
    /**
     * Prompt with multimodal attachments (images / videos) alongside optional
     * text. Images and videos become native content blocks the model can see;
     * non-media files are surfaced as a text note with their saved path so the
     * agent can open them with its tools. Slash-command parsing is skipped —
     * attachments are always a direct conversational turn.
     */
    promptWithAttachments(text: string, attachments: SessionAttachment[]): Promise<void>;
    /**
     * Build the native content blocks (text + image/video notes + file notes) for
     * a user message with attachments. Shared by {@link promptWithAttachments} and
     * the mid-run steering drain so queued media is delivered identically.
     */
    private buildAttachmentParts;
    /**
     * Reset per-run self-correction hook state. Mirrors the TUI's run_start
     * resets so each run evaluates the hooks from a clean slate. `originalRequest`
     * is the verbatim user ask, pinned for post-compaction re-grounding.
     */
    private resetHookState;
    /**
     * Fold one agent event into the hook stat accumulators. Pure bookkeeping —
     * the same signals the TUI's useAgentLoop collects, so the loop-break and
     * ideal-review decisions match across the CLI and the app.
     */
    private trackHookEvent;
    /**
     * Mid-loop steering hook: fires the loop-breaker when the agent looks stuck,
     * then post-compaction re-grounding. At most one of each per run. Mirrors the
     * TUI's getSteeringMessages ordering (minus user steering, which the app
     * delivers as normal prompts).
     */
    private getHookSteeringMessages;
    /**
     * Pre-stop follow-up hook: runs the ideal review once, when the agent would
     * otherwise finish and the change set is substantial enough to warrant it.
     */
    private getHookFollowUpMessages;
    /** Auto-compact if needed, run agent loop with auth retry, and persist messages. */
    private runLoop;
    switchModel(provider: string, model: string): Promise<void>;
    compact(existingCredentials?: {
        accessToken: string;
        accountId?: string;
        projectId?: string;
        baseUrl?: string;
    }): Promise<void>;
    newSession(): Promise<void>;
    loadSession(sessionPath: string): Promise<void>;
    /**
     * Create a branch at a specific point in the conversation.
     * Rewinds the message history to the given entry and sets the leaf
     * so new messages fork from that point.
     *
     * @param stepsBack Number of messages to rewind (default: 2 — backs up past last assistant + tool)
     */
    branch(stepsBack?: number): Promise<{
        branchedFrom: number;
        messagesKept: number;
    }>;
    /**
     * List all branches in the current session.
     */
    listBranches(): Promise<BranchInfo[]>;
    getState(): AgentSessionState;
    getPlanMode(): boolean;
    /** Queue a user message (optionally with attachments) to be injected mid-run
     *  as steering. Returns the new queue length. No-op semantics are the caller's
     *  concern. */
    queueMessage(text: string, attachments?: SessionAttachment[]): number;
    /** Number of messages currently queued. */
    getQueuedCount(): number;
    /** Remove and return the oldest queued message (text + attachments), or null.
     *  Used by the sidecar to run a message that queued while autopilot was
     *  reviewing (no run in flight to steer it into) — unlike {@link drainQueue},
     *  attachments survive so queued media isn't silently dropped. */
    takeNextQueuedMessage(): {
        text: string;
        attachments: SessionAttachment[];
    } | null;
    /** Clear the queue, returning the combined text (to restore to the composer).
     *  Queued attachments are dropped on cancel — the composer only restores text. */
    drainQueue(): string;
    /** Snapshot of background processes (bash run_in_background), newest-state. */
    listBackgroundProcesses(): BackgroundProcess[];
    /** Stop a background process by id. Returns a human-readable status string. */
    killBackgroundProcess(id: string): Promise<string>;
    /**
     * Toggle plan mode: flips the shared ref (so tools enforce read-only
     * restrictions) and rebuilds the system prompt in place so the model is told
     * about the mode change on its next turn. No-op when a custom system prompt
     * is in force (the host owns the prompt then).
     */
    setPlanMode(active: boolean): Promise<void>;
    /**
     * Bake an approved plan into the system prompt so the model is told to emit
     * `[DONE:n]` markers as it completes each step (the contract the UI's
     * plan-progress widget reads). Pass `undefined` to clear it. No-op when a
     * custom system prompt is in force (the host owns the prompt then).
     */
    setApprovedPlan(approvedPlanPath: string | undefined): Promise<void>;
    /** Rebuild messages[0] from current plan-mode + approved-plan state. */
    private rebuildSystemPromptInPlace;
    getMessages(): Message[];
    /** Ken Kai (mentor) turns recorded against this session, in record order. Used
     *  by the host to interleave Ken's advisory exchanges back into the transcript
     *  on resume. Never part of the LLM message history. */
    getKenTurns(): KenTurnPayload[];
    /** Autopilot verdict markers recorded against this session, in record order.
     *  Used by the host to interleave the auto-review loop's markers back into
     *  the transcript on resume, mirroring `getKenTurns`. */
    getAutopilotMarkers(): AutopilotMarkerPayload[];
    /**
     * Record one Ken Kai (mentor agent) turn against this build session: the
     * user's question + Ken's reply. Kept in memory for the live transcript and
     * persisted as a `custom` entry (parentId null, so it's never on the message
     * DAG and never seen by the LLM, and can't race the build session's leaf while
     * Ken runs concurrently). `afterMessageCount` anchors it among the messages so
     * the host can interleave it chronologically. No-op persistence for transient
     * sessions (kept in memory only). Best-effort: a write failure is swallowed by
     * appendEntry's own handling.
     */
    persistKenTurn(question: string, reply: string): Promise<void>;
    /** Re-append the in-memory Ken turns to the current session file. Called after
     *  a continuation/compaction file is created so Ken's advisory history isn't
     *  lost when the session is rewritten (those rewrites only re-persist
     *  messages). Each turn keeps its original `afterMessageCount` anchor. */
    private rePersistKenTurns;
    /**
     * Record one autopilot verdict marker (prompted / done / human / capped)
     * against this build session. Kept in memory for the live transcript and
     * persisted as a `custom` entry (parentId null, same as Ken turns) so a
     * resumed session renders the exact same Ken bubble the live run showed
     * instead of dropping the marker or falling back to a raw verdict string.
     * No-op persistence for transient sessions (kept in memory only).
     */
    persistAutopilotMarker(phase: AutopilotMarkerPayload["phase"], extra?: {
        reason?: string;
        body?: string;
    }): Promise<void>;
    /** Re-append the in-memory autopilot markers to the current session file.
     *  Mirrors `rePersistKenTurns` — called after a continuation/compaction file
     *  is created so the auto-review history survives the rewrite. */
    private rePersistAutopilotMarkers;
    /** App transcript markers recorded against this session, in record order.
     *  Used by the host to interleave display-only rows (plan banner, task
     *  header, errors, user-bubble hints) back into the transcript on resume. */
    getAppMarkers(): AppMarkerPayload[];
    /**
     * Record one app transcript marker (display-only row) against this session.
     * Same treatment as autopilot markers: kept in memory for the live
     * transcript, persisted as a `custom` entry (parentId null, never on the
     * message DAG) so a resumed session shows the identical row. `anchorOffset`
     * shifts the recorded `afterMessageCount` — pass +1 for a marker that should
     * attach to the user message about to be pushed by the imminent prompt.
     * No-op persistence for transient sessions.
     */
    persistAppMarker(kind: AppMarkerPayload["kind"], data: Record<string, unknown>, anchorOffset?: number): Promise<void>;
    /** Re-append the in-memory app markers to the current session file. Mirrors
     *  `rePersistKenTurns` — called after a continuation/compaction file is
     *  created so display-only rows survive the rewrite. */
    private rePersistAppMarkers;
    /**
     * Generate a short LLM session title from the conversation so far (first user
     * message + first assistant reply). Best-effort; returns null on failure or
     * when there's no user message yet. Uses the cheapest model for the provider.
     */
    generateTitle(): Promise<string | null>;
    /**
     * Rewrite a draft prompt into a tighter, terminology-correct version using
     * the ACTIVE provider/model. A stateless one-off LLM call (no agent loop, no
     * tools, no session mutation) — safe to run even mid-run. Returns the plain
     * enhanced text plus typed segments marking each corrected term. Errors throw
     * so the caller can surface them (unlike best-effort title generation).
     */
    enhancePrompt(text: string): Promise<EnhanceResult>;
    /** Current reasoning/thinking level, or undefined when thinking is off. */
    getThinkingLevel(): ThinkingLevel | undefined;
    /** Set the reasoning/thinking level (undefined turns thinking off). Takes
     * effect on the next prompt, since the in-flight loop reads it at start. */
    setThinkingLevel(level: ThinkingLevel | undefined): void;
    /** Sol/Terra Ultra delegates proactively; lower levels require an explicit request. */
    private syncUltraOrchestrationPrompt;
    /** Replace the abort signal (e.g. after cancellation). */
    setSignal(signal: AbortSignal): void;
    private bindManagerCancellation;
    /** True when speedProfile is "optimized" (1-h cache TTL + pre-warm), or the
     *  session was constructed with `forceLongCacheRetention` (Ken sessions). */
    private isSpeedOptimized;
    /**
     * Ordered auth-storage keys the current (provider, model) pair tries, first
     * match wins. Almost always just the provider id; Xiaomi models can prefer
     * one endpoint and fall back to another the user configured instead (e.g.
     * `mimo-v2.5-pro` prefers the Token Plan, falls back to API Credits; the
     * API-only `mimo-v2.5-pro-ultraspeed` has no fallback).
     */
    private currentAuthStorageKeys;
    private getPromptCacheKey;
    /** Stable cache-routing key for downstream sub-agent processes. */
    getCurrentCacheKey(): string | undefined;
    dispose(): Promise<void>;
    private createNewSession;
    private loadExistingSession;
    private prepareDynamicContext;
    private persistMessage;
    private createSlashCommandContext;
}
//# sourceMappingURL=agent-session.d.ts.map