solver-sdk 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +176 -468
  2. package/dist/cjs/api/{chat-api.js → chat-api/index.js} +77 -125
  3. package/dist/cjs/api/chat-api/index.js.map +1 -0
  4. package/dist/cjs/api/chat-api/interfaces.js +3 -0
  5. package/dist/cjs/api/chat-api/interfaces.js.map +1 -0
  6. package/dist/cjs/api/chat-api/models.js +6 -0
  7. package/dist/cjs/api/chat-api/models.js.map +1 -0
  8. package/dist/cjs/api/chat-api/stream-utils.js +192 -0
  9. package/dist/cjs/api/chat-api/stream-utils.js.map +1 -0
  10. package/dist/cjs/api/chat-api/websocket-helpers.js +211 -0
  11. package/dist/cjs/api/chat-api/websocket-helpers.js.map +1 -0
  12. package/dist/cjs/api/projects-api.js +275 -3
  13. package/dist/cjs/api/projects-api.js.map +1 -1
  14. package/dist/cjs/code-solver-sdk.js +21 -23
  15. package/dist/cjs/code-solver-sdk.js.map +1 -1
  16. package/dist/cjs/constants/websocket-events.constants.js +90 -52
  17. package/dist/cjs/constants/websocket-events.constants.js.map +1 -1
  18. package/dist/cjs/constants/websocket-namespaces.constants.js +18 -0
  19. package/dist/cjs/constants/websocket-namespaces.constants.js.map +1 -0
  20. package/dist/cjs/interfaces/websocket/callbacks.interfaces.js +3 -0
  21. package/dist/cjs/interfaces/websocket/callbacks.interfaces.js.map +1 -0
  22. package/dist/cjs/interfaces/websocket/client-options.interfaces.js +3 -0
  23. package/dist/cjs/interfaces/websocket/client-options.interfaces.js.map +1 -0
  24. package/dist/cjs/interfaces/websocket/events.interfaces.js +3 -0
  25. package/dist/cjs/interfaces/websocket/events.interfaces.js.map +1 -0
  26. package/dist/cjs/interfaces/websocket/stats.interfaces.js +3 -0
  27. package/dist/cjs/interfaces/websocket/stats.interfaces.js.map +1 -0
  28. package/dist/cjs/utils/code-solver-websocket-client.js +383 -1473
  29. package/dist/cjs/utils/code-solver-websocket-client.js.map +1 -1
  30. package/dist/cjs/utils/connection-state-manager.js +133 -0
  31. package/dist/cjs/utils/connection-state-manager.js.map +1 -0
  32. package/dist/cjs/utils/http-client.js +7 -0
  33. package/dist/cjs/utils/http-client.js.map +1 -1
  34. package/dist/cjs/utils/logger.js +106 -0
  35. package/dist/cjs/utils/logger.js.map +1 -0
  36. package/dist/cjs/utils/ping-pong-manager.js +306 -0
  37. package/dist/cjs/utils/ping-pong-manager.js.map +1 -0
  38. package/dist/cjs/utils/reasoning-auth-helper.js +58 -0
  39. package/dist/cjs/utils/reasoning-auth-helper.js.map +1 -0
  40. package/dist/cjs/utils/session-manager.js +114 -0
  41. package/dist/cjs/utils/session-manager.js.map +1 -0
  42. package/dist/cjs/utils/websocket-client.js +37 -10
  43. package/dist/cjs/utils/websocket-client.js.map +1 -1
  44. package/dist/cjs/ws/base-ws-client.js +286 -0
  45. package/dist/cjs/ws/base-ws-client.js.map +1 -0
  46. package/dist/cjs/ws/dependencies-ws-client.js +11 -0
  47. package/dist/cjs/ws/dependencies-ws-client.js.map +1 -0
  48. package/dist/cjs/ws/diagnostics-service.js +170 -0
  49. package/dist/cjs/ws/diagnostics-service.js.map +1 -0
  50. package/dist/cjs/ws/indexing-ws-client.js +223 -0
  51. package/dist/cjs/ws/indexing-ws-client.js.map +1 -0
  52. package/dist/cjs/ws/notifications-ws-client.js +12 -0
  53. package/dist/cjs/ws/notifications-ws-client.js.map +1 -0
  54. package/dist/cjs/ws/reasoning-ws-client.js +330 -0
  55. package/dist/cjs/ws/reasoning-ws-client.js.map +1 -0
  56. package/dist/esm/api/{chat-api.js → chat-api/index.js} +74 -125
  57. package/dist/esm/api/chat-api/index.js.map +1 -0
  58. package/dist/esm/api/chat-api/interfaces.js +2 -0
  59. package/dist/esm/api/chat-api/interfaces.js.map +1 -0
  60. package/dist/esm/api/chat-api/models.js +5 -0
  61. package/dist/esm/api/chat-api/models.js.map +1 -0
  62. package/dist/esm/api/chat-api/stream-utils.js +188 -0
  63. package/dist/esm/api/chat-api/stream-utils.js.map +1 -0
  64. package/dist/esm/api/chat-api/websocket-helpers.js +205 -0
  65. package/dist/esm/api/chat-api/websocket-helpers.js.map +1 -0
  66. package/dist/esm/api/projects-api.js +275 -3
  67. package/dist/esm/api/projects-api.js.map +1 -1
  68. package/dist/esm/code-solver-sdk.js +13 -15
  69. package/dist/esm/code-solver-sdk.js.map +1 -1
  70. package/dist/esm/constants/websocket-events.constants.js +89 -51
  71. package/dist/esm/constants/websocket-events.constants.js.map +1 -1
  72. package/dist/esm/constants/websocket-namespaces.constants.js +15 -0
  73. package/dist/esm/constants/websocket-namespaces.constants.js.map +1 -0
  74. package/dist/esm/interfaces/websocket/callbacks.interfaces.js +2 -0
  75. package/dist/esm/interfaces/websocket/callbacks.interfaces.js.map +1 -0
  76. package/dist/esm/interfaces/websocket/client-options.interfaces.js +2 -0
  77. package/dist/esm/interfaces/websocket/client-options.interfaces.js.map +1 -0
  78. package/dist/esm/interfaces/websocket/events.interfaces.js +2 -0
  79. package/dist/esm/interfaces/websocket/events.interfaces.js.map +1 -0
  80. package/dist/esm/interfaces/websocket/stats.interfaces.js +2 -0
  81. package/dist/esm/interfaces/websocket/stats.interfaces.js.map +1 -0
  82. package/dist/esm/utils/code-solver-websocket-client.js +382 -1473
  83. package/dist/esm/utils/code-solver-websocket-client.js.map +1 -1
  84. package/dist/esm/utils/connection-state-manager.js +129 -0
  85. package/dist/esm/utils/connection-state-manager.js.map +1 -0
  86. package/dist/esm/utils/http-client.js +7 -0
  87. package/dist/esm/utils/http-client.js.map +1 -1
  88. package/dist/esm/utils/logger.js +101 -0
  89. package/dist/esm/utils/logger.js.map +1 -0
  90. package/dist/esm/utils/ping-pong-manager.js +302 -0
  91. package/dist/esm/utils/ping-pong-manager.js.map +1 -0
  92. package/dist/esm/utils/reasoning-auth-helper.js +54 -0
  93. package/dist/esm/utils/reasoning-auth-helper.js.map +1 -0
  94. package/dist/esm/utils/session-manager.js +109 -0
  95. package/dist/esm/utils/session-manager.js.map +1 -0
  96. package/dist/esm/utils/websocket-client.js +37 -10
  97. package/dist/esm/utils/websocket-client.js.map +1 -1
  98. package/dist/esm/ws/base-ws-client.js +282 -0
  99. package/dist/esm/ws/base-ws-client.js.map +1 -0
  100. package/dist/esm/ws/dependencies-ws-client.js +7 -0
  101. package/dist/esm/ws/dependencies-ws-client.js.map +1 -0
  102. package/dist/esm/ws/diagnostics-service.js +166 -0
  103. package/dist/esm/ws/diagnostics-service.js.map +1 -0
  104. package/dist/esm/ws/indexing-ws-client.js +219 -0
  105. package/dist/esm/ws/indexing-ws-client.js.map +1 -0
  106. package/dist/esm/ws/notifications-ws-client.js +8 -0
  107. package/dist/esm/ws/notifications-ws-client.js.map +1 -0
  108. package/dist/esm/ws/reasoning-ws-client.js +326 -0
  109. package/dist/esm/ws/reasoning-ws-client.js.map +1 -0
  110. package/dist/types/api/chat-api/index.d.ts +81 -0
  111. package/dist/types/api/chat-api/index.d.ts.map +1 -0
  112. package/dist/types/api/chat-api/interfaces.d.ts +47 -0
  113. package/dist/types/api/chat-api/interfaces.d.ts.map +1 -0
  114. package/dist/types/api/{chat-api.d.ts → chat-api/models.d.ts} +10 -73
  115. package/dist/types/api/chat-api/models.d.ts.map +1 -0
  116. package/dist/types/api/chat-api/stream-utils.d.ts +31 -0
  117. package/dist/types/api/chat-api/stream-utils.d.ts.map +1 -0
  118. package/dist/types/api/chat-api/websocket-helpers.d.ts +40 -0
  119. package/dist/types/api/chat-api/websocket-helpers.d.ts.map +1 -0
  120. package/dist/types/api/projects-api.d.ts +114 -1
  121. package/dist/types/api/projects-api.d.ts.map +1 -1
  122. package/dist/types/code-solver-sdk.d.ts +3 -2
  123. package/dist/types/code-solver-sdk.d.ts.map +1 -1
  124. package/dist/types/constants/websocket-events.constants.d.ts +77 -36
  125. package/dist/types/constants/websocket-events.constants.d.ts.map +1 -1
  126. package/dist/types/constants/websocket-namespaces.constants.d.ts +14 -0
  127. package/dist/types/constants/websocket-namespaces.constants.d.ts.map +1 -0
  128. package/dist/types/interfaces/http-client.d.ts +1 -1
  129. package/dist/types/interfaces/http-client.d.ts.map +1 -1
  130. package/dist/types/interfaces/websocket/callbacks.interfaces.d.ts +30 -0
  131. package/dist/types/interfaces/websocket/callbacks.interfaces.d.ts.map +1 -0
  132. package/dist/types/interfaces/websocket/client-options.interfaces.d.ts +51 -0
  133. package/dist/types/interfaces/websocket/client-options.interfaces.d.ts.map +1 -0
  134. package/dist/types/interfaces/websocket/events.interfaces.d.ts +165 -0
  135. package/dist/types/interfaces/websocket/events.interfaces.d.ts.map +1 -0
  136. package/dist/types/interfaces/websocket/stats.interfaces.d.ts +72 -0
  137. package/dist/types/interfaces/websocket/stats.interfaces.d.ts.map +1 -0
  138. package/dist/types/types/index.d.ts +8 -0
  139. package/dist/types/types/index.d.ts.map +1 -1
  140. package/dist/types/utils/code-solver-websocket-client.d.ts +67 -612
  141. package/dist/types/utils/code-solver-websocket-client.d.ts.map +1 -1
  142. package/dist/types/utils/connection-state-manager.d.ts +94 -0
  143. package/dist/types/utils/connection-state-manager.d.ts.map +1 -0
  144. package/dist/types/utils/http-client.d.ts +5 -0
  145. package/dist/types/utils/http-client.d.ts.map +1 -1
  146. package/dist/types/utils/logger.d.ts +62 -0
  147. package/dist/types/utils/logger.d.ts.map +1 -0
  148. package/dist/types/utils/ping-pong-manager.d.ts +118 -0
  149. package/dist/types/utils/ping-pong-manager.d.ts.map +1 -0
  150. package/dist/types/utils/reasoning-auth-helper.d.ts +24 -0
  151. package/dist/types/utils/reasoning-auth-helper.d.ts.map +1 -0
  152. package/dist/types/utils/session-manager.d.ts +98 -0
  153. package/dist/types/utils/session-manager.d.ts.map +1 -0
  154. package/dist/types/utils/websocket-client.d.ts +6 -0
  155. package/dist/types/utils/websocket-client.d.ts.map +1 -1
  156. package/dist/types/ws/base-ws-client.d.ts +119 -0
  157. package/dist/types/ws/base-ws-client.d.ts.map +1 -0
  158. package/dist/types/ws/dependencies-ws-client.d.ts +6 -0
  159. package/dist/types/ws/dependencies-ws-client.d.ts.map +1 -0
  160. package/dist/types/ws/diagnostics-service.d.ts +93 -0
  161. package/dist/types/ws/diagnostics-service.d.ts.map +1 -0
  162. package/dist/types/ws/indexing-ws-client.d.ts +78 -0
  163. package/dist/types/ws/indexing-ws-client.d.ts.map +1 -0
  164. package/dist/types/ws/notifications-ws-client.d.ts +5 -0
  165. package/dist/types/ws/notifications-ws-client.d.ts.map +1 -0
  166. package/dist/types/ws/reasoning-ws-client.d.ts +87 -0
  167. package/dist/types/ws/reasoning-ws-client.d.ts.map +1 -0
  168. package/docs/API_REFERENCE.md +432 -0
  169. package/docs/AUTHENTICATION.md +83 -0
  170. package/docs/ERROR_HANDLING.md +240 -0
  171. package/docs/INTEGRATION_EXAMPLES.md +342 -0
  172. package/docs/PING_PONG.md +212 -0
  173. package/docs/README.md +102 -0
  174. package/docs/WEBSOCKET.md +139 -0
  175. package/docs/advanced/PING_PONG.md +212 -0
  176. package/docs/features/THINKING.md +158 -0
  177. package/docs/indexing/INDEXING.md +231 -0
  178. package/package.json +4 -3
  179. package/dist/cjs/api/chat-api.js.map +0 -1
  180. package/dist/esm/api/chat-api.js.map +0 -1
  181. package/dist/types/api/chat-api.d.ts.map +0 -1
@@ -1,1632 +1,542 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CodeSolverWebSocketClient = exports.WebSocketNamespace = void 0;
4
- const websocket_client_js_1 = require("./websocket-client.js");
5
- const websocket_events_constants_js_1 = require("../constants/websocket-events.constants.js");
4
+ const websocket_events_constants_1 = require("../constants/websocket-events.constants");
5
+ const websocket_namespaces_constants_js_1 = require("../constants/websocket-namespaces.constants.js");
6
+ const logger_js_1 = require("./logger.js");
7
+ const base_ws_client_js_1 = require("../ws/base-ws-client.js");
8
+ // Реэкспортируем WebSocketNamespace для других модулей
9
+ var websocket_namespaces_constants_js_2 = require("../constants/websocket-namespaces.constants.js");
10
+ Object.defineProperty(exports, "WebSocketNamespace", { enumerable: true, get: function () { return websocket_namespaces_constants_js_2.WebSocketNamespace; } });
11
+ // Дополнительные события, которые могут отсутствовать в основном перечислении
12
+ const CUSTOM_EVENTS = {
13
+ GET_REASONING_STATUS: 'get_reasoning_status'
14
+ };
6
15
  /**
7
- * Пространства имен для WebSocket
16
+ * Специализированный WebSocket клиент для пространства имен reasoning
8
17
  */
9
- var WebSocketNamespace;
10
- (function (WebSocketNamespace) {
11
- /** Основное пространство имен */
12
- WebSocketNamespace["DEFAULT"] = "/";
13
- /** Пространство для рассуждений */
14
- WebSocketNamespace["REASONING"] = "/reasoning";
15
- /** Пространство для индексации */
16
- WebSocketNamespace["INDEXING"] = "/indexing";
17
- /** Пространство для зависимостей */
18
- WebSocketNamespace["DEPENDENCIES"] = "/dependencies";
19
- })(WebSocketNamespace || (exports.WebSocketNamespace = WebSocketNamespace = {}));
20
- /**
21
- * WebSocket клиент для работы с Code Solver API
22
- */
23
- class CodeSolverWebSocketClient {
18
+ class ReasoningWsClient extends base_ws_client_js_1.BaseWebSocketClient {
24
19
  /**
25
- * Создает новый WebSocket клиент для Code Solver API
20
+ * Создает новый WebSocket клиент для рассуждений
26
21
  * @param {string} baseURL Базовый URL API
27
- * @param {CodeSolverWebSocketOptions} [options] Опции клиента
22
+ * @param {BaseWebSocketClientOptions} options Опции клиента
28
23
  */
29
24
  constructor(baseURL, options = {}) {
30
- /** Пространство имен для Socket.IO */
31
- this.namespace = '';
32
- /** WebSocket клиенты для разных пространств имен */
33
- this.clients = new Map();
25
+ super(websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING, baseURL, options);
34
26
  /** Активная сессия рассуждения */
35
27
  this.activeReasoningId = null;
36
- /** Активная сессия индексации */
37
- this.activeProjectId = null;
38
- /** Обработчики событий мышления */
39
- this.thinkingEventHandlers = new Map();
40
- /** Таймеры для ping/pong */
41
- this.pingIntervals = new Map();
42
- /** Статистика ping/pong */
43
- this.pingStats = new Map();
44
- /** Количество последовательных таймаутов */
45
- this.pingTimeouts = new Map();
46
- /** Задержка по умолчанию между ping-сообщениями (30 секунд) */
47
- this.defaultPingInterval = 30000;
48
- /** Порог таймаута (количество пропущенных pong) */
49
- this.timeoutThreshold = 3;
50
- /** Хранилище обработчиков ping/pong */
51
- this.pingPongEventHandlers = new Map();
52
- /** Токены сессий для разных пространств имен */
53
- this.sessionTokens = new Map();
54
- /** Состояние подключения для разных пространств имен */
55
- this.connectionState = new Map();
56
- /** Таймер для проверки здоровья соединений */
57
- this.healthCheckTimer = null;
58
- this.baseURL = baseURL.replace(/^http/, 'ws');
59
- this.options = {
60
- ...options,
61
- headers: {
62
- ...(options.headers || {}),
63
- ...(options.apiKey ? { 'Authorization': `Bearer ${options.apiKey}` } : {})
64
- }
65
- };
66
- // Инициализируем пространство имен
67
- this.namespace = String(WebSocketNamespace.REASONING);
68
28
  }
69
29
  /**
70
- * Логирование сообщений
71
- * @param {string} level Уровень логирования ('info', 'debug', 'error')
72
- * @param {string} message Сообщение для логирования
73
- * @param {any} [data] Дополнительные данные для логирования
30
+ * Подключается к серверу WebSocket с указанным ID рассуждения
31
+ * @param {string} reasoningId ID рассуждения
32
+ * @param {object} options Дополнительные опции
33
+ * @returns {Promise<boolean>} Успешность подключения
74
34
  */
75
- logger(level, message, data) {
76
- if (level === 'error') {
77
- console.error(`[CodeSolverWebSocket] ${message}`, data);
78
- }
79
- else if (level === 'info') {
80
- console.info(`[CodeSolverWebSocket] ${message}`, data);
81
- }
82
- else {
83
- console.debug(`[CodeSolverWebSocket] ${message}`, data);
84
- }
85
- }
86
- /**
87
- * Подключается к пространству имен WebSocket
88
- * @param {WebSocketNamespace} namespace Пространство имен
89
- * @param {Record<string, any>} [params] Параметры подключения
90
- * @returns {Promise<WebSocketClient>} WebSocket клиент
91
- */
92
- async connect(namespace, params = {}) {
93
- // Если клиент уже существует, возвращаем его
94
- if (this.clients.has(namespace)) {
95
- const client = this.clients.get(namespace);
96
- // Если клиент уже подключен, возвращаем его
97
- if (client.isConnected()) {
98
- console.debug(`[WS] Уже подключен к ${namespace}`);
99
- return client;
100
- }
101
- }
102
- // Формируем URL для подключения
103
- let baseUrl;
104
- let namespaceStr = '';
105
- // Добавляем namespace в URL путь (стандартный подход Socket.IO)
106
- if (namespace !== WebSocketNamespace.DEFAULT) {
107
- namespaceStr = String(namespace);
108
- if (!namespaceStr.startsWith('/')) {
109
- namespaceStr = '/' + namespaceStr;
110
- }
111
- }
112
- // Формируем правильный URL для Socket.IO
113
- if (this.baseURL.endsWith('/socket.io') || this.baseURL.endsWith('/socket.io/')) {
114
- // Для случая когда URL заканчивается на /socket.io, убираем слеш
115
- const cleanBaseUrl = this.baseURL.endsWith('/')
116
- ? this.baseURL.slice(0, -1)
117
- : this.baseURL;
118
- // Добавляем namespace к URL
119
- baseUrl = cleanBaseUrl + namespaceStr;
120
- }
121
- else {
122
- // Для случая когда URL не содержит /socket.io
123
- baseUrl = this.baseURL + namespaceStr;
35
+ async connectWithReasoning(reasoningId, options = {}) {
36
+ if (reasoningId) {
37
+ this.activeReasoningId = reasoningId;
124
38
  }
125
- // Создаем URL объект с параметрами
126
- const url = new URL(baseUrl);
127
- // Добавляем обязательные параметры для Socket.IO
128
- url.searchParams.append('EIO', '4');
129
- url.searchParams.append('transport', 'websocket');
130
- // Добавляем параметры к URL
131
- Object.entries(params).forEach(([key, value]) => {
132
- if (value !== undefined) {
133
- url.searchParams.append(key, String(value));
134
- }
135
- });
136
- const urlString = url.toString();
137
- console.debug(`[WS] Подключение к ${urlString}`, {
138
- namespace: String(namespace),
139
- hasApiKey: !!this.options.apiKey,
140
- apiKeyLength: this.options.apiKey ? this.options.apiKey.length : 0,
141
- params: Object.keys(params)
142
- });
143
- // Создаем новый WebSocket клиент
144
- const client = new websocket_client_js_1.WebSocketClient(urlString, {
145
- ...this.options,
146
- namespace: namespaceStr
147
- });
148
- // Добавляем обработчик для успешного подключения и отправки аутентификации
149
- client.on('open', () => {
150
- console.debug(`[WS] Подключение к ${String(namespace)} установлено`, {
151
- socketId: client.webSocket?.id,
152
- readyState: client.webSocket?.readyState
153
- });
154
- // Отправляем сообщение аутентификации, если задан API ключ
155
- if (this.options.apiKey && namespace !== WebSocketNamespace.DEFAULT) {
156
- try {
157
- const apiKeySafe = this.options.apiKey.length > 8
158
- ? `${this.options.apiKey.substring(0, 4)}...${this.options.apiKey.substring(this.options.apiKey.length - 4)}`
159
- : '[короткий ключ]';
160
- console.debug(`[WS] Отправка аутентификации для ${String(namespace)}`, {
161
- namespace: String(namespace),
162
- apiKey: apiKeySafe
163
- });
164
- // Отправляем сообщение аутентификации в формате Socket.IO
165
- const authMessage = {
166
- type: '2', // Socket.IO packet type: EVENT
167
- nsp: String(namespace),
168
- data: ['authenticate', { token: this.options.apiKey }]
169
- };
170
- client.send(authMessage);
171
- }
172
- catch (error) {
173
- console.error(`[WS] Ошибка при отправке аутентификации: ${error instanceof Error ? error.message : String(error)}`);
174
- }
175
- }
176
- });
177
- // Логирование ошибок
178
- client.on('error', (error) => {
179
- console.error(`[WS] Ошибка соединения с ${namespace}: ${error instanceof Error ? error.message : String(error)}`);
39
+ return super.connect({
40
+ reasoningId: this.activeReasoningId,
41
+ ...options
180
42
  });
181
- // Логирование разъединений
182
- client.on('close', (event) => {
183
- console.debug(`[WS] Соединение с ${namespace} закрыто: ${event.code || 'нет кода'}, ${event.reason || 'Причина не указана'}`);
184
- });
185
- // Логирование сообщений для отладки
186
- client.on('message', (data) => {
187
- try {
188
- console.debug(`[WS] Получено сообщение от ${namespace}: ${JSON.stringify(data).substring(0, 100)}...`);
189
- }
190
- catch (error) {
191
- console.debug(`[WS] Получено сообщение от ${namespace} (не может быть сериализовано в JSON)`);
192
- }
193
- });
194
- // Подключаемся к серверу
195
- await client.connect();
196
- // Сохраняем клиент
197
- this.clients.set(namespace, client);
198
- return client;
199
- }
200
- /**
201
- * Подключается к пространству имен индексации
202
- * @param projectId ID проекта (опционально)
203
- * @returns Promise с результатом подключения
204
- */
205
- async connectToIndexing(projectId) {
206
- try {
207
- this.logger('info', 'Подключение к пространству имен индексации', { projectId });
208
- // Если указан ID проекта, сохраняем его
209
- if (projectId) {
210
- this.activeProjectId = projectId;
211
- }
212
- // Подключаемся к пространству имен индексации
213
- const client = await this.connect(WebSocketNamespace.INDEXING);
214
- // Аутентифицируемся с увеличенным таймаутом
215
- try {
216
- const authResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.AUTHENTICATE, {
217
- token: this.options.apiKey,
218
- projectId: this.activeProjectId
219
- }, 10000);
220
- this.logger('debug', 'Результат аутентификации в namespace индексации', authResult);
221
- }
222
- catch (error) {
223
- this.logger('error', 'Ошибка аутентификации в namespace индексации', error);
224
- return false;
225
- }
226
- // Если у нас есть ID проекта, присоединяемся к нему
227
- if (this.activeProjectId) {
228
- try {
229
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_PROJECT, {
230
- projectId: this.activeProjectId,
231
- token: this.options.apiKey
232
- }, 10000);
233
- this.logger('debug', 'Результат присоединения к проекту', joinResult);
234
- return true;
235
- }
236
- catch (error) {
237
- this.logger('error', 'Ошибка присоединения к проекту', error);
238
- return false;
239
- }
240
- }
241
- return true;
242
- }
243
- catch (error) {
244
- this.logger('error', 'Ошибка подключения к пространству имен индексации', error);
245
- return false;
246
- }
247
43
  }
248
44
  /**
249
- * Подключается к уведомлениям
250
- * @returns {Promise<boolean>} Результат подключения
45
+ * Присоединяется к сессии рассуждения
46
+ * @param {string} reasoningId ID рассуждения
47
+ * @param {boolean} setActive Установить ли как активную сессию
48
+ * @returns {Promise<boolean>} Успешность операции
251
49
  */
252
- async connectToNotifications() {
253
- // Подключаемся к пространству имен
254
- try {
255
- await this.connect(WebSocketNamespace.DEFAULT);
256
- return true;
257
- }
258
- catch (error) {
50
+ async joinReasoning(reasoningId, setActive = true) {
51
+ if (!this.isConnected()) {
52
+ this.logger.warn(`Попытка присоединения к рассуждению ${reasoningId}, но клиент не подключен`);
259
53
  return false;
260
54
  }
261
- }
262
- /**
263
- * Подключается к пространству имен dependencies
264
- * @param projectId ID проекта (опционально)
265
- * @returns Promise с результатом подключения
266
- */
267
- async connectToDependencies(projectId) {
268
55
  try {
269
- this.logger('info', 'Подключение к пространству имен dependencies', { projectId });
270
- // Если указан ID проекта, сохраняем его
271
- if (projectId) {
272
- this.activeProjectId = projectId;
273
- }
274
- // Подключаемся к пространству имен dependencies
275
- const client = await this.connect(WebSocketNamespace.DEPENDENCIES);
276
- // Аутентифицируемся с увеличенным таймаутом
277
- try {
278
- const authResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.AUTHENTICATE, {
279
- token: this.options.apiKey,
280
- projectId: this.activeProjectId
281
- }, 10000);
282
- this.logger('debug', 'Результат аутентификации в namespace dependencies', authResult);
283
- }
284
- catch (error) {
285
- this.logger('error', 'Ошибка аутентификации в namespace dependencies', error);
286
- return false;
287
- }
288
- // Если у нас есть ID проекта, присоединяемся к нему
289
- if (this.activeProjectId) {
290
- try {
291
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_DEPENDENCIES, {
292
- projectId: this.activeProjectId,
293
- token: this.options.apiKey
294
- }, 10000);
295
- this.logger('debug', 'Результат присоединения к проекту', joinResult);
296
- return true;
297
- }
298
- catch (error) {
299
- this.logger('error', 'Ошибка присоединения к проекту', error);
300
- return false;
301
- }
56
+ // Отправляем запрос на присоединение
57
+ const result = await this.emitWithAck(websocket_events_constants_1.WebSocketEvents.JOIN_REASONING, { reasoningId });
58
+ if (result.success && setActive) {
59
+ this.activeReasoningId = reasoningId;
302
60
  }
303
- return true;
61
+ return result.success;
304
62
  }
305
63
  catch (error) {
306
- this.logger('error', 'Ошибка подключения к пространству имен dependencies', error);
64
+ this.logger.error(`Ошибка при присоединении к рассуждению ${reasoningId}`, error);
307
65
  return false;
308
66
  }
309
67
  }
310
68
  /**
311
- * Отключается от пространства имен
312
- * @param {WebSocketNamespace} namespace Пространство имен
69
+ * Подключает к сессии рассуждения и устанавливает обработчик для thinking
70
+ * @param {string} reasoningId ID рассуждения
71
+ * @param {function} thinkingHandler Обработчик событий thinking
72
+ * @returns {Promise<string>} ID рассуждения
313
73
  */
314
- disconnect(namespace) {
315
- const client = this.clients.get(namespace);
316
- if (client) {
317
- client.close();
318
- this.clients.delete(namespace);
319
- }
320
- // Сбрасываем активные сессии
321
- if (namespace === WebSocketNamespace.REASONING) {
322
- this.activeReasoningId = null;
74
+ async connectToThinkingSession(reasoningId, thinkingHandler) {
75
+ // Сначала подключаемся к сессии рассуждения
76
+ const connected = await this.connectWithReasoning(reasoningId, { autoJoin: true });
77
+ if (!connected) {
78
+ throw new Error(`Не удалось подключиться к рассуждению ${reasoningId}`);
323
79
  }
324
- else if (namespace === WebSocketNamespace.INDEXING) {
325
- this.activeProjectId = null;
80
+ // Затем подписываемся на мышление, если указан обработчик
81
+ if (thinkingHandler) {
82
+ this.subscribeToThinking(thinkingHandler);
326
83
  }
84
+ return reasoningId;
327
85
  }
328
86
  /**
329
- * Отключается от всех пространств имен
330
- * Отключает автоматический механизм ping/pong
87
+ * Подписаться на события мышления
88
+ * @param callback Функция обратного вызова для обработки событий мышления
331
89
  */
332
- disconnectAll() {
333
- // Отключаем ping/pong для всех соединений
334
- this.disablePingPong();
335
- // Отключаемся от всех namespace
336
- for (const [namespace, client] of this.clients.entries()) {
337
- if (client) {
338
- client.close();
339
- this.clients.delete(namespace);
340
- }
341
- }
342
- // Сбрасываем активные сессии
343
- this.activeReasoningId = null;
344
- this.activeProjectId = null;
90
+ subscribeToThinking(callback) {
91
+ this.on(websocket_events_constants_1.ReasoningEventNames.THINKING, callback);
345
92
  }
346
93
  /**
347
- * Добавляет обработчик события для пространства имен
348
- * @param {string} eventType Тип события
349
- * @param {Function} handler Обработчик события
350
- * @param {WebSocketNamespace} [namespace] Пространство имен (если не указано, добавляется ко всем активным)
94
+ * Отписаться от событий мышления
95
+ * @param callback Функция обратного вызова для обработки событий мышления
351
96
  */
352
- on(eventType, handler, namespace) {
353
- if (namespace) {
354
- // Если указано пространство имен, добавляем обработчик только к нему
355
- const client = this.clients.get(namespace);
356
- if (!client) {
357
- throw new Error(`Не подключен к пространству имен ${namespace}`);
358
- }
359
- client.on(eventType, handler);
360
- }
361
- else {
362
- // Если пространство имен не указано, добавляем обработчик ко всем активным пространствам
363
- for (const client of this.clients.values()) {
364
- client.on(eventType, handler);
365
- }
366
- }
97
+ unsubscribeFromThinking(callback) {
98
+ this.off(websocket_events_constants_1.ReasoningEventNames.THINKING, callback);
367
99
  }
368
100
  /**
369
- * Удаляет обработчик события для пространства имен
370
- * @param {string} eventType Тип события
371
- * @param {Function} [handler] Обработчик события (если не указан, удаляются все обработчики)
372
- * @param {WebSocketNamespace} [namespace] Пространство имен (если не указано, удаляется из всех активных)
101
+ * Проверяет статус рассуждения
102
+ * @param {string} reasoningId ID рассуждения
103
+ * @returns {Promise<object>} Объект с информацией о статусе
373
104
  */
374
- off(eventType, handler, namespace) {
375
- if (namespace) {
376
- // Если указано пространство имен, удаляем обработчик только из него
377
- const client = this.clients.get(namespace);
378
- if (!client) {
379
- return;
380
- }
381
- client.off(eventType, handler);
105
+ async getReasoningStatus(reasoningId) {
106
+ const id = reasoningId || this.activeReasoningId;
107
+ if (!id) {
108
+ return { exists: false, isActive: false };
382
109
  }
383
- else {
384
- // Если пространство имен не указано, удаляем обработчик из всех активных пространств
385
- for (const client of this.clients.values()) {
386
- client.off(eventType, handler);
110
+ try {
111
+ if (!this.isConnected()) {
112
+ await this.connect();
387
113
  }
114
+ const result = await this.emitWithAck(CUSTOM_EVENTS.GET_REASONING_STATUS, { reasoningId: id });
115
+ return result;
388
116
  }
389
- }
390
- /**
391
- * Отправляет сообщение в пространство имен
392
- * @param {WebSocketNamespace} namespace Пространство имен
393
- * @param {string} eventType Тип события
394
- * @param {any} [data] Данные сообщения
395
- * @returns {boolean} Успешно ли отправлено сообщение
396
- */
397
- send(namespace, eventType, data) {
398
- const client = this.clients.get(namespace);
399
- if (!client) {
400
- throw new Error(`Не подключен к пространству имен ${namespace}`);
401
- }
402
- return client.send({
403
- event: eventType,
404
- data
405
- });
406
- }
407
- /**
408
- * Отправляет сообщение в активную сессию рассуждения
409
- * @param {string} eventType Тип события
410
- * @param {any} [data] Данные сообщения
411
- * @returns {boolean} Успешно ли отправлено сообщение
412
- */
413
- sendToReasoning(eventType, data) {
414
- if (!this.activeReasoningId) {
415
- throw new Error('Не подключен к сессии рассуждения');
117
+ catch (error) {
118
+ this.logger.error(`Ошибка при получении статуса рассуждения ${id}`, error);
119
+ return { exists: false, isActive: false };
416
120
  }
417
- return this.send(WebSocketNamespace.REASONING, eventType, data);
418
121
  }
419
122
  /**
420
- * Отправляет сообщение в активную сессию индексации
421
- * @param {string} eventType Тип события
422
- * @param {any} [data] Данные сообщения
423
- * @returns {boolean} Успешно ли отправлено сообщение
123
+ * Проверяет существование рассуждения
124
+ * @param {string} reasoningId ID рассуждения
125
+ * @returns {Promise<boolean>} true, если рассуждение существует
424
126
  */
425
- sendToIndexing(eventType, data) {
426
- if (!this.activeProjectId) {
427
- throw new Error('Не подключен к сессии индексации');
127
+ async checkReasoningExists(reasoningId) {
128
+ try {
129
+ const { exists } = await this.getReasoningStatus(reasoningId);
130
+ return exists;
428
131
  }
429
- return this.send(WebSocketNamespace.INDEXING, eventType, data);
430
- }
431
- /**
432
- * Отправляет сообщение в уведомления
433
- * @param {string} eventType Тип события
434
- * @param {any} [data] Данные сообщения
435
- * @returns {boolean} Успешно ли отправлено сообщение
436
- */
437
- sendToNotifications(eventType, data) {
438
- return this.send(WebSocketNamespace.DEFAULT, eventType, data);
439
- }
440
- /**
441
- * Проверяет, подключен ли клиент к указанному пространству имен
442
- * @param {WebSocketNamespace} namespace Пространство имен
443
- * @returns {boolean} Статус подключения
444
- */
445
- isConnected(namespace) {
446
- const client = this.clients.get(namespace);
447
- return client ? client.isConnected() : false;
448
- }
449
- /**
450
- * Проверяет, подключен ли клиент к пространству имен рассуждений
451
- * @returns {boolean} Статус подключения
452
- */
453
- isConnectedToReasoning() {
454
- return this.isConnected(WebSocketNamespace.REASONING);
455
- }
456
- /**
457
- * Проверяет, подключен ли клиент к пространству имен индексации
458
- * @returns {boolean} Статус подключения
459
- */
460
- isConnectedToIndexing() {
461
- return this.isConnected(WebSocketNamespace.INDEXING);
462
- }
463
- /**
464
- * Проверяет, подключен ли клиент к пространству имен уведомлений
465
- * @returns {boolean} Статус подключения
466
- */
467
- isConnectedToNotifications() {
468
- return this.isConnected(WebSocketNamespace.DEFAULT);
469
- }
470
- /**
471
- * Получает ID сокета для указанного пространства имен
472
- * @param {WebSocketNamespace} [namespace=WebSocketNamespace.REASONING] Пространство имен
473
- * @returns {string|null} ID сокета или null, если соединение не установлено
474
- */
475
- getSocketId(namespace = WebSocketNamespace.REASONING) {
476
- const client = this.clients.get(namespace);
477
- if (!client || !client.isConnected()) {
478
- console.warn(`[WsClientWrapper] getSocketId: Нет активных соединений с Socket.IO сервером для ${namespace}`);
479
- return null;
132
+ catch (error) {
133
+ return false;
480
134
  }
481
- return client.getSocketId();
482
135
  }
483
136
  /**
484
- * Подписывается на события мышления
485
- * @param {string} reasoningId Идентификатор рассуждения
486
- * @param {Function} handler Обработчик событий мышления
487
- * @returns {void}
137
+ * Получает ID активной сессии рассуждения
138
+ * @returns {string | null} ID активной сессии или null
488
139
  */
489
- subscribeToThinking(reasoningId, handler) {
490
- // Сохраняем обработчик
491
- this.thinkingEventHandlers.set(reasoningId, handler);
492
- // Получаем клиент рассуждений
493
- const client = this.clients.get(WebSocketNamespace.REASONING);
494
- if (!client) {
495
- throw new Error('Не подключен к пространству имен рассуждения');
496
- }
497
- // Подписываемся на события мышления
498
- client.on(`thinking:${reasoningId}`, (data) => {
499
- handler(data);
500
- });
501
- // Дублируем подписку для полной совместимости
502
- client.on(`reasoning:thinking:${reasoningId}`, (data) => {
503
- handler(data);
504
- });
140
+ getActiveReasoningId() {
141
+ return this.activeReasoningId;
505
142
  }
143
+ }
144
+ /**
145
+ * Специализированный WebSocket клиент для пространства имен indexing
146
+ */
147
+ class IndexingWsClient extends base_ws_client_js_1.BaseWebSocketClient {
506
148
  /**
507
- * Отписывается от событий мышления
508
- * @param {string} reasoningId Идентификатор рассуждения
509
- * @returns {void}
149
+ * Создает новый WebSocket клиент для индексации
150
+ * @param {string} baseURL Базовый URL API
151
+ * @param {BaseWebSocketClientOptions} options Опции клиента
510
152
  */
511
- unsubscribeFromThinking(reasoningId) {
512
- // Удаляем обработчик
513
- this.thinkingEventHandlers.delete(reasoningId);
514
- // Получаем клиент рассуждений
515
- const client = this.clients.get(WebSocketNamespace.REASONING);
516
- if (!client)
517
- return;
518
- // Отписываемся от событий
519
- client.off(`thinking:${reasoningId}`);
520
- client.off(`reasoning:thinking:${reasoningId}`);
153
+ constructor(baseURL, options = {}) {
154
+ super(websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING, baseURL, options);
155
+ /** Активный проект */
156
+ this.activeProjectId = null;
521
157
  }
522
158
  /**
523
- * Подключается к сессии рассуждения с thinking
524
- * @param {string} [reasoningId="system"] Идентификатор рассуждения
525
- * @param {Function} [thinkingHandler] Обработчик событий мышления
526
- * @returns {Promise<string>} Идентификатор сессии рассуждения
159
+ * Подключается к серверу WebSocket с указанным ID проекта
160
+ * @param {string} projectId ID проекта
161
+ * @returns {Promise<boolean>} Успешность подключения
527
162
  */
528
- async connectToThinkingSession(reasoningId = "system", thinkingHandler) {
529
- try {
530
- // Подключаемся к пространству имен
531
- await this.connect(WebSocketNamespace.REASONING);
532
- // Получаем клиент
533
- const client = this.clients.get(WebSocketNamespace.REASONING);
534
- if (!client) {
535
- throw new Error(`Не удалось получить WebSocket клиент для ${WebSocketNamespace.REASONING}`);
536
- }
537
- // Если reasoningId == "system", сервер заменит его на новый
538
- // с префиксом "system-". Для получения нового ID нужно подписаться
539
- // на событие создания рассуждения.
540
- if (reasoningId === "system") {
541
- // Будем ждать ответа о создании рассуждения
542
- return new Promise((resolve, reject) => {
543
- // Устанавливаем таймаут
544
- const timeout = setTimeout(() => {
545
- reject(new Error('Таймаут ожидания ответа о создании рассуждения'));
546
- }, 10000);
547
- // Подписываемся на событие создания рассуждения
548
- client.once(`${websocket_events_constants_js_1.WebSocketEvents.CREATE_REASONING}_response`, (data) => {
549
- clearTimeout(timeout);
550
- if (data.error) {
551
- reject(new Error(`Ошибка создания рассуждения: ${data.error}`));
552
- return;
553
- }
554
- const newReasoningId = data.reasoningId;
555
- this.activeReasoningId = newReasoningId;
556
- // Отправляем запрос на присоединение к сессии рассуждения
557
- client.sendSocketIOEvent(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, { reasoningId: newReasoningId }, (joinResponse) => {
558
- if (joinResponse.success === false) {
559
- reject(new Error(`Ошибка при присоединении к сессии рассуждения: ${joinResponse.error || 'Неизвестная ошибка'}`));
560
- return;
561
- }
562
- // Отправляем запрос на запуск рассуждения
563
- client.sendSocketIOEvent(websocket_events_constants_js_1.WebSocketEvents.START_REASONING, { reasoningId: newReasoningId }, (startResponse) => {
564
- if (startResponse.success === false) {
565
- reject(new Error(`Ошибка при запуске рассуждения: ${startResponse.error || 'Неизвестная ошибка'}`));
566
- return;
567
- }
568
- // Если передан обработчик событий мышления, подписываемся
569
- if (thinkingHandler) {
570
- this.subscribeToThinking(newReasoningId, thinkingHandler);
571
- }
572
- resolve(newReasoningId);
573
- }, this.namespace);
574
- }, this.namespace);
575
- });
576
- });
577
- }
578
- else {
579
- this.activeReasoningId = reasoningId;
580
- // Отправляем запрос на присоединение к сессии рассуждения
581
- return new Promise((resolve, reject) => {
582
- client.sendSocketIOEvent(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, { reasoningId }, (joinResponse) => {
583
- if (joinResponse.success === false) {
584
- reject(new Error(`Ошибка при присоединении к сессии рассуждения: ${joinResponse.error || 'Неизвестная ошибка'}`));
585
- return;
586
- }
587
- // Отправляем запрос на запуск рассуждения
588
- client.sendSocketIOEvent(websocket_events_constants_js_1.WebSocketEvents.START_REASONING, { reasoningId }, (startResponse) => {
589
- if (startResponse.success === false) {
590
- reject(new Error(`Ошибка при запуске рассуждения: ${startResponse.error || 'Неизвестная ошибка'}`));
591
- return;
592
- }
593
- // Если передан обработчик событий мышления, подписываемся
594
- if (thinkingHandler) {
595
- this.subscribeToThinking(reasoningId, thinkingHandler);
596
- }
597
- resolve(reasoningId);
598
- }, this.namespace);
599
- }, this.namespace);
600
- });
601
- }
602
- }
603
- catch (error) {
604
- throw new Error(`Ошибка при подключении к сессии thinking: ${error instanceof Error ? error.message : String(error)}`);
163
+ async connectWithProject(projectId) {
164
+ if (projectId) {
165
+ this.activeProjectId = projectId;
605
166
  }
606
- }
607
- /**
608
- * Настраивает отладочное логирование для WebSocket клиента
609
- * @param namespace Пространство имен
610
- */
611
- setupDebugLogging(namespace) {
612
- const client = this.clients.get(namespace);
613
- if (!client)
614
- return;
615
- // Добавляем детальное логирование всех событий
616
- client.on('socket.io_event', (data) => {
617
- this.logger('debug', `[WS:${namespace}] Получено Socket.IO событие: ${data.event}`, data.data);
618
- });
619
- // Добавляем обработчик для всех событий (onAny)
620
- client.on('message', (data) => {
621
- if (typeof data === 'string') {
622
- try {
623
- this.logger('debug', `[WS:${namespace}] Получено сырое сообщение`, data);
624
- }
625
- catch (e) {
626
- this.logger('error', `[WS:${namespace}] Ошибка при обработке сырого сообщения`, data);
627
- }
628
- }
629
- });
630
- // Отслеживаем состояние соединения
631
- client.on('connect', () => {
632
- this.logger('info', `[WS:${namespace}] Соединение установлено`);
633
- });
634
- client.on('close', (data) => {
635
- this.logger('info', `[WS:${namespace}] Соединение закрыто: ${data.code}, Причина: ${data.reason}`);
636
- });
637
- client.on('error', (error) => {
638
- this.logger('error', `[WS:${namespace}] Ошибка соединения`, error);
639
- });
640
- // Отслеживаем ping/pong для проверки состояния соединения
641
- client.on('ping', () => this.logger('debug', `[WS:${namespace}] Отправлен ping`));
642
- client.on('pong', () => this.logger('debug', `[WS:${namespace}] Получен pong`));
643
- // Добавляем обработчик для отслеживания ответов на события
644
- client.on('socket.io_raw', (data) => {
645
- this.logger('debug', `[WS:${namespace}] Socket.IO raw пакет`, { type: data.type, data: data.data });
167
+ return super.connect({
168
+ projectId: this.activeProjectId
646
169
  });
647
170
  }
648
171
  /**
649
- * Проверяет наличие callback-функции в данных и правильно вызывает ее
650
- * @param eventName Имя события
651
- * @param data Данные события
652
- * @private
172
+ * Получает ID активного проекта
173
+ * @returns {string | null} ID активного проекта или null
653
174
  */
654
- extractAndCallCallback(eventName, data) {
655
- if (data && typeof data === 'object' && typeof data.callback === 'function') {
656
- try {
657
- // Копируем данные без callback
658
- const dataCopy = { ...data };
659
- delete dataCopy.callback;
660
- // Получаем callback-функцию
661
- const callback = data.callback;
662
- // Вызываем callback
663
- this.logger('debug', `Вызов callback для события ${eventName}`);
664
- // Создаем таймаут для предотвращения зависания
665
- const timeoutId = setTimeout(() => {
666
- this.logger('warn', `Таймаут выполнения callback для события ${eventName}`);
667
- }, 5000);
668
- // Вызываем callback и очищаем таймаут
669
- callback();
670
- clearTimeout(timeoutId);
671
- }
672
- catch (error) {
673
- this.logger('error', `Ошибка при вызове callback для события ${eventName}: ${error instanceof Error ? error.message : String(error)}`);
674
- }
675
- }
175
+ getActiveProjectId() {
176
+ return this.activeProjectId;
676
177
  }
178
+ }
179
+ /**
180
+ * Специализированный WebSocket клиент для пространства имен dependencies
181
+ */
182
+ class DependenciesWsClient extends base_ws_client_js_1.BaseWebSocketClient {
677
183
  /**
678
- * Включить автоматическую отправку ping-сообщений и сбор статистики
679
- * @param {number} interval - Интервал между ping-сообщениями в миллисекундах
680
- * @param {number} timeoutThreshold - Количество пропущенных pong-сообщений, после которого соединение считается потерянным
681
- * @returns {boolean} - Успешность включения ping/pong
184
+ * Создает новый WebSocket клиент для зависимостей
185
+ * @param {string} baseURL Базовый URL API
186
+ * @param {BaseWebSocketClientOptions} options Опции клиента
682
187
  */
683
- enablePingPong(interval = this.defaultPingInterval, timeoutThreshold = 3) {
684
- // Сохраняем порог таймаута
685
- this.timeoutThreshold = timeoutThreshold;
686
- // Для каждого активного соединения
687
- for (const [namespace, client] of this.clients.entries()) {
688
- try {
689
- // Проверяем, активно ли соединение
690
- if (!client || !this.isConnected(namespace)) {
691
- this.logger('warn', `Невозможно включить ping/pong для неактивного соединения в ${namespace}`);
692
- continue;
693
- }
694
- // Останавливаем существующий таймер, если есть
695
- this.disablePingPong(namespace);
696
- // Инициализируем статистику, если не была создана
697
- if (!this.pingStats.has(namespace)) {
698
- this.pingStats.set(namespace, {
699
- namespace,
700
- socketId: client.getSocketId(),
701
- pingSent: 0,
702
- pongReceived: 0,
703
- averageRtt: 0,
704
- minRtt: Number.MAX_SAFE_INTEGER,
705
- maxRtt: 0,
706
- lastRtt: 0,
707
- lastPongTimestamp: Date.now(),
708
- isConnected: true
709
- });
710
- }
711
- // Сбрасываем счетчик таймаутов
712
- this.pingTimeouts.set(namespace, 0);
713
- // Устанавливаем обработчик для события connection_pong
714
- client.on(websocket_events_constants_js_1.WebSocketEvents.CONNECTION_PONG, (data) => {
715
- // Обновляем статистику
716
- const stats = this.pingStats.get(namespace);
717
- if (stats) {
718
- stats.pongReceived++;
719
- stats.lastPongTimestamp = Date.now();
720
- stats.isConnected = true;
721
- // Рассчитываем RTT, если есть метка времени эхо
722
- if (data && data.echo) {
723
- const rtt = Date.now() - data.echo;
724
- stats.lastRtt = rtt;
725
- // Обновляем min и max
726
- stats.minRtt = Math.min(stats.minRtt, rtt);
727
- stats.maxRtt = Math.max(stats.maxRtt, rtt);
728
- // Обновляем среднее значение
729
- stats.averageRtt = (stats.averageRtt * (stats.pongReceived - 1) + rtt) / stats.pongReceived;
730
- }
731
- // Сбрасываем счетчик таймаутов
732
- this.pingTimeouts.set(namespace, 0);
733
- }
734
- // Логируем получение pong
735
- this.logger('debug', `Получен pong для ${namespace}`, {
736
- rtt: stats?.lastRtt,
737
- socketId: client.getSocketId()
738
- });
739
- });
740
- // Устанавливаем интервал отправки ping
741
- const pingInterval = setInterval(() => {
742
- if (this.isConnected(namespace)) {
743
- // Формируем данные ping
744
- const pingData = { timestamp: Date.now() };
745
- // Отправляем ping
746
- const sent = this.send(namespace, websocket_events_constants_js_1.WebSocketEvents.CONNECTION_PING, pingData);
747
- // Если успешно отправлено, обновляем статистику
748
- if (sent) {
749
- const stats = this.pingStats.get(namespace);
750
- if (stats) {
751
- stats.pingSent++;
752
- }
753
- this.logger('debug', `Отправлен ping для ${namespace}`, pingData);
754
- }
755
- else {
756
- this.logger('warn', `Не удалось отправить ping для ${namespace}`);
757
- }
758
- // Проверяем таймаут
759
- const timeouts = this.pingTimeouts.get(namespace) || 0;
760
- const stats = this.pingStats.get(namespace);
761
- // Если разница между отправленными и полученными превышает порог,
762
- // или последний pong был получен слишком давно
763
- if ((stats && stats.pingSent - stats.pongReceived > this.timeoutThreshold) ||
764
- (stats && Date.now() - stats.lastPongTimestamp > interval * this.timeoutThreshold)) {
765
- // Увеличиваем счетчик таймаутов
766
- this.pingTimeouts.set(namespace, timeouts + 1);
767
- if (timeouts + 1 >= this.timeoutThreshold) {
768
- // Соединение потеряно
769
- this.logger('error', `Соединение потеряно (таймаут ping/pong) для ${namespace}`);
770
- // Установка флага неактивного соединения
771
- if (stats) {
772
- stats.isConnected = false;
773
- }
774
- // На прямую отправку события через socket
775
- this.send(namespace, 'connection_timeout', {
776
- namespace,
777
- socketId: client.getSocketId(),
778
- timeouts: timeouts + 1,
779
- threshold: this.timeoutThreshold
780
- });
781
- // Также вызываем обработчики событий
782
- const timeoutHandlers = this.pingPongEventHandlers.get('connection_timeout') || [];
783
- timeoutHandlers.forEach(handler => {
784
- try {
785
- handler({
786
- namespace,
787
- socketId: client.getSocketId(),
788
- timeouts: timeouts + 1,
789
- threshold: this.timeoutThreshold
790
- });
791
- }
792
- catch (error) {
793
- this.logger('error', `Ошибка при обработке события connection_timeout`, error);
794
- }
795
- });
796
- }
797
- }
798
- }
799
- }, interval);
800
- // Сохраняем интервал
801
- this.pingIntervals.set(namespace, pingInterval);
802
- this.logger('info', `Включен механизм ping/pong для ${namespace} с интервалом ${interval}ms`);
803
- }
804
- catch (error) {
805
- this.logger('error', `Ошибка при включении ping/pong для ${namespace}`, error);
806
- return false;
807
- }
808
- }
809
- return true;
188
+ constructor(baseURL, options = {}) {
189
+ super(websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES, baseURL, options);
810
190
  }
811
191
  /**
812
- * Отключить автоматическую отправку ping-сообщений
813
- * @param {WebSocketNamespace} [namespace] - Пространство имен для отключения (если не указано - отключается везде)
192
+ * Подключается к серверу WebSocket с указанным ID проекта
193
+ * @param {string} projectId ID проекта
194
+ * @returns {Promise<boolean>} Успешность подключения
814
195
  */
815
- disablePingPong(namespace) {
816
- if (namespace) {
817
- // Отключаем для указанного namespace
818
- const interval = this.pingIntervals.get(namespace);
819
- if (interval) {
820
- clearInterval(interval);
821
- this.pingIntervals.delete(namespace);
822
- this.logger('info', `Отключен механизм ping/pong для ${namespace}`);
823
- }
824
- }
825
- else {
826
- // Отключаем для всех namespace
827
- for (const [ns, interval] of this.pingIntervals.entries()) {
828
- clearInterval(interval);
829
- this.pingIntervals.delete(ns);
830
- this.logger('info', `Отключен механизм ping/pong для ${ns}`);
831
- }
832
- }
196
+ async connectWithProject(projectId) {
197
+ return super.connect({ projectId });
833
198
  }
199
+ }
200
+ /**
201
+ * Специализированный WebSocket клиент для пространства имен notifications
202
+ */
203
+ class NotificationsWsClient extends base_ws_client_js_1.BaseWebSocketClient {
834
204
  /**
835
- * Получить статистику ping/pong
836
- * @param {WebSocketNamespace} [namespace] - Пространство имен для получения статистики
837
- * @returns {PingPongStats | PingPongStats[] | null} - Статистика ping/pong
205
+ * Создает новый WebSocket клиент для уведомлений
206
+ * @param {string} baseURL Базовый URL API
207
+ * @param {BaseWebSocketClientOptions} options Опции клиента
838
208
  */
839
- getPingStats(namespace) {
840
- if (namespace) {
841
- // Возвращаем статистику для указанного namespace
842
- return this.pingStats.get(namespace) || null;
843
- }
844
- else {
845
- // Возвращаем статистику для всех namespace
846
- return Array.from(this.pingStats.values());
847
- }
209
+ constructor(baseURL, options = {}) {
210
+ super(websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT, baseURL, options);
848
211
  }
212
+ }
213
+ /**
214
+ * Сервис для диагностики WebSocket соединений
215
+ */
216
+ class DiagnosticsService {
849
217
  /**
850
- * Добавляет обработчик для событий ping/pong
851
- * @param {string} eventType - Тип события (connection_timeout)
852
- * @param {(data: any) => void} handler - Обработчик события
218
+ * Создает новый сервис диагностики
219
+ * @param {DiagnosticsServiceOptions} options Опции сервиса
853
220
  */
854
- onPingPongEvent(eventType, handler) {
855
- if (!this.pingPongEventHandlers.has(eventType)) {
856
- this.pingPongEventHandlers.set(eventType, []);
857
- }
858
- const handlers = this.pingPongEventHandlers.get(eventType);
859
- if (handlers) {
860
- handlers.push(handler);
861
- }
221
+ constructor(options) {
222
+ this.clients = options.clients;
223
+ this.logger = options.logger;
862
224
  }
863
225
  /**
864
- * Удаляет обработчик для событий ping/pong
865
- * @param {string} eventType - Тип события
866
- * @param {(data: any) => void} [handler] - Обработчик события (если не указан, удаляются все обработчики)
226
+ * Получает диагностическую информацию о всех соединениях
227
+ * @returns {object} Диагностическая информация
867
228
  */
868
- offPingPongEvent(eventType, handler) {
869
- if (!handler) {
870
- // Если обработчик не указан, удаляем все обработчики для этого типа события
871
- this.pingPongEventHandlers.delete(eventType);
872
- }
873
- else {
874
- // Если обработчик указан, удаляем только его
875
- const handlers = this.pingPongEventHandlers.get(eventType);
876
- if (handlers) {
877
- const index = handlers.findIndex(h => h === handler);
878
- if (index !== -1) {
879
- handlers.splice(index, 1);
880
- }
881
- }
229
+ getDiagnostics() {
230
+ const result = {};
231
+ // Собираем информацию о каждом соединении
232
+ for (const [namespace, client] of Object.entries(this.clients)) {
233
+ result[namespace] = {
234
+ isConnected: client.isConnected(),
235
+ socketId: client.getSocketId()
236
+ // При необходимости можно добавить дополнительную информацию
237
+ };
882
238
  }
239
+ return result;
883
240
  }
241
+ }
242
+ /**
243
+ * WebSocket клиент для работы с Code Solver API (фасад)
244
+ */
245
+ class CodeSolverWebSocketClient {
884
246
  /**
885
- * Возвращает функцию-обработчик для pong-ответов, которая рассчитывает RTT
886
- * @returns {(data: any) => void} Функция-обработчик
247
+ * Создает новый WebSocket клиент для Code Solver API
248
+ * @param {string} baseURL Базовый URL API
249
+ * @param {CodeSolverWebSocketOptions} [options] Опции клиента
887
250
  */
888
- getPongHandler() {
889
- return (data) => {
890
- if (data && data.echo) {
891
- const rtt = Date.now() - data.echo;
892
- console.log(`[PONG] RTT: ${rtt}ms, namespace: ${data.namespace || 'unknown'}`);
893
- return rtt;
251
+ constructor(baseURL, options = {}) {
252
+ this.baseURL = baseURL.replace(/^http/, 'ws');
253
+ this.options = {
254
+ ...options,
255
+ headers: {
256
+ ...(options.headers || {}),
257
+ ...(options.apiKey ? { 'Authorization': `Bearer ${options.apiKey}` } : {})
894
258
  }
895
- return -1;
896
259
  };
260
+ // Создаем логгер
261
+ this.logger = (0, logger_js_1.createWebSocketLogger)('CodeSolverWebSocket');
262
+ // Трансформируем опции для специализированных клиентов
263
+ const clientOptions = {
264
+ ...this.options,
265
+ enableAutoPing: options.enableAutoPing !== false,
266
+ enableSessionPersistence: options.enableSessionPersistence !== false,
267
+ // Преобразуем функцию логгера в экземпляр Logger, если передана функция
268
+ logger: typeof options.logger === 'function' ?
269
+ (0, logger_js_1.createWebSocketLogger)('CodeSolverWebSocket', options.logger) :
270
+ options.logger
271
+ };
272
+ // Создаем специализированные клиенты
273
+ this.reasoningClient = new ReasoningWsClient(this.baseURL, { ...clientOptions, logger: this.logger.withPrefix('Reasoning') });
274
+ this.indexingClient = new IndexingWsClient(this.baseURL, { ...clientOptions, logger: this.logger.withPrefix('Indexing') });
275
+ this.dependenciesClient = new DependenciesWsClient(this.baseURL, { ...clientOptions, logger: this.logger.withPrefix('Dependencies') });
276
+ this.notificationsClient = new NotificationsWsClient(this.baseURL, { ...clientOptions, logger: this.logger.withPrefix('Notifications') });
277
+ // Создаем сервис диагностики
278
+ this.diagnosticsService = new DiagnosticsService({
279
+ clients: {
280
+ [websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING]: this.reasoningClient,
281
+ [websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING]: this.indexingClient,
282
+ [websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES]: this.dependenciesClient,
283
+ [websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT]: this.notificationsClient
284
+ },
285
+ logger: this.logger.withPrefix('Diagnostics')
286
+ });
897
287
  }
898
288
  /**
899
- * Выполняет диагностику соединения и возвращает подробный отчет
900
- * @param {WebSocketNamespace} namespace Пространство имен
901
- * @returns {ConnectionDiagnostics} Объект с диагностической информацией
289
+ * Подключается к пространству имен рассуждений
290
+ * @param {string} reasoningId ID рассуждения (опционально)
291
+ * @param {object} options Дополнительные настройки подключения
292
+ * @returns {Promise<boolean>} Результат подключения
902
293
  */
903
- diagnoseConnection(namespace) {
904
- const client = this.clients.get(namespace);
905
- const stats = this.pingStats.get(namespace);
906
- const connectionState = this.getConnectionState(namespace);
907
- const sessionToken = this.getSessionToken(namespace);
908
- return {
909
- namespace,
910
- isConnected: client?.isConnected() || false,
911
- socketId: client?.getSocketId() || null,
912
- lastActivity: stats?.lastPongTimestamp || 0,
913
- rtt: {
914
- current: stats?.lastRtt || -1,
915
- min: stats?.minRtt === Number.MAX_SAFE_INTEGER ? -1 : (stats?.minRtt || -1),
916
- max: stats?.maxRtt || -1,
917
- avg: stats?.averageRtt || -1
918
- },
919
- pingSent: stats?.pingSent || 0,
920
- pongReceived: stats?.pongReceived || 0,
921
- missedPongs: (stats?.pingSent || 0) - (stats?.pongReceived || 0),
922
- timeoutCount: this.pingTimeouts.get(namespace) || 0,
923
- reconnectAttempts: connectionState.reconnectAttempts,
924
- lastConnectTime: connectionState.lastConnectTime,
925
- sessionRecovery: {
926
- hasSessionToken: !!sessionToken,
927
- tokenLength: sessionToken?.length || 0,
928
- wasRecovered: !!sessionToken && (stats?.pongReceived || 0) > 0
929
- }
930
- };
294
+ async connectToReasoning(reasoningId, options = {}) {
295
+ return this.reasoningClient.connectWithReasoning(reasoningId, options);
931
296
  }
932
297
  /**
933
- * Выполняет диагностику всех активных соединений
934
- * @returns {Record<string, ConnectionDiagnostics>} Объект с диагностической информацией по всем соединениям
298
+ * Подключается к пространству имен индексации
299
+ * @param {string} projectId ID проекта (опционально)
300
+ * @returns {Promise<boolean>} Результат подключения
935
301
  */
936
- diagnoseAllConnections() {
937
- const result = {};
938
- // Проверяем каждое возможное пространство имен
939
- for (const namespace of Object.values(WebSocketNamespace)) {
940
- if (this.clients.has(namespace)) {
941
- result[String(namespace)] = this.diagnoseConnection(namespace);
942
- }
943
- }
944
- return result;
302
+ async connectToIndexing(projectId) {
303
+ return this.indexingClient.connectWithProject(projectId);
945
304
  }
946
305
  /**
947
- * Рассчитывает задержку для переподключения на основе количества попыток и стратегии
948
- * @param {WebSocketNamespace} namespace Пространство имен
949
- * @returns {number} Задержка в миллисекундах
306
+ * Подключается к уведомлениям
307
+ * @returns {Promise<boolean>} Результат подключения
950
308
  */
951
- calculateReconnectDelay(namespace) {
952
- const state = this.getConnectionState(namespace);
953
- const attempts = state.reconnectAttempts;
954
- const strategy = this.options.reconnectStrategy || 'exponential';
955
- const baseDelay = this.options.retryDelay || 1000;
956
- const maxDelay = this.options.maxRetryDelay || 30000;
957
- if (strategy === 'exponential') {
958
- // Экспоненциальный рост с фактором 1.5
959
- const calculatedDelay = Math.min(baseDelay * Math.pow(1.5, attempts), maxDelay);
960
- // Добавляем случайный фактор (jitter) для предотвращения штормов переподключений
961
- return calculatedDelay * (0.8 + Math.random() * 0.4);
962
- }
963
- else {
964
- // Линейный рост
965
- return Math.min(baseDelay * (attempts + 1), maxDelay);
966
- }
309
+ async connectToNotifications() {
310
+ return this.notificationsClient.connect({});
967
311
  }
968
312
  /**
969
- * Принудительно переподключает соединение для указанного пространства имен
970
- * @param {WebSocketNamespace} namespace Пространство имен
971
- * @param {boolean} immediate Выполнить переподключение немедленно, без задержки
972
- * @returns {Promise<boolean>} Успешность операции
313
+ * Подключается к пространству имен dependencies
314
+ * @param {string} projectId ID проекта (опционально)
315
+ * @returns {Promise<boolean>} Результат подключения
973
316
  */
974
- async reconnectNamespace(namespace, immediate = false) {
975
- const client = this.clients.get(namespace);
976
- try {
977
- // Если клиент уже существует, закрываем его
978
- if (client) {
979
- this.logger('info', `Принудительное переподключение для ${namespace}`);
980
- try {
981
- // Отключаем ping/pong для этого namespace
982
- this.disablePingPong(namespace);
983
- // Закрываем соединение
984
- client.close();
985
- }
986
- catch (e) {
987
- this.logger('warn', `Ошибка при закрытии соединения с ${namespace}: ${e instanceof Error ? e.message : String(e)}`);
988
- }
989
- // Удаляем клиент из кэша
990
- this.clients.delete(namespace);
991
- }
992
- else {
993
- this.logger('info', `Инициируем новое подключение для ${namespace}`);
994
- }
995
- // Устанавливаем состояние переподключения
996
- this.setConnectionState(namespace, false, true);
997
- // Инкрементируем счетчик попыток
998
- this.incrementReconnectAttempts(namespace);
999
- // Рассчитываем задержку, если не требуется немедленное переподключение
1000
- if (!immediate) {
1001
- const delay = this.calculateReconnectDelay(namespace);
1002
- this.logger('info', `Переподключение для ${namespace} через ${delay}ms (попытка ${this.getConnectionState(namespace).reconnectAttempts})`);
1003
- // Ждем рассчитанное время
1004
- await new Promise(resolve => setTimeout(resolve, delay));
1005
- }
1006
- // Выполняем подключение с соответствующими параметрами
1007
- let params = {};
1008
- // Проверяем тип пространства имен и добавляем соответствующие параметры
1009
- if (namespace === WebSocketNamespace.REASONING && this.activeReasoningId) {
1010
- params.reasoningId = this.activeReasoningId;
1011
- }
1012
- else if ((namespace === WebSocketNamespace.INDEXING || namespace === WebSocketNamespace.DEPENDENCIES) && this.activeProjectId) {
1013
- params.projectId = this.activeProjectId;
1014
- }
1015
- // Подключаемся
1016
- await this.connect(namespace, params);
1017
- // Если это пространство имен рассуждений и есть активное рассуждение,
1018
- // пытаемся присоединиться к нему
1019
- if (namespace === WebSocketNamespace.REASONING && this.activeReasoningId) {
1020
- await this.connectToReasoning(this.activeReasoningId);
1021
- }
1022
- else if (namespace === WebSocketNamespace.INDEXING && this.activeProjectId) {
1023
- await this.connectToIndexing(this.activeProjectId);
1024
- }
1025
- else if (namespace === WebSocketNamespace.DEPENDENCIES && this.activeProjectId) {
1026
- await this.connectToDependencies(this.activeProjectId);
1027
- }
1028
- return true;
1029
- }
1030
- catch (error) {
1031
- this.logger('error', `Ошибка при переподключении к ${namespace}: ${error instanceof Error ? error.message : String(error)}`);
1032
- return false;
1033
- }
317
+ async connectToDependencies(projectId) {
318
+ return this.dependenciesClient.connectWithProject(projectId);
1034
319
  }
1035
320
  /**
1036
- * Настраивает периодическую проверку здоровья соединения
1037
- * @param {number} [interval=30000] Интервал проверки в миллисекундах
321
+ * Отключается от пространства имен
322
+ * @param {WebSocketNamespace} namespace Пространство имен
1038
323
  */
1039
- setupConnectionHealthCheck(interval = 30000) {
1040
- // Останавливаем существующую проверку, если она есть
1041
- if (this.healthCheckTimer) {
1042
- clearInterval(this.healthCheckTimer);
324
+ disconnect(namespace) {
325
+ switch (namespace) {
326
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
327
+ this.reasoningClient.disconnect();
328
+ break;
329
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
330
+ this.indexingClient.disconnect();
331
+ break;
332
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
333
+ this.dependenciesClient.disconnect();
334
+ break;
335
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
336
+ this.notificationsClient.disconnect();
337
+ break;
1043
338
  }
1044
- this.healthCheckTimer = setInterval(() => {
1045
- for (const namespace of Object.values(WebSocketNamespace)) {
1046
- const typedNamespace = namespace;
1047
- const client = this.clients.get(typedNamespace);
1048
- if (!client)
1049
- continue;
1050
- // Проверяем соединение через WebSocket клиент
1051
- if (!client.isConnected()) {
1052
- this.logger('warn', `Соединение с ${namespace} не активно, инициируем переподключение`);
1053
- this.reconnectNamespace(typedNamespace, false).catch(() => { });
1054
- continue;
1055
- }
1056
- // Проверяем статистику ping/pong
1057
- const stats = this.pingStats.get(typedNamespace);
1058
- if (stats) {
1059
- const now = Date.now();
1060
- // Если последний pong был получен слишком давно
1061
- if (now - stats.lastPongTimestamp > interval * 2) {
1062
- this.logger('warn', `Долгое отсутствие активности для ${namespace}, проверка соединения...`);
1063
- // Отправляем проверочный ping
1064
- this.send(typedNamespace, 'connection_health_check', { timestamp: now, echo: now });
1065
- // Устанавливаем таймаут для проверки ответа
1066
- setTimeout(() => {
1067
- const currentStats = this.pingStats.get(typedNamespace);
1068
- if (currentStats && now - currentStats.lastPongTimestamp > interval * 2) {
1069
- this.logger('error', `Соединение не отвечает для ${namespace}, инициируем переподключение`);
1070
- this.reconnectNamespace(typedNamespace, false).catch(() => { });
1071
- }
1072
- }, 5000); // Ждем 5 секунд на ответ
1073
- }
1074
- }
1075
- }
1076
- }, interval);
1077
- this.logger('info', 'Настроена периодическая проверка здоровья соединения с интервалом ' + interval + 'ms');
1078
339
  }
1079
340
  /**
1080
- * Сохраняет токен сессии для пространства имен
1081
- * @param {WebSocketNamespace} namespace Пространство имен
1082
- * @param {string} token Токен сессии
341
+ * Отключается от всех пространств имен
1083
342
  */
1084
- saveSessionToken(namespace, token) {
1085
- if (this.options.enableSessionPersistence !== false) {
1086
- this.sessionTokens.set(namespace, token);
1087
- this.logger('info', `Сохранен токен сессии для ${namespace}`, { tokenLength: token.length });
1088
- }
343
+ disconnectAll() {
344
+ this.reasoningClient.disconnect();
345
+ this.indexingClient.disconnect();
346
+ this.dependenciesClient.disconnect();
347
+ this.notificationsClient.disconnect();
1089
348
  }
1090
349
  /**
1091
- * Получает сохраненный токен сессии для пространства имен
350
+ * Проверяет, подключен ли клиент к указанному пространству имен
1092
351
  * @param {WebSocketNamespace} namespace Пространство имен
1093
- * @returns {string | null} Токен сессии или null, если не найден
352
+ * @returns {boolean} Статус подключения
1094
353
  */
1095
- getSessionToken(namespace) {
1096
- if (this.options.enableSessionPersistence === false) {
1097
- return null;
354
+ isConnected(namespace) {
355
+ switch (namespace) {
356
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
357
+ return this.reasoningClient.isConnected();
358
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
359
+ return this.indexingClient.isConnected();
360
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
361
+ return this.dependenciesClient.isConnected();
362
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
363
+ return this.notificationsClient.isConnected();
364
+ default:
365
+ return false;
1098
366
  }
1099
- return this.sessionTokens.get(namespace) || null;
1100
367
  }
1101
368
  /**
1102
- * Удаляет сохраненный токен сессии для пространства имен
1103
- * @param {WebSocketNamespace} namespace Пространство имен
369
+ * Проверяет, подключен ли клиент к пространству имен рассуждений
370
+ * @returns {boolean} Статус подключения
1104
371
  */
1105
- clearSessionToken(namespace) {
1106
- this.sessionTokens.delete(namespace);
1107
- this.logger('info', `Удален токен сессии для ${namespace}`);
372
+ isConnectedToReasoning() {
373
+ return this.reasoningClient.isConnected();
1108
374
  }
1109
375
  /**
1110
- * Устанавливает состояние подключения для пространства имен
1111
- * @param {WebSocketNamespace} namespace Пространство имен
1112
- * @param {boolean} connected Состояние подключения
1113
- * @param {boolean} reconnecting Состояние переподключения
376
+ * Проверяет, подключен ли клиент к пространству имен индексации
377
+ * @returns {boolean} Статус подключения
1114
378
  */
1115
- setConnectionState(namespace, connected, reconnecting = false) {
1116
- const state = this.getConnectionState(namespace);
1117
- state.connected = connected;
1118
- state.reconnecting = reconnecting;
1119
- if (connected) {
1120
- state.lastConnectTime = Date.now();
1121
- state.reconnectAttempts = 0;
1122
- }
1123
- this.connectionState.set(namespace, state);
379
+ isConnectedToIndexing() {
380
+ return this.indexingClient.isConnected();
1124
381
  }
1125
382
  /**
1126
- * Увеличивает счетчик попыток переподключения для пространства имен
1127
- * @param {WebSocketNamespace} namespace Пространство имен
1128
- * @returns {number} Новое количество попыток
383
+ * Проверяет, подключен ли клиент к пространству имен уведомлений
384
+ * @returns {boolean} Статус подключения
1129
385
  */
1130
- incrementReconnectAttempts(namespace) {
1131
- const state = this.getConnectionState(namespace);
1132
- state.reconnectAttempts++;
1133
- state.reconnecting = true;
1134
- this.connectionState.set(namespace, state);
1135
- return state.reconnectAttempts;
386
+ isConnectedToNotifications() {
387
+ return this.notificationsClient.isConnected();
1136
388
  }
1137
389
  /**
1138
- * Получает состояние подключения для пространства имен
1139
- * @param {WebSocketNamespace} namespace Пространство имен
1140
- * @returns {object} Состояние подключения
390
+ * Получает ID активной сессии рассуждения
391
+ * @returns {string | null} ID активной сессии рассуждения или null
1141
392
  */
1142
- getConnectionState(namespace) {
1143
- return this.connectionState.get(namespace) || {
1144
- lastConnectTime: 0,
1145
- reconnectAttempts: 0,
1146
- connected: false,
1147
- reconnecting: false
1148
- };
393
+ getActiveReasoningId() {
394
+ return this.reasoningClient.getActiveReasoningId();
1149
395
  }
1150
396
  /**
1151
- * Устанавливает ID активной сессии рассуждения
1152
- * @param {string} reasoningId ID сессии рассуждения
1153
- * @returns {boolean} Успешность установки
397
+ * Получает ID активного проекта
398
+ * @returns {string | null} ID активного проекта или null
1154
399
  */
1155
- setActiveReasoningId(reasoningId) {
1156
- if (!reasoningId) {
1157
- this.logger('error', 'Попытка установить пустой reasoningId');
1158
- return false;
1159
- }
1160
- this.activeReasoningId = reasoningId;
1161
- this.logger('info', `Установлен активный reasoningId: ${reasoningId}`);
1162
- // Если мы уже подключены к пространству имен рассуждений, проверяем, нужно ли присоединиться
1163
- const client = this.clients.get(WebSocketNamespace.REASONING);
1164
- if (client && client.isConnected()) {
1165
- // Пробуем присоединиться к рассуждению асинхронно, но не ждем результата
1166
- this.logger('debug', `Автоматическое присоединение к рассуждению: ${reasoningId}`);
1167
- client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1168
- reasoningId,
1169
- token: this.options.apiKey
1170
- }, 10000).catch(err => {
1171
- this.logger('warn', `Не удалось автоматически присоединиться к рассуждению: ${err.message}`);
1172
- });
1173
- }
1174
- return true;
400
+ getActiveProjectId() {
401
+ return this.indexingClient.getActiveProjectId();
1175
402
  }
1176
403
  /**
1177
- * Устанавливает ID активного проекта
1178
- * @param {string} projectId ID проекта
1179
- * @returns {boolean} Успешность установки
404
+ * Отправляет сообщение в пространство имен
405
+ * @param {WebSocketNamespace} namespace Пространство имен
406
+ * @param {string} eventType Тип события
407
+ * @param {any} [data] Данные сообщения
408
+ * @returns {boolean} Успешно ли отправлено сообщение
1180
409
  */
1181
- setActiveProjectId(projectId) {
1182
- if (!projectId) {
1183
- this.logger('error', 'Попытка установить пустой projectId');
1184
- return false;
410
+ send(namespace, eventType, data) {
411
+ switch (namespace) {
412
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
413
+ return this.reasoningClient.send(eventType, data);
414
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
415
+ return this.indexingClient.send(eventType, data);
416
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
417
+ return this.dependenciesClient.send(eventType, data);
418
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
419
+ return this.notificationsClient.send(eventType, data);
420
+ default:
421
+ throw new Error(`Неизвестное пространство имен ${namespace}`);
1185
422
  }
1186
- this.activeProjectId = projectId;
1187
- this.logger('info', `Установлен активный projectId: ${projectId}`);
1188
- return true;
1189
423
  }
1190
424
  /**
1191
- * Устанавливает ID активной сессии рассуждения с расширенными возможностями
1192
- * @param {string} reasoningId ID сессии рассуждения
1193
- * @param {boolean} waitForJoin Дождаться результата присоединения
1194
- * @param {boolean} createIfNotExists Создать новое рассуждение, если ID не существует
1195
- * @returns {Promise<boolean>} Результат операции
425
+ * Отправляет сообщение в активную сессию рассуждения
426
+ * @param {string} eventType Тип события
427
+ * @param {any} [data] Данные сообщения
428
+ * @returns {boolean} Успешно ли отправлено сообщение
1196
429
  */
1197
- async setActiveReasoningIdAsync(reasoningId, waitForJoin = false, createIfNotExists = false) {
1198
- if (!reasoningId && !createIfNotExists) {
1199
- this.logger('error', 'Попытка установить пустой reasoningId');
1200
- return false;
1201
- }
1202
- // Если указан createIfNotExists и нет reasoningId, создаем новое рассуждение
1203
- if (createIfNotExists && !reasoningId) {
1204
- try {
1205
- reasoningId = await this.createNewReasoning();
1206
- this.logger('info', `Создано новое рассуждение с ID: ${reasoningId}`);
1207
- }
1208
- catch (error) {
1209
- this.logger('error', 'Не удалось создать новое рассуждение', error);
1210
- return false;
1211
- }
1212
- }
1213
- // Отключаемся от предыдущего рассуждения, если оно отличается
1214
- if (this.activeReasoningId && this.activeReasoningId !== reasoningId) {
1215
- this.logger('debug', `Отписываемся от предыдущего рассуждения: ${this.activeReasoningId}`);
1216
- this.unsubscribeFromThinking(this.activeReasoningId);
1217
- }
1218
- this.activeReasoningId = reasoningId;
1219
- this.logger('info', `Установлен активный reasoningId: ${reasoningId}`);
1220
- // Если соединение уже установлено, присоединяемся к рассуждению
1221
- const client = this.clients.get(WebSocketNamespace.REASONING);
1222
- if (client && client.isConnected()) {
1223
- try {
1224
- if (waitForJoin) {
1225
- this.logger('debug', `Ожидание присоединения к рассуждению: ${reasoningId}`);
1226
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1227
- reasoningId,
1228
- token: this.options.apiKey
1229
- }, 10000);
1230
- if (joinResult.success === true) {
1231
- this.logger('info', `Успешно присоединились к рассуждению: ${reasoningId}`);
1232
- return true;
1233
- }
1234
- else {
1235
- this.logger('warn', `Не удалось присоединиться к рассуждению: ${reasoningId}`, joinResult.error);
1236
- return false;
1237
- }
1238
- }
1239
- else {
1240
- // Асинхронное присоединение
1241
- this.logger('debug', `Асинхронное присоединение к рассуждению: ${reasoningId}`);
1242
- client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1243
- reasoningId,
1244
- token: this.options.apiKey
1245
- }, 10000).then(result => {
1246
- if (result.success === true) {
1247
- this.logger('info', `Успешно присоединились к рассуждению: ${reasoningId}`);
1248
- }
1249
- else {
1250
- this.logger('warn', `Не удалось присоединиться к рассуждению: ${reasoningId}`, result.error);
1251
- }
1252
- }).catch(err => {
1253
- this.logger('warn', `Ошибка при присоединении к рассуждению: ${reasoningId}`, err);
1254
- });
1255
- }
1256
- }
1257
- catch (error) {
1258
- this.logger('error', `Ошибка при присоединении к рассуждению: ${reasoningId}`, error);
1259
- if (waitForJoin)
1260
- return false;
1261
- }
1262
- }
1263
- else if (waitForJoin) {
1264
- // Если ждем присоединения, но соединение отсутствует
1265
- this.logger('warn', `Нет активного соединения с сервером для присоединения к рассуждению: ${reasoningId}`);
1266
- return false;
1267
- }
1268
- return true;
430
+ sendToReasoning(eventType, data) {
431
+ return this.reasoningClient.send(eventType, data);
1269
432
  }
1270
433
  /**
1271
- * Создает новое рассуждение на сервере
1272
- * @private
1273
- * @returns {Promise<string>} ID нового рассуждения
434
+ * Отправляет сообщение в активную сессию индексации
435
+ * @param {string} eventType Тип события
436
+ * @param {any} [data] Данные сообщения
437
+ * @returns {boolean} Успешно ли отправлено сообщение
1274
438
  */
1275
- async createNewReasoning() {
1276
- // Подключаемся, если еще не подключены
1277
- if (!this.isConnectedToReasoning()) {
1278
- this.logger('debug', 'Подключение к пространству имен рассуждений для создания нового рассуждения');
1279
- const connected = await this.connectToReasoning();
1280
- if (!connected) {
1281
- throw new Error('Не удалось подключиться к пространству имен рассуждений');
1282
- }
1283
- }
1284
- const client = this.clients.get(WebSocketNamespace.REASONING);
1285
- if (!client) {
1286
- throw new Error('Не удалось получить клиент для пространства имен рассуждений');
1287
- }
1288
- this.logger('debug', 'Отправка запроса на создание нового рассуждения');
1289
- const result = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.CREATE_REASONING, {
1290
- token: this.options.apiKey
1291
- }, 10000);
1292
- if (!result.reasoningId) {
1293
- throw new Error(`Сервер не вернул ID рассуждения: ${JSON.stringify(result)}`);
1294
- }
1295
- return result.reasoningId;
439
+ sendToIndexing(eventType, data) {
440
+ return this.indexingClient.send(eventType, data);
1296
441
  }
1297
442
  /**
1298
- * Проверяет существование рассуждения на сервере
1299
- * @param {string} reasoningId ID рассуждения для проверки
1300
- * @returns {Promise<boolean>} Существует ли рассуждение
443
+ * Отправляет сообщение в уведомления
444
+ * @param {string} eventType Тип события
445
+ * @param {any} [data] Данные сообщения
446
+ * @returns {boolean} Успешно ли отправлено сообщение
1301
447
  */
1302
- async checkReasoningExists(reasoningId) {
1303
- if (!reasoningId) {
1304
- return false;
1305
- }
1306
- // Подключаемся, если еще не подключены
1307
- if (!this.isConnectedToReasoning()) {
1308
- const connected = await this.connectToReasoning();
1309
- if (!connected) {
1310
- this.logger('warn', 'Не удалось подключиться к пространству имен рассуждений для проверки существования');
1311
- return false;
1312
- }
1313
- }
1314
- const client = this.clients.get(WebSocketNamespace.REASONING);
1315
- if (!client) {
1316
- this.logger('warn', 'Не удалось получить клиент для пространства имен рассуждений');
1317
- return false;
1318
- }
1319
- try {
1320
- this.logger('debug', `Проверка существования рассуждения: ${reasoningId}`);
1321
- // Используем более правильный подход для проверки существования сессии
1322
- // Пытаемся присоединиться, и если успешно - значит сессия существует
1323
- const result = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1324
- reasoningId,
1325
- token: this.options.apiKey
1326
- }, 10000);
1327
- return result.success === true;
1328
- }
1329
- catch (error) {
1330
- this.logger('warn', `Ошибка при проверке существования рассуждения: ${reasoningId}`, error);
1331
- return false;
1332
- }
448
+ sendToNotifications(eventType, data) {
449
+ return this.notificationsClient.send(eventType, data);
1333
450
  }
1334
451
  /**
1335
- * Подключается к пространству имен рассуждений
1336
- * @param reasoningId ID рассуждения (опционально)
1337
- * @param options Дополнительные настройки подключения
1338
- * @returns Promise с результатом подключения
452
+ * Добавляет обработчик события для пространства имен
453
+ * @param {string} eventType Тип события
454
+ * @param {Function} handler Обработчик события
455
+ * @param {WebSocketNamespace} [namespace] Пространство имен (если не указано, добавляется ко всем активным)
1339
456
  */
1340
- async connectToReasoning(reasoningId, options = {}) {
1341
- try {
1342
- // Значения опций по умолчанию
1343
- const { autoJoin = true, createIfNotExists = false, checkExistence = false, saveSession = this.options.enableSessionPersistence !== false } = options;
1344
- this.logger('info', 'Подключение к пространству имен рассуждений', {
1345
- reasoningId,
1346
- options: { autoJoin, createIfNotExists, checkExistence, saveSession }
1347
- });
1348
- // Если указан ID рассуждения, обрабатываем его
1349
- if (reasoningId) {
1350
- // Если нужно проверить существование
1351
- if (checkExistence) {
1352
- const client = this.clients.get(WebSocketNamespace.REASONING);
1353
- // Если уже подключены, проверяем существование
1354
- if (client && client.isConnected()) {
1355
- const exists = await this.checkReasoningExists(reasoningId);
1356
- if (!exists) {
1357
- if (createIfNotExists) {
1358
- this.logger('info', `Рассуждение ${reasoningId} не существует, создаем новое`);
1359
- reasoningId = await this.createNewReasoning();
1360
- }
1361
- else {
1362
- this.logger('warn', `Рассуждение ${reasoningId} не существует`);
1363
- return false;
1364
- }
1365
- }
1366
- }
1367
- }
1368
- // Устанавливаем ID активного рассуждения
1369
- this.activeReasoningId = reasoningId;
1370
- }
1371
- else if (createIfNotExists) {
1372
- // Если нет ID, но нужно создать, создаем новое рассуждение
1373
- this.logger('info', 'Создание нового рассуждения');
1374
- try {
1375
- // Сначала подключаемся к пространству имен
1376
- const client = await this.connect(WebSocketNamespace.REASONING);
1377
- // Затем создаем новое рассуждение
1378
- const newReasoningId = await this.createNewReasoning();
1379
- this.activeReasoningId = newReasoningId;
1380
- this.logger('info', `Создано новое рассуждение: ${newReasoningId}`);
1381
- }
1382
- catch (error) {
1383
- this.logger('error', 'Ошибка при создании нового рассуждения', error);
1384
- return false;
1385
- }
1386
- }
1387
- // Подключаемся к пространству имен рассуждений
1388
- const client = await this.connect(WebSocketNamespace.REASONING);
1389
- // Аутентифицируемся с увеличенным таймаутом
1390
- try {
1391
- const authResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.AUTHENTICATE, {
1392
- token: this.options.apiKey,
1393
- reasoningId: this.activeReasoningId
1394
- }, 10000);
1395
- this.logger('debug', 'Результат аутентификации в namespace рассуждений', authResult);
1396
- // Если сервер вернул токен сессии и нужно его сохранить
1397
- if (saveSession && authResult.sessionToken) {
1398
- this.saveSessionToken(WebSocketNamespace.REASONING, authResult.sessionToken);
1399
- }
1400
- }
1401
- catch (error) {
1402
- this.logger('error', 'Ошибка аутентификации в namespace рассуждений', error);
1403
- return false;
1404
- }
1405
- // Если у нас есть ID рассуждения и включено автоматическое присоединение
1406
- if (this.activeReasoningId && autoJoin) {
1407
- try {
1408
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1409
- reasoningId: this.activeReasoningId,
1410
- token: this.options.apiKey
1411
- }, 10000);
1412
- this.logger('debug', 'Результат присоединения к рассуждению', joinResult);
1413
- if (joinResult.success !== true) {
1414
- this.logger('warn', `Не удалось присоединиться к рассуждению: ${this.activeReasoningId}`, joinResult.error);
1415
- return false;
1416
- }
1417
- }
1418
- catch (error) {
1419
- this.logger('error', 'Ошибка присоединения к рассуждению', error);
1420
- return false;
1421
- }
1422
- }
1423
- // Включаем автоматический ping/pong, если настроено
1424
- if (this.options.enableAutoPing !== false) {
1425
- this.enablePingPong(this.options.pingInterval, this.options.pingTimeoutThreshold);
457
+ on(eventType, handler, namespace) {
458
+ if (namespace) {
459
+ // Если указано пространство имен, добавляем обработчик только к нему
460
+ switch (namespace) {
461
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
462
+ this.reasoningClient.on(eventType, handler);
463
+ break;
464
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
465
+ this.indexingClient.on(eventType, handler);
466
+ break;
467
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
468
+ this.dependenciesClient.on(eventType, handler);
469
+ break;
470
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
471
+ this.notificationsClient.on(eventType, handler);
472
+ break;
1426
473
  }
1427
- return true;
1428
474
  }
1429
- catch (error) {
1430
- this.logger('error', 'Ошибка подключения к пространству имен рассуждений', error);
1431
- return false;
475
+ else {
476
+ // Если пространство имен не указано, добавляем обработчик ко всем активным
477
+ this.reasoningClient.on(eventType, handler);
478
+ this.indexingClient.on(eventType, handler);
479
+ this.dependenciesClient.on(eventType, handler);
480
+ this.notificationsClient.on(eventType, handler);
1432
481
  }
1433
482
  }
1434
483
  /**
1435
- * Получает текущий статус сессии рассуждения
1436
- * @param {string} reasoningId ID сессии рассуждения (опционально, по умолчанию активная)
1437
- * @returns {Promise<{exists: boolean, isActive: boolean, metadata?: any}>} Статус сессии
484
+ * Удаляет обработчик события для пространства имен
485
+ * @param {string} eventType Тип события
486
+ * @param {Function} [handler] Обработчик события (если не указан, удаляются все обработчики)
487
+ * @param {WebSocketNamespace} [namespace] Пространство имен (если не указано, удаляется из всех активных)
1438
488
  */
1439
- async getReasoningStatus(reasoningId) {
1440
- const targetId = reasoningId || this.activeReasoningId;
1441
- if (!targetId) {
1442
- return { exists: false, isActive: false };
1443
- }
1444
- if (!this.isConnectedToReasoning()) {
1445
- const connected = await this.connectToReasoning(undefined, { autoJoin: false });
1446
- if (!connected) {
1447
- this.logger('warn', 'Не удалось подключиться к пространству имен рассуждений');
1448
- return { exists: false, isActive: false };
1449
- }
1450
- }
1451
- const client = this.clients.get(WebSocketNamespace.REASONING);
1452
- if (!client) {
1453
- return { exists: false, isActive: false };
1454
- }
1455
- try {
1456
- // Используем событие GET_REASONING_STATUS для получения статуса
1457
- // Если сервер не поддерживает это событие, используем более простую проверку
1458
- try {
1459
- const status = await client.emitWithAck('get_reasoning_status', {
1460
- reasoningId: targetId,
1461
- token: this.options.apiKey
1462
- }, 10000);
1463
- return {
1464
- exists: status.exists === true,
1465
- isActive: status.isActive === true,
1466
- metadata: status.metadata || {}
1467
- };
1468
- }
1469
- catch (e) {
1470
- // Если произошла ошибка (скорее всего, сервер не поддерживает этот метод),
1471
- // используем проверку через JOIN_REASONING
1472
- const result = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1473
- reasoningId: targetId,
1474
- token: this.options.apiKey
1475
- }, 10000);
1476
- return {
1477
- exists: result.success === true,
1478
- isActive: result.success === true,
1479
- metadata: result.data
1480
- };
489
+ off(eventType, handler, namespace) {
490
+ if (namespace) {
491
+ // Если указано пространство имен, удаляем обработчик только из него
492
+ switch (namespace) {
493
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
494
+ this.reasoningClient.off(eventType, handler);
495
+ break;
496
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
497
+ this.indexingClient.off(eventType, handler);
498
+ break;
499
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
500
+ this.dependenciesClient.off(eventType, handler);
501
+ break;
502
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
503
+ this.notificationsClient.off(eventType, handler);
504
+ break;
1481
505
  }
1482
506
  }
1483
- catch (error) {
1484
- this.logger('warn', `Ошибка при получении статуса рассуждения: ${targetId}`, error);
1485
- return { exists: false, isActive: false };
507
+ else {
508
+ // Если пространство имен не указано, удаляем обработчик из всех активных
509
+ this.reasoningClient.off(eventType, handler);
510
+ this.indexingClient.off(eventType, handler);
511
+ this.dependenciesClient.off(eventType, handler);
512
+ this.notificationsClient.off(eventType, handler);
1486
513
  }
1487
514
  }
1488
515
  /**
1489
- * Присоединяется к сессии рассуждения
1490
- * @param {string} reasoningId ID сессии рассуждения
1491
- * @param {boolean} setActive Установить как активное рассуждение
1492
- * @returns {Promise<boolean>} Результат операции
516
+ * Получает ID сокета для указанного пространства имен
517
+ * @param {WebSocketNamespace} [namespace=WebSocketNamespace.REASONING] Пространство имен
518
+ * @returns {string|null} ID сокета или null, если соединение не установлено
1493
519
  */
1494
- async joinReasoning(reasoningId, setActive = true) {
1495
- if (!reasoningId) {
1496
- this.logger('error', 'Попытка присоединиться к пустому reasoningId');
1497
- return false;
1498
- }
1499
- // Если нужно установить как активное, делаем это
1500
- if (setActive) {
1501
- this.activeReasoningId = reasoningId;
1502
- }
1503
- // Если не подключены, подключаемся сначала
1504
- if (!this.isConnectedToReasoning()) {
1505
- const connected = await this.connectToReasoning(reasoningId);
1506
- if (!connected) {
1507
- this.logger('warn', `Не удалось подключиться к пространству имен рассуждений для ${reasoningId}`);
1508
- return false;
1509
- }
1510
- return true; // connectToReasoning уже выполнил join
1511
- }
1512
- // Если уже подключены, отправляем join запрос
1513
- const client = this.clients.get(WebSocketNamespace.REASONING);
1514
- if (!client) {
1515
- this.logger('warn', 'Не удалось получить клиент для пространства имен рассуждений');
1516
- return false;
1517
- }
1518
- try {
1519
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1520
- reasoningId,
1521
- token: this.options.apiKey
1522
- }, 10000);
1523
- this.logger('debug', `Результат присоединения к рассуждению ${reasoningId}`, joinResult);
1524
- return joinResult.success === true;
1525
- }
1526
- catch (error) {
1527
- this.logger('error', `Ошибка при присоединении к рассуждению ${reasoningId}`, error);
1528
- return false;
520
+ getSocketId(namespace = websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING) {
521
+ switch (namespace) {
522
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.REASONING:
523
+ return this.reasoningClient.getSocketId();
524
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.INDEXING:
525
+ return this.indexingClient.getSocketId();
526
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEPENDENCIES:
527
+ return this.dependenciesClient.getSocketId();
528
+ case websocket_namespaces_constants_js_1.WebSocketNamespace.DEFAULT:
529
+ return this.notificationsClient.getSocketId();
530
+ default:
531
+ return null;
1529
532
  }
1530
533
  }
1531
534
  /**
1532
- * Подключается к пространству имен рассуждений с расширенными опциями
1533
- * @param reasoningId ID рассуждения (опционально)
1534
- * @param options Дополнительные настройки подключения
1535
- * @returns Promise с результатом подключения
535
+ * Получает диагностическую информацию о соединениях
536
+ * @returns {object} Диагностическая информация
1536
537
  */
1537
- async connectToReasoningEx(reasoningId, options = {}) {
1538
- try {
1539
- // Значения опций по умолчанию
1540
- const { autoJoin = true, createIfNotExists = false, checkExistence = false, saveSession = this.options.enableSessionPersistence !== false } = options;
1541
- this.logger('info', 'Подключение к пространству имен рассуждений', {
1542
- reasoningId,
1543
- options: { autoJoin, createIfNotExists, checkExistence, saveSession }
1544
- });
1545
- // Если указан ID рассуждения, обрабатываем его
1546
- if (reasoningId) {
1547
- // Если нужно проверить существование
1548
- if (checkExistence) {
1549
- const client = this.clients.get(WebSocketNamespace.REASONING);
1550
- // Если уже подключены, проверяем существование
1551
- if (client && client.isConnected()) {
1552
- const exists = await this.checkReasoningExists(reasoningId);
1553
- if (!exists) {
1554
- if (createIfNotExists) {
1555
- this.logger('info', `Рассуждение ${reasoningId} не существует, создаем новое`);
1556
- reasoningId = await this.createNewReasoning();
1557
- }
1558
- else {
1559
- this.logger('warn', `Рассуждение ${reasoningId} не существует`);
1560
- return false;
1561
- }
1562
- }
1563
- }
1564
- }
1565
- // Устанавливаем ID активного рассуждения
1566
- this.activeReasoningId = reasoningId;
1567
- }
1568
- else if (createIfNotExists) {
1569
- // Если нет ID, но нужно создать, создаем новое рассуждение
1570
- this.logger('info', 'Создание нового рассуждения');
1571
- try {
1572
- // Сначала подключаемся к пространству имен
1573
- const client = await this.connect(WebSocketNamespace.REASONING);
1574
- // Затем создаем новое рассуждение
1575
- const newReasoningId = await this.createNewReasoning();
1576
- this.activeReasoningId = newReasoningId;
1577
- this.logger('info', `Создано новое рассуждение: ${newReasoningId}`);
1578
- }
1579
- catch (error) {
1580
- this.logger('error', 'Ошибка при создании нового рассуждения', error);
1581
- return false;
1582
- }
1583
- }
1584
- // Подключаемся к пространству имен рассуждений
1585
- const client = await this.connect(WebSocketNamespace.REASONING);
1586
- // Аутентифицируемся с увеличенным таймаутом
1587
- try {
1588
- const authResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.AUTHENTICATE, {
1589
- token: this.options.apiKey,
1590
- reasoningId: this.activeReasoningId
1591
- }, 10000);
1592
- this.logger('debug', 'Результат аутентификации в namespace рассуждений', authResult);
1593
- // Если сервер вернул токен сессии и нужно его сохранить
1594
- if (saveSession && authResult.sessionToken) {
1595
- this.saveSessionToken(WebSocketNamespace.REASONING, authResult.sessionToken);
1596
- }
1597
- }
1598
- catch (error) {
1599
- this.logger('error', 'Ошибка аутентификации в namespace рассуждений', error);
1600
- return false;
1601
- }
1602
- // Если у нас есть ID рассуждения и включено автоматическое присоединение
1603
- if (this.activeReasoningId && autoJoin) {
1604
- try {
1605
- const joinResult = await client.emitWithAck(websocket_events_constants_js_1.WebSocketEvents.JOIN_REASONING, {
1606
- reasoningId: this.activeReasoningId,
1607
- token: this.options.apiKey
1608
- }, 10000);
1609
- this.logger('debug', 'Результат присоединения к рассуждению', joinResult);
1610
- if (joinResult.success !== true) {
1611
- this.logger('warn', `Не удалось присоединиться к рассуждению: ${this.activeReasoningId}`, joinResult.error);
1612
- return false;
1613
- }
1614
- }
1615
- catch (error) {
1616
- this.logger('error', 'Ошибка присоединения к рассуждению', error);
1617
- return false;
1618
- }
1619
- }
1620
- // Включаем автоматический ping/pong, если настроено
1621
- if (this.options.enableAutoPing !== false) {
1622
- this.enablePingPong(this.options.pingInterval, this.options.pingTimeoutThreshold);
1623
- }
1624
- return true;
1625
- }
1626
- catch (error) {
1627
- this.logger('error', 'Ошибка подключения к пространству имен рассуждений', error);
1628
- return false;
1629
- }
538
+ getDiagnostics() {
539
+ return this.diagnosticsService.getDiagnostics();
1630
540
  }
1631
541
  }
1632
542
  exports.CodeSolverWebSocketClient = CodeSolverWebSocketClient;