/** * API Client * * 用于连接远程 Server 的客户端 */ export interface ClientConfig { /** 服务器地址 */ baseUrl: string; /** 认证 token */ token?: string; /** 请求超时 (ms) */ timeout?: number; } export interface Session { id: string; name?: string; createdAt: string; updatedAt: string; status: string; messageCount: number; } export interface Message { id: string; role: 'user' | 'assistant' | 'system'; content: string; timestamp: string; } export interface HealthStatus { status: string; timestamp: string; agent: { coreAvailable: boolean; }; auth: { enabled: boolean; tokenCount: number; }; stats: { sessions: number; websocket: { connections: number }; sse: { connections: number }; }; } // ============ Command 相关 ============ export interface CommandInfo { name: string; description?: string; agent?: string; model?: string; subtask?: boolean; source: string; hasTemplate: boolean; } export interface CommandSearchResult { name: string; description?: string; source: string; score: number; } export interface CommandExecuteResult { prompt: string; agent?: string; model?: string; subtask?: boolean; } export interface CommandListResponse { commands: Array<{ name: string; description?: string; source: string }>; stats: { total: number; bySource: Record }; } // ============ Command CRUD 相关 ============ export interface CreateCommandInput { name: string; description?: string; template: string; agent?: string; model?: string; subtask?: boolean; scope: 'user' | 'project'; } export interface UpdateCommandInput { description?: string; template?: string; agent?: string; model?: string; subtask?: boolean; } export interface CommandContent { name: string; description?: string; template: string; agent?: string; model?: string; subtask?: boolean; source: string; sourcePath?: string; } /** * API Client 类 */ export class APIClient { private baseUrl: string; private token?: string; private timeout: number; constructor(config: ClientConfig) { this.baseUrl = config.baseUrl.replace(/\/$/, ''); this.token = config.token; this.timeout = config.timeout || 30000; } /** * 发送 HTTP 请求 */ private async request( method: string, path: string, body?: unknown ): Promise { const url = `${this.baseUrl}${path}`; const headers: Record = { 'Content-Type': 'application/json', }; if (this.token) { headers['Authorization'] = `Bearer ${this.token}`; } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const response = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined, signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { const errorData = await response.json().catch(() => ({ error: response.statusText })) as { error?: string }; throw new Error(errorData.error || `HTTP ${response.status}`); } return response.json() as Promise; } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === 'AbortError') { throw new Error('Request timeout'); } throw error; } } // ============================================================================ // Health // ============================================================================ async health(): Promise { return this.request('GET', '/health'); } // ============================================================================ // Sessions // ============================================================================ async listSessions(): Promise<{ success: boolean; data: Session[] }> { return this.request('GET', '/api/sessions'); } async createSession(name?: string): Promise<{ success: boolean; data: Session }> { return this.request('POST', '/api/sessions', { name }); } async getSession(id: string): Promise<{ success: boolean; data: Session }> { return this.request('GET', `/api/sessions/${id}`); } async deleteSession(id: string): Promise<{ success: boolean }> { return this.request('DELETE', `/api/sessions/${id}`); } // ============================================================================ // Messages // ============================================================================ async getMessages(sessionId: string): Promise<{ success: boolean; data: Message[] }> { return this.request('GET', `/api/sessions/${sessionId}/messages`); } async sendMessage( sessionId: string, content: string ): Promise<{ success: boolean; data: Message }> { return this.request('POST', `/api/sessions/${sessionId}/messages`, { content }); } // ============================================================================ // WebSocket // ============================================================================ /** * 创建 WebSocket 连接 */ connectWebSocket(sessionId: string): WebSocket { const wsUrl = this.baseUrl .replace(/^http/, 'ws') .concat(`/api/ws/${sessionId}`); const url = this.token ? `${wsUrl}?token=${encodeURIComponent(this.token)}` : wsUrl; return new WebSocket(url); } // ============================================================================ // SSE // ============================================================================ /** * 获取 SSE URL (用于外部 EventSource 连接) */ getSSEUrl(sessionId: string): string { const sseUrl = `${this.baseUrl}/api/sessions/${sessionId}/events`; return this.token ? `${sseUrl}?token=${encodeURIComponent(this.token)}` : sseUrl; } // ============================================================================ // Commands // ============================================================================ async listCommands(): Promise<{ success: boolean; data: CommandListResponse }> { return this.request('GET', '/api/commands'); } async getCommand(name: string): Promise<{ success: boolean; data: CommandInfo }> { return this.request('GET', `/api/commands/${encodeURIComponent(name)}`); } async executeCommand( name: string, args: string = '' ): Promise<{ success: boolean; data?: CommandExecuteResult; error?: string }> { return this.request('POST', `/api/commands/${encodeURIComponent(name)}/execute`, { arguments: args, }); } async searchCommands( query: string, limit: number = 10 ): Promise<{ success: boolean; data: CommandSearchResult[] }> { return this.request('POST', '/api/commands/search', { query, limit }); } async reloadCommands(): Promise<{ success: boolean; data: { message: string; stats: { total: number; bySource: Record } }; }> { return this.request('POST', '/api/commands/reload'); } // ============================================================================ // Commands CRUD // ============================================================================ async createCommand( input: CreateCommandInput ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return this.request('POST', '/api/commands', input); } async getCommandContent( name: string ): Promise<{ success: boolean; data?: CommandContent; error?: string }> { return this.request('GET', `/api/commands/${encodeURIComponent(name)}/content`); } async updateCommand( name: string, input: UpdateCommandInput ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return this.request('PUT', `/api/commands/${encodeURIComponent(name)}`, input); } async deleteCommand( name: string ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return this.request('DELETE', `/api/commands/${encodeURIComponent(name)}`); } } /** * 创建 API Client */ export function createClient(config: ClientConfig): APIClient { return new APIClient(config); }