import { request } from './client' // Admin DTO from `internal/acp/dto.go: AgentKindAdminDTO`. export interface AgentKindAdmin { id: string name: string display_name: string description: string binary_path: string args: string[] env_keys: string[] enabled: boolean tool_allowlist: string[] created_by: string created_at: string updated_at: string } // Public DTO (non-admin view) from `internal/acp/dto.go: AgentKindPublicDTO`. export interface AgentKindPublic { id: string name: string display_name: string enabled: boolean } // Type guard distinguishing admin vs public DTO based on presence of admin-only fields. export function isAgentKindAdmin(k: AgentKindAdmin | AgentKindPublic): k is AgentKindAdmin { return 'binary_path' in k } export interface CreateAgentKindReq { name: string display_name: string description?: string binary_path: string args?: string[] env?: Record enabled?: boolean tool_allowlist?: string[] } export interface UpdateAgentKindReq { display_name?: string description?: string binary_path?: string args?: string[] env?: Record enabled?: boolean tool_allowlist?: string[] } // PermissionRequest mirrors backend PermissionRequestDTO. export interface PermissionRequest { id: string session_id: string tool_name: string tool_call: unknown options: { id: string; name?: string }[] status: string created_at: string } // AcpSession mirrors the backend session DTO returned by /api/v1/acp/sessions. export interface AcpSession { id: string workspace_id: string project_id: string agent_kind_id: string user_id: string issue_id: string | null requirement_id: string | null agent_session_id: string | null branch: string cwd_path: string is_main_worktree: boolean status: 'starting' | 'running' | 'crashed' | 'exited' pid: number | null exit_code: number | null last_error: string | null started_at: string ended_at: string | null } export interface CreateSessionReq { workspace_id: string agent_kind_id: string branch?: string issue_number?: number requirement_number?: number initial_prompt?: string } // AcpEvent is one frame from the session event stream (history REST + WS push). export interface AcpEvent { id: number direction: 'in' | 'out' kind: | 'request' | 'response' | 'notification' | 'error' | 'state' | 'session_terminated' | 'slow_consumer_disconnect' | 'client_error' | 'permission_request' | 'permission_resolved' method?: string payload: unknown truncated: boolean } const enc = (v: string) => encodeURIComponent(v) export const acpApi = { agentKinds: { list: () => request<(AgentKindAdmin | AgentKindPublic)[]>('/api/v1/acp/agent-kinds'), get: (id: string) => request(`/api/v1/acp/agent-kinds/${enc(id)}`), create: (req: CreateAgentKindReq) => request('/api/v1/acp/agent-kinds', { method: 'POST', body: req }), update: (id: string, req: UpdateAgentKindReq) => request(`/api/v1/acp/agent-kinds/${enc(id)}`, { method: 'PATCH', body: req }), remove: (id: string) => request(`/api/v1/acp/agent-kinds/${enc(id)}`, { method: 'DELETE' }), }, sessions: { list: (all?: boolean) => request('/api/v1/acp/sessions' + (all ? '?all=true' : '')), get: (id: string) => request(`/api/v1/acp/sessions/${enc(id)}`), create: (req: CreateSessionReq) => request('/api/v1/acp/sessions', { method: 'POST', body: req }), terminate: (id: string) => request(`/api/v1/acp/sessions/${enc(id)}`, { method: 'DELETE' }), events: (id: string, since: number) => request(`/api/v1/acp/sessions/${enc(id)}/events?since=${since}`), permissions: (id: string) => request(`/api/v1/acp/sessions/${enc(id)}/permissions`), }, permissions: { approve: (reqID: string, optionId?: string) => request(`/api/v1/acp/permissions/${enc(reqID)}/approve`, { method: 'POST', body: optionId ? { option_id: optionId } : {}, }), deny: (reqID: string) => request(`/api/v1/acp/permissions/${enc(reqID)}/deny`, { method: 'POST' }), }, } // openSessionWS opens a native WebSocket to /sessions/{id}/ws. // // Auth: browser WebSocket cannot send custom headers, so the token is sent // via the ?token= query parameter. The backend auth middleware accepts it // as a fallback to Authorization. Keep token lifetimes short. export function openSessionWS(sessionId: string, since: number, token: string): WebSocket { const proto = window.location.protocol === 'https:' ? 'wss' : 'ws' const host = window.location.host const url = `${proto}://${host}/api/v1/acp/sessions/${enc(sessionId)}` + `/ws?since=${since}&token=${enc(token)}` return new WebSocket(url) }