import type { AdapterContext, AdapterDescriptor, AgentRunRequest, AgentRuntimeCapabilities, AgentRuntimeEvent, ArtifactByteRange, ArtifactPut, ArtifactStreamPut, BackgroundJob, BackgroundJobHandlers, BrowserActRequest, BrowserActResult, BrowserCapabilities, BrowserNavigateRequest, BrowserNavigateResult, BrowserSnapshotRequest, BrowserSnapshotResult, CloudAgentCapabilities, CloudAgentHandle, CloudAgentLaunchRequest, CloudAgentReplyRequest, CloudAgentSnapshot, CommandRequest, ComputerActionRequest, ComputerActionResult, ComputerFileEntry, ComputerInput, ComputerObservation, ComputerRef, ConnectorCall, ConnectorCapabilities, ConnectorCatalogItem, ConnectorEvent, ConnectorTool, ControlLeaseRef, EmbeddingCapabilities, MemoryCapabilities, MemoryCommitRequest, MemoryExportRequest, MemoryReadRequest, MemoryRevision, MemorySearchRequest, MemorySearchResult, MemorySnapshot, MessagingInboundEvent, MessagingPlatformDescriptor, MessagingSendRequest, MessagingSendResult, NotificationMessage, PageBrowserCommand, PageBrowserResult, PortableFile, ProcessEvent, SandboxCapabilities, ScreenRequest, ScreenSession, SecretRecord, SemanticMemoryCapabilities, SemanticMemoryForgetRequest, SemanticMemoryPurgeHistoryRequest, SemanticMemoryRecallRequest, SemanticMemoryResponse, SemanticMemoryResult, SemanticMemorySaveRequest, SnapshotRef, SpeechClip, StoredArtifactStream, TransactionalEmail, VoiceCapabilities, VoiceInfo, VoiceSynthesizeRequest, VoiceTranscribeRequest, VoiceVerifyResult, WebFetchCapabilities, WebFetchRequest, WebFetchResult, WebSearchCapabilities, WebSearchHit, WebSearchRequest, } from "./types.js"; export interface SandboxProvider { describe(): AdapterDescriptor; /** Optional live browser on the same leased screen as observe/act. */ pageBrowser?( computer: ComputerRef, request: PageBrowserCommand, context: AdapterContext, ): Promise; /** Allocate or reconnect the computer, returning its reference before fallible setup. */ provision( request: { botId: string; homePath: string; providerRef?: string; providerKind?: ComputerRef["kind"]; }, context: AdapterContext, ): Promise; /** Perform idempotent provider setup after the lifecycle has captured the reference. */ prepare(computer: ComputerRef, context: AdapterContext): Promise; execute( computer: ComputerRef, request: CommandRequest, context: AdapterContext, ): AsyncIterable; inspectBackgroundWork?( computer: ComputerRef, markerId: string, context: AdapterContext, ): Promise<"active" | "idle" | "unknown">; connectScreen( computer: ComputerRef, request: ScreenRequest, context: AdapterContext, ): Promise; setScreenControl?( computer: ComputerRef, interactive: boolean, context: AdapterContext, controlToken?: string, ): Promise; sendInput( computer: ComputerRef, input: ComputerInput, lease: ControlLeaseRef, context: AdapterContext, ): Promise; observe(computer: ComputerRef, context: AdapterContext): Promise; act( computer: ComputerRef, request: ComputerActionRequest, context: AdapterContext, ): Promise; listFiles( computer: ComputerRef, path: string, context: AdapterContext, ): Promise; readFile( computer: ComputerRef, path: string, context: AdapterContext, options?: { maxBytes?: number }, ): Promise; writeFile(computer: ComputerRef, file: PortableFile, context: AdapterContext): Promise; exportWorkspace(computer: ComputerRef, context: AdapterContext): AsyncIterable; importWorkspace( computer: ComputerRef, files: AsyncIterable, context: AdapterContext, ): Promise; snapshot(computer: ComputerRef, context: AdapterContext): Promise; keepAlive?(computer: ComputerRef): Promise; /** Drop a single-screen graphical claim for this bot so another Team bot can use the display. */ releaseScreen?(computer: ComputerRef, context: AdapterContext): Promise; stop(computer: ComputerRef, context: AdapterContext): Promise; destroy(computer: ComputerRef, context: AdapterContext): Promise; } export interface ConnectorProvider { describe(): AdapterDescriptor; discoverTools(context: AdapterContext): Promise; /** Resolve a lazy catalog call to its authoritative authorized tool before approval. */ resolveCall?( call: ConnectorCall, context: AdapterContext, ): Promise<{ call: ConnectorCall; tool: ConnectorTool } | undefined>; execute(call: ConnectorCall, context: AdapterContext): AsyncIterable; } export interface ConnectionAuthProvider { describe(): AdapterDescriptor<{ oauth: boolean }>; begin( request: { provider: string; redirectUrl: string }, context: AdapterContext, ): Promise<{ authorizationUrl: string | null; state: string }>; complete( request: { state: string; code?: string }, context: AdapterContext, ): Promise<{ connectionRef: string }>; revoke(connectionRef: string, context: AdapterContext): Promise; } /** A connector that also owns an end-user app catalog and connection lifecycle. */ export interface ManagedConnectorProvider extends ConnectorProvider, Omit { catalog(context: AdapterContext, query?: string): Promise; listConnectedExternalIds(context: AdapterContext): Promise; connectionReady(context: AdapterContext, externalId: string): Promise; warmDirectory?(): Promise; } export interface MemoryStore { describe(): AdapterDescriptor; read(request: MemoryReadRequest, context: AdapterContext): Promise; search(request: MemorySearchRequest, context: AdapterContext): Promise; commit(request: MemoryCommitRequest, context: AdapterContext): Promise; exportMarkdown( request: MemoryExportRequest, context: AdapterContext, ): AsyncIterable; importMarkdown( files: AsyncIterable, context: AdapterContext, ): Promise; } /** Optional semantic memory. Durable Markdown memory remains owned by MemoryStore. */ export interface SemanticMemoryProvider { describe(): AdapterDescriptor; recall( request: SemanticMemoryRecallRequest, context: AdapterContext, ): Promise>; save( request: SemanticMemorySaveRequest, context: AdapterContext, ): Promise; purgeHistory( request: SemanticMemoryPurgeHistoryRequest, context: AdapterContext, ): Promise; /** Optional durable forget. Providers without a forget verb omit this. */ forget?( request: SemanticMemoryForgetRequest, context: AdapterContext, ): Promise>; } /** Optional text embeddings, such as a self-hosted model server, for recall and deduplication. */ export interface EmbeddingProvider { describe(): AdapterDescriptor; /** One vector per text, in input order, all of the same length. */ embed(texts: string[], signal?: AbortSignal): Promise; } export interface AgentRuntime { describe(): AdapterDescriptor; run( request: AgentRunRequest, context?: Partial, ): AsyncIterable; abort(runId: string): Promise; } export interface ModelProvider { describe(): AdapterDescriptor<{ catalog: boolean; byok: boolean }>; listModels(): Promise>; } export interface JobPublisher { enqueue(job: BackgroundJob): Promise; cancel(key: string): Promise; close(): Promise; } export interface JobWorkerHost { start(handlers: BackgroundJobHandlers): Promise; stop(): Promise; } export interface AgentHomeStore { describe(): AdapterDescriptor<{ revisions: boolean }>; checkout(botId: string, dest: string, context: AdapterContext): Promise; commit(botId: string, src: string, context: AdapterContext): Promise; restore(botId: string, revision: string, dest: string, context: AdapterContext): Promise; exportHome( botId: string, context: AdapterContext, options?: { prefix?: string }, ): AsyncIterable; readFile( botId: string, path: string, context: AdapterContext, options?: { maxBytes?: number }, ): Promise; writeFile(botId: string, path: string, content: string, context: AdapterContext): Promise; list( botId: string, path: string, context: AdapterContext, ): Promise>; } /** * Artifact bytes, keyed per space (`context.spaceId`). `stream: true` means large media can be * stored and served without holding it in memory. */ export interface ArtifactStore { describe(): AdapterDescriptor<{ stream: boolean }>; put(artifact: ArtifactPut, context: AdapterContext): Promise<{ id: string; hash: string }>; get(id: string, context: AdapterContext): Promise; remove(id: string, context: AdapterContext): Promise; stat(key: string, context: AdapterContext): Promise<{ size: number }>; /** Rejects with a RangeError when the range does not fit the stored size. */ createReadStream( key: string, context: AdapterContext, range?: ArtifactByteRange, ): Promise>; putStream(artifact: ArtifactStreamPut, context: AdapterContext): Promise; /** A local file path for tools such as ffmpeg that read in place; only stores on local disk. */ localPath?(key: string, context: AdapterContext): Promise; } export interface SecretStore { describe(): AdapterDescriptor<{ rotate: boolean }>; /** Optional recordId binds ciphertext AAD to the persisted secret/session row id. */ put(plaintext: string, context: AdapterContext, recordId?: string): Promise; get(id: string, context: AdapterContext): Promise; redact(value: string): string; } export interface RealtimeFanout { describe(): AdapterDescriptor<{ distributed: boolean; push: boolean }>; publish(topic: string, payload: string): Promise; subscribe(topic: string, onMessage: (payload: string) => void): Promise<() => Promise>; close(): Promise; } export interface NotificationProvider { describe(): AdapterDescriptor<{ push: boolean; email: boolean }>; send(message: NotificationMessage, context: AdapterContext): Promise; } /** Outbound account and security email. Product code owns content; adapters own delivery. */ export interface TransactionalEmailProvider { describe(): AdapterDescriptor<{ transactional: boolean }>; send(message: TransactionalEmail): Promise; /** Wait for accepted in-flight deliveries before a graceful shutdown completes. */ drain?(): Promise; } export interface ExecutionRunner { describe(): AdapterDescriptor<{ cloud: boolean; selfHosted: boolean; desktop: boolean }>; dispatch(runId: string, target: "cloud" | "self-hosted" | "desktop"): Promise; } export interface VoiceProvider { describe(): AdapterDescriptor; verify(apiKey: string, context: AdapterContext): Promise; listVoices(apiKey: string, context: AdapterContext): Promise; synthesize(request: VoiceSynthesizeRequest, context: AdapterContext): Promise; transcribe?(request: VoiceTranscribeRequest, context: AdapterContext): Promise<{ text: string }>; } /** * Deployment-wide external chat surface: one bot presence across messaging * platforms (iMessage/SMS, Slack, WhatsApp, …). Conversations are addressed * by opaque provider-prefixed thread ids ("sendblue:…", "slack:C1:…"), so * orchestration never sees platform wire formats. Webhook verification and * payload translation live behind handleWebhook, per platform. */ export interface MessagingSurface { describe(): AdapterDescriptor<{ providers: string[] }>; /** Enabled platforms and what each supports. */ platforms(): MessagingPlatformDescriptor[]; /** * Verify and process one platform webhook request. Parsed events reach the * sink registered via onInbound before the returned response resolves. * Returns null for a provider this surface does not host. */ handleWebhook(provider: string, request: Request): Promise | null; /** Register the single downstream consumer of inbound events. */ onInbound(sink: (event: MessagingInboundEvent) => Promise): void; sendToThread( request: MessagingSendRequest, context: AdapterContext, ): Promise; /** Resolve (or create) the 1:1 thread for a provider address. */ openDirectThread(provider: string, address: string, context: AdapterContext): Promise; /** * Best-effort "…" typing bubbles for 1:1 chats. Cosmetic: never gates * message delivery, and silently no-ops on platforms without support. */ sendTyping(threadId: string, context: AdapterContext): Promise; /** * Start the surface eagerly instead of waiting for the first inbound * webhook or outbound send to touch it. Needed for adapters that pull * updates themselves (e.g. Telegram in "auto"/"polling" mode, used when * no public webhook URL is reachable): without an explicit call here, * nothing kicks off that pull loop until something else happens to * initialize the adapter first. */ initialize?(): Promise; /** * Release long-lived inbound resources (Telegram getUpdates polling) so a * replacement process can claim them. No-op when the surface never started. */ shutdown?(): Promise; } /** * Provider-neutral web search. Builtin `web_search` routes here so backends * (keyless HTTP, model-native search, future paid APIs) can be swapped without * changing tool names or the executor. */ export interface WebSearchProvider { describe(): AdapterDescriptor; search(request: WebSearchRequest, context: AdapterContext): Promise; } /** * Provider-neutral page fetch. Builtin `web_fetch` routes here. Read-only: * no JS execution, no headless browser. */ export interface WebFetchProvider { describe(): AdapterDescriptor; fetch(request: WebFetchRequest, context: AdapterContext): Promise; } /** Convenience when one adapter owns both search and fetch. */ export interface WebProvider extends WebSearchProvider, WebFetchProvider { describe(): AdapterDescriptor; } /** * Provider-neutral page browser on the bot computer. Builtin browser_* tools * route here so backends (in-process page session, CDP against the computer's * Chrome, future adapters) can swap without changing tool names. Not a second * hosted browser product. Prefer this for web pages; use computer_act when the * page tool cannot operate or the task needs the desktop itself. */ export interface BrowserProvider { describe(): AdapterDescriptor; navigate( computer: ComputerRef, request: BrowserNavigateRequest, context: AdapterContext, ): Promise; snapshot( computer: ComputerRef, request: BrowserSnapshotRequest, context: AdapterContext, ): Promise; act( computer: ComputerRef, request: BrowserActRequest, context: AdapterContext, ): Promise; } /** * Provider-neutral remote cloud coding agents (clone a repo on a vendor VM, * open a PR). Not the bot computer — shell/sandbox stays separate. Core runs * with none configured; tools are injected only when a provider is present. */ export interface CloudAgentProvider { describe(): AdapterDescriptor; launch(request: CloudAgentLaunchRequest, context: AdapterContext): Promise; get(id: string, context: AdapterContext, runId?: string): Promise; reply( id: string, request: CloudAgentReplyRequest, context: AdapterContext, ): Promise; cancel(id: string, context: AdapterContext, runId?: string): Promise; }