import { SERVICE_SESSION_SCOPE } from '../config.js'; import { type PairedTurnIdentity } from '../paired-turn-identity.js'; import { AgentType, PairedProject, PairedRoomRole, PairedTask, PairedTurnOutput, PairedTurnReservationIntentKind, PairedWorkspace, } from '../types.js'; import { clearChannelOwnerLeaseInDatabase, getAllChannelOwnerLeasesFromDatabase, getChannelOwnerLeaseFromDatabase, setChannelOwnerLeaseInDatabase, type ChannelOwnerLeaseRow, type SetChannelOwnerLeaseInput, } from './channel-owner-leases.js'; import { claimPairedTurnReservationInDatabase, clearPairedTaskExecutionLeasesInDatabase, clearPairedTurnReservationsInDatabase, type PairedTaskUpdates, createPairedTaskInDatabase, getAllOpenPairedTasksFromDatabase, getLastBotFinalMessageFromDatabase, getLatestOpenPairedTaskForChatFromDatabase, getLatestPreviousPairedTaskForChatFromDatabase, getLatestPairedTaskForChatFromDatabase, getPairedProjectFromDatabase, getPairedTaskByIdFromDatabase, getPairedWorkspaceFromDatabase, listPairedWorkspacesForTaskFromDatabase, refreshPairedTaskExecutionLeaseInDatabase, releasePairedTaskExecutionLeaseInDatabase, reservePairedTurnReservationInDatabase, updatePairedTaskIfUnchangedInDatabase, updatePairedTaskInDatabase, upsertPairedProjectInDatabase, upsertPairedWorkspaceInDatabase, } from './paired-state.js'; import { clearPairedTurnAttemptsInDatabase, getOwnerCodexBadRequestFailureSummaryForTaskFromDatabase, getPairedTurnAttemptsForTurnFromDatabase, recoverInterruptedPairedTurnAttemptsForServiceInDatabase, type InterruptedPairedTurnAttemptRecoveryCandidate, type OwnerCodexBadRequestFailureSummary, type PairedTurnAttemptRecord, } from './paired-turn-attempts.js'; import { getLatestTurnNumberFromDatabase, getPairedTurnOutputsFromDatabase, getRecentPairedTurnOutputsForChatFromDatabase, insertPairedTurnOutputInDatabase, } from './paired-turn-outputs.js'; import { cancelPairedTurnInDatabase, clearPairedTurnsInDatabase, completePairedTurnInDatabase, failPairedTurnInDatabase, getPairedTurnByIdFromDatabase, getPairedTurnsForTaskFromDatabase, getLatestPairedTurnForTaskFromDatabase, updatePairedTurnProgressTextFromDatabase, markPairedTurnRunningInDatabase, type PairedTurnRecord, } from './paired-turns.js'; import { requireDatabase } from './runtime-database.js'; import { type CompleteServiceHandoffCursorInput, type CreateServiceHandoffInput, type ServiceHandoff, claimServiceHandoffInDatabase, completeServiceHandoffAndAdvanceTargetCursorInDatabase, completeServiceHandoffInDatabase, createServiceHandoffInDatabase, failServiceHandoffInDatabase, getAllPendingServiceHandoffsFromDatabase, getPendingServiceHandoffsFromDatabase, } from './service-handoffs.js'; export function upsertPairedProject(project: PairedProject): void { upsertPairedProjectInDatabase(requireDatabase(), project); } export function getPairedProject(chatJid: string): PairedProject | undefined { return getPairedProjectFromDatabase(requireDatabase(), chatJid); } export function createPairedTask(task: PairedTask): void { createPairedTaskInDatabase(requireDatabase(), task); } export function getPairedTaskById(id: string): PairedTask | undefined { return getPairedTaskByIdFromDatabase(requireDatabase(), id); } export function getLatestPairedTaskForChat( chatJid: string, ): PairedTask | undefined { return getLatestPairedTaskForChatFromDatabase(requireDatabase(), chatJid); } export function getLatestOpenPairedTaskForChat( chatJid: string, ): PairedTask | undefined { return getLatestOpenPairedTaskForChatFromDatabase(requireDatabase(), chatJid); } export function getLatestPreviousPairedTaskForChat( chatJid: string, currentTaskId: string, ): PairedTask | undefined { return getLatestPreviousPairedTaskForChatFromDatabase( requireDatabase(), chatJid, currentTaskId, ); } export function getAllOpenPairedTasks(): PairedTask[] { return getAllOpenPairedTasksFromDatabase(requireDatabase()); } export function updatePairedTask(id: string, updates: PairedTaskUpdates): void { updatePairedTaskInDatabase(requireDatabase(), id, updates); } export function updatePairedTaskIfUnchanged( id: string, expectedUpdatedAt: string, updates: PairedTaskUpdates, ): boolean { return updatePairedTaskIfUnchangedInDatabase( requireDatabase(), id, expectedUpdatedAt, updates, ); } export function reservePairedTurnReservation(args: { chatJid: string; taskId: string; taskStatus: PairedTask['status']; roundTripCount: number; taskUpdatedAt: string; intentKind: PairedTurnReservationIntentKind; runId: string; }): boolean { return reservePairedTurnReservationInDatabase(requireDatabase(), args); } export function claimPairedTurnReservation(args: { chatJid: string; taskId: string; taskStatus: PairedTask['status']; roundTripCount: number; taskUpdatedAt: string; intentKind: PairedTurnReservationIntentKind; runId: string; }): boolean { return claimPairedTurnReservationInDatabase(requireDatabase(), args); } export function releasePairedTaskExecutionLease(args: { taskId: string; runId: string; }): void { releasePairedTaskExecutionLeaseInDatabase(requireDatabase(), args); } export function refreshPairedTaskExecutionLease(args: { taskId: string; runId: string; now?: string; }): boolean { return refreshPairedTaskExecutionLeaseInDatabase(requireDatabase(), args); } export function markPairedTurnRunning(args: { turnIdentity: PairedTurnIdentity; executorServiceId?: string | null; executorAgentType?: AgentType | null; runId?: string | null; }): void { markPairedTurnRunningInDatabase(requireDatabase(), args); } export function completePairedTurn(turnIdentity: PairedTurnIdentity): void { completePairedTurnInDatabase(requireDatabase(), turnIdentity); } export function failPairedTurn(args: { turnIdentity: PairedTurnIdentity; error?: string | null; }): void { failPairedTurnInDatabase(requireDatabase(), args); } export function cancelPairedTurn(args: { turnIdentity: PairedTurnIdentity; error?: string | null; }): void { cancelPairedTurnInDatabase(requireDatabase(), args); } export function getPairedTurnById( turnId: string, ): PairedTurnRecord | undefined { return getPairedTurnByIdFromDatabase(requireDatabase(), turnId); } export function getPairedTurnsForTask(taskId: string): PairedTurnRecord[] { return getPairedTurnsForTaskFromDatabase(requireDatabase(), taskId); } export function getLatestPairedTurnForTask( taskId: string, ): PairedTurnRecord | null { return getLatestPairedTurnForTaskFromDatabase(requireDatabase(), taskId); } export function updatePairedTurnProgressText( turnId: string, progressText: string | null, ): void { updatePairedTurnProgressTextFromDatabase( requireDatabase(), turnId, progressText, ); } export function getPairedTurnAttempts( turnId: string, ): PairedTurnAttemptRecord[] { return getPairedTurnAttemptsForTurnFromDatabase(requireDatabase(), turnId); } export function recoverInterruptedPairedTurnAttemptsForService(args: { serviceIds: string[]; now?: string; error?: string; }): InterruptedPairedTurnAttemptRecoveryCandidate[] { return recoverInterruptedPairedTurnAttemptsForServiceInDatabase( requireDatabase(), args, ); } export function getOwnerCodexBadRequestFailureSummaryForTask(args: { taskId: string; threshold: number; }): OwnerCodexBadRequestFailureSummary | null { return getOwnerCodexBadRequestFailureSummaryForTaskFromDatabase( requireDatabase(), args, ); } export function upsertPairedWorkspace(workspace: PairedWorkspace): void { upsertPairedWorkspaceInDatabase(requireDatabase(), workspace); } export function getPairedWorkspace( taskId: string, role: PairedWorkspace['role'], ): PairedWorkspace | undefined { return getPairedWorkspaceFromDatabase(requireDatabase(), taskId, role); } export function listPairedWorkspacesForTask(taskId: string): PairedWorkspace[] { return listPairedWorkspacesForTaskFromDatabase(requireDatabase(), taskId); } /** @internal - for tests only. */ export function _clearPairedTurnReservationsForTests(): void { const db = requireDatabase(); clearPairedTurnReservationsInDatabase(db); clearPairedTaskExecutionLeasesInDatabase(db); clearPairedTurnAttemptsInDatabase(db); clearPairedTurnsInDatabase(db); } export function getLastBotFinalMessage( chatJid: string, agentType: AgentType = 'claude-code', limit: number = 1, ): Array<{ content: string; timestamp: string }> { return getLastBotFinalMessageFromDatabase( requireDatabase(), chatJid, agentType, limit, ); } export function getChannelOwnerLease( chatJid: string, ): ChannelOwnerLeaseRow | undefined { return getChannelOwnerLeaseFromDatabase(requireDatabase(), chatJid); } export function getAllChannelOwnerLeases(): ChannelOwnerLeaseRow[] { return getAllChannelOwnerLeasesFromDatabase(requireDatabase()); } export function setChannelOwnerLease(input: SetChannelOwnerLeaseInput): void { setChannelOwnerLeaseInDatabase(requireDatabase(), input); } export function clearChannelOwnerLease(chatJid: string): void { clearChannelOwnerLeaseInDatabase(requireDatabase(), chatJid); } export function createServiceHandoff( input: CreateServiceHandoffInput, ): ServiceHandoff { return createServiceHandoffInDatabase(requireDatabase(), input); } export function getPendingServiceHandoffs( targetServiceId: string = SERVICE_SESSION_SCOPE, ): ServiceHandoff[] { return getPendingServiceHandoffsFromDatabase( requireDatabase(), targetServiceId, ); } export function getAllPendingServiceHandoffs(): ServiceHandoff[] { return getAllPendingServiceHandoffsFromDatabase(requireDatabase()); } export function claimServiceHandoff(id: number): boolean { return claimServiceHandoffInDatabase(requireDatabase(), id); } export function completeServiceHandoff(id: number): void { completeServiceHandoffInDatabase(requireDatabase(), id); } export function failServiceHandoff(id: number, error: string): void { failServiceHandoffInDatabase(requireDatabase(), id, error); } export function completeServiceHandoffAndAdvanceTargetCursor( input: CompleteServiceHandoffCursorInput, ): string | null { return completeServiceHandoffAndAdvanceTargetCursorInDatabase( requireDatabase(), input, ); } export function insertPairedTurnOutput( taskId: string, turnNumber: number, role: PairedRoomRole, outputText: string, createdAtOrOptions?: | string | { createdAt?: string; attachments?: import('../types.js').OutboundAttachment[]; }, ): void { const options = typeof createdAtOrOptions === 'string' ? { createdAt: createdAtOrOptions } : (createdAtOrOptions ?? {}); insertPairedTurnOutputInDatabase( requireDatabase(), taskId, turnNumber, role, outputText, options, ); } export function getPairedTurnOutputs(taskId: string): PairedTurnOutput[] { return getPairedTurnOutputsFromDatabase(requireDatabase(), taskId); } export function getRecentPairedTurnOutputsForChat( chatJid: string, limit: number = 8, ): PairedTurnOutput[] { return getRecentPairedTurnOutputsForChatFromDatabase( requireDatabase(), chatJid, limit, ); } export function getLatestTurnNumber(taskId: string): number { return getLatestTurnNumberFromDatabase(requireDatabase(), taskId); }