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,824 @@
1
+ /**
2
+ * Módulo de Interfaz de Usuario para Perfiles de Conexión (ZeroChat).
3
+ * Gestiona el diálogo de edición de perfiles, detección de cambios sin guardar (dirty state),
4
+ * guardado, borrado, importación cifrada, exportación y menú desplegable de perfiles activos.
5
+ */
6
+ (function (root, factory) {
7
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
8
+ module.exports = factory();
9
+ } else {
10
+ root.ChatUIProfiles = factory();
11
+ }
12
+ }(typeof self !== 'undefined' ? self : this, function () {
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 getProfiles() { return resolveDep('ChatProfileRepository', './profile-repository.js'); }
26
+ function getProfileBackup() { return resolveDep('ChatProfileBackup', './profile-backup.js'); }
27
+ function getProfileExportBundle() { return resolveDep('ChatProfileExportBundle', './profile-export-bundle.js'); }
28
+ function getConfig() { return resolveDep('ChatConfig', './config-store.js'); }
29
+ function getProviders() { return resolveDep('ChatProviders', './providers.js'); }
30
+ function getExport() { return resolveDep('ChatExport', './export.js'); }
31
+ function getDialogs() { return resolveDep('ChatDialogs', './ui-dialogs.js'); }
32
+ function getUISettings() { return resolveDep('ChatUISettings', './ui-settings.js'); }
33
+
34
+ function t(key, params) {
35
+ const I18n = getI18n();
36
+ return I18n?.t?.(key, params) || key;
37
+ }
38
+
39
+ let activeCleanupFns = [];
40
+ let cachedElements = null;
41
+ let cachedOptions = {};
42
+
43
+ function isDownloadedWebLLMModel(modelId) {
44
+ if (!modelId) return false;
45
+ const providers = getProviders();
46
+ const adapter = providers?.registry?.get?.('webllm');
47
+ if (typeof adapter?.isModelCompleted === 'function') {
48
+ return adapter.isModelCompleted(modelId);
49
+ }
50
+ const WebLLM = resolveDep('ChatWebLLM', './providers-webllm.js');
51
+ return WebLLM?.isModelCompleted?.(modelId) || false;
52
+ }
53
+
54
+ function populateProfileSelector(elements, selectedProfileName) {
55
+ const Profiles = getProfiles();
56
+ if (!Profiles?.list) return;
57
+ const profiles = Profiles.list();
58
+ const els = elements || cachedElements || {};
59
+
60
+ if (els.profileDatalist) {
61
+ els.profileDatalist.innerHTML = '';
62
+ profiles.forEach(profile => {
63
+ const opt = document.createElement('option');
64
+ opt.value = profile.name;
65
+ els.profileDatalist.appendChild(opt);
66
+ });
67
+ }
68
+
69
+ if (els.profileSelectHelper) {
70
+ if (els.profileSelectHelper.tagName === 'SELECT') {
71
+ els.profileSelectHelper.innerHTML = `<option value="" disabled data-i18n="profile_select_default">▾ Elegir perfil guardado...</option>`;
72
+ profiles.forEach(profile => {
73
+ const opt = document.createElement('option');
74
+ opt.value = profile.id;
75
+ opt.textContent = profile.name;
76
+ if (profile.id === selectedProfileName) {
77
+ opt.selected = true;
78
+ }
79
+ els.profileSelectHelper.appendChild(opt);
80
+ });
81
+ }
82
+ els.profileSelectHelper.value = selectedProfileName || '';
83
+ }
84
+
85
+ if (els.settingProfileName) {
86
+ const selected = profiles.find(profile => profile.id === selectedProfileName);
87
+ els.settingProfileName.value = selected?.name || '';
88
+ }
89
+ if (els.settingProfileDescription) {
90
+ const selected = profiles.find(profile => profile.id === selectedProfileName);
91
+ els.settingProfileDescription.value = selected?.description || '';
92
+ }
93
+ }
94
+
95
+ async function applyProfileToForm(elements, profileData, profileId = null, options = {}) {
96
+ const UISettings = getUISettings();
97
+ const Profiles = getProfiles();
98
+ const Config = getConfig();
99
+ const els = elements || cachedElements || {};
100
+ const opts = options || cachedOptions || {};
101
+
102
+ if (UISettings?.applyProfileToForm) {
103
+ const currentActiveId = opts.getRuntimeConfig?.()?.activeProfile?.id || Config?.getActive?.()?.activeProfile?.id;
104
+ const id = profileId !== null ? profileId : (els.profileSelectHelper?.value || currentActiveId);
105
+ const keyInput = els.settingApiKey;
106
+ if (keyInput) {
107
+ keyInput._loadedApiKey = undefined;
108
+ keyInput.value = '';
109
+ }
110
+ setProfileDirty(els, false);
111
+ UISettings.applyProfileToForm(els, profileData);
112
+ syncProfileSaveState(els, opts);
113
+ try {
114
+ const profile = id ? await Profiles?.load?.(id) : null;
115
+ const currentSelectedId = els.profileSelectHelper?.value || opts.getRuntimeConfig?.()?.activeProfile?.id;
116
+ if (!keyInput || currentSelectedId !== id) return;
117
+ const apiKey = profile?.settings?.apiKey || '';
118
+ keyInput.value = apiKey;
119
+ keyInput._loadedApiKey = apiKey;
120
+ if (!isProfileFormDirty(els)) {
121
+ setProfileDirty(els, false);
122
+ }
123
+ syncProfileSaveState(els, opts);
124
+ } catch (error) {
125
+ const currentSelectedId = els.profileSelectHelper?.value || opts.getRuntimeConfig?.()?.activeProfile?.id;
126
+ if (currentSelectedId !== id) return;
127
+ if (!isProfileFormDirty(els)) {
128
+ setProfileDirty(els, false);
129
+ }
130
+ syncProfileSaveState(els, opts);
131
+ showProfileFeedback(els, t('err_profiles_backup', { err: error?.message || t('notice_error') }), 'error');
132
+ }
133
+ }
134
+ }
135
+
136
+ function showProfileFeedback(elements, msg, type = 'success') {
137
+ const UISettings = getUISettings();
138
+ const els = elements || cachedElements || {};
139
+ if (UISettings?.showProfileFeedback) {
140
+ UISettings.showProfileFeedback(els, msg, type);
141
+ }
142
+ }
143
+
144
+ function isProfileQueryReady(elements) {
145
+ const els = elements || cachedElements || {};
146
+ return els.profilesDialog?.dataset?.queryReady === 'true';
147
+ }
148
+
149
+ function isProfileFormDirty(elements) {
150
+ const els = elements || cachedElements || {};
151
+ if (els._profileDirty !== undefined) return Boolean(els._profileDirty);
152
+ return els.profilesDialog?.dataset?.profileDirty === 'true';
153
+ }
154
+
155
+ function setProfileDirty(elements, dirty = true) {
156
+ const els = elements || cachedElements || {};
157
+ const isDirty = Boolean(dirty);
158
+ els._profileDirty = isDirty;
159
+ if (els.profilesDialog) {
160
+ if (!els.profilesDialog.dataset) els.profilesDialog.dataset = {};
161
+ els.profilesDialog.dataset.profileDirty = String(isDirty);
162
+ }
163
+ return isDirty;
164
+ }
165
+
166
+ function canSaveProfile(elements, options = {}) {
167
+ const els = elements || cachedElements || {};
168
+ if (els.settingProfileName && !String(els.settingProfileName.value || '').trim()) {
169
+ return false;
170
+ }
171
+ return isProfileFormDirty(els) || isProfileQueryReady(els);
172
+ }
173
+
174
+ function syncProfileSaveState(elements, options = {}) {
175
+ const els = elements || cachedElements || {};
176
+ const opts = options || cachedOptions || {};
177
+ const Profiles = getProfiles();
178
+ const canSave = canSaveProfile(els, opts);
179
+ const currentId = els.profileSelectHelper?.value || els.profilesDialog?.dataset?.profileId || '';
180
+ const isReadOnly = currentId === Profiles?.READONLY_PROFILE_ID;
181
+ const UISettings = getUISettings();
182
+ UISettings?.syncProfileEditor?.(els, isReadOnly, canSave);
183
+
184
+ const keyUnavailable = els.settingApiKey?._loadedApiKey === undefined;
185
+ if (keyUnavailable && els.settingApiKey) els.settingApiKey.disabled = true;
186
+ if (keyUnavailable && els.btnSaveProfile) els.btnSaveProfile.disabled = true;
187
+ if (!isReadOnly) {
188
+ if (els.btnSaveProfile) {
189
+ els.btnSaveProfile.disabled = !canSave || keyUnavailable || els.profilesDialog?.dataset?.profileLocked === 'true';
190
+ }
191
+ if (els.profileSaveQueryHint) {
192
+ const apiType = els.settingApiType?.value || '';
193
+ const selectedModel = (els.settingModel?.value || els.modelSelectHelper?.value || '').trim();
194
+ const profileName = String(els.settingProfileName?.value || '').trim();
195
+ if (!profileName) {
196
+ els.profileSaveQueryHint.textContent = t('field_profile_placeholder') || 'Nombre del perfil requerido.';
197
+ } else if (!canSave) {
198
+ els.profileSaveQueryHint.textContent = t('profile_save_changes_required');
199
+ } else if (apiType === 'webllm' && selectedModel && isDownloadedWebLLMModel(selectedModel)) {
200
+ els.profileSaveQueryHint.textContent = t('webllm_query_optional');
201
+ } else {
202
+ els.profileSaveQueryHint.textContent = t('profile_save_pending');
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ function setProfileQueryState(elements, ready) {
209
+ const els = elements || cachedElements || {};
210
+ if (els.profilesDialog) {
211
+ if (!els.profilesDialog.dataset) els.profilesDialog.dataset = {};
212
+ els.profilesDialog.dataset.queryReady = String(ready);
213
+ }
214
+ syncProfileSaveState(els);
215
+ }
216
+
217
+ function activateConnectionProfile(profileId, options = {}) {
218
+ const Config = getConfig();
219
+ const opts = options || cachedOptions || {};
220
+ if (!profileId || !Config?.activateProfile) return;
221
+ const WebLLM = resolveDep('ChatWebLLM', './providers-webllm.js');
222
+ WebLLM?.adapter?.disposeActiveEngine?.().catch?.(() => {});
223
+ Config.activateProfile(profileId);
224
+ if (typeof opts.loadCachedModels === 'function') opts.loadCachedModels();
225
+ if (typeof opts.resetTelemetryDisplay === 'function') opts.resetTelemetryDisplay();
226
+ }
227
+
228
+ function setSelectedProfileAsDefault(profile, options = {}) {
229
+ if (!profile) return;
230
+ activateConnectionProfile(profile.id, options);
231
+ }
232
+
233
+ function setProfileMenuOpen(elements, open) {
234
+ const els = elements || cachedElements || {};
235
+ if (!els.activeProfileTrigger || !els.activeProfilePopover) return;
236
+ els.activeProfileTrigger.setAttribute('aria-expanded', String(open));
237
+ els.activeProfilePopover.hidden = !open;
238
+ }
239
+
240
+ function openProfileMenu(elements, options = {}) {
241
+ const els = elements || cachedElements || {};
242
+ const opts = options || cachedOptions || {};
243
+ const Profiles = getProfiles();
244
+ const Config = getConfig();
245
+ const runtimeConfig = opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {});
246
+ const UISettings = getUISettings();
247
+ UISettings?.renderProfileMenu?.(els, Profiles?.list?.() || [], runtimeConfig.activeProfile?.id);
248
+ setProfileMenuOpen(els, true);
249
+ }
250
+
251
+ function closeProfileMenu(elements) {
252
+ const els = elements || cachedElements || {};
253
+ setProfileMenuOpen(els, false);
254
+ }
255
+
256
+ async function handleSaveProfile(elements, options = {}) {
257
+ const els = elements || cachedElements || {};
258
+ const opts = options || cachedOptions || {};
259
+ const Profiles = getProfiles();
260
+ const Config = getConfig();
261
+ const runtimeConfig = opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {});
262
+
263
+ if (els.settingApiKey?._loadedApiKey === undefined) return false;
264
+ if (els.profilesDialog?.dataset?.profileLocked === 'true') return false;
265
+ if (!canSaveProfile(els, opts)) {
266
+ showProfileFeedback(els, t('profile_save_changes_required'), 'error');
267
+ return false;
268
+ }
269
+ const name = String(els.settingProfileName?.value || '').trim();
270
+ if (!name || !Profiles?.saveEditable) return false;
271
+ const selectedId = els.profileSelectHelper?.value || els.profilesDialog?.dataset?.profileId || '';
272
+ const selected = Profiles.get?.(selectedId) || null;
273
+ if (selected?.id === Profiles.READONLY_PROFILE_ID) {
274
+ showProfileFeedback(els, t('err_profile_read_only'), 'error');
275
+ return false;
276
+ }
277
+ const sameName = Profiles.findByName?.(name) || null;
278
+ if (sameName?.id === Profiles.READONLY_PROFILE_ID) {
279
+ showProfileFeedback(els, t('err_profile_read_only'), 'error');
280
+ return false;
281
+ }
282
+ if (selected && sameName && sameName.id !== selected.id) {
283
+ showProfileFeedback(els, t('err_profile_name_exists', { name }) || `Ya existe un perfil llamado "${name}".`, 'error');
284
+ return false;
285
+ }
286
+ if (!selected && sameName) {
287
+ showProfileFeedback(els, t('err_profile_name_exists', { name }) || `Ya existe un perfil llamado "${name}".`, 'error');
288
+ return false;
289
+ }
290
+
291
+ const existing = selected;
292
+ const baseSettings = existing?.settings || Profiles?.NEW_PROFILE_SETTINGS || runtimeConfig;
293
+ const UISettings = getUISettings();
294
+ const formConfig = UISettings?.gatherCurrentFormConfig ? UISettings.gatherCurrentFormConfig(els, runtimeConfig) : runtimeConfig;
295
+ const apiKey = els.settingApiKey?.value.trim() || '';
296
+ const description = els.settingProfileDescription?.value.trim() || '';
297
+ const apiType = els.settingApiType?.value || baseSettings.apiType;
298
+ const apiUrl = els.settingApiUrl?.value.trim() || baseSettings.apiUrl || getProviders()?.registry?.get?.(apiType)?.getConnectionConfig?.().endpoint || 'http://localhost:1234/v1';
299
+ const model = els.settingModel?.value.trim() || '';
300
+ const systemPrompt = els.settingSystemPrompt?.value.trim() || '';
301
+ const temperature = els.settingTemperature?.value || baseSettings.temperature || '0.7';
302
+ const maxAgentTurns = els.settingMaxAgentTurns?.value ? Number(els.settingMaxAgentTurns.value) : (baseSettings.maxAgentTurns || 15);
303
+ const apiKeyLocked = els.settingApiKeyLocked?.checked === true;
304
+
305
+ const saved = await Profiles.saveEditable({
306
+ id: existing?.id || `profile:${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
307
+ name,
308
+ description,
309
+ settings: {
310
+ ...baseSettings,
311
+ apiType,
312
+ apiUrl,
313
+ apiKey,
314
+ apiKeyLocked,
315
+ model,
316
+ systemPrompt,
317
+ temperature,
318
+ maxAgentTurns,
319
+ webllmConfig: formConfig?.webllmConfig || baseSettings.webllmConfig || {
320
+ context_window_size: 'default',
321
+ prefill_chunk_size: 'default'
322
+ }
323
+ }
324
+ });
325
+
326
+ populateProfileSelector(els, saved.id);
327
+ if (els.profileSelectHelper) els.profileSelectHelper.value = saved.id;
328
+ if (els.profilesDialog) {
329
+ els.profilesDialog.dataset.profileId = saved.id;
330
+ delete els.profilesDialog.dataset.isNew;
331
+ }
332
+ if (els.settingApiKey) els.settingApiKey._loadedApiKey = apiKey;
333
+ setProfileDirty(els, false);
334
+ setProfileQueryState(els, false);
335
+ setSelectedProfileAsDefault(saved, opts);
336
+ syncProfileSaveState(els, opts);
337
+ showProfileFeedback(els, t('msg_profile_saved', { name }) || `Perfil "${name}" guardado con éxito.`, 'success');
338
+ return true;
339
+ }
340
+
341
+ async function handleDeleteProfile(elements, options = {}) {
342
+ const els = elements || cachedElements || {};
343
+ const id = els.profileSelectHelper?.value || '';
344
+ return handleDeleteProfileById(id, els, options);
345
+ }
346
+
347
+ async function handleDeleteProfileById(profileId, elements, options = {}) {
348
+ const els = elements || cachedElements || {};
349
+ const opts = options || cachedOptions || {};
350
+ const Profiles = getProfiles();
351
+ const Config = getConfig();
352
+ const Dialogs = getDialogs();
353
+ const runtimeConfig = opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {});
354
+
355
+ if (!profileId || profileId === Profiles?.READONLY_PROFILE_ID || profileId === 'profile:mirror') {
356
+ showProfileFeedback(els, t('err_profile_read_only'), 'error');
357
+ return false;
358
+ }
359
+ const profile = Profiles?.get ? Profiles.get(profileId) : null;
360
+ if (!profile) return false;
361
+ if (Dialogs?.confirm && !await Dialogs.confirm(t('confirm_delete_profile', { name: profile.name }))) return false;
362
+
363
+ const currentProfile = Profiles?.get ? Profiles.get(profileId) : null;
364
+ if (!currentProfile) return false;
365
+ if (Profiles?.remove?.(currentProfile.id)) {
366
+ if (runtimeConfig.activeProfile?.id === currentProfile.id) {
367
+ Config?.activateFallbackProfile?.();
368
+ }
369
+ const nextActiveId = (opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {})).activeProfile?.id || '';
370
+ populateProfileSelector(els, nextActiveId);
371
+ applyProfileToForm(els, opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {}));
372
+ setProfileQueryState(els, false);
373
+ // Keep the active-profile control synchronized even when the deleted
374
+ // profile was not the active one and therefore did not change config.
375
+ if (typeof opts.updateUIFromConfig === 'function') opts.updateUIFromConfig();
376
+ const UISettings = getUISettings();
377
+ UISettings?.renderProfileMenu?.(els, Profiles?.list?.() || [], nextActiveId);
378
+ showProfileFeedback(els, t('msg_profile_deleted', { name: currentProfile.name }) || `Perfil "${currentProfile.name}" eliminado.`, 'success');
379
+ return true;
380
+ }
381
+ return false;
382
+ }
383
+
384
+ async function handleMenuNewProfile(elements, options = {}) {
385
+ const els = elements || cachedElements || {};
386
+ const opts = options || cachedOptions || {};
387
+ closeProfileMenu(els);
388
+ openNewProfileModal(els, opts);
389
+ return null;
390
+ }
391
+
392
+ async function requestNewProfileName(message) {
393
+ const Dialogs = getDialogs();
394
+ const Profiles = getProfiles();
395
+ const name = String((Dialogs?.prompt ? await Dialogs.prompt(message) : '') || '').trim();
396
+ if (!name) return null;
397
+ if (Profiles?.findByName?.(name)) {
398
+ showProfileFeedback(null, t('err_profile_name_exists', { name }) || `Ya existe un perfil llamado "${name}".`, 'error');
399
+ return null;
400
+ }
401
+ return name;
402
+ }
403
+
404
+ async function saveProfileRecord(elements, name, settings, description = '', options = {}) {
405
+ const Profiles = getProfiles();
406
+ const els = elements || cachedElements || {};
407
+ const opts = options || cachedOptions || {};
408
+ if (!Profiles?.saveEditable) return null;
409
+ const saved = await Profiles.saveEditable({
410
+ id: `profile:${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
411
+ name,
412
+ description,
413
+ settings: { ...settings, apiKey: '' }
414
+ });
415
+ populateProfileSelector(els, saved.id);
416
+ applyProfileToForm(els, saved.settings, saved.id, opts);
417
+ setSelectedProfileAsDefault(saved, opts);
418
+ setProfileQueryState(els, false);
419
+ return saved;
420
+ }
421
+
422
+ async function handleNewProfile(elements, options = {}) {
423
+ const els = elements || cachedElements || {};
424
+ const opts = options || cachedOptions || {};
425
+ const Profiles = getProfiles();
426
+ const name = await requestNewProfileName(t('prompt_new_profile_name') || 'Nombre del nuevo perfil:');
427
+ if (!name) return;
428
+ const defaultSettings = Profiles?.NEW_PROFILE_SETTINGS || { apiType: 'openai', apiUrl: 'http://localhost:1234/v1', model: '' };
429
+ const saved = await saveProfileRecord(els, name, defaultSettings, '', opts);
430
+ if (saved) showProfileFeedback(els, t('msg_profile_created', { name }) || `Perfil "${name}" creado.`, 'success');
431
+ }
432
+
433
+ async function handleExportProfiles(elements) {
434
+ const els = elements || cachedElements || {};
435
+ const ProfileBackup = getProfileBackup();
436
+ const ProfileExportBundle = getProfileExportBundle();
437
+ const Export = getExport();
438
+ const Profiles = getProfiles();
439
+ try {
440
+ if (!ProfileBackup?.encryptProfiles || !ProfileExportBundle?.generateExportHTML || !Export?.downloadFile || !Profiles?.list) {
441
+ throw new Error('La exportación de perfiles no está disponible.');
442
+ }
443
+ const profiles = Profiles.list().filter(profile => profile.id !== Profiles.READONLY_PROFILE_ID);
444
+
445
+ if (profiles.length === 0) {
446
+ showProfileFeedback(els, t('err_no_profiles_to_export') || 'No hay perfiles para exportar.', 'error');
447
+ return;
448
+ }
449
+
450
+ const encrypted = await ProfileBackup.encryptProfiles(profiles);
451
+ const date = new Date().toISOString().slice(0, 10);
452
+
453
+ // Generar HTML bundle con postMessage
454
+ const htmlBundle = ProfileExportBundle.generateExportHTML(encrypted, {
455
+ profileCount: profiles.length,
456
+ exportDate: date
457
+ });
458
+
459
+ // Descargar como HTML
460
+ if (!Export.downloadFile(htmlBundle, `zerochat_profiles_${date}.html`, 'text/html')) {
461
+ throw new Error('No se pudo descargar el archivo.');
462
+ }
463
+
464
+ showProfileFeedback(els, t('msg_profiles_exported_html') || 'Perfiles exportados. Abre el archivo HTML descargado para importarlos.', 'success');
465
+ } catch (error) {
466
+ showProfileFeedback(els, t('err_profiles_backup', { err: error?.message || t('notice_error') }), 'error');
467
+ }
468
+ }
469
+
470
+ function resetProfileFormToSelected(elements, options = {}) {
471
+ const els = elements || cachedElements || {};
472
+ const opts = options || cachedOptions || {};
473
+ const Profiles = getProfiles();
474
+ const Config = getConfig();
475
+ const runtimeConfig = opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {});
476
+ const selectedId = els.profileSelectHelper?.value || runtimeConfig.activeProfile?.id || '';
477
+ const profile = Profiles?.get ? Profiles.get(selectedId) : null;
478
+ applyProfileToForm(els, profile?.settings || runtimeConfig, selectedId, opts);
479
+ if (els.serverQueryStatus) els.serverQueryStatus.style.display = 'none';
480
+ if (els.profileActionFeedback) els.profileActionFeedback.style.display = 'none';
481
+ setProfileQueryState(els, false);
482
+ }
483
+
484
+ function openNewProfileModal(elements, options = {}) {
485
+ const els = elements || cachedElements || {};
486
+ const opts = options || cachedOptions || {};
487
+ closeProfileMenu(els);
488
+ if (typeof opts.closeSettingsModal === 'function') opts.closeSettingsModal();
489
+
490
+ const Profiles = getProfiles();
491
+ const defaultSettings = Profiles?.NEW_PROFILE_SETTINGS || { apiType: 'openai', apiUrl: 'http://localhost:1234/v1', model: '' };
492
+
493
+ if (els.profilesDialog) {
494
+ els.profilesDialog.dataset.profileId = '';
495
+ els.profilesDialog.dataset.profileLocked = 'false';
496
+ els.profilesDialog.dataset.isNew = 'true';
497
+ }
498
+ if (els.profileSelectHelper) {
499
+ els.profileSelectHelper.value = '';
500
+ }
501
+
502
+ applyProfileToForm(els, defaultSettings, '', opts);
503
+ if (els.settingProfileName) els.settingProfileName.value = '';
504
+ if (els.settingProfileDescription) els.settingProfileDescription.value = '';
505
+ if (els.settingApiKey) {
506
+ els.settingApiKey.value = '';
507
+ els.settingApiKey._loadedApiKey = '';
508
+ }
509
+ if (els.settingApiKeyLocked) els.settingApiKeyLocked.checked = false;
510
+
511
+ if (els.serverQueryStatus) els.serverQueryStatus.style.display = 'none';
512
+ if (els.profileActionFeedback) els.profileActionFeedback.style.display = 'none';
513
+ setProfileQueryState(els, false);
514
+ setProfileDirty(els, false);
515
+
516
+ const UISettings = getUISettings();
517
+ UISettings?.syncProviderFields?.(els);
518
+ UISettings?.syncApiKeyLock?.(els, false);
519
+
520
+ if (typeof opts.loadCachedModels === 'function') opts.loadCachedModels();
521
+ syncProfileSaveState(els, opts);
522
+
523
+ if (els.profilesDialog && !els.profilesDialog.open) {
524
+ if (typeof els.profilesDialog.showModal === 'function') {
525
+ els.profilesDialog.showModal();
526
+ } else {
527
+ els.profilesDialog.style.display = 'block';
528
+ }
529
+ }
530
+ els.settingProfileName?.focus?.();
531
+ }
532
+
533
+ function openProfilesModal(elements, options = {}, targetProfileId = null) {
534
+ const els = elements || cachedElements || {};
535
+ const opts = options || cachedOptions || {};
536
+ closeProfileMenu(els);
537
+ if (typeof opts.closeSettingsModal === 'function') opts.closeSettingsModal();
538
+
539
+ if (targetProfileId === '__new__') {
540
+ openNewProfileModal(els, opts);
541
+ return;
542
+ }
543
+
544
+ const Config = getConfig();
545
+ const Profiles = getProfiles();
546
+ const runtimeConfig = opts.getRuntimeConfig ? opts.getRuntimeConfig() : (Config?.getActive?.() || {});
547
+ const activeId = targetProfileId || runtimeConfig.activeProfile?.id || '';
548
+ if (els.profilesDialog) {
549
+ els.profilesDialog.dataset.profileId = activeId;
550
+ delete els.profilesDialog.dataset.isNew;
551
+ }
552
+ populateProfileSelector(els, activeId);
553
+ const activeProfile = Profiles?.get ? Profiles.get(activeId) : null;
554
+ applyProfileToForm(els, activeProfile?.settings || runtimeConfig, activeId, opts);
555
+ if (els.serverQueryStatus) els.serverQueryStatus.style.display = 'none';
556
+ if (els.profileActionFeedback) els.profileActionFeedback.style.display = 'none';
557
+ setProfileQueryState(els, false);
558
+ setProfileDirty(els, false);
559
+ if (typeof opts.loadCachedModels === 'function') opts.loadCachedModels();
560
+ syncProfileSaveState(els, opts);
561
+ if (els.profilesDialog && !els.profilesDialog.open) {
562
+ if (typeof els.profilesDialog.showModal === 'function') {
563
+ els.profilesDialog.showModal();
564
+ } else {
565
+ els.profilesDialog.style.display = 'block';
566
+ }
567
+ }
568
+ }
569
+
570
+ let isClosingProfilesModal = false;
571
+
572
+ async function closeProfilesModal(elements, force = false, options = {}) {
573
+ const els = elements || cachedElements || {};
574
+ const opts = options || cachedOptions || {};
575
+ if (!els.profilesDialog?.open) return;
576
+ if (isClosingProfilesModal) return false;
577
+ const Dialogs = getDialogs();
578
+
579
+ const hasUnsavedQuery = isProfileQueryReady(els);
580
+ const hasUnsavedChanges = force ? false : isProfileFormDirty(els, opts);
581
+
582
+ if (!force && (hasUnsavedQuery || hasUnsavedChanges)) {
583
+ isClosingProfilesModal = true;
584
+ try {
585
+ const msgKey = hasUnsavedQuery ? 'confirm_profile_query_not_saved' : 'confirm_profile_unsaved_changes';
586
+ const discard = Dialogs?.confirm ? await Dialogs.confirm(t(msgKey)) : true;
587
+ if (!discard) {
588
+ els.btnSaveProfile?.focus?.();
589
+ return false;
590
+ }
591
+ } finally {
592
+ isClosingProfilesModal = false;
593
+ }
594
+ }
595
+ setProfileQueryState(els, false);
596
+ setProfileDirty(els, false);
597
+ resetProfileFormToSelected(els, opts);
598
+ if (typeof els.profilesDialog.close === 'function') {
599
+ els.profilesDialog.close();
600
+ } else {
601
+ els.profilesDialog.style.display = 'none';
602
+ }
603
+ return true;
604
+ }
605
+
606
+ function mount({ elements, getRuntimeConfig, updateUIFromConfig, loadCachedModels, resetTelemetryDisplay, closeSettingsModal, readFileAsText } = {}) {
607
+ dispose();
608
+ cachedElements = elements || {};
609
+ cachedOptions = { getRuntimeConfig, updateUIFromConfig, loadCachedModels, resetTelemetryDisplay, closeSettingsModal, readFileAsText };
610
+
611
+ const els = cachedElements;
612
+
613
+ if (els.profilesDialog) {
614
+ const onCancel = (e) => {
615
+ e.preventDefault();
616
+ closeProfilesModal(els, false, cachedOptions);
617
+ };
618
+ els.profilesDialog.addEventListener('cancel', onCancel);
619
+ activeCleanupFns.push(() => els.profilesDialog.removeEventListener('cancel', onCancel));
620
+
621
+ const onModify = (e) => {
622
+ if (e && (e.target === els.profileSelectHelper || e.target === els.profilesImportInput)) return;
623
+ setProfileDirty(els, true);
624
+ syncProfileSaveState(els, cachedOptions);
625
+ };
626
+ els.profilesDialog.addEventListener('input', onModify);
627
+ els.profilesDialog.addEventListener('change', onModify);
628
+ activeCleanupFns.push(() => els.profilesDialog.removeEventListener('input', onModify));
629
+ activeCleanupFns.push(() => els.profilesDialog.removeEventListener('change', onModify));
630
+ }
631
+
632
+ if (els.profileSelectHelper) {
633
+ const onChange = () => {
634
+ const selectedId = els.profileSelectHelper.value;
635
+ const Profiles = getProfiles();
636
+ const profile = Profiles?.get ? Profiles.get(selectedId) : null;
637
+ if (profile) {
638
+ applyProfileToForm(els, profile.settings, profile.id, cachedOptions);
639
+ if (els.settingProfileName) els.settingProfileName.value = profile.name;
640
+ if (els.settingProfileDescription) els.settingProfileDescription.value = profile.description || '';
641
+ }
642
+ setProfileQueryState(els, false);
643
+ };
644
+ els.profileSelectHelper.addEventListener('change', onChange);
645
+ activeCleanupFns.push(() => els.profileSelectHelper.removeEventListener('change', onChange));
646
+ }
647
+
648
+ if (els.settingProfileName) {
649
+ const onChange = () => syncProfileSaveState(els, cachedOptions);
650
+ els.settingProfileName.addEventListener('change', onChange);
651
+ els.settingProfileName.addEventListener('input', onChange);
652
+ activeCleanupFns.push(() => {
653
+ els.settingProfileName.removeEventListener('change', onChange);
654
+ els.settingProfileName.removeEventListener('input', onChange);
655
+ });
656
+ }
657
+
658
+ if (els.settingApiType) {
659
+ const onChange = () => {
660
+ setProfileQueryState(els, false);
661
+ const UISettings = getUISettings();
662
+ const Providers = getProviders();
663
+ const val = els.settingApiType.value;
664
+ const currentUrl = els.settingApiUrl ? els.settingApiUrl.value.trim() : '';
665
+ const knownEndpoints = Providers?.registry?.getConnectionEndpoints?.() || [];
666
+ const isDefaultOrEmpty = !currentUrl || knownEndpoints.includes(currentUrl);
667
+ if (isDefaultOrEmpty && els.settingApiUrl) {
668
+ const endpoint = Providers?.registry?.get?.(val)?.getConnectionConfig?.().endpoint;
669
+ if (endpoint) els.settingApiUrl.value = endpoint;
670
+ }
671
+ UISettings?.syncProviderFields?.(els);
672
+ if (typeof cachedOptions?.loadCachedModels === 'function') {
673
+ cachedOptions.loadCachedModels();
674
+ }
675
+ syncProfileSaveState(els, cachedOptions);
676
+ };
677
+ els.settingApiType.addEventListener('change', onChange);
678
+ activeCleanupFns.push(() => els.settingApiType.removeEventListener('change', onChange));
679
+ }
680
+
681
+ if (els.modelSelectHelper) {
682
+ const onChange = () => {
683
+ if (els.settingModel) {
684
+ els.settingModel.value = els.modelSelectHelper.value;
685
+ syncProfileSaveState(els, cachedOptions);
686
+ }
687
+ };
688
+ els.modelSelectHelper.addEventListener('change', onChange);
689
+ activeCleanupFns.push(() => els.modelSelectHelper.removeEventListener('change', onChange));
690
+ }
691
+
692
+ if (els.settingModel) {
693
+ const onInput = () => syncProfileSaveState(els, cachedOptions);
694
+ els.settingModel.addEventListener('input', onInput);
695
+ activeCleanupFns.push(() => els.settingModel.removeEventListener('input', onInput));
696
+ }
697
+
698
+ if (els.btnSaveProfile) {
699
+ const onClick = () => handleSaveProfile(els, cachedOptions);
700
+ els.btnSaveProfile.addEventListener('click', onClick);
701
+ activeCleanupFns.push(() => els.btnSaveProfile.removeEventListener('click', onClick));
702
+ }
703
+
704
+ if (els.btnDeleteProfile) {
705
+ const onClick = () => handleDeleteProfile(els, cachedOptions);
706
+ els.btnDeleteProfile.addEventListener('click', onClick);
707
+ activeCleanupFns.push(() => els.btnDeleteProfile.removeEventListener('click', onClick));
708
+ }
709
+
710
+ if (els.btnNewProfile) {
711
+ const onClick = () => handleNewProfile(els, cachedOptions);
712
+ els.btnNewProfile.addEventListener('click', onClick);
713
+ activeCleanupFns.push(() => els.btnNewProfile.removeEventListener('click', onClick));
714
+ }
715
+
716
+ if (els.btnExportProfiles) {
717
+ const onClick = () => handleExportProfiles(els);
718
+ els.btnExportProfiles.addEventListener('click', onClick);
719
+ activeCleanupFns.push(() => els.btnExportProfiles.removeEventListener('click', onClick));
720
+ }
721
+
722
+ if (els.btnCloseProfiles) {
723
+ const onClick = () => closeProfilesModal(els, false, cachedOptions);
724
+ els.btnCloseProfiles.addEventListener('click', onClick);
725
+ activeCleanupFns.push(() => els.btnCloseProfiles.removeEventListener('click', onClick));
726
+ }
727
+
728
+ if (els.btnCancelProfiles) {
729
+ const onClick = () => closeProfilesModal(els, false, cachedOptions);
730
+ els.btnCancelProfiles.addEventListener('click', onClick);
731
+ activeCleanupFns.push(() => els.btnCancelProfiles.removeEventListener('click', onClick));
732
+ }
733
+
734
+ if (els.activeProfileTrigger) {
735
+ const onClick = (e) => {
736
+ e.stopPropagation();
737
+ const isOpen = els.activeProfilePopover && !els.activeProfilePopover.hidden;
738
+ if (isOpen) closeProfileMenu(els);
739
+ else openProfileMenu(els, cachedOptions);
740
+ };
741
+ els.activeProfileTrigger.addEventListener('click', onClick);
742
+ activeCleanupFns.push(() => els.activeProfileTrigger.removeEventListener('click', onClick));
743
+ }
744
+
745
+ if (els.btnEditProfiles) {
746
+ const onClick = () => {
747
+ closeProfileMenu(els);
748
+ openProfilesModal(els, cachedOptions);
749
+ };
750
+ els.btnEditProfiles.addEventListener('click', onClick);
751
+ activeCleanupFns.push(() => els.btnEditProfiles.removeEventListener('click', onClick));
752
+ }
753
+
754
+ if (els.btnMenuNewProfile) {
755
+ const onClick = () => handleMenuNewProfile(els, cachedOptions);
756
+ els.btnMenuNewProfile.addEventListener('click', onClick);
757
+ activeCleanupFns.push(() => els.btnMenuNewProfile.removeEventListener('click', onClick));
758
+ }
759
+
760
+ if (els.btnMenuExportProfiles) {
761
+ const onClick = () => handleExportProfiles(els);
762
+ els.btnMenuExportProfiles.addEventListener('click', onClick);
763
+ activeCleanupFns.push(() => els.btnMenuExportProfiles.removeEventListener('click', onClick));
764
+ }
765
+
766
+ if (els.btnMenuCloseProfiles) {
767
+ const onClick = () => closeProfileMenu(els);
768
+ els.btnMenuCloseProfiles.addEventListener('click', onClick);
769
+ activeCleanupFns.push(() => els.btnMenuCloseProfiles.removeEventListener('click', onClick));
770
+ }
771
+
772
+ return {
773
+ populateProfileSelector: (name) => populateProfileSelector(els, name),
774
+ applyProfileToForm: (data, id) => applyProfileToForm(els, data, id, cachedOptions),
775
+ syncProfileSaveState: () => syncProfileSaveState(els, cachedOptions),
776
+ isProfileFormDirty: () => isProfileFormDirty(els),
777
+ setProfileDirty: (dirty) => setProfileDirty(els, dirty),
778
+ openProfilesModal: (targetId) => openProfilesModal(els, cachedOptions, targetId),
779
+ openNewProfileModal: () => openNewProfileModal(els, cachedOptions),
780
+ closeProfilesModal: (force) => closeProfilesModal(els, force, cachedOptions),
781
+ handleSaveProfile: () => handleSaveProfile(els, cachedOptions),
782
+ handleDeleteProfile: () => handleDeleteProfile(els, cachedOptions),
783
+ handleDeleteProfileById: (id) => handleDeleteProfileById(id, els, cachedOptions),
784
+ handleNewProfile: () => handleNewProfile(els, cachedOptions),
785
+ handleMenuNewProfile: () => handleMenuNewProfile(els, cachedOptions)
786
+ };
787
+ }
788
+
789
+ function dispose() {
790
+ activeCleanupFns.forEach(fn => { try { fn(); } catch (_) {} });
791
+ activeCleanupFns = [];
792
+ cachedElements = null;
793
+ cachedOptions = {};
794
+ }
795
+
796
+ return {
797
+ populateProfileSelector,
798
+ applyProfileToForm,
799
+ syncProfileSaveState,
800
+ canSaveProfile,
801
+ isProfileFormDirty,
802
+ setProfileDirty,
803
+ isProfileQueryReady,
804
+ setProfileQueryState,
805
+ openProfilesModal,
806
+ openNewProfileModal,
807
+ closeProfilesModal,
808
+ resetProfileFormToSelected,
809
+ handleSaveProfile,
810
+ handleDeleteProfile,
811
+ handleDeleteProfileById,
812
+ handleNewProfile,
813
+ handleMenuNewProfile,
814
+ handleExportProfiles,
815
+ openProfileMenu,
816
+ closeProfileMenu,
817
+ setProfileMenuOpen,
818
+ activateConnectionProfile,
819
+ setSelectedProfileAsDefault,
820
+ isDownloadedWebLLMModel,
821
+ mount,
822
+ dispose
823
+ };
824
+ }));