/** * useOracleExecution — manages prompt submission and durable execution history. */ import { useState, useCallback, useRef } from 'react'; import type { PromptExecution, CanvasComponent, PlacementMode, OracleExecutionMode } from '../types/canvas'; import { submitPrompt } from '../lib/oracleApiClient'; export interface ExecutionEntry { execution: PromptExecution; componentsCreated: string[]; } export interface OracleExecutionState { history: ExecutionEntry[]; inFlight: PromptExecution | null; lastError: string | null; submit: (params: { pageId: string; branchId: string; prompt: string; tenantId: string; actorId: string; executionMode?: OracleExecutionMode; placementMode?: PlacementMode; conversationContext?: Array<{ role: 'user' | 'assistant'; content: string }>; onExecutionCommitted?: (commit: { headRevision: number; components: CanvasComponent[]; execution: PromptExecution; }) => void; }) => Promise; clearError: () => void; resetHistory: () => void; } export function useOracleExecution(): OracleExecutionState { const [history, setHistory] = useState([]); const [inFlight, setInFlight] = useState(null); const [lastError, setLastError] = useState(null); const requestIdRef = useRef(0); const submit = useCallback( async ({ pageId, branchId, prompt, tenantId, actorId, executionMode = 'auto', placementMode = 'append_after_last_visible_component', conversationContext = [], onExecutionCommitted, }: { pageId: string; branchId: string; prompt: string; tenantId: string; actorId: string; executionMode?: OracleExecutionMode; placementMode?: PlacementMode; conversationContext?: Array<{ role: 'user' | 'assistant'; content: string }>; onExecutionCommitted?: (commit: { headRevision: number; components: CanvasComponent[]; execution: PromptExecution; }) => void; }) => { const clientRequestId = `cli_${Date.now()}_${++requestIdRef.current}`; const now = new Date().toISOString(); const optimistic: PromptExecution = { executionId: `pex_${clientRequestId}`, tenantId, pageId, branchId, actorId, prompt, intentClass: 'analytical', status: 'planning', modelRuntime: executionMode === 'thinking' ? 'colony_orchestrator' : 'oracle_runtime', semanticModelVersion: 'oracle_semantic_v2026_04_08_01', warnings: [], createdAt: now, executionMode, }; setInFlight(optimistic); setLastError(null); try { setInFlight((prev) => (prev ? { ...prev, status: 'executing' } : prev)); const response = await submitPrompt(pageId, { clientRequestId, branchId, prompt, conversationContext, placementMode, executionMode, }); const completed: PromptExecution = { ...optimistic, executionId: response.executionId, status: response.status, summary: response.summary, warnings: response.warnings, componentsCreated: response.componentsCreated, executionMode: response.executionMode ?? executionMode, resolvedMode: response.resolvedMode, colonyMissionId: response.colonyMissionId, completedAt: new Date().toISOString(), }; onExecutionCommitted?.({ headRevision: response.headRevision, components: response.components, execution: completed, }); setHistory((prev) => [...prev, { execution: completed, componentsCreated: response.componentsCreated }]); setInFlight(null); } catch (err) { const msg = err instanceof Error ? err.message : 'Prompt execution failed'; const failed: PromptExecution = { ...optimistic, status: 'failed', warnings: [msg], completedAt: new Date().toISOString(), }; setHistory((prev) => [...prev, { execution: failed, componentsCreated: [] }]); setInFlight(null); setLastError(msg); } }, [], ); return { history, inFlight, lastError, submit, clearError: () => setLastError(null), resetHistory: () => setHistory([]), }; }