diff options
Diffstat (limited to 'makima/frontend/src/lib')
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index d7ac8b6..2ea1128 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -590,6 +590,9 @@ export interface Task { version: number; createdAt: string; updatedAt: string; + + // Supervisor flag + isSupervisor: boolean; } export interface TaskWithSubtasks extends Task { @@ -892,6 +895,75 @@ export async function checkTargetExists( return res.json(); } +// ============================================================================= +// Task Recovery (Daemon Failover) +// ============================================================================= + +/** Request to reassign a task to a new daemon */ +export interface ReassignTaskRequest { + targetDaemonId?: string; + includeContext?: boolean; +} + +/** Response from reassigning a task */ +export interface ReassignTaskResponse { + task: Task; + daemonId: string; + oldTaskId: string; + contextIncluded: boolean; + contextEntries: number; +} + +/** + * Reassign a task to a new daemon after daemon disconnect. + * Creates a new task with conversation context, deletes the old one. + */ +export async function reassignTask( + taskId: string, + options?: ReassignTaskRequest +): Promise<ReassignTaskResponse> { + const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/reassign`, { + method: "POST", + body: JSON.stringify(options || {}), + }); + if (!res.ok) { + const errorText = await res.text(); + throw new Error(`Failed to reassign task: ${errorText || res.statusText}`); + } + return res.json(); +} + +/** Request to continue a task */ +export interface ContinueTaskRequest { + targetDaemonId?: string; +} + +/** Response from continuing a task */ +export interface ContinueTaskResponse { + task: Task; + daemonId: string; + contextEntries: number; +} + +/** + * Continue a task after daemon disconnect by restarting it with conversation context. + * Unlike reassign, this keeps the same task ID. + */ +export async function continueTask( + taskId: string, + options?: ContinueTaskRequest +): Promise<ContinueTaskResponse> { + const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/continue`, { + method: "POST", + body: JSON.stringify(options || {}), + }); + if (!res.ok) { + const errorText = await res.text(); + throw new Error(`Failed to continue task: ${errorText || res.statusText}`); + } + return res.json(); +} + export async function listSubtasks(taskId: string): Promise<TaskListResponse> { const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/subtasks`); if (!res.ok) { @@ -1848,3 +1920,56 @@ export async function getTemplate(id: string): Promise<FileTemplate> { } return res.json(); } + +// ============================================================================= +// Supervisor Question Types and Functions +// ============================================================================= + +export interface PendingQuestion { + questionId: string; + taskId: string; + contractId: string; + question: string; + choices: string[]; + context: string | null; + createdAt: string; +} + +export interface AnswerQuestionRequest { + response: string; +} + +export interface AnswerQuestionResponse { + success: boolean; +} + +/** + * Get all pending supervisor questions for the current user. + */ +export async function listPendingQuestions(): Promise<PendingQuestion[]> { + const res = await authFetch(`${API_BASE}/api/v1/mesh/questions`); + if (!res.ok) { + throw new Error(`Failed to list questions: ${res.statusText}`); + } + return res.json(); +} + +/** + * Answer a pending supervisor question. + */ +export async function answerQuestion( + questionId: string, + response: string +): Promise<AnswerQuestionResponse> { + const res = await authFetch( + `${API_BASE}/api/v1/mesh/questions/${questionId}/answer`, + { + method: "POST", + body: JSON.stringify({ response }), + } + ); + if (!res.ok) { + throw new Error(`Failed to answer question: ${res.statusText}`); + } + return res.json(); +} |
