import type { SessionApi } from "@opencode/client/effect/api" import type { GenerationOptionsFields, Message, SystemPart } from "@opencode/ai" import type { Agent } from "@opencode/schema/agent" import type { Model } from "@opencode/schema/model" import type { PromptInput } from "@opencode/schema/prompt-input" import type { Session } from "@opencode/schema/session" import type { SessionInbox } from "@opencode/schema/session-inbox" import type { SessionError } from "@opencode/schema/session-error" import type { SessionMessage } from "@opencode/schema/session-message" import type { TokenUsage } from "@opencode/schema/token-usage" import type { JsonSchema, Types } from "effect" import type { ModelHooks } from "./registration.js" export interface SessionPrompt { readonly sessionID: Session.ID readonly messageID: SessionMessage.ID prompt: Types.DeepMutable metadata?: Record delivery: SessionInbox.Delivery } /** Request overrides. Typed keys are generation settings; any other key is a provider option. */ export type SessionRequestOptions = Types.DeepMutable & Record export interface SessionRequest { readonly sessionID: Session.ID readonly model: Model.Ref system: Array messages: Array options: SessionRequestOptions } export interface SessionContext extends SessionRequest { readonly agent: Agent.ID tools: Record } export interface SessionCompactionResult { summary: string providerState?: SessionMessage.ProviderState metadata?: Record tokens?: TokenUsage.Info } export interface SessionCompaction extends SessionContext { /** Set to use this compaction and skip the model request. */ result?: SessionCompactionResult } export interface SessionGenerate extends SessionContext {} export interface SessionTitle extends SessionRequest { /** Set to use this title and skip the model request. */ result?: string } /** * Why a Session request is being made. Auxiliary requests share the Session's * hook identity but need to be told apart from the agent loop. */ export type SessionRequestKind = "primary" | "compaction" | "title" | "generate" export interface SessionModelRequest { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind baseURL?: string headers: Record } export interface SessionHttpRequest { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind request: Request } export interface SessionHttpResponse { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind readonly request: Request response: Response } /** * Connection a WebSocket-backed request opens or reuses. Runs once per model call before the * Session's socket is selected; changing `url` or `headers` reopens the socket. Experimental. */ export interface SessionWebSocketHandshake { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind url: string headers: Record } /** * Outbound frame about to be written to the Session's socket, after the provider driver has built * it. Replacing `frame` sends the replacement verbatim; the driver still tracks state from the * provider's replies, so a rewrite that changes protocol meaning is on the plugin. Experimental. */ export interface SessionWebSocketSend { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind frame: string } /** * Inbound frame read from the Session's socket, before the provider driver observes it. Replacing * `frame` hands the replacement to the driver verbatim. Experimental. */ export interface SessionWebSocketReceive { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly kind: SessionRequestKind frame: string } export type SessionRetryDecision = { retry: false } | { retry: true; delay: number } export interface SessionRetry { readonly sessionID: Session.ID readonly agent: Agent.ID readonly model: Model.Ref readonly error: SessionError.Error readonly attempt: number decision: SessionRetryDecision } export interface SessionHooks { readonly prompt: SessionPrompt readonly context: SessionContext readonly compaction: SessionCompaction readonly generate: SessionGenerate readonly title: SessionTitle readonly "model.request": SessionModelRequest readonly "http.request": SessionHttpRequest readonly "http.response": SessionHttpResponse readonly "experimental.ws.handshake": SessionWebSocketHandshake readonly "experimental.ws.send": SessionWebSocketSend readonly "experimental.ws.receive": SessionWebSocketReceive readonly retry: SessionRetry } export type SessionDomain = Pick< SessionApi, | "create" | "get" | "switchAgent" | "switchModel" | "prompt" | "generate" | "command" | "synthetic" | "interrupt" | "update" | "move" | "wait" | "context" > & { readonly hook: ModelHooks }