import type { BackendProfile, JsonRecord } from "./types.js"; export const backendProfileIdPattern = /^[a-z0-9][a-z0-9-]{0,63}$/u; export interface BackendProfileSpec { profile: BackendProfile; backendKind: "codex-app-server-stdio"; protocol: "codex-app-server-jsonrpc-stdio"; transport: "stdio"; command: "codex app-server --listen stdio://"; status: "registered"; requiredSecretKeys: readonly string[]; defaultSecretName: string; profileIsolation: "profile-scoped-codex-home"; description: string; } const builtinBackendProfileSpecs: readonly BackendProfileSpec[] = [ { profile: "codex", backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml"], defaultSecretName: "agentrun-v01-provider-codex", profileIsolation: "profile-scoped-codex-home", description: "Default Codex-compatible profile", }, { profile: "deepseek", backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml"], defaultSecretName: "agentrun-v01-provider-deepseek", profileIsolation: "profile-scoped-codex-home", description: "DeepSeek-compatible profile through Codex app-server stdio", }, { profile: "minimax-m3", backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml"], defaultSecretName: "agentrun-v01-provider-minimax-m3", profileIsolation: "profile-scoped-codex-home", description: "MiniMax M3 OpenAI-compatible profile through Codex app-server stdio", }, { profile: "dsflash-go", backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml", "model-catalog.json"], defaultSecretName: "agentrun-v01-provider-dsflash-go", profileIsolation: "profile-scoped-codex-home", description: "DeepSeek V4 Flash profile through OpenCode Zen Go Moon Bridge", }, ]; export const backendProfileSpecs = builtinBackendProfileSpecs; export const backendProfiles = builtinBackendProfileSpecs.map((item) => item.profile) as readonly BackendProfile[]; export function compareBackendProfiles(left: string, right: string): number { const leftIndex = builtinBackendProfileSpecs.findIndex((item) => item.profile === left); const rightIndex = builtinBackendProfileSpecs.findIndex((item) => item.profile === right); if (leftIndex >= 0 || rightIndex >= 0) { if (leftIndex < 0) return 1; if (rightIndex < 0) return -1; if (leftIndex !== rightIndex) return leftIndex - rightIndex; } return left.localeCompare(right); } export function defaultSecretNameForProfile(profile: string): string { return `agentrun-v01-provider-${profile}`; } function dynamicBackendProfileSpec(profile: string): BackendProfileSpec { return { profile, backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml"], defaultSecretName: defaultSecretNameForProfile(profile), profileIsolation: "profile-scoped-codex-home", description: `Dynamic Codex-compatible profile ${profile}`, }; } export function backendProfileSpec(profile: string): BackendProfileSpec | null { if (!isBackendProfileSlug(profile)) return null; return builtinBackendProfileSpecs.find((item) => item.profile === profile) ?? dynamicBackendProfileSpec(profile); } export function isBackendProfileSlug(value: string): boolean { return backendProfileIdPattern.test(value); } export function isBackendProfile(value: string): value is BackendProfile { return isBackendProfileSlug(value); } export function backendCapability(spec: BackendProfileSpec): JsonRecord { const defaultSecretRef = { name: spec.defaultSecretName, keys: [...spec.requiredSecretKeys], valuesPrinted: false }; return { profile: spec.profile, backendKind: spec.backendKind, protocol: spec.protocol, transport: spec.transport, command: spec.command, status: spec.status, requiredSecretKeys: [...spec.requiredSecretKeys], defaultSecretRef, preflight: { readiness: "requires-profile-secret-ref", defaultSecretRef, requiredSecretKeys: [...spec.requiredSecretKeys], profileIsolation: spec.profileIsolation, credentialValuesPrinted: false, valuesPrinted: false, }, profileIsolation: spec.profileIsolation, description: spec.description, }; } export function mergeBackendCapability(profile: string, storedCapabilities: JsonRecord): JsonRecord { const spec = backendProfileSpec(profile); if (!spec) return { profile, ...storedCapabilities, valuesPrinted: false }; const base = backendCapability(spec); return { ...base, ...storedCapabilities, defaultSecretRef: base.defaultSecretRef, preflight: base.preflight, }; } export function backendCapabilities(profiles: readonly string[] = backendProfiles): JsonRecord[] { const profileIds = new Set(backendProfiles); for (const profile of profiles) { if (isBackendProfileSlug(profile)) profileIds.add(profile as BackendProfile); } return [...profileIds] .sort(compareBackendProfiles) .map((profile) => backendCapability(backendProfileSpec(profile) as BackendProfileSpec)); } export function backendCapabilitiesSqlValues(profiles?: readonly BackendProfile[], options: { requiredSecretKeysByProfile?: Record } = {}): string { const specs = profiles ? profiles.map((profile) => { const spec = backendProfileSpec(profile); if (!spec) throw new Error(`unknown backend profile for SQL seed: ${profile}`); return spec; }) : builtinBackendProfileSpecs; return specs.map((spec) => { const requiredSecretKeys = options.requiredSecretKeysByProfile?.[spec.profile] ?? spec.requiredSecretKeys; const capabilities = JSON.stringify({ backendKind: spec.backendKind, protocol: spec.protocol, transport: spec.transport, command: spec.command, requiredSecretKeys, defaultSecretRef: { name: spec.defaultSecretName, keys: requiredSecretKeys }, profileIsolation: spec.profileIsolation, description: spec.description, }); return `('${sqlString(spec.profile)}', '${sqlString(capabilities)}'::jsonb, '{"mode":"manual-runner-v0.1"}'::jsonb, '{"status":"${sqlString(spec.status)}"}'::jsonb, now())`; }).join(",\n"); } function sqlString(value: string): string { return value.replace(/'/gu, "''"); }