UNPKG

solver-sdk

Version:

SDK для интеграции с Code Solver Backend API (совместимо с браузером и Node.js), с поддержкой функциональности мышления (Thinking Mode)

503 lines 19.8 kB
import { HttpClient } from './utils/http-client.js'; import { ProjectsApi } from './api/projects-api.js'; import { SearchApi } from './api/search-api.js'; import { ContextApi } from './api/context-api.js'; import { ReasoningApi } from './api/reasoning-api.js'; import { CodeModificationApi } from './api/code-modification-api.js'; import { CodeSolverWebSocketClient, WebSocketNamespace } from './utils/code-solver-websocket-client.js'; import { AgentsApi } from './api/agents-api.js'; import { ChatApi } from './api/chat-api.js'; import { ModelsApi } from './api/models-api.js'; import { DependenciesApi } from './api/dependencies-api.js'; // Версия SDK const SDK_VERSION = '1.5.0'; /** * Определение типа среды выполнения * @returns 'browser' | 'node' | 'unknown' */ function getEnvironment() { if (typeof window !== 'undefined' && typeof window.document !== 'undefined') { return 'browser'; } else if (typeof process !== 'undefined' && process.versions && process.versions.node) { return 'node'; } return 'unknown'; } /** * Основной класс SDK для работы с Code Solver API * Поддерживает работу как в браузере, так и в Node.js */ export class CodeSolverSDK { /** * Создает новый экземпляр SDK * @param {CodeSolverSDKOptions} options Опции SDK */ constructor(options) { /** WebSocket клиент для работы с реалтайм API */ this.wsClient = null; /** Logger для внутреннего использования */ this.logger = { log: (message) => { if (this._options.debug) { console.log(`[CodeSolverSDK] ${message}`); } }, warn: (message) => { if (this._options.debug) { console.warn(`[CodeSolverSDK] ⚠️ ${message}`); } }, error: (message) => { console.error(`[CodeSolverSDK] 🔴 ${message}`); }, debug: (message) => { if (this._options.debug === 'verbose') { console.debug(`[CodeSolverSDK] 🔍 ${message}`); } } }; this._options = { ...options, mode: options.mode || 'auto' }; // Определяем среду выполнения this.environment = this._options.mode === 'auto' ? getEnvironment() : this._options.mode === 'browser' ? 'browser' : 'node'; // Инициализируем HTTP клиент this.httpClient = new HttpClient(this._options.baseURL, { headers: { ...(this._options.apiKey ? { 'Authorization': `Bearer ${this._options.apiKey}` } : {}), ...(this._options.headers || {}) }, timeout: this._options.timeout, httpsAgent: this.environment === 'node' ? this._options.httpsAgent : undefined }); // Инициализируем API клиенты this._projects = new ProjectsApi(this.httpClient); this._search = new SearchApi(this.httpClient); this._reasoning = new ReasoningApi(this.httpClient, this._projects); this._context = new ContextApi(this.httpClient, this._projects); this._codeModification = new CodeModificationApi(this.httpClient); this._agents = new AgentsApi(this.httpClient); this._chat = new ChatApi(this.httpClient); this._models = new ModelsApi(this.httpClient); this._dependencies = new DependenciesApi(this.httpClient); // Устанавливаем ссылку на SDK для API классов, поддерживающих WebSocket if (typeof this._projects.setParent === 'function') { this._projects.setParent(this); } if (typeof this._reasoning.setParent === 'function') { this._reasoning.setParent(this); } if (typeof this._dependencies.setParent === 'function') { this._dependencies.setParent(this); } } /** * Проверяет доступность API * @returns {Promise<boolean>} Доступен ли API */ async checkHealth() { try { await this.httpClient.get('/health'); return true; } catch (error) { return false; } } /** * Получает WebSocket клиент * @returns {CodeSolverWebSocketClient} WebSocket клиент */ getWebSocketClient() { if (!this.wsClient) { const wsURL = this.wsURL; this.wsClient = new CodeSolverWebSocketClient(wsURL, { apiKey: this._options.apiKey, headers: this._options.headers, autoReconnect: this.wsConfig.reconnect !== false, maxRetries: this.wsConfig.reconnectAttempts || 5, retryDelay: this.wsConfig.reconnectDelay || 1000, rejectUnauthorized: this.wsConfig.rejectUnauthorized }); } return this.wsClient; } /** * API для работы с агентами */ get agents() { return this._agents; } /** * API для работы с контекстом */ get context() { return this._context; } /** * API для работы с проектами */ get projects() { return this._projects; } /** * API для поиска кода */ get search() { return this._search; } /** * API для работы с рассуждениями */ get reasoning() { return this._reasoning; } /** * API для модификации кода */ get codeModification() { return this._codeModification; } /** * Возвращает API для работы с чатом * @returns {ChatApi} API для работы с чатом */ get chat() { return this._chat; } /** * API для работы с моделями */ get models() { return this._models; } /** * Доступ к API зависимостей */ get dependencies() { return this._dependencies; } /** * Получает опции SDK */ get options() { return this._options; } /** * Получает конфигурацию WebSocket */ get wsConfig() { return this._options.websocket || {}; } /** * Получает URL для WebSocket соединений */ get wsURL() { return this._options.wsURL || this._options.baseURL.replace(/^http/, 'ws'); } /** * Получает HTTP-клиент */ get client() { return this.httpClient; } /** * Получает текущую среду выполнения * @returns {string} Среда выполнения ('browser', 'node', 'unknown') */ getEnvironment() { return this.environment; } /** * Закрывает все соединения и освобождает ресурсы */ dispose() { if (this.wsClient) { this.wsClient.disconnectAll(); this.wsClient = null; } } /** * Устанавливает глобальный обработчик ошибок SDK * @param {(error: Error) => void} handler Функция-обработчик ошибок */ static setErrorHandler(handler) { CodeSolverSDK.errorHandler = handler; } /** * Обрабатывает ошибку через глобальный обработчик, если он установлен * @param {Error} error Ошибка для обработки */ static handleError(error) { if (CodeSolverSDK.errorHandler) { CodeSolverSDK.errorHandler(error); } else { console.error('[CodeSolverSDK]', error); } } /** * Возвращает текущую версию SDK * @returns {string} Версия SDK */ static getVersion() { return SDK_VERSION; } /** * Возвращает текущую версию SDK * @returns {string} Версия SDK */ getVersion() { return SDK_VERSION; } /** * Устанавливает новый API ключ для SDK * @param {string} apiKey Новый API ключ */ setApiKey(apiKey) { if (!apiKey) { throw new Error('API ключ не может быть пустым'); } // Обновляем опции this._options.apiKey = apiKey; // Пересоздаем HTTP клиент с новым API ключом const newHttpClient = new HttpClient(this._options.baseURL, { headers: { ...this._options.headers, 'Authorization': `Bearer ${apiKey}` }, timeout: this._options.timeout, httpsAgent: this.environment === 'node' ? this._options.httpsAgent : undefined }); // Обновляем ссылки на клиент и API this.httpClient = newHttpClient; this._agents = new AgentsApi(newHttpClient); this._context = new ContextApi(newHttpClient, this._projects); this._projects = new ProjectsApi(newHttpClient); this._search = new SearchApi(newHttpClient); this._reasoning = new ReasoningApi(newHttpClient, this._projects); this._codeModification = new CodeModificationApi(newHttpClient); this._chat = new ChatApi(newHttpClient); this._models = new ModelsApi(newHttpClient); this._dependencies = new DependenciesApi(newHttpClient); // Если есть WebSocket клиент, пересоздаем его if (this.wsClient) { const isConnected = this.wsClient.isConnectedToReasoning() || this.wsClient.isConnectedToIndexing(); this.wsClient.disconnectAll(); this.wsClient = new CodeSolverWebSocketClient(this._options.baseURL, { apiKey, headers: this._options.headers }); // Если был подключен, восстанавливаем соединение if (isConnected) { this.connect().catch(() => { }); } } } /** * Подключается к WebSocket серверу * @returns {Promise<boolean>} Promise с результатом подключения */ async connect() { try { const wsClient = this.getWebSocketClient(); // Проверяем доступность сервера перед подключением const serverAvailable = await this.checkHealth().catch(() => false); if (!serverAvailable) { this.logger.warn('Сервер недоступен, WebSocket подключение может быть нестабильным'); } // Подключаемся к обоим пространствам имен await wsClient.connectToReasoning(); await wsClient.connectToIndexing(); return true; } catch (error) { CodeSolverSDK.handleError(error); return false; } } /** * Отключается от WebSocket сервера * @returns {Promise<void>} Promise без результата */ async disconnect() { if (this.wsClient) { await this.wsClient.disconnectAll(); } } /** * Проверяет, подключен ли SDK к WebSocket серверу * @returns {boolean} Статус подключения */ isConnected() { if (!this.wsClient) return false; return this.wsClient.isConnectedToReasoning() || this.wsClient.isConnectedToIndexing(); } /** * Проверяет доступность API (алиас для checkHealth) * @returns {Promise<boolean>} Promise с результатом проверки */ async isHealthy() { return this.checkHealth(); } /** * Проверяет доступность всех сервисов API * @returns {Promise<{[key: string]: boolean}>} Статус каждого сервиса */ async checkServices() { try { const results = { api: false, websocket: false, database: false, search: false }; try { // Проверка API results.api = await this.checkHealth(); // Проверка других компонентов через запрос статуса const response = await this.httpClient.get('/api/v1/status'); if (response && typeof response === 'object') { results.database = Boolean(response.database?.connected); results.search = Boolean(response.search?.connected); // Проверка WebSocket соединения if (this.wsClient) { results.websocket = this.wsClient.isConnectedToReasoning() || this.wsClient.isConnectedToIndexing(); } else { try { const wsClient = this.getWebSocketClient(); await wsClient.connectToReasoning(); results.websocket = true; await wsClient.disconnect(WebSocketNamespace.REASONING); } catch (e) { results.websocket = false; } } } } catch (error) { // Игнорируем ошибки при проверке } return results; } catch (error) { return { api: false, websocket: false, database: false, search: false }; } } /** * Закрывает соединение с сервером (алиас для dispose) */ close() { this.dispose(); return Promise.resolve(); } /** * Выполняет запрос к API для генерации рассуждения с использованием Anthropic API * с поддержкой потоковой передачи данных через WebSocket * * @param {ReasoningOptions} options Опции для рассуждения * @param {AnthropicStreamCallbacks} callbacks Коллбэки для обработки событий * @returns {Promise<void>} Promise без результата */ async executeReasoning(options, callbacks) { try { // Подключаемся к WebSocket серверу если еще не подключены if (!this.isConnected()) { await this.connect(); } // Получаем WebSocket клиент const wsClient = this.getWebSocketClient(); // Подписываемся на события this.setupAnthropicEventHandlers(wsClient, callbacks); // Отправляем запрос на выполнение рассуждения wsClient.sendToReasoning('execute_reasoning', { projectId: options.projectId, prompt: options.query, level: options.level || 'STANDARD', type: options.type || 'THINKING', currentFile: options.currentFilePath, selection: options.selection, options: { modelProvider: options.options?.modelProvider || 'anthropic', modelName: options.options?.modelName || 'claude-3-sonnet-20240229', streamResponse: true, ...(options.options || {}) } }); this.logger.debug(`Запрос на выполнение рассуждения отправлен: ${JSON.stringify({ projectId: options.projectId, prompt: options.query.substring(0, 50) + '...', level: options.level })}`); } catch (error) { this.logger.error(`Ошибка при отправке запроса на рассуждение: ${error instanceof Error ? error.message : String(error)}`); callbacks.onError?.({ code: 'SDK_ERROR', message: `Ошибка при отправке запроса: ${error instanceof Error ? error.message : String(error)}` }); throw error; } } /** * Настраивает обработчики событий Anthropic API * @param {CodeSolverWebSocketClient} wsClient WebSocket клиент * @param {AnthropicStreamCallbacks} callbacks Коллбэки для обработки событий * @private */ setupAnthropicEventHandlers(wsClient, callbacks) { // Регистрируем обработчики для всех типов событий wsClient.on('message_start', (data) => { callbacks.onMessageStart?.(data); callbacks.onAny?.('message_start', data); }, WebSocketNamespace.REASONING); wsClient.on('thinking_block_start', (data) => { callbacks.onThinkingStart?.(data); callbacks.onAny?.('thinking_block_start', data); }, WebSocketNamespace.REASONING); wsClient.on('thinking_block_delta', (data) => { callbacks.onThinkingDelta?.(data); callbacks.onAny?.('thinking_block_delta', data); }, WebSocketNamespace.REASONING); wsClient.on('thinking_block_stop', (data) => { callbacks.onThinkingStop?.(data); callbacks.onAny?.('thinking_block_stop', data); }, WebSocketNamespace.REASONING); wsClient.on('content_block_start', (data) => { callbacks.onContentStart?.(data); callbacks.onAny?.('content_block_start', data); }, WebSocketNamespace.REASONING); wsClient.on('content_block_delta', (data) => { callbacks.onContentDelta?.(data); callbacks.onAny?.('content_block_delta', data); }, WebSocketNamespace.REASONING); wsClient.on('content_block_stop', (data) => { callbacks.onContentStop?.(data); callbacks.onAny?.('content_block_stop', data); }, WebSocketNamespace.REASONING); wsClient.on('message_stop', (data) => { callbacks.onMessageStop?.(data); callbacks.onAny?.('message_stop', data); }, WebSocketNamespace.REASONING); wsClient.on('error', (data) => { callbacks.onError?.(data); callbacks.onAny?.('error', data); }, WebSocketNamespace.REASONING); } } /** Глобальный обработчик ошибок */ CodeSolverSDK.errorHandler = null; //# sourceMappingURL=code-solver-sdk.js.map