/** * Intake API Client * * API client methods for the study intake workflow. */ import { CreateInboxRequest, CreateInboxResponse, IntrospectRequest, IntrospectResponse, ListInboxResponse, ListTopicsResponse, InboxStudyDetail, GenerateReadmeResponse, FinalizeRequest, FinalizeResponse, UploadFilesResponse, } from '../types/intake'; const API_BASE = '/api'; /** * Intake API client for study creation workflow. */ export const intakeApi = { /** * Create a new inbox study folder with initial spec. */ async createInbox(request: CreateInboxRequest): Promise { const response = await fetch(`${API_BASE}/intake/create`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(request), }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to create inbox study'); } return response.json(); }, /** * Run NX introspection on an inbox study. */ async introspect(request: IntrospectRequest): Promise { const response = await fetch(`${API_BASE}/intake/introspect`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(request), }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Introspection failed'); } return response.json(); }, /** * List all studies in the inbox. */ async listInbox(): Promise { const response = await fetch(`${API_BASE}/intake/list`); if (!response.ok) { throw new Error('Failed to fetch inbox studies'); } return response.json(); }, /** * List existing topic folders. */ async listTopics(): Promise { const response = await fetch(`${API_BASE}/intake/topics`); if (!response.ok) { throw new Error('Failed to fetch topics'); } return response.json(); }, /** * Get detailed information about an inbox study. */ async getInboxStudy(studyName: string): Promise { const response = await fetch(`${API_BASE}/intake/${encodeURIComponent(studyName)}`); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to fetch inbox study'); } return response.json(); }, /** * Delete an inbox study. */ async deleteInboxStudy(studyName: string): Promise<{ success: boolean; deleted: string }> { const response = await fetch(`${API_BASE}/intake/${encodeURIComponent(studyName)}`, { method: 'DELETE', }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to delete inbox study'); } return response.json(); }, /** * Generate README for an inbox study using Claude AI. */ async generateReadme(studyName: string): Promise { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/readme`, { method: 'POST' } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'README generation failed'); } return response.json(); }, /** * Finalize an inbox study and move to studies directory. */ async finalize(studyName: string, request: FinalizeRequest): Promise { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/finalize`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(request), } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Finalization failed'); } return response.json(); }, /** * Upload model files to an inbox study. */ async uploadFiles(studyName: string, files: File[]): Promise { const formData = new FormData(); files.forEach((file) => { formData.append('files', file); }); const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/upload`, { method: 'POST', body: formData, } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'File upload failed'); } return response.json(); }, /** * Upload context files to an inbox study. * Context files help Claude understand optimization goals. */ async uploadContextFiles(studyName: string, files: File[]): Promise { const formData = new FormData(); files.forEach((file) => { formData.append('files', file); }); const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/context`, { method: 'POST', body: formData, } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Context file upload failed'); } return response.json(); }, /** * List context files for an inbox study. */ async listContextFiles(studyName: string): Promise<{ study_name: string; context_files: Array<{ name: string; path: string; size: number; extension: string }>; total: number; }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/context` ); if (!response.ok) { throw new Error('Failed to list context files'); } return response.json(); }, /** * Delete a context file from an inbox study. */ async deleteContextFile(studyName: string, filename: string): Promise<{ success: boolean; deleted: string }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/context/${encodeURIComponent(filename)}`, { method: 'DELETE' } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to delete context file'); } return response.json(); }, /** * Create design variables from selected expressions. */ async createDesignVariables( studyName: string, expressionNames: string[], options?: { autoBounds?: boolean; boundFactor?: number } ): Promise<{ success: boolean; study_name: string; created: Array<{ id: string; name: string; expression_name: string; bounds_min: number; bounds_max: number; baseline: number; units: string | null; }>; total_created: number; }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/design-variables`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ expression_names: expressionNames, auto_bounds: options?.autoBounds ?? true, bound_factor: options?.boundFactor ?? 0.5, }), } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to create design variables'); } return response.json(); }, // =========================================================================== // Studio Endpoints (Atomizer Studio - Unified Creation Environment) // =========================================================================== /** * Create an anonymous draft study for Studio workflow. * Returns a temporary draft_id that can be renamed during finalization. */ async createDraft(): Promise<{ success: boolean; draft_id: string; inbox_path: string; spec_path: string; status: string; }> { const response = await fetch(`${API_BASE}/intake/draft`, { method: 'POST', }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to create draft'); } return response.json(); }, /** * Get extracted text content from context files. * Used for AI context injection. */ async getContextContent(studyName: string): Promise<{ success: boolean; study_name: string; content: string; files_read: Array<{ name: string; extension: string; size: number; status: string; characters?: number; error?: string; }>; total_characters: number; }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/context/content` ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to get context content'); } return response.json(); }, /** * Finalize a Studio draft with rename support. * Enhanced version that supports renaming draft_xxx to proper names. */ async finalizeStudio( studyName: string, request: { topic: string; newName?: string; runBaseline?: boolean; } ): Promise<{ success: boolean; original_name: string; final_name: string; final_path: string; status: string; baseline_success: boolean | null; readme_generated: boolean; }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/finalize/studio`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ topic: request.topic, new_name: request.newName, run_baseline: request.runBaseline ?? false, }), } ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Studio finalization failed'); } return response.json(); }, /** * Get complete draft information for Studio UI. * Convenience endpoint that returns everything the Studio needs. */ async getStudioDraft(studyName: string): Promise<{ success: boolean; draft_id: string; spec: Record; model_files: string[]; context_files: string[]; introspection_available: boolean; design_variable_count: number; objective_count: number; }> { const response = await fetch( `${API_BASE}/intake/${encodeURIComponent(studyName)}/studio` ); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to get studio draft'); } return response.json(); }, }; export default intakeApi;