UNPKG

solver-sdk

Version:

SDK для интеграции с Code Solver Backend API

291 lines 13.4 kB
import { WebSocketNamespace } from '../utils/code-solver-websocket-client.js'; /** * API для работы с рассуждениями */ export class ReasoningApi { /** * Создает новый экземпляр API для работы с рассуждениями * @param {HttpClient} httpClient HTTP клиент * @param {ProjectsApi} projectsApi API для работы с проектами */ constructor(httpClient, projectsApi) { /** WebSocket клиент */ this.wsClient = null; /** Родительский SDK */ this.parentSdk = null; this.httpClient = httpClient; this.projectsApi = projectsApi; } /** * Получает список рассуждений * @param {GetReasoningsParams} [params] Параметры для получения списка * @returns {Promise<Reasoning[]>} Список рассуждений */ async getReasonings(params) { return this.httpClient.get('/api/reasonings', params); } /** * Получает рассуждение по ID * @param {string} reasoningId ID рассуждения * @returns {Promise<Reasoning>} Рассуждение */ async getReasoning(reasoningId) { return this.httpClient.get(`/api/v1/reasoning/${reasoningId}`); } /** * Создает новое рассуждение * @param {ReasoningOptions} options Опции для рассуждения * @returns {Promise<Reasoning>} Созданное рассуждение */ async createReasoning(options) { return this.httpClient.post('/api/v1/reasoning/create', options); } /** * Создает новое рассуждение с автоматическим переключением между регионами при ошибке перегрузки * @param {ReasoningOptions} options Опции для рассуждения * @returns {Promise<Reasoning>} Созданное рассуждение */ async createReasoningWithRegionFailover(options) { // Список всех доступных регионов const allRegions = ['us-east-1', 'eu-west-1', 'ap-southeast-2']; // Начинаем с региона из параметров, или первого в списке let startRegionIndex = 0; if (options.options?.region) { const regionIndex = allRegions.indexOf(options.options.region); if (regionIndex !== -1) { startRegionIndex = regionIndex; } } // Реорганизуем массив, чтобы начать с указанного региона const regions = [ ...allRegions.slice(startRegionIndex), ...allRegions.slice(0, startRegionIndex) ]; // Последняя ошибка, будет возвращена если все регионы недоступны let lastError = null; // Пробуем каждый регион по очереди for (let i = 0; i < regions.length; i++) { const region = regions[i]; try { console.log(`Попытка запроса рассуждения к Anthropic API в регионе ${region}`); // Копируем опции и устанавливаем текущий регион const regionOptions = { ...options, options: { ...(options.options || {}), region } }; // Отправляем запрос с конкретным регионом return await this.createReasoning(regionOptions); } catch (error) { lastError = error; // Проверяем, является ли ошибка ошибкой перегрузки (код 529) const isOverloadError = error.status === 529 || error.code === 529 || (error.response?.status === 529) || (error.message && error.message.includes('overloaded')) || (error.error?.type === 'overloaded_error'); if (isOverloadError) { console.warn(`Регион ${region} перегружен, пробуем следующий регион для рассуждения`); // Продолжаем цикл и пробуем следующий регион continue; } else { // Если ошибка не связана с перегрузкой, прекращаем попытки console.error(`Ошибка в регионе ${region}, не связанная с перегрузкой:`, error); throw error; } } } // Если мы здесь, значит все регионы перегружены throw lastError || new Error('Все регионы Anthropic API перегружены, попробуйте создать рассуждение позже'); } /** * Запускает рассуждение * @param {string} reasoningId ID рассуждения * @returns {Promise<Reasoning>} Обновленное рассуждение */ async startReasoning(reasoningId) { return this.httpClient.post(`/api/v1/reasoning/start/${reasoningId}`); } /** * Останавливает рассуждение * @param {string} reasoningId ID рассуждения * @returns {Promise<Reasoning>} Обновленное рассуждение */ async stopReasoning(reasoningId) { return this.httpClient.post(`/api/v1/reasoning/cancel/${reasoningId}`); } /** * Удаляет рассуждение * @param {string} reasoningId ID рассуждения * @returns {Promise<void>} */ async deleteReasoning(reasoningId) { return this.httpClient.delete(`/api/v1/reasoning/${reasoningId}`); } /** * Получает ход мыслей рассуждения * @param {string} reasoningId ID рассуждения * @returns {Promise<ThinkingStep[]>} Ход мыслей */ async getThinking(reasoningId) { return this.httpClient.get(`/api/v1/reasoning/${reasoningId}/thinking`); } /** * Получает все рассуждения проекта * @param {string} projectId ID проекта * @returns {Promise<Reasoning[]>} Список рассуждений */ async getAllReasonings(projectId) { return this.httpClient.get(`/api/v1/reasoning/project/${projectId}`); } /** * Получает список доступных моделей для рассуждений * @deprecated Используйте sdk.models.getAllModels() вместо этого метода * @returns {Promise<AllModelsResponse>} Список доступных моделей */ async getModels() { return this.httpClient.get('/api/v1/models'); } /** * Подключается к WebSocket для событий рассуждений * @returns {Promise<boolean>} Результат подключения */ async connectWebSocket() { try { if (!this.parentSdk || typeof this.parentSdk.getWebSocketClient !== 'function') { throw new Error('Родительский SDK не настроен или не поддерживает WebSocket'); } this.wsClient = this.parentSdk.getWebSocketClient(); await this.wsClient.connect(WebSocketNamespace.REASONING); return this.wsClient.isConnected(WebSocketNamespace.REASONING); } catch (error) { console.error('[ReasoningApi] Ошибка при подключении к WebSocket:', error.message); return false; } } /** * Отключается от WebSocket для событий рассуждений * @returns {Promise<void>} */ async disconnectWebSocket() { if (this.wsClient) { await this.wsClient.disconnect(WebSocketNamespace.REASONING); } } /** * Проверяет, подключен ли WebSocket * @returns {boolean} Состояние подключения */ isWebSocketConnected() { return this.wsClient ? this.wsClient.isConnected(WebSocketNamespace.REASONING) : false; } /** * Устанавливает родительский SDK * @param sdk Родительский SDK */ setParent(sdk) { this.parentSdk = sdk; } /** * Подписывается на событие через WebSocket * @param event Название события * @param callback Функция обратного вызова */ on(event, callback) { if (!this.wsClient) { console.warn('[ReasoningApi] WebSocket не подключен'); return; } this.wsClient.on(event, callback); } /** * Отправляет событие через WebSocket * @param event Название события * @param data Данные для отправки */ emitSocketEvent(event, data) { if (!this.wsClient) { console.warn('[ReasoningApi] WebSocket не подключен'); return; } this.wsClient.send(WebSocketNamespace.REASONING, event, data); } /** * Отправляет событие через WebSocket с ожиданием ответа * @param event Имя события * @param data Данные для отправки * @param timeout Таймаут ожидания ответа * @returns {Promise<any>} Ответ от сервера */ async sendSocketEventWithResponse(event, data, timeout = 5000) { if (!this.wsClient) { throw new Error('[ReasoningApi] WebSocket не подключен'); } // Реализуем собственный механизм emitWithAck, если wsClient не поддерживает его return new Promise((resolve, reject) => { try { // Создаем уникальный ID для запроса const requestId = `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`; // Имя события для ответа const responseEvent = `${event}_response`; // Обработчик для получения ответа const responseHandler = (response) => { if (response && response.requestId === requestId) { // Очищаем таймер и удаляем обработчик clearTimeout(timeoutId); if (this.wsClient) { this.wsClient.off(responseEvent, responseHandler); } // Разрешаем промис с ответом resolve(response.data || response); } }; // Устанавливаем таймаут const timeoutId = setTimeout(() => { if (this.wsClient) { this.wsClient.off(responseEvent, responseHandler); } reject(new Error(`Таймаут ожидания ответа на событие ${event}`)); }, timeout); // Регистрируем обработчик this.wsClient.on(responseEvent, responseHandler); // Отправляем событие this.wsClient.send(WebSocketNamespace.REASONING, event, { ...data, requestId }); } catch (error) { reject(error); } }); } /** * Присоединяется к конкретному рассуждению через WebSocket * @param reasoningId ID рассуждения * @returns {Promise<any>} Результат операции */ async joinReasoning(reasoningId) { if (!this.wsClient || !this.isWebSocketConnected()) { await this.connectWebSocket(); } return this.sendSocketEventWithResponse('JOIN_REASONING', { reasoningId }, 5000); } /** * Покидает конкретное рассуждение через WebSocket * @param reasoningId ID рассуждения */ leaveReasoning(reasoningId) { if (!this.wsClient || !this.isWebSocketConnected()) { console.warn('[ReasoningApi] WebSocket не подключен'); return; } this.emitSocketEvent('LEAVE_REASONING', { reasoningId }); } } //# sourceMappingURL=reasoning-api.js.map