/** * Engine Types (Backend) * * Defines the AIEngine interface that all engine adapters must implement. * Every adapter converts SDK-specific events to EngineOutput (unified format) * so stream-manager and frontend remain engine-agnostic. */ import type { EngineType, UserMessage, EngineOutput } from '$shared/types/unified'; import type { EngineModel } from '$shared/types/unified'; export type { EngineType }; /** Execution context for MCP tool handlers (project isolation) */ export interface McpExecutionContext { projectId?: string; chatSessionId?: string; streamId?: string; /** * Active Profile for this stream (resolved in stream-manager from the * session's choice or the project default). Scopes the materialized artifact * set + MCP connectors to the profile's bundle. Undefined = no active profile. */ profileId?: number; } /** Options passed to engine.streamQuery() */ export interface EngineQueryOptions { projectPath: string; prompt: UserMessage; resume?: string; forkSession?: boolean; maxTurns?: number; /** Provider slug (e.g. 'anthropic', 'openai'). Required for OpenCode. */ providerSlug: string; /** Model ID (e.g. 'claude-opus-4-6', 'gpt-5'). */ modelId: string; /** * Reasoning/thinking level token chosen for this turn (native per engine — * see `EngineModel.capabilities.reasoningControl`). Undefined → the engine's * own default applies. Each adapter clamps/maps it to its SDK's knob. */ reasoningEffort?: string; includePartialMessages?: boolean; abortController?: AbortController; accountId?: number; /** Context bound to MCP tool handlers for project isolation */ mcpContext?: McpExecutionContext; } /** Options for one-shot structured generation (no tools, no streaming) */ export interface StructuredGenerationOptions { prompt: string; /** Provider slug (e.g. 'anthropic', 'openai'). Required for OpenCode. */ providerSlug: string; /** Model ID. */ modelId: string; schema: Record; projectPath: string; abortController?: AbortController; accountId?: number; } /** The contract every engine adapter must fulfil */ export interface AIEngine { /** Engine identifier */ readonly name: EngineType; /** Whether the engine has been initialized */ readonly isInitialized: boolean; /** Lazy initialization (start server, load config, etc.) */ initialize(): Promise; /** Cleanup resources */ dispose(): Promise; /** * Stream a query. * MUST yield events in EngineOutput format (unified types). */ streamQuery(options: EngineQueryOptions): AsyncGenerator; /** * Cancel ONE run — the stream whose AbortController is `owner`. * * One engine instance is shared by every chat session of a project, so it can * be streaming several chats at once. `owner` is the controller that stream * passed to `streamQuery`, and the same object `StreamState.abortController` * holds — the handle both sides already agree on. Adapters must stop that run * alone and leave the others streaming. * * The parameter is deliberately required: there is no "cancel whatever you * are doing" for callers. Stopping every run is `dispose()`'s job, and only * shutdown and engine retirement get to ask for it. */ cancel(owner: AbortController): Promise; /** Interrupt one run (soft stop). Targeted like `cancel`. */ interrupt(owner: AbortController): Promise; /** True while at least ONE run is in flight — not just the most recent one. */ readonly isActive: boolean; /** Return the list of models this engine supports */ getAvailableModels(): Promise; /** * Resolve a pending AskUserQuestion by providing the user's answers. * Unblocks the canUseTool callback so the SDK can continue. */ resolveUserAnswer?(toolUseId: string, answers: Record): boolean; /** * One-shot structured JSON generation (no tools, no streaming). * Returns parsed JSON matching the provided schema. * Optional — engines that don't support it leave undefined. */ generateStructured?(options: StructuredGenerationOptions): Promise; }