/** * Extension runner - executes extensions and manages their lifecycle. */ import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type { CredentialDisabledEvent, ImageContent, Model, ProviderResponseMetadata } from "@oh-my-pi/pi-ai"; import type { KeyId } from "@oh-my-pi/pi-tui"; import type { ModelRegistry } from "../../config/model-registry"; import type { SessionManager } from "../../session/session-manager"; import type { AfterProviderResponseEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, ContextEvent, Extension, ExtensionActions, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, InputEvent, InputEventResult, MessageRenderer, RegisteredCommand, RegisteredTool, ResourcesDiscoverEvent, SessionBeforeBranchResult, SessionBeforeCompactResult, SessionBeforeSwitchResult, SessionBeforeTreeResult, SessionCompactingResult, ToolCallEvent, ToolCallEventResult, ToolResultEvent, ToolResultEventResult, UserBashEvent, UserBashEventResult, UserPythonEvent, UserPythonEventResult } from "./types"; /** Combined result from all before_agent_start handlers */ interface BeforeAgentStartCombinedResult { messages?: NonNullable[]; systemPrompt?: string[]; } export type ExtensionErrorListener = (error: ExtensionError) => void; export declare const EXTENSION_HANDLER_TIMEOUT_MS = 30000; export declare function testSetExtensionHandlerTimeoutMs(timeoutMs: number): void; /** * Events handled by the generic emit() method. * Events with dedicated emitXxx() methods are excluded for stronger type safety. */ type RunnerEmitEvent = Exclude; type RunnerEmitResult = TEvent extends { type: "session_before_switch"; } ? SessionBeforeSwitchResult | undefined : TEvent extends { type: "session_before_branch"; } ? SessionBeforeBranchResult | undefined : TEvent extends { type: "session_before_compact"; } ? SessionBeforeCompactResult | undefined : TEvent extends { type: "session_before_tree"; } ? SessionBeforeTreeResult | undefined : TEvent extends { type: "session.compacting"; } ? SessionCompactingResult | undefined : undefined; export type NewSessionHandler = (options?: { parentSession?: string; setup?: (sessionManager: SessionManager) => Promise; }) => Promise<{ cancelled: boolean; }>; export type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean; }>; export type NavigateTreeHandler = (targetId: string, options?: { summarize?: boolean; }) => Promise<{ cancelled: boolean; }>; export type SwitchSessionHandler = (sessionPath: string) => Promise<{ cancelled: boolean; }>; export type ShutdownHandler = () => void; /** * Helper function to emit session_shutdown event to extensions. * Returns true if the event was emitted, false if there were no handlers. */ export declare function emitSessionShutdownEvent(extensionRunner: ExtensionRunner | undefined): Promise; export declare class ExtensionRunner { #private; private readonly extensions; private readonly runtime; private readonly cwd; private readonly sessionManager; private readonly modelRegistry; constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry); initialize(actions: ExtensionActions, contextActions: ExtensionContextActions, commandContextActions?: ExtensionCommandContextActions, uiContext?: ExtensionUIContext): void; /** * Forward a `credential_disabled` event from `AuthStorage` to extension handlers. * * If {@link initialize} has not yet run, the event is buffered and replayed once * initialize wires the runtime/UI context. This matters because mode controllers * (interactive, RPC, ACP, print, subagent) call `initialize()` AFTER `createAgentSession` * returns, but `AuthStorage` can fire `credential_disabled` during startup model probes * inside `createAgentSession()`. Without deferral, extension handlers would observe * `hasUI=false`, an unset model, and no-op runtime actions on exactly the headline * "OAuth invalid_grant during startup" path the event was designed to surface. * * Always returns; never throws. Errors from handlers are routed through * {@link onError} via {@link emit}'s normal isolation. */ emitCredentialDisabled(event: CredentialDisabledEvent): Promise; getUIContext(): ExtensionUIContext; hasUI(): boolean; getExtensionPaths(): string[]; /** Get all registered tools from all extensions. */ getAllRegisteredTools(): RegisteredTool[]; getFlags(): Map; getFlagValues(): Map; setFlagValue(name: string, value: boolean | string): void; getShortcuts(): Map; onError(listener: ExtensionErrorListener): () => void; emitError(error: ExtensionError): void; hasHandlers(eventType: string): boolean; getMessageRenderer(customType: string): MessageRenderer | undefined; getRegisteredCommands(reserved?: Set): RegisteredCommand[]; getCommandDiagnostics(): Array<{ type: string; message: string; path: string; }>; getCommand(name: string): RegisteredCommand | undefined; createContext(): ExtensionContext; /** * Request a graceful shutdown. Called by extension tools and event handlers. */ shutdown(): void; createCommandContext(): ExtensionCommandContext; emit(event: TEvent): Promise>; emitToolResult(event: ToolResultEvent): Promise; emitToolCall(event: ToolCallEvent): Promise; emitUserBash(event: UserBashEvent): Promise; emitUserPython(event: UserPythonEvent): Promise; private emitUserEvent; emitResourcesDiscover(cwd: string, reason: ResourcesDiscoverEvent["reason"]): Promise<{ skillPaths: Array<{ path: string; extensionPath: string; }>; promptPaths: Array<{ path: string; extensionPath: string; }>; themePaths: Array<{ path: string; extensionPath: string; }>; }>; /** Emit input event. Transforms chain, "handled" short-circuits. */ emitInput(text: string, images: ImageContent[] | undefined, source: "interactive" | "rpc" | "extension"): Promise; emitContext(messages: AgentMessage[]): Promise; emitBeforeProviderRequest(payload: unknown): Promise; emitAfterProviderResponse(response: ProviderResponseMetadata, _model?: Model): Promise; emitBeforeAgentStart(prompt: string, images: ImageContent[] | undefined, systemPrompt: string[]): Promise; } export {};