qalita 2.3.1__py3-none-any.whl → 2.3.2__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.
qalita/internal/utils.py CHANGED
@@ -14,7 +14,7 @@ logger = init_logging()
14
14
 
15
15
 
16
16
  def get_version():
17
- return "2.3.1"
17
+ return "2.3.2"
18
18
 
19
19
 
20
20
  def make_tarfile(output_filename, source_dir):
@@ -111,6 +111,17 @@ def _augment_prompt_with_context(prompt: str, issue_id: str | None, source_id: s
111
111
  return meta + base
112
112
 
113
113
 
114
+ def _cloud_enabled() -> bool:
115
+ """Return whether Studio cloud providers are enabled via env flag.
116
+
117
+ Env: QALITA_STUDIO_ENABLE_CLOUD = 1|true|yes|on to enable. Default: disabled.
118
+ """
119
+ try:
120
+ raw = str(os.getenv("QALITA_STUDIO_ENABLE_CLOUD", "0") or "").strip().lower()
121
+ return raw in ("1", "true", "yes", "on")
122
+ except Exception:
123
+ return False
124
+
114
125
  def _studio_conv_dir() -> str:
115
126
  """Return the conversations directory, ensuring it exists."""
116
127
  root = _qalita_home()
@@ -261,8 +272,16 @@ def studio_status():
261
272
  current_provider = next(iter(data["providers"].keys()))
262
273
  except Exception:
263
274
  current_provider = None
275
+ # Enforce local-only when cloud is disabled
276
+ if not _cloud_enabled() and current_provider and current_provider != "local":
277
+ current_provider = "local"
264
278
  return jsonify(
265
- {"configured": exists, "config": data, "current_provider": current_provider}
279
+ {
280
+ "configured": exists,
281
+ "config": data,
282
+ "current_provider": current_provider,
283
+ "cloud_enabled": _cloud_enabled(),
284
+ }
266
285
  )
267
286
 
268
287
 
@@ -294,6 +313,15 @@ def studio_save_config():
294
313
  )
295
314
  set_current = bool(payload.get("set_current"))
296
315
  if provider and conf is not None:
316
+ # Block saving non-local provider when cloud is disabled
317
+ if provider != "local" and not _cloud_enabled():
318
+ return (
319
+ jsonify({
320
+ "ok": False,
321
+ "message": "Cloud providers are disabled. Set QALITA_STUDIO_ENABLE_CLOUD=1 to enable.",
322
+ }),
323
+ 403,
324
+ )
297
325
  providers[provider] = conf
298
326
  if set_current:
299
327
  current["current_provider"] = provider
@@ -367,11 +395,14 @@ def list_providers():
367
395
  {"id": "claude", "name": "Claude", "logo": "/static/sources-logos/api.svg"},
368
396
  {"id": "gemini", "name": "Gemini", "logo": "/static/sources-logos/api.svg"},
369
397
  ]
398
+ if not _cloud_enabled():
399
+ available = [it for it in available if it.get("id") == "local"]
370
400
  return jsonify(
371
401
  {
372
402
  "available": available,
373
403
  "current": current,
374
404
  "configs": providers,
405
+ "cloud_enabled": _cloud_enabled(),
375
406
  }
376
407
  )
377
408
 
@@ -383,6 +414,14 @@ def check_remote():
383
414
  Body: { "provider": "openai"|"mistral", "api_key": "...", "model": "..." }
384
415
  Returns: { ok: bool, message?: str, provider: str }
385
416
  """
417
+ if not _cloud_enabled():
418
+ return (
419
+ jsonify({
420
+ "ok": False,
421
+ "message": "Cloud providers are disabled. Set QALITA_STUDIO_ENABLE_CLOUD=1 to enable.",
422
+ }),
423
+ 403,
424
+ )
386
425
  data = request.get_json(silent=True) or {}
387
426
  provider = (data.get("provider") or "").strip().lower()
388
427
  api_key = (data.get("api_key") or "").strip()
@@ -311,6 +311,8 @@
311
311
  const r = await fetch('/studio/status');
312
312
  const j = await r.json();
313
313
  lastStatus = j;
314
+ // Rebuild provider options depending on cloud flag
315
+ setProviderOptions(!!j.cloud_enabled);
314
316
  const current = j.current_provider || 'local';
315
317
  if (providerSelect) providerSelect.value = current;
316
318
  updateProviderUI(current, j);
@@ -410,6 +412,38 @@
410
412
  } catch (e) { if (msg) msg.textContent = 'Connectivity failed'; }
411
413
  }
412
414
 
415
+ function setProviderOptions(cloudEnabled) {
416
+ try {
417
+ if (!providerSelect) return;
418
+ // Desired list depending on cloud flag
419
+ var desired = cloudEnabled ? [
420
+ { v: 'local', t: 'Ollama' },
421
+ { v: 'openai', t: 'ChatGPT' },
422
+ { v: 'mistral', t: 'Mistral' },
423
+ { v: 'claude', t: 'Claude' },
424
+ { v: 'gemini', t: 'Gemini' }
425
+ ] : [
426
+ { v: 'local', t: 'Ollama' }
427
+ ];
428
+ // If options already match, skip rebuild (lightweight check by values set)
429
+ var currentValues = Array.prototype.map.call(providerSelect.options || [], function (o) { return o && o.value; });
430
+ var desiredValues = desired.map(function (d) { return d.v; });
431
+ var equal = currentValues.length === desiredValues.length && currentValues.every(function (v, i) { return v === desiredValues[i]; });
432
+ if (!equal) {
433
+ providerSelect.innerHTML = '';
434
+ desired.forEach(function (d) {
435
+ var opt = document.createElement('option');
436
+ opt.value = d.v; opt.textContent = d.t;
437
+ providerSelect.appendChild(opt);
438
+ });
439
+ }
440
+ // Force selection to local if cloud is disabled
441
+ if (!cloudEnabled) {
442
+ providerSelect.value = 'local';
443
+ }
444
+ } catch (e) { /* noop */ }
445
+ }
446
+
413
447
  function updateProviderUI(provider, statusObj) {
414
448
  // Update logo
415
449
  let src = '/static/ollama.png';
@@ -421,15 +455,29 @@
421
455
  if (providerLogoInline) { providerLogoInline.src = src; providerLogoInline.alt = alt; }
422
456
  if (providerLogoRemote) { providerLogoRemote.src = src; providerLogoRemote.alt = alt; }
423
457
  // Toggle setup cards
458
+ var cloudEnabled = !!(statusObj && statusObj.cloud_enabled);
459
+ if (provider !== 'local' && !cloudEnabled) {
460
+ // Force local UI when cloud disabled
461
+ provider = 'local';
462
+ if (providerSelect) providerSelect.value = 'local';
463
+ }
424
464
  if (provider === 'local') {
425
465
  const isConfigured = !!(statusObj && statusObj.configured);
426
466
  elOnboarding.style.display = isConfigured ? 'none' : 'block';
427
467
  elRemote.style.display = 'none';
428
468
  elChat.style.display = isConfigured ? 'block' : 'none';
429
469
  } else {
430
- elOnboarding.style.display = 'none';
431
- elRemote.style.display = 'block';
432
- elChat.style.display = 'none';
470
+ // Only show remote setup when cloud is enabled
471
+ if (cloudEnabled) {
472
+ elOnboarding.style.display = 'none';
473
+ elRemote.style.display = 'block';
474
+ elChat.style.display = 'none';
475
+ } else {
476
+ const isConfigured = !!(statusObj && statusObj.configured);
477
+ elOnboarding.style.display = isConfigured ? 'none' : 'block';
478
+ elRemote.style.display = 'none';
479
+ elChat.style.display = isConfigured ? 'block' : 'none';
480
+ }
433
481
  }
434
482
  // Toggle provider-specific help
435
483
  const h11 = document.getElementById('help_openai_1');
@@ -440,14 +488,16 @@
440
488
  const c12 = document.getElementById('help_claude_2');
441
489
  const g11 = document.getElementById('help_gemini_1');
442
490
  const g12 = document.getElementById('help_gemini_2');
443
- if (h11) h11.style.display = provider === 'openai' ? '' : 'none';
444
- if (h12) h12.style.display = provider === 'openai' ? '' : 'none';
445
- if (h21) h21.style.display = provider === 'mistral' ? '' : 'none';
446
- if (h22) h22.style.display = provider === 'mistral' ? '' : 'none';
447
- if (c11) c11.style.display = provider === 'claude' ? '' : 'none';
448
- if (c12) c12.style.display = provider === 'claude' ? '' : 'none';
449
- if (g11) g11.style.display = provider === 'gemini' ? '' : 'none';
450
- if (g12) g12.style.display = provider === 'gemini' ? '' : 'none';
491
+ var showHelp = function (cond) { return cond ? '' : 'none'; };
492
+ var allowRemoteHelp = cloudEnabled;
493
+ if (h11) h11.style.display = allowRemoteHelp && provider === 'openai' ? '' : 'none';
494
+ if (h12) h12.style.display = allowRemoteHelp && provider === 'openai' ? '' : 'none';
495
+ if (h21) h21.style.display = allowRemoteHelp && provider === 'mistral' ? '' : 'none';
496
+ if (h22) h22.style.display = allowRemoteHelp && provider === 'mistral' ? '' : 'none';
497
+ if (c11) c11.style.display = allowRemoteHelp && provider === 'claude' ? '' : 'none';
498
+ if (c12) c12.style.display = allowRemoteHelp && provider === 'claude' ? '' : 'none';
499
+ if (g11) g11.style.display = allowRemoteHelp && provider === 'gemini' ? '' : 'none';
500
+ if (g12) g12.style.display = allowRemoteHelp && provider === 'gemini' ? '' : 'none';
451
501
  }
452
502
 
453
503
  // --- Source pre-prompt helpers ---
@@ -717,7 +767,14 @@
717
767
  btnSave && btnSave.addEventListener('click', saveStudio);
718
768
  (document.getElementById('btn_save_remote')) && document.getElementById('btn_save_remote').addEventListener('click', saveRemote);
719
769
  (document.getElementById('btn_check_remote')) && document.getElementById('btn_check_remote').addEventListener('click', checkRemote);
720
- providerSelect && providerSelect.addEventListener('change', function () { updateProviderUI(providerSelect.value, lastStatus); });
770
+ providerSelect && providerSelect.addEventListener('change', function () {
771
+ try {
772
+ var cloudEnabled = !!(lastStatus && lastStatus.cloud_enabled);
773
+ var target = cloudEnabled ? providerSelect.value : 'local';
774
+ if (providerSelect.value !== target) providerSelect.value = target;
775
+ updateProviderUI(target, lastStatus);
776
+ } catch (e) { updateProviderUI('local', lastStatus); }
777
+ });
721
778
  send && send.addEventListener('click', sendMessage);
722
779
  stop && stop.addEventListener('click', function () { if (streamingController) { try { streamingController.abort(); } catch (e) { } } });
723
780
  input && input.addEventListener('keydown', function (e) { if (e.key === 'Enter') sendMessage(); });
@@ -747,6 +804,8 @@
747
804
  });
748
805
 
749
806
  renderAgentTabs();
807
+ // Default to local-only providers until status says otherwise
808
+ try { setProviderOptions(false); } catch (e) { }
750
809
  refreshStatus();
751
810
  checkOllama();
752
811
  // Load conversation if present in URL
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qalita
3
- Version: 2.3.1
3
+ Version: 2.3.2
4
4
  Summary: QALITA Platform Command Line Interface
5
5
  License-File: LICENSE
6
6
  Author: QALITA SAS
@@ -9,7 +9,7 @@ qalita/internal/config.py,sha256=P9UU3BH-CIH68-qZjmnk8juzZZ5HJ701hrY6EvrPFOA,408
9
9
  qalita/internal/error_patterns.py,sha256=QDFNZEoTmqVOHkiGFljstY6VOhux7d4p8FIL3pKzwtQ,1447
10
10
  qalita/internal/logger.py,sha256=4xWy2BZII89nUw4tKrLXFPOlVGONm8KUBgzX2XZ3u7g,1868
11
11
  qalita/internal/request.py,sha256=s-rE9kKRhV9IEveclB2YjAY8FRevKb6qjblM8-PbV20,6209
12
- qalita/internal/utils.py,sha256=UIXH_BS2ZiP0crARISYHuJMnvajaTSHchpXoP_sZXXs,5746
12
+ qalita/internal/utils.py,sha256=JUrdNlEEbxiBofwIKXnsfV4znIQFfNuj2DgvnsCaSIs,5746
13
13
  qalita/web/__init__.py,sha256=NRcQjZSizkqN0a-LutsN7X9LBQ8MhyazXBSuqzUEmXE,62
14
14
  qalita/web/app.py,sha256=92M2K7vxDIYaI81D-zvdj4VfCsaTTDs6KJZu6dy5s6U,1323
15
15
  qalita/web/blueprints/agents.py,sha256=q_SqdSzzHMsstSzEjHGtq75jFt3wQ6p3atjOSzKgiUw,17367
@@ -17,7 +17,7 @@ qalita/web/blueprints/context.py,sha256=wIcfBtu3l9qwMe5IPa0VQShELsY3ENPt4Q9OO3L8
17
17
  qalita/web/blueprints/dashboard.py,sha256=R_1_oAM-Ol0kx5GZkKTaB8c5vjdz-iIK-SGu2RIHE_w,7454
18
18
  qalita/web/blueprints/helpers.py,sha256=Hnulyrd-YrHoz2LtGCKCq9MgUeoNoNECTyGDap2DFYI,12724
19
19
  qalita/web/blueprints/sources.py,sha256=NqwvzrH9QHARfaXy4ycUXSYpIA8ZkeZULo5-UWOVTWk,34926
20
- qalita/web/blueprints/studio.py,sha256=6anwRTVOONkKI7Z3dngxUKSsf38H1nc47hrTSZ-dzoE,49224
20
+ qalita/web/blueprints/studio.py,sha256=FRsFed38akzccJFLi8Ki85bBECqc_HN99AYhApdSlIo,50656
21
21
  qalita/web/public/chatgpt.svg,sha256=pmuiRfxoZ3rhpHpfcm1g1pHkyNWUICgyjcK-s7jOtNw,1739
22
22
  qalita/web/public/claude.png,sha256=6ZIrc9WcQ3Wh7ef9nGbVMAwZrsVzmSXoFl34PlbOpdU,1953
23
23
  qalita/web/public/favicon.ico,sha256=K0TYoueuDhQ32R3UXXNI31c701EiJ6TpPy7ieb6iXf8,2549
@@ -89,13 +89,13 @@ qalita/web/templates/navbar.html,sha256=W0eBuH_vrs4GyxkSzxsppOchkgtvnKM-uc07mP5m
89
89
  qalita/web/templates/sources/added.html,sha256=uTu5jofRi9t9pvWRnc9AtD9B396DvnqDo6HoajVU3DA,1938
90
90
  qalita/web/templates/sources/edit.html,sha256=DM5i3Y__MMG0PzJm--OXQSo5PbI4fcRo4UYHm2qGMxA,19723
91
91
  qalita/web/templates/sources/select-source.html,sha256=dBTEpCu8KTjmiOG_gBIUFEdGAnGmnV8EFQid7chsVA0,6179
92
- qalita/web/templates/studio/agent-panel.html,sha256=cc_zcUgkQHwxBz2_Nkvw3BCO3L_zhQDcrnp0woMwI_A,38790
92
+ qalita/web/templates/studio/agent-panel.html,sha256=Ygt2PKee1kaJrVs2-TP_-ClyEr3ACb5kdL1-j4PglNY,41521
93
93
  qalita/web/templates/studio/context-panel.html,sha256=M8yfYcJQ_2WSwnOLlCTQETzctzL-rjlKLF7PlAUV0PU,15312
94
94
  qalita/web/templates/studio/index.html,sha256=NI7zF-4cHQ3id-a_R3GNQ8gQ2Bw4A6liyEZ53AO0QOU,2823
95
95
  qalita/web/templates/studio/navbar.html,sha256=IQZ7TFOXv3r5yZmP9f1v7BMUCQU8mOajMV82UPeY3cg,746
96
96
  qalita/web/templates/studio/view-panel.html,sha256=JREfFIabpuAZctAzbE_mT_ZDk65MBWevjRNxQUrO8Pw,25198
97
- qalita-2.3.1.dist-info/METADATA,sha256=q5Rw3NHpPohDXswrcEnGPTXDc5-GwrtbCMvlOtx1_EY,2412
98
- qalita-2.3.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
99
- qalita-2.3.1.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
100
- qalita-2.3.1.dist-info/licenses/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
101
- qalita-2.3.1.dist-info/RECORD,,
97
+ qalita-2.3.2.dist-info/METADATA,sha256=VfFB9CwnPeo2GCc4VnUNuVShaARGGVvH-Tzun32rBkU,2412
98
+ qalita-2.3.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
99
+ qalita-2.3.2.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
100
+ qalita-2.3.2.dist-info/licenses/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
101
+ qalita-2.3.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any