zerochat 7.3.0__py3-none-any.whl

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 (130) hide show
  1. zerochat-7.3.0.dist-info/METADATA +70 -0
  2. zerochat-7.3.0.dist-info/RECORD +130 -0
  3. zerochat-7.3.0.dist-info/WHEEL +5 -0
  4. zerochat-7.3.0.dist-info/entry_points.txt +2 -0
  5. zerochat-7.3.0.dist-info/licenses/LICENSE +34 -0
  6. zerochat-7.3.0.dist-info/top_level.txt +2 -0
  7. zerochat.py +2004 -0
  8. zerochat_runtime/__init__.py +1 -0
  9. zerochat_runtime/assets/css/base.css +199 -0
  10. zerochat_runtime/assets/css/components/composer.css +1258 -0
  11. zerochat_runtime/assets/css/components/debug.css +777 -0
  12. zerochat_runtime/assets/css/components/header.css +97 -0
  13. zerochat_runtime/assets/css/components/icons.css +39 -0
  14. zerochat_runtime/assets/css/components/markdown.css +685 -0
  15. zerochat_runtime/assets/css/components/messages.css +473 -0
  16. zerochat_runtime/assets/css/components/modals.css +1319 -0
  17. zerochat_runtime/assets/css/components/sidebar.css +622 -0
  18. zerochat_runtime/assets/css/components/tools.css +1223 -0
  19. zerochat_runtime/assets/css/layout.css +171 -0
  20. zerochat_runtime/assets/css/print.css +120 -0
  21. zerochat_runtime/assets/css/styles.css +18 -0
  22. zerochat_runtime/assets/css/theme-overrides.css +555 -0
  23. zerochat_runtime/assets/css/tokens.css +165 -0
  24. zerochat_runtime/assets/help/architecture.html +247 -0
  25. zerochat_runtime/assets/help/composer.html +134 -0
  26. zerochat_runtime/assets/help/conversations.html +105 -0
  27. zerochat_runtime/assets/help/debug.html +108 -0
  28. zerochat_runtime/assets/help/en/architecture.html +247 -0
  29. zerochat_runtime/assets/help/en/composer.html +134 -0
  30. zerochat_runtime/assets/help/en/conversations.html +104 -0
  31. zerochat_runtime/assets/help/en/debug.html +105 -0
  32. zerochat_runtime/assets/help/en/gemini-free.html +39 -0
  33. zerochat_runtime/assets/help/en/index.html +191 -0
  34. zerochat_runtime/assets/help/en/learning.html +71 -0
  35. zerochat_runtime/assets/help/en/mcp.html +143 -0
  36. zerochat_runtime/assets/help/en/openrouter-free.html +39 -0
  37. zerochat_runtime/assets/help/en/profiles.html +173 -0
  38. zerochat_runtime/assets/help/en/rag.html +130 -0
  39. zerochat_runtime/assets/help/en/reasoning-telemetry.html +108 -0
  40. zerochat_runtime/assets/help/en/tools-agent.html +133 -0
  41. zerochat_runtime/assets/help/en/webllm.html +355 -0
  42. zerochat_runtime/assets/help/gemini-free.html +39 -0
  43. zerochat_runtime/assets/help/help.css +604 -0
  44. zerochat_runtime/assets/help/help.js +51 -0
  45. zerochat_runtime/assets/help/index.html +194 -0
  46. zerochat_runtime/assets/help/learning.html +71 -0
  47. zerochat_runtime/assets/help/mcp.html +143 -0
  48. zerochat_runtime/assets/help/openrouter-free.html +39 -0
  49. zerochat_runtime/assets/help/profiles.html +174 -0
  50. zerochat_runtime/assets/help/rag.html +130 -0
  51. zerochat_runtime/assets/help/reasoning-telemetry.html +111 -0
  52. zerochat_runtime/assets/help/tools-agent.html +133 -0
  53. zerochat_runtime/assets/help/webllm.html +359 -0
  54. zerochat_runtime/assets/js/agent-core.js +1553 -0
  55. zerochat_runtime/assets/js/api.js +844 -0
  56. zerochat_runtime/assets/js/app.js +2558 -0
  57. zerochat_runtime/assets/js/attachments.js +220 -0
  58. zerochat_runtime/assets/js/charts.js +338 -0
  59. zerochat_runtime/assets/js/chat-engine.js +566 -0
  60. zerochat_runtime/assets/js/config-store.js +207 -0
  61. zerochat_runtime/assets/js/context-manager.js +584 -0
  62. zerochat_runtime/assets/js/conversation-service.js +484 -0
  63. zerochat_runtime/assets/js/cookies.js +688 -0
  64. zerochat_runtime/assets/js/data-reset-service.js +136 -0
  65. zerochat_runtime/assets/js/debug.js +508 -0
  66. zerochat_runtime/assets/js/defaults.js +16 -0
  67. zerochat_runtime/assets/js/export.js +179 -0
  68. zerochat_runtime/assets/js/file-parser.js +2088 -0
  69. zerochat_runtime/assets/js/generation-controller.js +417 -0
  70. zerochat_runtime/assets/js/i18n.js +1483 -0
  71. zerochat_runtime/assets/js/icons.js +156 -0
  72. zerochat_runtime/assets/js/ingestionEngine.js +436 -0
  73. zerochat_runtime/assets/js/markdown.js +588 -0
  74. zerochat_runtime/assets/js/mcp.js +1271 -0
  75. zerochat_runtime/assets/js/message-turns.js +62 -0
  76. zerochat_runtime/assets/js/profile-backup.js +118 -0
  77. zerochat_runtime/assets/js/profile-export-bundle.js +481 -0
  78. zerochat_runtime/assets/js/profile-repository.js +213 -0
  79. zerochat_runtime/assets/js/providers-webllm.js +486 -0
  80. zerochat_runtime/assets/js/providers.js +1560 -0
  81. zerochat_runtime/assets/js/rag-index.js +295 -0
  82. zerochat_runtime/assets/js/rag-service.js +530 -0
  83. zerochat_runtime/assets/js/rag-ui.js +997 -0
  84. zerochat_runtime/assets/js/ragStorage.js +676 -0
  85. zerochat_runtime/assets/js/sandbox.js +449 -0
  86. zerochat_runtime/assets/js/state.js +704 -0
  87. zerochat_runtime/assets/js/storage-db.js +144 -0
  88. zerochat_runtime/assets/js/tool-cards.js +330 -0
  89. zerochat_runtime/assets/js/tool-security.js +653 -0
  90. zerochat_runtime/assets/js/tools/README.md +50 -0
  91. zerochat_runtime/assets/js/tools/builtin/agent-checkpoint.tool.js +212 -0
  92. zerochat_runtime/assets/js/tools/builtin/download-pdf.tool.js +111 -0
  93. zerochat_runtime/assets/js/tools/builtin/execute-javascript.tool.js +219 -0
  94. zerochat_runtime/assets/js/tools/builtin/fetch-web-page.tool.js +112 -0
  95. zerochat_runtime/assets/js/tools/builtin/list-documents.tool.js +117 -0
  96. zerochat_runtime/assets/js/tools/builtin/read-knowledge-chunk.tool.js +129 -0
  97. zerochat_runtime/assets/js/tools/builtin/read-knowledge-image.tool.js +95 -0
  98. zerochat_runtime/assets/js/tools/builtin/render-chart.tool.js +90 -0
  99. zerochat_runtime/assets/js/tools/builtin/search-knowledge-base.tool.js +124 -0
  100. zerochat_runtime/assets/js/tools/builtin/search-web.tool.js +125 -0
  101. zerochat_runtime/assets/js/tools/tool-manifest.js +53 -0
  102. zerochat_runtime/assets/js/tools/tool-runtime.js +77 -0
  103. zerochat_runtime/assets/js/ui-composer.js +319 -0
  104. zerochat_runtime/assets/js/ui-conversation.js +655 -0
  105. zerochat_runtime/assets/js/ui-dialogs.js +132 -0
  106. zerochat_runtime/assets/js/ui-generation-status.js +119 -0
  107. zerochat_runtime/assets/js/ui-inspector.js +804 -0
  108. zerochat_runtime/assets/js/ui-mcp.js +604 -0
  109. zerochat_runtime/assets/js/ui-profiles.js +824 -0
  110. zerochat_runtime/assets/js/ui-reasoning.js +146 -0
  111. zerochat_runtime/assets/js/ui-settings.js +825 -0
  112. zerochat_runtime/assets/js/ui-shell.js +215 -0
  113. zerochat_runtime/assets/js/ui-sidebar.js +429 -0
  114. zerochat_runtime/assets/js/ui-telemetry.js +404 -0
  115. zerochat_runtime/assets/js/ui-transfer.js +262 -0
  116. zerochat_runtime/assets/js/utils.js +216 -0
  117. zerochat_runtime/assets/js/vendor/orama.browser.js +11 -0
  118. zerochat_runtime/assets/js/web-browser.js +569 -0
  119. zerochat_runtime/assets/js/web-search.js +519 -0
  120. zerochat_runtime/assets/manifest.webmanifest +20 -0
  121. zerochat_runtime/assets/services/dummy_mcp/dummy_mcp_server.py +47 -0
  122. zerochat_runtime/assets/services/dummy_mcp/service.json +22 -0
  123. zerochat_runtime/assets/services/lsp/installer.json +9 -0
  124. zerochat_runtime/assets/services/lsp/service.json +22 -0
  125. zerochat_runtime/assets/services/memory/installer.json +9 -0
  126. zerochat_runtime/assets/services/memory/service.json +24 -0
  127. zerochat_runtime/assets/services/playwright/installer.json +10 -0
  128. zerochat_runtime/assets/services/playwright/service.json +39 -0
  129. zerochat_runtime/assets/sw.js +164 -0
  130. zerochat_runtime/assets/zerochat.html +671 -0
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Servicio de Dominio para Gestión de Conversaciones y Sesiones de Chat (ZeroChat).
3
+ * Coordina el ciclo de vida de las sesiones (crear, guardar, renombrar, borrar, cambiar de sesión,
4
+ * bifurcar ramas / branching y persistir en State y Storage).
5
+ */
6
+ (function (root, factory) {
7
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
8
+ module.exports = factory(require('./message-turns.js'));
9
+ } else {
10
+ root.ChatConversationService = factory(root.ChatMessageTurns);
11
+ }
12
+ }(typeof self !== 'undefined' ? self : this, function (MessageTurns) {
13
+ 'use strict';
14
+
15
+ function resolveDep(globalName, relPath) {
16
+ if (typeof window !== 'undefined' && window[globalName]) return window[globalName];
17
+ if (typeof globalThis !== 'undefined' && globalThis[globalName]) return globalThis[globalName];
18
+ if (typeof require !== 'undefined') {
19
+ try { return require(relPath); } catch (_) {}
20
+ }
21
+ return null;
22
+ }
23
+
24
+ function getI18n() { return resolveDep('ChatI18n', './i18n.js'); }
25
+ function getState() { return resolveDep('ChatState', './state.js'); }
26
+ function getStorage(options = {}) {
27
+ if (options && options.storage) return options.storage;
28
+ return resolveDep('ChatStorage', './cookies.js') || resolveDep('ZeroChatDB', './storage-db.js');
29
+ }
30
+ function getDialogs() { return resolveDep('ChatDialogs', './ui-dialogs.js'); }
31
+ function getEngine() { return resolveDep('ChatEngine', './chat-engine.js'); }
32
+ function getUtils() { return resolveDep('ChatUtils', './utils.js'); }
33
+ function getConfig() { return resolveDep('ChatConfig', './config-store.js'); }
34
+
35
+ function t(key, params) {
36
+ const I18n = getI18n();
37
+ return I18n?.t?.(key, params) || key;
38
+ }
39
+
40
+ const extractBaseId = MessageTurns.extractBaseId;
41
+
42
+ const isDateTimeInitialTurn = MessageTurns.isDateTimeInitialTurn;
43
+
44
+ function createInitialChatHistory(options = {}) {
45
+ const Engine = getEngine();
46
+ const Config = getConfig();
47
+ const runtimeConfig = options.getRuntimeConfig ? options.getRuntimeConfig() : (Config?.getActive?.() || {});
48
+ const lang = options.language || runtimeConfig.language || 'es';
49
+ const systemPrompt = typeof options.getConfiguredSystemPrompt === 'function'
50
+ ? options.getConfiguredSystemPrompt(runtimeConfig)
51
+ : (runtimeConfig.systemPrompt || '');
52
+
53
+ return [
54
+ {
55
+ id: 'system_root',
56
+ role: 'system',
57
+ content: systemPrompt,
58
+ contextDateAnchor: Engine?.getConversationDateAnchor ? Engine.getConversationDateAnchor(lang) : undefined
59
+ }
60
+ ];
61
+ }
62
+
63
+ function blockSessionTransitionIfBusy(messageKey) {
64
+ const State = getState();
65
+ const isBusy = State?.isConversationBusy?.() === true;
66
+ if (!isBusy) return false;
67
+ const Dialogs = getDialogs();
68
+ if (Dialogs?.alert) Dialogs.alert(t(messageKey));
69
+ return true;
70
+ }
71
+
72
+ function initializeSessionState(sessionId, history, blockedMessageKey, options = {}) {
73
+ const State = getState();
74
+ const initialization = State?.replaceConversation
75
+ ? State.replaceConversation({ sessionId, messages: history })
76
+ : (State?.initializeConversation
77
+ ? State.initializeConversation({ sessionId, messages: history })
78
+ : { ok: true });
79
+
80
+ if (!initialization.ok) {
81
+ const Dialogs = getDialogs();
82
+ if (Dialogs?.alert) Dialogs.alert(t(blockedMessageKey));
83
+ return false;
84
+ }
85
+
86
+ if (typeof options.onSessionReset === 'function') {
87
+ options.onSessionReset();
88
+ }
89
+ return true;
90
+ }
91
+
92
+ async function loadSessionsFromStorage(options = {}) {
93
+ const State = getState();
94
+ const Storage = getStorage(options);
95
+ let sessionsList = [];
96
+ try {
97
+ if (Storage?.initDB) await Storage.initDB();
98
+ if (Storage?.getConversationsList) {
99
+ sessionsList = await Storage.getConversationsList();
100
+ }
101
+ } catch (e) {
102
+ console.warn('Error al cargar sesiones de chat:', e);
103
+ sessionsList = [];
104
+ }
105
+
106
+ if (!Array.isArray(sessionsList)) {
107
+ sessionsList = [];
108
+ }
109
+
110
+ const nextSessionId = (typeof crypto !== 'undefined' && crypto.randomUUID)
111
+ ? 'session_' + crypto.randomUUID()
112
+ : 'session_' + Date.now() + '_' + Math.random().toString(36).slice(2, 7);
113
+ const initialHistory = createInitialChatHistory(options);
114
+
115
+ if (State?.initializeConversation) {
116
+ State.initializeConversation({ sessionId: nextSessionId, sessions: sessionsList, messages: initialHistory });
117
+ }
118
+
119
+ if (typeof options.renderSessionMessages === 'function') {
120
+ options.renderSessionMessages(options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || initialHistory));
121
+ }
122
+ if (typeof options.renderSidebarChats === 'function') {
123
+ options.renderSidebarChats();
124
+ }
125
+ }
126
+
127
+ async function saveCurrentSession(options = {}) {
128
+ const State = getState();
129
+ const Storage = getStorage(options);
130
+ const history = options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || []);
131
+ const currId = options.getCurrentSessionId ? options.getCurrentSessionId() : (State?.getActiveSessionId?.() || '');
132
+ const sessionsList = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
133
+
134
+ const hasRealUserMessages = Array.isArray(history) && history.some(m => {
135
+ if (!m || m.role !== 'user') return false;
136
+ return !isDateTimeInitialTurn(m);
137
+ });
138
+
139
+ if (!hasRealUserMessages) {
140
+ if (State?.removeSession) {
141
+ State.removeSession(currId);
142
+ }
143
+ if (Storage?.deleteConversation) {
144
+ await Storage.deleteConversation(currId);
145
+ }
146
+ if (typeof options.renderSidebarChats === 'function') {
147
+ options.renderSidebarChats();
148
+ }
149
+ return;
150
+ }
151
+
152
+ let sess = sessionsList.find(s => s.id === currId);
153
+ const now = Date.now();
154
+ if (!sess) {
155
+ sess = {
156
+ id: currId,
157
+ title: t('chat_untitled') || 'Nueva conversación',
158
+ createdAt: now,
159
+ updatedAt: now,
160
+ messageCount: history.length
161
+ };
162
+ } else {
163
+ sess = Object.assign({}, sess, {
164
+ updatedAt: now,
165
+ messageCount: history.length
166
+ });
167
+ }
168
+
169
+ const isUntitled = !sess.title ||
170
+ sess.title === t('chat_untitled') ||
171
+ sess.title === 'Nueva conversación' ||
172
+ sess.title === 'New conversation';
173
+
174
+ if (isUntitled && history.length > 1) {
175
+ const firstRealUser = history.find(m => m.role === 'user' && !isDateTimeInitialTurn(m));
176
+ if (firstRealUser && firstRealUser.content) {
177
+ const rawContent = typeof firstRealUser.content === 'string' ? firstRealUser.content : (firstRealUser.content[0]?.text || '');
178
+ const candidate = rawContent.split('\n')[0].replace(/[#*`_>\[\]]/g, '').trim();
179
+ if (candidate) {
180
+ sess.title = candidate.length > 35 ? candidate.substring(0, 32) + '…' : candidate;
181
+ }
182
+ }
183
+ }
184
+
185
+ if (State?.saveSessionMetadata) {
186
+ State.saveSessionMetadata(sess);
187
+ }
188
+ if (Storage?.saveConversation) {
189
+ await Storage.saveConversation(sess, history);
190
+ }
191
+
192
+ if (typeof options.renderSidebarChats === 'function') {
193
+ options.renderSidebarChats();
194
+ }
195
+ }
196
+
197
+ async function switchToSession(sessionId, options = {}) {
198
+ const { force = false, saveCurrent = true } = options;
199
+ const State = getState();
200
+ const Storage = getStorage(options);
201
+ const Engine = getEngine();
202
+ const Config = getConfig();
203
+ const currId = options.getCurrentSessionId ? options.getCurrentSessionId() : (State?.getActiveSessionId?.() || '');
204
+
205
+ if (!force && sessionId === currId) return;
206
+ if (blockSessionTransitionIfBusy('chat_switch_blocked_generating')) return false;
207
+ if (saveCurrent) await saveCurrentSession(options);
208
+
209
+ let targetConv = null;
210
+ if (Storage?.getConversation) {
211
+ targetConv = await Storage.getConversation(sessionId);
212
+ }
213
+
214
+ const sessionsList = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
215
+ if (!targetConv) {
216
+ const found = sessionsList.find(s => s.id === sessionId);
217
+ if (found && found.history) targetConv = found;
218
+ }
219
+
220
+ if (!targetConv) return;
221
+
222
+ const runtimeConfig = options.getRuntimeConfig ? options.getRuntimeConfig() : (Config?.getActive?.() || {});
223
+ const sysPrompt = typeof options.getConfiguredSystemPrompt === 'function'
224
+ ? options.getConfiguredSystemPrompt(runtimeConfig)
225
+ : (runtimeConfig.systemPrompt || '');
226
+
227
+ const restoredHistory = targetConv.history && targetConv.history.length > 0 ? [...targetConv.history] : [
228
+ { id: 'system_root', role: 'system', content: sysPrompt }
229
+ ];
230
+
231
+ const lang = options.language || runtimeConfig.language || 'es';
232
+ if (Engine?.ensureConversationDate) {
233
+ Engine.ensureConversationDate(restoredHistory, lang, targetConv.createdAt);
234
+ }
235
+
236
+ if (!initializeSessionState(targetConv.id, restoredHistory, 'chat_switch_blocked_generating', options)) return false;
237
+ if (typeof options.renderSessionMessages === 'function') {
238
+ options.renderSessionMessages(options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || []));
239
+ }
240
+ if (typeof options.renderSidebarChats === 'function') {
241
+ options.renderSidebarChats();
242
+ }
243
+
244
+ if (typeof window !== 'undefined' && window.innerWidth < 900 && typeof options.closeSidebar === 'function') {
245
+ options.closeSidebar();
246
+ }
247
+ return true;
248
+ }
249
+
250
+ async function createNewSession(options = {}) {
251
+ const { saveCurrent = true } = options;
252
+ if (blockSessionTransitionIfBusy('chat_new_blocked_generating')) return false;
253
+
254
+ if (saveCurrent) await saveCurrentSession(options);
255
+
256
+ const nextSessionId = (typeof crypto !== 'undefined' && crypto.randomUUID)
257
+ ? 'session_' + crypto.randomUUID()
258
+ : 'session_' + Date.now() + '_' + Math.random().toString(36).slice(2, 7);
259
+
260
+ const nextHistory = createInitialChatHistory(options);
261
+ if (!initializeSessionState(nextSessionId, nextHistory, 'chat_new_blocked_generating', options)) return false;
262
+
263
+ const State = getState();
264
+ if (typeof options.renderSessionMessages === 'function') {
265
+ options.renderSessionMessages(options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || []));
266
+ }
267
+ if (typeof options.renderSidebarChats === 'function') {
268
+ options.renderSidebarChats();
269
+ }
270
+
271
+ if (typeof options.resetComposerInput === 'function') {
272
+ options.resetComposerInput();
273
+ }
274
+
275
+ if (typeof window !== 'undefined' && window.innerWidth < 900 && typeof options.closeSidebar === 'function') {
276
+ options.closeSidebar();
277
+ }
278
+ return true;
279
+ }
280
+
281
+ function getBranchBoundaryIndex(wrapper, history) {
282
+ if (!wrapper || !Array.isArray(history)) return -1;
283
+ const messageIds = new Set((wrapper.getAttribute?.('data-msg-ids') || '').split(',').filter(Boolean));
284
+ const messageId = wrapper.getAttribute?.('data-msg-id');
285
+ const baseId = wrapper.getAttribute?.('data-base-id');
286
+ if (messageId) messageIds.add(messageId);
287
+ if (baseId) messageIds.add(baseId);
288
+
289
+ let boundary = -1;
290
+ history.forEach((message, index) => {
291
+ if (!message || !message.id) return;
292
+ const messageBaseId = extractBaseId(message.id);
293
+ if (messageIds.has(message.id) || (messageBaseId && messageIds.has(messageBaseId))) {
294
+ boundary = index;
295
+ }
296
+ });
297
+ return boundary;
298
+ }
299
+
300
+ function setAssistantGroupMessageIds(wrapper, history) {
301
+ if (!wrapper || !Array.isArray(history)) return;
302
+ let lastUserIndex = -1;
303
+ for (let index = history.length - 1; index >= 0; index--) {
304
+ if (history[index]?.role === 'user') {
305
+ lastUserIndex = index;
306
+ break;
307
+ }
308
+ }
309
+ const ids = history.slice(lastUserIndex + 1).map(message => message?.id).filter(Boolean);
310
+ if (ids.length > 0) wrapper.setAttribute('data-msg-ids', ids.join(','));
311
+ }
312
+
313
+ function cloneBranchHistory(history, boundary, sessionId) {
314
+ const Utils = getUtils();
315
+ const sourceHistory = history.slice(0, boundary + 1);
316
+ const clonedHistory = Utils?.clone ? Utils.clone(sourceHistory) : JSON.parse(JSON.stringify(sourceHistory));
317
+ return clonedHistory.map((message, index) => Object.assign({}, message, {
318
+ id: `msg_${sessionId}_${index}`
319
+ }));
320
+ }
321
+
322
+ async function createConversationBranch(wrapper, options = {}) {
323
+ if (blockSessionTransitionIfBusy('chat_new_blocked_generating')) return false;
324
+
325
+ const State = getState();
326
+ const Storage = getStorage(options);
327
+ const history = options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || []);
328
+ const boundary = getBranchBoundaryIndex(wrapper, history);
329
+ if (boundary < 0) return false;
330
+
331
+ await saveCurrentSession(options);
332
+ if (blockSessionTransitionIfBusy('chat_new_blocked_generating')) return false;
333
+
334
+ const parentSessionId = options.getCurrentSessionId ? options.getCurrentSessionId() : (State?.getActiveSessionId?.() || '');
335
+ const sessionsList = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
336
+ const parentSession = sessionsList.find(session => session.id === parentSessionId);
337
+ const parentTitle = parentSession?.title || t('chat_untitled');
338
+ const branchSessionId = (typeof crypto !== 'undefined' && crypto.randomUUID)
339
+ ? 'session_' + crypto.randomUUID()
340
+ : 'session_' + Date.now() + '_' + Math.random().toString(36).slice(2, 7);
341
+ const branchHistory = cloneBranchHistory(history, boundary, branchSessionId);
342
+ const now = Date.now();
343
+ const branchSession = {
344
+ id: branchSessionId,
345
+ title: t('chat_branch_title', { title: parentTitle }),
346
+ createdAt: now,
347
+ updatedAt: now,
348
+ messageCount: branchHistory.length,
349
+ metadata: {
350
+ parentSessionId,
351
+ branchedFromMessageIds: (wrapper?.getAttribute?.('data-msg-ids') || '').split(',').filter(Boolean)
352
+ }
353
+ };
354
+
355
+ const Dialogs = getDialogs();
356
+ if (!Storage?.saveConversation || !await Storage.saveConversation(branchSession, branchHistory)) {
357
+ if (Dialogs?.alert) Dialogs.alert(t('chat_branch_error'), { type: 'error' });
358
+ return false;
359
+ }
360
+ if (!initializeSessionState(branchSessionId, branchHistory, 'chat_new_blocked_generating', options)) {
361
+ await Storage?.deleteConversation?.(branchSessionId);
362
+ return false;
363
+ }
364
+ if (State?.saveSessionMetadata) State.saveSessionMetadata(branchSession);
365
+ if (typeof options.renderSessionMessages === 'function') {
366
+ options.renderSessionMessages(options.getChatHistory ? options.getChatHistory() : (State?.getMessages?.() || []));
367
+ }
368
+ if (typeof options.renderSidebarChats === 'function') {
369
+ options.renderSidebarChats();
370
+ }
371
+
372
+ if (typeof options.resetComposerInput === 'function') {
373
+ options.resetComposerInput();
374
+ }
375
+ if (typeof window !== 'undefined' && window.innerWidth < 900 && typeof options.closeSidebar === 'function') {
376
+ options.closeSidebar();
377
+ }
378
+ return true;
379
+ }
380
+
381
+ async function deleteSession(sessionId, event, options = {}) {
382
+ if (event && event.stopPropagation) event.stopPropagation();
383
+ const Dialogs = getDialogs();
384
+ if (Dialogs?.confirm && !await Dialogs.confirm(t('chat_delete_confirm'))) return;
385
+ if (blockSessionTransitionIfBusy('chat_delete_blocked_generating')) return;
386
+
387
+ const State = getState();
388
+ const Storage = getStorage(options);
389
+ const currId = options.getCurrentSessionId ? options.getCurrentSessionId() : (State?.getActiveSessionId?.() || '');
390
+
391
+ if (State?.removeSession) {
392
+ const res = State.removeSession(sessionId);
393
+ if (!res.ok && res.reason === 'generation-active') {
394
+ if (Dialogs?.alert) Dialogs.alert(t('chat_delete_blocked_generating'));
395
+ return;
396
+ }
397
+ }
398
+
399
+ if (Storage?.deleteConversation) {
400
+ await Storage.deleteConversation(sessionId);
401
+ }
402
+
403
+ const remainingSessions = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
404
+ if (remainingSessions.length === 0) {
405
+ await createNewSession({ ...options, saveCurrent: false });
406
+ } else if (currId === sessionId) {
407
+ const next = remainingSessions[0];
408
+ await switchToSession(next.id, { ...options, force: true, saveCurrent: false });
409
+ } else {
410
+ if (typeof options.renderSidebarChats === 'function') {
411
+ options.renderSidebarChats();
412
+ }
413
+ }
414
+ }
415
+
416
+ async function deleteAllSessions(options = {}) {
417
+ const State = getState();
418
+ const Storage = getStorage(options);
419
+ const Dialogs = getDialogs();
420
+ const sessionsList = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
421
+ if (!sessionsList || sessionsList.length === 0) return;
422
+ if (blockSessionTransitionIfBusy('chat_delete_blocked_generating')) return;
423
+ if (Dialogs?.confirm && !await Dialogs.confirm(t('chat_delete_all_confirm'))) return;
424
+ if (blockSessionTransitionIfBusy('chat_delete_blocked_generating')) return;
425
+
426
+ const deleted = Storage?.deleteAllConversations ? await Storage.deleteAllConversations() : true;
427
+ if (!deleted) {
428
+ if (Dialogs?.alert) Dialogs.alert(t('chat_delete_history_err'), { type: 'error' });
429
+ return;
430
+ }
431
+
432
+ if (State?.set) {
433
+ State.set('sessions', { activeId: null, list: [] });
434
+ }
435
+
436
+ await createNewSession({ ...options, saveCurrent: false });
437
+ }
438
+
439
+ async function renameSession(sessionId, event, options = {}) {
440
+ if (event && event.stopPropagation) event.stopPropagation();
441
+ const State = getState();
442
+ const Storage = getStorage(options);
443
+ const Dialogs = getDialogs();
444
+ const sessionsList = options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || []);
445
+ let sess = sessionsList.find(s => s.id === sessionId);
446
+ if (!sess) return;
447
+
448
+ const newTitle = Dialogs?.prompt ? await Dialogs.prompt(t('prompt_rename_conversation'), sess.title || '') : null;
449
+ if (newTitle !== null && newTitle.trim() !== '') {
450
+ sess = (options.getSavedSessions ? options.getSavedSessions() : (State?.getSavedSessions?.() || [])).find(s => s.id === sessionId);
451
+ if (!sess) return;
452
+ sess.title = newTitle.trim();
453
+ sess.updatedAt = Date.now();
454
+ if (State?.saveSessionMetadata) {
455
+ State.saveSessionMetadata(sess);
456
+ }
457
+ if (Storage?.renameConversation) {
458
+ await Storage.renameConversation(sessionId, sess.title);
459
+ }
460
+ if (typeof options.renderSidebarChats === 'function') {
461
+ options.renderSidebarChats();
462
+ }
463
+ }
464
+ }
465
+
466
+ return {
467
+ extractBaseId,
468
+ isDateTimeInitialTurn,
469
+ createInitialChatHistory,
470
+ blockSessionTransitionIfBusy,
471
+ initializeSessionState,
472
+ loadSessionsFromStorage,
473
+ saveCurrentSession,
474
+ switchToSession,
475
+ createNewSession,
476
+ getBranchBoundaryIndex,
477
+ setAssistantGroupMessageIds,
478
+ cloneBranchHistory,
479
+ createConversationBranch,
480
+ deleteSession,
481
+ deleteAllSessions,
482
+ renameSession
483
+ };
484
+ }));