// --------------------------------------------------------------------------- // CapabilityMatrix — runtime-enforced provider contract // Spec reference: §3.4 // --------------------------------------------------------------------------- import type { PendingQuestionType } from '../task/task-state.js'; /** * Declares what a provider adapter can do at runtime. * TaskManager reads these at startup and uses them to route behavior. */ export interface ProviderCapabilities { /** Session survives server restart (e.g. Codex rollout files). */ sessionPersistence: boolean; /** Distinct approve/decline protocol (e.g. Codex 4 approval types). */ structuredApproval: boolean; /** Can stream tokens/chunks. */ streamingOutput: boolean; /** Has explicit cancel primitive (e.g. turn/interrupt). */ abortPrimitive: boolean; /** Supports thread/read-style probe for crash recovery. */ crashRecovery: boolean; /** How the provider selects a model. */ modelRouting: 'config' | 'api-param' | 'none'; /** Emits structured rate-limit error. */ rateLimitSignal: boolean; /** Subset of the 5 PendingQuestion types this provider supports. */ pauseTypes: readonly PendingQuestionType[]; } // --------------------------------------------------------------------------- // Concrete capability declarations — Phase 1 matrix // --------------------------------------------------------------------------- const ALL_PAUSE_TYPES: readonly PendingQuestionType[] = [ 'user_input', 'command_approval', 'file_approval', 'elicitation', 'dynamic_tool', ] as const; export const CODEX_CAPABILITIES: Readonly = { sessionPersistence: true, structuredApproval: true, streamingOutput: true, abortPrimitive: true, crashRecovery: true, modelRouting: 'config', rateLimitSignal: true, pauseTypes: ALL_PAUSE_TYPES, }; export const COPILOT_CAPABILITIES: Readonly = { sessionPersistence: false, structuredApproval: false, streamingOutput: true, abortPrimitive: true, crashRecovery: false, modelRouting: 'api-param', rateLimitSignal: true, pauseTypes: ['user_input'] as const, }; export const CLAUDE_CAPABILITIES: Readonly = { sessionPersistence: false, structuredApproval: false, streamingOutput: true, abortPrimitive: true, crashRecovery: false, modelRouting: 'api-param', rateLimitSignal: true, pauseTypes: ['user_input'] as const, }; // --------------------------------------------------------------------------- // Validation // --------------------------------------------------------------------------- export interface ValidationResult { ok: boolean; reason?: string; } /** * Validates that a pause type is supported by the provider's capabilities. * Returns `{ ok: false, reason }` if the provider does not support the given type. */ export function validateResponseAgainstCapabilities( caps: ProviderCapabilities, pauseType: PendingQuestionType, ): ValidationResult { if (caps.pauseTypes.includes(pauseType)) { return { ok: true }; } return { ok: false, reason: `this provider does not support ${pauseType} responses`, }; }