import type { Task, Handoff, Decision, Memory, Message, ActivityItem } from '../core/schema.js'; import type { IndexEntry } from '../core/index.js'; import type { InboxMessage } from '../core/services/messageService.js'; import type { TaskLogEntry } from '../core/services/taskLogService.js'; export class RemoteError extends Error { constructor(public status: number, message: string) { super(message); } } async function request(baseUrl: string, method: string, path: string, body?: unknown): Promise { const url = `${baseUrl}${path}`; let res: Response; try { res = await fetch(url, { method, headers: body ? { 'Content-Type': 'application/json' } : undefined, body: body ? JSON.stringify(body) : undefined, }); } catch (err) { const message = err instanceof Error ? err.message : String(err); throw new RemoteError(0, `Cannot reach AgentHub server at ${baseUrl}: ${message}`); } const text = await res.text(); if (!res.ok) { throw new RemoteError(res.status, text || `HTTP ${res.status}`); } if (!text) { throw new RemoteError(res.status, 'Empty response from server'); } return JSON.parse(text) as T; } export const remoteClient = { async getStatus(baseUrl: string): Promise { return request<{ body: string }>(baseUrl, 'GET', '/status').then((r) => r.body); }, async announce(baseUrl: string, agent: string, role?: string, action: 'joined' | 'left' = 'joined'): Promise { await request<{ ok: boolean }>(baseUrl, 'POST', '/announce', { agent, role, action }); }, async updateStatus(baseUrl: string): Promise { return request<{ body: string }>(baseUrl, 'POST', '/status/update').then((r) => r.body); }, async createTask(baseUrl: string, options: Partial): Promise { return request(baseUrl, 'POST', '/tasks', options); }, async listTasks(baseUrl: string, filters?: { status?: string; role?: string }): Promise { const params = new URLSearchParams((filters ?? {}) as Record); const qs = params.toString(); return request(baseUrl, 'GET', `/tasks${qs ? '?' + qs : ''}`); }, async getTask(baseUrl: string, id: string): Promise<{ task: Task; body: string }> { return request<{ task: Task; body: string }>(baseUrl, 'GET', `/tasks/${id}`); }, async claimTask(baseUrl: string, id: string, agentName: string): Promise { return request(baseUrl, 'PATCH', `/tasks/${id}`, { status: 'in_progress', assignedTo: agentName }); }, async doneTask( baseUrl: string, id: string, meta?: { tokens?: number; duration?: number; by?: string }, ): Promise { return request(baseUrl, 'PATCH', `/tasks/${id}`, { status: 'done', doneTokens: meta?.tokens, doneDuration: meta?.duration, doneBy: meta?.by, }); }, async assignTask(baseUrl: string, id: string, agentName: string): Promise { return request(baseUrl, 'PATCH', `/tasks/${id}`, { assignedTo: agentName }); }, async reviewTask(baseUrl: string, id: string): Promise { return request(baseUrl, 'PATCH', `/tasks/${id}`, { status: 'review' }); }, async reopenTask(baseUrl: string, id: string): Promise { return request(baseUrl, 'PATCH', `/tasks/${id}`, { status: 'open' }); }, async getTaskActivity(baseUrl: string, id: string): Promise { return request(baseUrl, 'GET', `/tasks/${id}/activity`); }, async appendTaskLog( baseUrl: string, id: string, entry: { text: string; agent?: string; level?: string }, ): Promise { return request(baseUrl, 'POST', `/tasks/${id}/log`, entry); }, async createHandoff(baseUrl: string, options: Partial): Promise { return request(baseUrl, 'POST', '/handoffs', options); }, async listHandoffs(baseUrl: string): Promise { return request(baseUrl, 'GET', '/handoffs'); }, async getHandoff(baseUrl: string, id: string): Promise<{ handoff: Handoff; body: string }> { return request<{ handoff: Handoff; body: string }>(baseUrl, 'GET', `/handoffs/${id}`); }, async createDecision(baseUrl: string, options: Partial): Promise { return request(baseUrl, 'POST', '/decisions', options); }, async listDecisions(baseUrl: string): Promise { return request(baseUrl, 'GET', '/decisions'); }, async addMemory(baseUrl: string, options: Partial): Promise { return request(baseUrl, 'POST', '/memory', options); }, async searchMemory(baseUrl: string, query: string): Promise { return request(baseUrl, 'GET', `/memory/search?q=${encodeURIComponent(query)}`); }, async listMemory(baseUrl: string): Promise { return request(baseUrl, 'GET', '/memory'); }, async sendMessage(baseUrl: string, options: Partial): Promise { return request(baseUrl, 'POST', '/messages', options); }, async getInbox(baseUrl: string, agent: string, unreadOnly = false): Promise { const q = `?agent=${encodeURIComponent(agent)}${unreadOnly ? '&unread=1' : ''}`; return request(baseUrl, 'GET', `/messages${q}`); }, async markMessageRead(baseUrl: string, id: string): Promise { return request(baseUrl, 'POST', `/messages/${id}/read`); }, async ackMessage(baseUrl: string, id: string, by?: string): Promise { return request(baseUrl, 'POST', `/messages/${id}/ack`, by ? { by } : undefined); }, async getMessage(baseUrl: string, id: string): Promise<{ message: Message; body: string }> { return request<{ message: Message; body: string }>(baseUrl, 'GET', `/messages/${id}`); }, async delegate(baseUrl: string, auto: boolean): Promise<{ suggestion?: { task: IndexEntry; role: string; preferredAgent: string }; handoff?: Handoff }> { return request<{ suggestion?: { task: IndexEntry; role: string; preferredAgent: string }; handoff?: Handoff }>(baseUrl, 'POST', `/delegate?auto=${auto}`); }, };