syntaxmatrix 2.6.1__py3-none-any.whl → 2.6.3__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.
@@ -757,17 +757,16 @@ def agentic_generate_page(*,
757
757
 
758
758
  if provider == "openai":
759
759
  if int(model.split("gpt-")[1][0])>=5:
760
+
760
761
  response = client.responses.create(
761
- model=model,
762
- instructions=system_prompt,
762
+ model=model,
763
+ instructions=system_prompt,
763
764
  input=[
764
765
  {"role": "user", "content": user_prompt}
765
766
  ],
766
767
  reasoning={"effort": "medium"},
767
- text=[
768
- {"verbosity": "low"},
769
- {"format": {"type": "json_object"}}
770
- ],
768
+ # IMPORTANT: 'text' must be an object (not a list)
769
+ text={"format": {"type": "json_object"}},
771
770
  )
772
771
 
773
772
  txt = (response.output_text or "")
syntaxmatrix/core.py CHANGED
@@ -115,11 +115,12 @@ class SyntaxMUI:
115
115
  self.coder_profile = {}
116
116
  self.imagetexter_profile = {}
117
117
  self.textimager_profile = {}
118
- self.imagereditor_profile = {}
118
+ self.imageeditor_profile = {}
119
119
 
120
120
  self._gpt_models_latest_prev_resp_ids = {}
121
121
  self.is_streaming = False
122
122
  self.stream_args = {}
123
+ self._apply_feature_flags_from_db()
123
124
 
124
125
  self._recent_visual_summaries = []
125
126
 
@@ -329,6 +330,24 @@ class SyntaxMUI:
329
330
 
330
331
  def enable_registration(self):
331
332
  self.registration_enabled = True
333
+
334
+ def _apply_feature_flags_from_db(self):
335
+ """
336
+ Pull persisted toggles from app_settings.
337
+ """
338
+ def _truthy(v):
339
+ return str(v or "").strip().lower() in ("1", "true", "yes", "on")
340
+
341
+ try:
342
+ stream_v = db.get_setting("feature.stream_mode", "0")
343
+ user_files_v = db.get_setting("feature.user_files", "0")
344
+
345
+ self.is_streaming = _truthy(stream_v)
346
+ self.user_files_enabled = _truthy(user_files_v)
347
+ except Exception:
348
+ # Keep defaults if DB isn't ready for any reason
349
+ pass
350
+
332
351
 
333
352
  @staticmethod
334
353
  def columns(components):
syntaxmatrix/db.py CHANGED
@@ -68,6 +68,14 @@ def init_db():
68
68
  )
69
69
  """)
70
70
 
71
+ conn.execute("""
72
+ CREATE TABLE IF NOT EXISTS app_settings (
73
+ key TEXT PRIMARY KEY,
74
+ value TEXT NOT NULL,
75
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
76
+ )
77
+ """)
78
+
71
79
  conn.commit()
72
80
  conn.close()
73
81
 
@@ -447,7 +455,7 @@ def get_page_layout(page_name: str) -> dict | None:
447
455
 
448
456
 
449
457
  def _init_media_assets_table() -> None:
450
- import sqlite3
458
+
451
459
  conn = sqlite3.connect(DB_PATH)
452
460
  try:
453
461
  with conn:
@@ -495,7 +503,7 @@ def upsert_media_asset(
495
503
  if not rel_path:
496
504
  return
497
505
  _init_media_assets_table()
498
- import sqlite3
506
+
499
507
  conn = sqlite3.connect(DB_PATH)
500
508
  try:
501
509
  with conn:
@@ -564,3 +572,39 @@ def get_media_asset_by_rel_path(rel_path: str) -> dict | None:
564
572
  }
565
573
  finally:
566
574
  conn.close()
575
+
576
+ # ***************************************
577
+ # App Settings Helpers (feature toggles)
578
+ # ***************************************
579
+ def set_setting(key: str, value: str) -> None:
580
+ if not key:
581
+ return
582
+ key = key.strip()
583
+ value = "" if value is None else str(value)
584
+ conn = sqlite3.connect(DB_PATH)
585
+ try:
586
+ with conn:
587
+ conn.execute(
588
+ """
589
+ INSERT INTO app_settings (key, value, updated_at)
590
+ VALUES (?, ?, CURRENT_TIMESTAMP)
591
+ ON CONFLICT(key) DO UPDATE SET
592
+ value = excluded.value,
593
+ updated_at = CURRENT_TIMESTAMP
594
+ """,
595
+ (key, value),
596
+ )
597
+ finally:
598
+ conn.close()
599
+
600
+
601
+ def get_setting(key: str, default: str | None = None) -> str | None:
602
+ if not key:
603
+ return default
604
+ key = key.strip()
605
+ conn = sqlite3.connect(DB_PATH)
606
+ try:
607
+ row = conn.execute("SELECT value FROM app_settings WHERE key = ?", (key,)).fetchone()
608
+ return row[0] if row else default
609
+ finally:
610
+ conn.close()
syntaxmatrix/routes.py CHANGED
@@ -3326,6 +3326,10 @@ def setup_routes(smx):
3326
3326
  def upload_user_file():
3327
3327
  import uuid
3328
3328
  from flask import jsonify
3329
+
3330
+ if not getattr(smx, "user_files_enabled", False):
3331
+ return jsonify({"error": "user_files_disabled"}), 403
3332
+
3329
3333
  # Define the upload folder for user files.
3330
3334
  upload_folder = os.path.join(_CLIENT_DIR, "uploads", "user")
3331
3335
  if not os.path.exists(upload_folder):
@@ -3385,7 +3389,7 @@ def setup_routes(smx):
3385
3389
 
3386
3390
  @smx.app.route("/admin", methods=["GET", "POST"])
3387
3391
  # @superadmin_required
3388
- @admin_required
3392
+ # @admin_required
3389
3393
  def admin_panel():
3390
3394
  bp = Blueprint("admin", __name__)
3391
3395
 
@@ -4501,9 +4505,15 @@ def setup_routes(smx):
4501
4505
  <ul class="catalog-list" style="padding-left:1rem; margin-bottom:0;">
4502
4506
  {profile_items or "<li class='li-row'>No profiles yet.</li>"}
4503
4507
  </ul>
4508
+
4509
+ <!-- Refresh button (reload admin page; anchor back to Models section) -->
4510
+ <div style="display:flex; justify-content:flex-end; margin-top:10px;">
4511
+ <a class="btn" href="/admin?refresh=profiles#models" title="Reload to refresh profiles list">Refresh</a>
4512
+ </div>
4504
4513
  </div>
4505
4514
  """
4506
4515
 
4516
+
4507
4517
  # ────────────────────────────────────────────────────────────────────────────────
4508
4518
  # SYSTEM FILES
4509
4519
  # ────────────────────────────────────────────────────────────────────────────────
@@ -4973,6 +4983,16 @@ def setup_routes(smx):
4973
4983
  </div>
4974
4984
  """
4975
4985
 
4986
+ features_link_card = f"""
4987
+ <div class="card span-4">
4988
+ <h4>Feature toggles</h4>
4989
+ <div style="font-size:.72rem;color:#555;margin-top:-6px;margin-bottom:10px;line-height:1.35;">
4990
+ Turn streaming on/off and allow user file uploads in chat.
4991
+ </div>
4992
+ <a href="{url_for('admin_features')}" class="btn">Manage features</a>
4993
+ </div>
4994
+ """
4995
+
4976
4996
  branding_link_card = f"""
4977
4997
  <div class="card span-3">
4978
4998
  <h4>Branding</h4>
@@ -4989,6 +5009,7 @@ def setup_routes(smx):
4989
5009
  <div class="admin-grid">
4990
5010
  {secretes_link_card}
4991
5011
  {branding_link_card}
5012
+ {features_link_card}
4992
5013
  {sys_files_card}
4993
5014
  {manage_sys_files_card}
4994
5015
  </div>
@@ -5637,6 +5658,40 @@ def setup_routes(smx):
5637
5658
  default_favicon_url=default_favicon_url,
5638
5659
  )
5639
5660
 
5661
+
5662
+ @smx.app.route("/admin/features", methods=["GET", "POST"])
5663
+ @admin_required
5664
+ def admin_features():
5665
+ # Defaults from DB (or fall back)
5666
+ def _truthy(v):
5667
+ return str(v or "").strip().lower() in ("1", "true", "yes", "on")
5668
+
5669
+ if request.method == "POST":
5670
+ stream_on = "1" if request.form.get("stream_mode") == "on" else "0"
5671
+ user_files_on = "1" if request.form.get("user_files") == "on" else "0"
5672
+
5673
+ db.set_setting("feature.stream_mode", stream_on)
5674
+ db.set_setting("feature.user_files", user_files_on)
5675
+
5676
+ # Apply immediately (no restart)
5677
+ try:
5678
+ smx._apply_feature_flags_from_db()
5679
+ except Exception:
5680
+ pass
5681
+
5682
+ flash("Settings updated ✓")
5683
+ return redirect(url_for("admin_features"))
5684
+
5685
+ stream_mode = _truthy(db.get_setting("feature.stream_mode", "0"))
5686
+ user_files = _truthy(db.get_setting("feature.user_files", "0"))
5687
+
5688
+ return render_template(
5689
+ "admin_features.html",
5690
+ stream_mode=stream_mode,
5691
+ user_files=user_files,
5692
+ )
5693
+
5694
+
5640
5695
  @smx.app.route("/admin/delete.json", methods=["POST"])
5641
5696
  def admin_delete_universal():
5642
5697
 
@@ -0,0 +1,63 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Feature toggles</title>
7
+ <style>
8
+ body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;margin:0;background:#0b1224;color:#e5e7eb;}
9
+ .wrap{max-width:980px;margin:0 auto;padding:18px;}
10
+ .top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px;}
11
+ .top h1{margin:0;font-size:1.1rem;}
12
+ .btn{display:inline-block;padding:8px 12px;border-radius:999px;border:1px solid rgba(148,163,184,.35);color:#e5e7eb;text-decoration:none;background:transparent;cursor:pointer;font-weight:650;font-size:.85rem;}
13
+ .btn:hover{border-color:rgba(56,189,248,.6);color:#38bdf8;}
14
+ .card{background:rgba(2,6,23,.65);border:1px solid rgba(148,163,184,.25);border-radius:14px;padding:14px;box-shadow:0 18px 36px rgba(15,23,42,.6);margin-bottom:12px;}
15
+ .flash{background:rgba(34,197,94,.12);border:1px solid rgba(34,197,94,.35);padding:10px;border-radius:12px;margin-bottom:10px;color:#bbf7d0;font-size:.85rem;}
16
+ .hint{color:#9ca3af;font-size:.78rem;line-height:1.35;margin-top:8px;}
17
+ .row{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-top:1px solid rgba(148,163,184,.15);}
18
+ .row:first-child{border-top:none;}
19
+ .label{font-weight:750;}
20
+ input[type="checkbox"]{transform: translateY(2px); width:16px; height:16px;}
21
+ </style>
22
+ </head>
23
+ <body>
24
+ <div class="wrap">
25
+ <div class="top">
26
+ <h1>Feature toggles</h1>
27
+ <a class="btn" href="{{ url_for('admin_panel') }}#system">Back to Admin</a>
28
+ </div>
29
+
30
+ {% with messages = get_flashed_messages(with_categories=False) %}
31
+ {% if messages %}
32
+ {% for m in messages %}
33
+ <div class="flash">{{ m }}</div>
34
+ {% endfor %}
35
+ {% endif %}
36
+ {% endwith %}
37
+
38
+ <div class="card">
39
+ <form method="post">
40
+ <div class="row">
41
+ <input type="checkbox" id="stream_mode" name="stream_mode" {% if stream_mode %}checked{% endif %}>
42
+ <div>
43
+ <div class="label">Enable stream mode</div>
44
+ <div class="hint">Streams assistant responses in real time (SSE). Applies to the chat UI immediately.</div>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="row">
49
+ <input type="checkbox" id="user_files" name="user_files" {% if user_files %}checked{% endif %}>
50
+ <div>
51
+ <div class="label">Enable user files</div>
52
+ <div class="hint">Shows the “➕” upload icon and allows users to upload PDFs for that chat session.</div>
53
+ </div>
54
+ </div>
55
+
56
+ <div style="margin-top:12px;display:flex;justify-content:flex-end;gap:10px;">
57
+ <button class="btn" type="submit">Save</button>
58
+ </div>
59
+ </form>
60
+ </div>
61
+ </div>
62
+ </body>
63
+ </html>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syntaxmatrix
3
- Version: 2.6.1
3
+ Version: 2.6.3
4
4
  Summary: SyntaxMUI: A customizable framework for Python AI Assistant Projects.
5
5
  Author: Bob Nti
6
6
  Author-email: bob.nti@syntaxmatrix.net
@@ -2,9 +2,9 @@ syntaxmatrix/__init__.py,sha256=_LnTrYAW2tbYA37Y233Vv4OMOk8NUnoJi-1yzFyHxEI,2573
2
2
  syntaxmatrix/auth.py,sha256=SCD6uWojXjj9yjUTKzgV5kBYe6ZkXASEG2VopLFkEtM,18140
3
3
  syntaxmatrix/bootstrap.py,sha256=Y7ZNg-Z3ecrr1iYem5EMzPmGstXnEKmO9kqKVoOoljo,817
4
4
  syntaxmatrix/commentary.py,sha256=3c8qBAKJI2IcYd9PBZrFEwmv-c4_tfa3ebEoPa5vW7U,12428
5
- syntaxmatrix/core.py,sha256=8xZgXO2F0QXsLimxGujJY7Qnpfw849MQOuLO0RxsMN4,64489
5
+ syntaxmatrix/core.py,sha256=pxgJve3H6zWwvpV_dnHuvBFw0kRy0ETca3k8nVGKpTE,65137
6
6
  syntaxmatrix/dataset_preprocessing.py,sha256=wtV4MWzkyfOsBHTsS0H1gqHho77ZQHGDI9skJryyZWA,8732
7
- syntaxmatrix/db.py,sha256=utS_nUIoTspuLV9hgrpg0jdMiqAVHe9Ho0U46GFWdyE,18921
7
+ syntaxmatrix/db.py,sha256=Tqy-iGZtVIrh_qkdJDUVd_cJCsLtnbccfhNZUYL1z6M,20233
8
8
  syntaxmatrix/display_html.py,sha256=tBeeHcRbmAOKqRTXY0hUehThFspCDsvjW4myi2zj0iU,3568
9
9
  syntaxmatrix/emailer.py,sha256=KazaSY0ieE5kC5nTVmh-O2N3gjfeG_oBnl4pl_UHEws,949
10
10
  syntaxmatrix/file_processor.py,sha256=9-TT20qfhZ7Q0eWCJpdxDA54jWM9g56A6VJNFme2azY,2863
@@ -21,7 +21,7 @@ syntaxmatrix/plottings.py,sha256=MjHQ9T1_oC5oyr4_wkM2GJDrpjp0sbvudbs2lGaMyzk,610
21
21
  syntaxmatrix/preface.py,sha256=tCm0C0BhY_SOntQT5I7cOJr6TB5mVDAeL9i8UmHLu5g,21237
22
22
  syntaxmatrix/profiles.py,sha256=hPg27IQjl8-Tpo3BanQQsByeAgcizqIA2I_IKKNZ0TI,2900
23
23
  syntaxmatrix/project_root.py,sha256=1ckvbFVV1szHtHsfSCoGcImHkRwbfszmPG1kGh9ZZlE,2227
24
- syntaxmatrix/routes.py,sha256=hA2uc4rvxGURkZJET9Nvcmt5vAljkWO7uKPYEOvrPXM,353176
24
+ syntaxmatrix/routes.py,sha256=QWLAwtKrv013zohZeSxnA6QQ-1XvZFQfXDaYsT_gpkI,355273
25
25
  syntaxmatrix/selftest_page_templates.py,sha256=JY1i2xu7FBkN0TIPiAXhEk_iIjdOBmfc1g9aX98iqhw,14833
26
26
  syntaxmatrix/session.py,sha256=v0qgxnVM_LEaNvZQJSa-13Q2eiwc3RDnjd2SahNnHQk,599
27
27
  syntaxmatrix/smiv.py,sha256=1lSN3UYpXvYoVNd6VrkY5iZuF_nDxD6xxvLnTn9wcbQ,1405
@@ -34,7 +34,7 @@ syntaxmatrix/vectorizer.py,sha256=5w_UQiUIirm_W-Q9TcaEI8LTcTYIuDBdKfz79T1aZ8g,13
34
34
  syntaxmatrix/workspace_db.py,sha256=Xu9OlW8wo3iaH5Y88ZMdLOf-fiZxF1NBb5rAw3KcbfY,4715
35
35
  syntaxmatrix/agentic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  syntaxmatrix/agentic/agent_tools.py,sha256=yQwavONP23ziMxNQf3j2Y4TVo_LxEsiAWecKuBK8WDg,866
37
- syntaxmatrix/agentic/agents.py,sha256=eyciLz7_lPZK_-jPbXuUOx28bFx0c5Ohr66ztQyiFT0,75270
37
+ syntaxmatrix/agentic/agents.py,sha256=n8lqelmTn_u3MIfFySIWQZgUA_qsfzbzBGdLPNIqT9M,75261
38
38
  syntaxmatrix/agentic/agents_orchestrer.py,sha256=NMC0Mr1zRxxWBr-KRZxu1iLMBJowqesNIkuNwY1AlQA,14681
39
39
  syntaxmatrix/agentic/code_tools_registry.py,sha256=rV0sA1qf_a9A4mmJXGuLnPD6qzAtTBjVgViYpwykfRU,1489
40
40
  syntaxmatrix/agentic/model_templates.py,sha256=A3ROE3BHkvnU9cxqSGjlCBIw9U15zRaTKgK-WxcZtUI,76033
@@ -60,6 +60,7 @@ syntaxmatrix/static/js/chat.js,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
60
60
  syntaxmatrix/static/js/sidebar.js,sha256=zHp4skKLY2Dlqx7aLPQ8_cR0iTRT17W0SC2TR38Yl64,7609
61
61
  syntaxmatrix/static/js/widgets.js,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  syntaxmatrix/templates/admin_branding.html,sha256=uoYgF3Si3BHusXWqwn_A6VVkqxBt3FXGw2YepLdOgTc,4839
63
+ syntaxmatrix/templates/admin_features.html,sha256=K2ETWQM7t-YNhChzubgi0c3VnA33bn57uTxyPl3q65c,2917
63
64
  syntaxmatrix/templates/admin_secretes.html,sha256=lG8NpJSokdC27SZTLo0j2fHpbukts2-lgJyqyWnqCu8,4973
64
65
  syntaxmatrix/templates/change_password.html,sha256=YWEcnwJLccLyKGzQxIrc0xuP-p00BtEIwcYq4oFvJ-0,3332
65
66
  syntaxmatrix/templates/code_cell.html,sha256=LOr9VjvNQcOGKKJ1ecpcZh3C3qsUxBHueg2iQtpdxl8,638
@@ -77,8 +78,8 @@ syntaxmatrix/vectordb/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
77
78
  syntaxmatrix/vectordb/adapters/milvus_adapter.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
79
  syntaxmatrix/vectordb/adapters/pgvector_adapter.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
80
  syntaxmatrix/vectordb/adapters/sqlite_adapter.py,sha256=L8M2qHfwZRAFVxWeurUVdHaJXz6F5xTUSWh3uy6TSUs,6035
80
- syntaxmatrix-2.6.1.dist-info/licenses/LICENSE.txt,sha256=j1P8naTdy1JMxTC80XYQjbyAQnuOlpDusCUhncrvpy8,1083
81
- syntaxmatrix-2.6.1.dist-info/METADATA,sha256=R9QuWYbRtdKs6ZBit1f2DKJaSEL4ONXeI1UCYJl9eE8,18219
82
- syntaxmatrix-2.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
83
- syntaxmatrix-2.6.1.dist-info/top_level.txt,sha256=HKP_zkl4V_nt7osC15DlacoBZktHrbZYOqf_pPkF3T8,13
84
- syntaxmatrix-2.6.1.dist-info/RECORD,,
81
+ syntaxmatrix-2.6.3.dist-info/licenses/LICENSE.txt,sha256=j1P8naTdy1JMxTC80XYQjbyAQnuOlpDusCUhncrvpy8,1083
82
+ syntaxmatrix-2.6.3.dist-info/METADATA,sha256=1oIQ3LUTuL4Js5qCOJozwjPIUqhAkNFH6xClW9vgW64,18219
83
+ syntaxmatrix-2.6.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
84
+ syntaxmatrix-2.6.3.dist-info/top_level.txt,sha256=HKP_zkl4V_nt7osC15DlacoBZktHrbZYOqf_pPkF3T8,13
85
+ syntaxmatrix-2.6.3.dist-info/RECORD,,