import { PiClient, PiHostUiResponse, PiSendMessageInput, PiThinkingLevel } from "../types.js"; import { PiThreadState } from "./threadState.js"; import { AppendMessage, ExportedMessageRepository, ThreadMessageLike } from "@assistant-ui/react"; //#region src/runtime/ThreadController.d.ts export type PiSendOptions = { /** Overrides the derived behavior. While the thread is running this is * REQUIRED by Pi (`prompt()` throws otherwise); the controller derives a * `"followUp"` default from run status when omitted. */ streamingBehavior?: "followUp" | "steer"; }; export type PiNotificationScheduler = (flush: () => void) => void; /** `getStateSnapshot` (or `getState` where it is absent) and * `getMessageRepository` are read as `useSyncExternalStore` snapshots, so an * implementation must return a reference that changes only when a subscribed * channel notifies; a freshly built value per call loops React. */ export interface PiThreadControllerLike { getState(): PiThreadState; /** The state as of the last listener notification. `getState()` can run * ahead of it while a coalesced message frame is pending, so only this is a * valid `useSyncExternalStore` snapshot. Optional for backwards * compatibility; callers fall back to `getState()`. */ getStateSnapshot?(): PiThreadState; getProjectedMessages(): readonly ThreadMessageLike[]; getMessageRepository(): ExportedMessageRepository; getVersion(): number; connect(): () => void; subscribe(listener: () => void): () => void; subscribeMetadata(listener: () => void): () => void; subscribeMessages(listener: () => void): () => void; load(force?: boolean): Promise; refresh(): Promise; sendMessage(message: AppendMessage, options?: PiSendOptions): Promise; cancel(): Promise; /** Clear Pi's server-side queue; resolves with the cleared text so the UI * can restore it to the composer. */ clearQueue(): Promise<{ steering: string[]; followUp: string[]; }>; setModel(input: { provider: string; modelId: string; }): Promise; setThinkingLevel(level: PiThinkingLevel): Promise; /** Answer a request by its id with a decision alone: a `confirm` takes it as * is, a refusal dismisses any other kind, and accepting one without its * option or text rejects. */ respondToToolApproval(approvalId: string, approved: boolean): Promise; /** Answer the host-UI request raised during a tool call, by `toolCallId`. */ resumeToolCall(toolCallId: string, payload: unknown): Promise; /** Answer a side-channel (free-standing) host-UI request directly. */ respondToHostUiRequest(response: PiHostUiResponse): Promise; dispose(): void; } /** All content parts of an append message, with attachment parts flattened in. */ export declare const appendMessageParts: (message: AppendMessage) => (import("@assistant-ui/core").ThreadUserMessagePart | import("@assistant-ui/core").ReasoningMessagePart | import("@assistant-ui/core").ToolCallMessagePart | { readonly type: "source"; readonly sourceType: "url"; readonly id: string; readonly url: string; readonly title?: string; readonly providerMetadata?: import("@assistant-ui/core").SourceProviderMetadata; readonly parentId?: string; } | { readonly type: "source"; readonly sourceType: "document"; readonly id: string; readonly url?: undefined; readonly title: string; readonly mediaType: string; readonly filename?: string; readonly providerMetadata?: import("@assistant-ui/core").SourceProviderMetadata; readonly parentId?: string; } | import("@assistant-ui/core").GenerativeUIMessagePart)[]; export declare const buildPiSendInput: (message: AppendMessage, streamingBehavior: "followUp" | "steer" | undefined) => PiSendMessageInput; export declare class PiThreadController implements PiThreadControllerLike { private state; private stateSnapshot; private projectedMessages; private messageRepository; private version; private readonly allListeners; private readonly metadataListeners; private readonly messageListeners; private connectionRetainers; private readonly optimisticUserMessages; private unsubscribeFromEvents; private disconnectTimer; private loadPromise; private messageFlushScheduled; /** Synthetic seq for snapshots produced locally (via `getThread`), kept below * the supervisor's live seqs so they never suppress real events. */ private readonly localSnapshotSeq; private readonly client; private readonly threadId; private readonly options; constructor(client: PiClient, threadId: string, options?: { scheduleNotify?: PiNotificationScheduler; }); getState(): PiThreadState; getStateSnapshot(): PiThreadState; getProjectedMessages(): readonly ThreadMessageLike[]; getMessageRepository(): ExportedMessageRepository; getVersion(): number; connect(): () => void; subscribe(listener: () => void): () => void; subscribeMetadata(listener: () => void): () => void; subscribeMessages(listener: () => void): () => void; dispose(): void; private ensureEventSubscription; private hasConsumers; private maybeDisconnectFromEvents; private clearDisconnectTimer; load(force?: boolean): Promise; refresh(): Promise; private refreshInBackground; sendMessage(message: AppendMessage, options?: PiSendOptions): Promise; /** Mid-run sends land in Pi's queue, not the transcript (Pi appends the user * message only when the queue flushes), so the optimistic mirror goes into * `state.queue` — the thread stays clean and the queue UI shows it instantly. * The next real `queue_update` replaces the arrays wholesale and self-heals. */ private sendQueued; clearQueue(): Promise<{ steering: string[]; followUp: string[]; }>; cancel(): Promise; setModel(input: { provider: string; modelId: string; }): Promise; setThinkingLevel(level: PiThinkingLevel): Promise; respondToToolApproval(approvalId: string, approved: boolean): Promise; resumeToolCall(toolCallId: string, payload: unknown): Promise; respondToHostUiRequest(response: PiHostUiResponse): Promise; private respond; private applySnapshot; private dispatch; private setState; private projectedInputMessages; private reconcileOptimisticUserMessages; private projectMessages; private recomputeProjectedMessagesAndNotify; private scheduleProjectedMessageFlush; private bumpVersion; /** `message_end` advances state without moving the projection, so neither * the metadata nor the message channel describes what changed. Publishing on * `all` alone reaches every state subscriber without redefining what * `subscribeMetadata` fires for. */ private publishState; private notifyMetadataListeners; private notifyMessageListeners; } //#endregion //# sourceMappingURL=ThreadController.d.ts.map