import type { AgentSessionEvent, AgentSessionRuntime } from "@earendil-works/pi-coding-agent"; import type { ConversationViewport } from "../rendering/conversation-viewport.js"; import { type LoadOlderSessionHistoryOptions, type SessionHistoryOlderLoader } from "./session-history.js"; import type { Entry, SessionActivity } from "../types.js"; import type { WorkspaceMutation, WorkspaceMutationPreparation } from "../workspace/workspace-undo.js"; export type AppSessionEventControllerState = { toolEntryIdsByCallId: Map; pendingToolCallIdsByContentIndex: Map; toolMutationPreparationsByCallId: Map; olderHistoryLoader: SessionHistoryOlderLoader | undefined; currentUserEntryId: string | undefined; currentAssistantEntryId: string | undefined; currentAssistantTextBlockEntryId: string | undefined; currentAssistantTextBlockStartLength: number | undefined; currentAssistantTextBlockContentIndex: number | undefined; assistantTextBlocksByContentIndex: Map; currentThinkingEntryId: string | undefined; currentThinkingEntryStartedAt: number | undefined; assistantMessageClosed: boolean; assistantTextBuffer: string; entryRenderVersions: Map; historyEntries: Entry[]; historyWindowStart: number; }; export type AppSessionEventControllerHost = { readonly entries: Entry[]; runtime(): AgentSessionRuntime | undefined; awaitSessionExtensions?(runtime: AgentSessionRuntime): Promise; conversationViewport(): ConversationViewport; conversationViewportColumns?(): number; onHistoryWindowPruned?(edge: "top" | "bottom", lineCount: number): void; isRunning(): boolean; render(): void; scheduleRender(): void; setStatus(status: string): void; restoreSessionStatus(): void; setSessionStatus(session: AgentSessionRuntime["session"] | undefined): void; setSessionActivity(activity: SessionActivity): void; updateQueuedMessageStatus(): void; flushAutoUserMessages(): void; /** * Emit a signal onto the active runtime's extension event bus. The SDK * strips retry/streaming state from the events it forwards to extensions, * so this is how the renderer informs extensions (terminal-bell, todo) * about lifecycle state such as an auto-retry being in progress. */ emitExtensionEvent(channel: string, data: unknown): void; prepareWorkspaceMutation(toolName: string, args: unknown): WorkspaceMutationPreparation | undefined; recordWorkspaceMutationForUserEntry(entryId: string, mutation: WorkspaceMutation): void; workspaceMutationFromToolExecution(input: { toolName: string; args: unknown; details: unknown; isError: boolean; preparation?: WorkspaceMutationPreparation | undefined; }): WorkspaceMutation | undefined; scheduleUserSessionEntryMetadataSync(): void; toolDefaultExpanded(toolName: string): boolean; observeSubagentsToolResult(toolName: string, details: unknown, options?: { showSnapshot?: boolean; }): void; observeTodoToolResult(toolName: string, details: unknown, isError?: boolean): void; showToast(message: string, kind: "success" | "error" | "warning" | "info", options?: { action?: { label: string; onSelect: () => void; }; }): void; }; export declare class AppSessionEventController { private readonly host; readonly entryRenderVersions: Map; private readonly toolEntryIdsByCallId; private readonly pendingToolCallIdsByContentIndex; private readonly toolMutationPreparationsByCallId; private olderHistoryLoader; private currentUserEntryId; private currentAssistantEntryId; private currentAssistantTextBlockEntryId; private currentAssistantTextBlockStartLength; private currentAssistantTextBlockContentIndex; private readonly assistantTextBlocksByContentIndex; private readonly finalizedToolCallContentIndexes; private historyEntries; private historyWindowStart; private currentThinkingEntryId; private currentThinkingEntryStartedAt; private thinkingElapsedRenderTimer; private assistantMessageClosed; private currentAssistantTerminalErrorRendered; private assistantTextBuffer; constructor(host: AppSessionEventControllerHost); snapshotState(): AppSessionEventControllerState; restoreState(state: AppSessionEventControllerState): void; reset(): void; allEntries(): readonly Entry[]; loadSessionHistory(): void; loadSessionHistoryAsync(options: { isCancelled: () => boolean; render: () => void; lazyOlderHistory?: boolean; }): Promise; hasOlderSessionHistory(): boolean; isLoadingOlderSessionHistory(): boolean; loadOlderSessionHistory(options?: LoadOlderSessionHistoryOptions): Promise; /** * Reveal the conversation entry for a session entry id (e.g. a user message * selected from the jump menu) by shifting the sliding window directly onto * it, then return its local entry id so the caller can scroll to it. * * Unlike paging older history in fixed increments, this works for any branch * position in a single synchronous step and does not race with concurrent * window re-anchors (e.g. while the agent is streaming). Returns undefined * when the entry is neither in the full history window nor in the live * entries (e.g. older than the loaded branch). */ revealHistoryEntryForSessionEntryId(sessionEntryId: string): string | undefined; hasNewerSessionHistory(): boolean; isLoadingNewerSessionHistory(): boolean; loadNewerSessionHistory(options?: { render?: boolean; }): Promise; handleSessionEvent(event: AgentSessionEvent): void; private retryFailedTurn; /** * The SDK only emits `auto_retry_end` (whose toast carries the Retry button) * when auto-retry actually runs. When retry is disabled, a transient streaming * error such as a 429 rate limit surfaces only as the error entry above, with * no way to resume the failed turn. Offer a manual Retry toast in that case, * mirroring the auto-retry path. User aborts and non-retryable errors are * excluded, and retry being enabled means the auto-retry toast will handle it. */ private showManualRetryOnTerminalError; private retryFailedTurnAsync; private isActiveRuntimeSession; addCustomMessageEntry(message: Record): void; findEntry(id: string): Entry | undefined; findUserEntry(id: string): Extract | undefined; touchEntry(entry: Entry): void; addEntry(entry: Entry): void; prependEntries(entries: readonly Entry[]): void; private prependLoadedHistoryEntries; private shiftHistoryWindow; private setHistoryWindowStart; private historyWindowSize; private maxHistoryWindowStart; private registerEntry; private pruneHistoryWindow; private measuredLineCountForEntries; private forgetEntry; private removeToolEntryOrphan; addSessionAbortedEntry(): void; private finalizeAbandonedToolEntries; private handleMessageStart; private handleMessageEnd; private prepareToolWorkspaceMutation; private finalizeToolResultMessage; private recordToolWorkspaceMutation; private handleMessageUpdate; private handleToolCallStreamUpdate; private appendAssistantText; private flushAssistantTextBuffer; private reconcileAssistantTextBlock; private ensureAssistantTextBlockStarted; private finishCurrentAssistantTextBlock; private hasVisibleTextBeforeCurrentAssistantBlock; private drainAssistantTextBuffer; private hasVisibleAssistantText; private hasStartedCurrentAssistantText; private appendThinkingText; private finishCurrentThinkingEntry; private reconcileThinkingText; private syncThinkingElapsedRenderTimer; private startThinkingElapsedRenderTimer; private stopThinkingElapsedRenderTimer; private currentThinkingLevel; private reconcileAssistantTextFromFinalMessage; private renderAssistantToolCallsFromMessage; private upsertPendingToolCall; private upsertToolEntry; private clearCurrentAssistantState; }