import type { BackendEvent, BackendTurnResult, CommandRecord, RunRecord } from "../common/types.js"; import { CodexStdioBackendSession, runCodexStdioTurn, type CodexStdioTurnOptions } from "./codex-stdio.js"; import { backendProfileSpec } from "../common/backend-profiles.js"; export interface BackendAdapterOptions { codexCommand?: string; codexArgs?: string[]; codexHome?: string; workspacePath?: string; abortSignal?: AbortSignal; onEvent?: (event: BackendEvent) => void | Promise; env?: NodeJS.ProcessEnv; } export interface BackendSession { runTurn(run: RunRecord, command: CommandRecord, options?: BackendAdapterOptions): Promise; close(): Promise; } export async function runBackendTurn(run: RunRecord, command: CommandRecord, options: BackendAdapterOptions = {}): Promise { const spec = backendProfileSpec(run.backendProfile); if (!spec || spec.backendKind !== "codex-app-server-stdio") { return { terminalStatus: "failed", failureKind: "backend-failed", failureMessage: `unsupported backendProfile ${run.backendProfile}`, events: [{ type: "error", payload: { failureKind: "backend-failed", backendProfile: run.backendProfile } }] }; } return runCodexStdioTurn(backendTurnOptions(run, command, options)); } export function createBackendSession(run: RunRecord, options: BackendAdapterOptions = {}): BackendSession | null { const spec = backendProfileSpec(run.backendProfile); if (!spec || spec.backendKind !== "codex-app-server-stdio") return null; const session = new CodexStdioBackendSession(); return { runTurn: async (nextRun, command, turnOptions = {}) => session.runTurn(backendTurnOptions(nextRun, command, { ...options, ...turnOptions })), close: async () => session.close(), }; } export function backendTurnOptions(run: RunRecord, command: CommandRecord, options: BackendAdapterOptions = {}): CodexStdioTurnOptions { const prompt = typeof command.payload.prompt === "string" ? command.payload.prompt : JSON.stringify(command.payload); const turnOptions: CodexStdioTurnOptions = { backendProfile: run.backendProfile, prompt, cwd: options.workspacePath ?? (typeof run.workspaceRef.path === "string" ? run.workspaceRef.path : process.cwd()), approvalPolicy: run.executionPolicy.approval, sandbox: run.executionPolicy.sandbox, timeoutMs: run.executionPolicy.timeoutMs, }; if (typeof command.payload.model === "string") turnOptions.model = command.payload.model; if (typeof command.payload.threadId === "string") turnOptions.threadId = command.payload.threadId; else if (typeof run.sessionRef?.threadId === "string") turnOptions.threadId = run.sessionRef.threadId; if (options.codexCommand) turnOptions.command = options.codexCommand; if (options.codexArgs) turnOptions.args = options.codexArgs; if (options.env) turnOptions.env = options.env; if (options.codexHome) turnOptions.codexHome = options.codexHome; if (options.abortSignal) turnOptions.abortSignal = options.abortSignal; if (options.onEvent) turnOptions.onEvent = options.onEvent; return turnOptions; }