import type { ImageContent } from "@bastani/pi-ai/compat"; import type { BashResult } from "../../core/bash-executor.ts"; import type { WorkflowActivityFrame } from "../../core/extensions/workflow-events.js"; import type { BashOutputChannel } from "../../core/tools/bash.js"; import type { ActivityWatchdogDiagnostic } from "../interactive-engine/activity-watchdog.ts"; import type { InteractiveEngineGenerationEndedListener } from "../interactive-engine/engine-generation.ts"; import { type EngineKeybindingState, type InteractiveEngineCommand, type InteractiveEngineMessage } from "../interactive-engine/protocol.ts"; import { RpcClientApi, type RpcCommandBody } from "./rpc-client-api.ts"; import type { RpcEvent, RpcExtensionUIRequest, RpcExtensionUIResponse, RpcResponse } from "./rpc-types.ts"; export type { ModelInfo, RpcCommandBody } from "./rpc-client-api.ts"; export type { RpcEvent } from "./rpc-types.ts"; export interface RpcClientOptions { cliPath?: string; cwd?: string; env?: Record; provider?: string; model?: string; args?: string[]; runtimeExecutable?: string; runtimeArgs?: string[]; /** * Bounded deadline (ms) applied to short metadata/control requests. Long-lived * commands (see LONG_LIVED_COMMANDS) never use this timer. Defaults to 30s. */ requestTimeoutMs?: number; interactiveEngine?: { onDiagnostic: (diagnostic: ActivityWatchdogDiagnostic) => void; onActivityChange?: (active: boolean) => void; /** * Heartbeat observer. Deliberately NOT a generic engine-message listener: * subscribing there drains the buffered startup custom-UI messages into the * first subscriber and stops buffering for the real controllers. */ onHeartbeat?: () => void; /** * Credential for the engine child. Delivered through the protected * bootstrap file, never through the child's environment or argv. */ apiKey?: string; }; } export type RpcEventListener = (event: RpcEvent) => void; export declare class RpcClient extends RpcClientApi { private process; private stopReadingStdout; private eventListeners; private extensionUIListeners; private readonly pendingExtensionUIRequests; private engineMessageListeners; private latestEngineKeybindingState; private readonly workflowActivity; private readonly pendingEngineMessages; private readonly pendingProjectTrustFrames; private boundGeneration; private explicitQuitAck; private readonly pendingRequests; /** Bumped by every explicit stop; a restart holds a permit across its own stop. */ private restartRevision; private stopPromise; private readonly terminalDrain; private stdoutDrained; private requestId; private stderr; private exitError; private engineMonitor; private eventBuffer; private stdinWriter; private generation; private lastEndedGeneration; private generationEndedListeners; /** * The latest generation-end event, retained so a subscriber that attaches * after the child died still observes it. A child can exit between * `start()` returning and the runtime constructing its listeners. */ private retainedGenerationEnd; private readonly activeActivityIds; private enginePid; private options; constructor(options?: RpcClientOptions); start(): Promise; /** * Tell the engine child the host is quitting on purpose, and wait (bounded) for it to * record that. Call it before `stop()` for a quit the user asked for: stopping closes * stdin and sends SIGTERM, which is also how the child is stopped when the host itself * was signalled, so only this announcement lets the child tell the two apart. * Resolves true only when the child acknowledged the quit, and false without waiting when * there is no live engine child, or when the child exits or misses the deadline first. */ announceExplicitQuit(timeoutMs?: number): Promise; /** * Explicit stop. Voids any in-flight restart permit, so a replacement caught * between its own stop and start can never spawn after this returns. */ stop(): Promise; /** * Tear down the current child without touching the restart permit. The reader * stays attached and the generation stays current until the dead child's * stdout settles, so an ownership frame it already sent still reaches its * request; only then is the generation retired (see RpcTerminalDrain). */ private stopCurrentGeneration; /** Subscribe to agent events. */ onEvent(listener: RpcEventListener): () => void; onExtensionUIRequest(listener: (request: RpcExtensionUIRequest) => void): () => void; respondExtensionUI(response: RpcExtensionUIResponse): Promise; onInteractiveEngineMessage(listener: (message: InteractiveEngineMessage) => void): () => void; onInteractiveEngineKeybindingState(listener: (state: EngineKeybindingState) => void): () => void; /** * Subscribe to the engine's workflow activity. The engine publishes its snapshot as soon as it binds, * so an observer that attaches later starts from the current snapshot instead of missing it. */ onInteractiveEngineWorkflowActivity(listener: (frame: WorkflowActivityFrame) => void): () => void; /** * Subscribe to host-local generation death. Fires at most once per * generation, synchronously, before any restart work. A death that has * already happened for the current generation replays immediately, so a * listener attached after an exit still sees it. */ onGenerationEnded(listener: InteractiveEngineGenerationEndedListener): () => void; sendInteractiveEngineCommand(command: InteractiveEngineCommand): void; waitForInteractiveEngineBound(): Promise; waitForInteractiveEngineProjectTrust(): Promise; waitForInteractiveEngineResources(): Promise; getEnginePid(): number | undefined; getGeneration(): number; /** * Replace the engine child, unless an explicit stop supersedes this attempt. * The permit is checked immediately before spawning, so a `stop()` in that * window is always observed; cancellation throws rather than returning * quietly, because callers go on to initialize against the new child. */ restart(sessionId: string | undefined, options?: { sessionDirectory?: string; cwd?: string; }): Promise; requestInternal(command: RpcCommandBody): Promise; userBashWithUpdates(command: string, onUpdate: (delta: string, channel: BashOutputChannel) => void, options?: { excludeFromContext?: boolean; onRequestId?: (id: string) => void; }): Promise; getStderr(): string; waitForIdle(timeout?: number): Promise; collectEvents(timeout?: number): Promise; promptAndWait(message: string, images?: ImageContent[], timeout?: number): Promise; private handleLine; private emitEvent; private emitInteractiveEngineMessage; private createProcessExitError; private invalidateEngineShortcuts; private observeInteractiveEngineMessage; /** * Shared teardown for every unexpected end of `generation`. Death publishes * at once for the host UI; its requests wait for stdout (RpcTerminalDrain). */ private failGeneration; /** Hold this generation's requests until its stdout drains (RpcTerminalDrain). */ private beginTerminalDrain; private publishGenerationEnded; private failTransport; private requireWriter; private bestEffort; protected request(command: RpcCommandBody, onRequestId?: (id: string) => void): Promise; private assertSuccess; protected data(response: RpcResponse): T; } //# sourceMappingURL=rpc-client.d.ts.map