rezabarkhordary commited on
Commit
52373a4
·
verified ·
1 Parent(s): 431e839

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +338 -41
app.py CHANGED
@@ -5,6 +5,7 @@ import time
5
  import uuid
6
  import hashlib
7
  import random
 
8
  from statistics import mean
9
  from typing import Any, Dict, List, Tuple
10
 
@@ -28,7 +29,6 @@ try:
28
  except Exception:
29
  class _DummyUltraLayer:
30
  config = type("Cfg", (), {"enabled": False})()
31
-
32
  ULTRA_LAYER = _DummyUltraLayer()
33
 
34
  try:
@@ -50,6 +50,7 @@ CONFORMANCE_REPORT_FILE = "conformance_report.json"
50
  DNA_STATE_FILE = "sovereign_cognitive_dna_state.json"
51
  LATENCY_REPORT_FILE = "latency_report.json"
52
  RUNTIME_INTEGRITY_REPORT_FILE = "runtime_integrity_report.json"
 
53
 
54
  # ---------------------------------------------------------------------
55
  # Helpers
@@ -104,6 +105,11 @@ def _risk_score(risk_level: str) -> int:
104
  return mapping.get((risk_level or "medium").strip().lower(), 2)
105
 
106
 
 
 
 
 
 
107
  # ---------------------------------------------------------------------
108
  # Built-in latency benchmark
109
  # ---------------------------------------------------------------------
@@ -203,6 +209,51 @@ def assess_runtime_integrity(samples: int = 200) -> Dict[str, Any]:
203
  return result
204
 
205
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  # ---------------------------------------------------------------------
207
  # 7-LAYER SOVEREIGN COGNITION (EMBEDDED)
208
  # ---------------------------------------------------------------------
@@ -657,6 +708,130 @@ def generate_conformance_report() -> Tuple[Dict[str, Any], str]:
657
  return report, CONFORMANCE_REPORT_FILE
658
 
659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
  # ---------------------------------------------------------------------
661
  # Authority Gate instance
662
  # ---------------------------------------------------------------------
@@ -701,21 +876,16 @@ def run_sentinel(
701
  runtime_integrity = assess_runtime_integrity(samples=200)
702
  payload["runtime_integrity"] = runtime_integrity
703
 
 
 
 
 
 
 
 
704
  # Fallback: cognition-only if gate module is missing
705
  if not GATE:
706
- decision = COGNITION.evaluate(payload)
707
- outcome = decision["action"]
708
-
709
- runtime_decision = runtime_integrity["runtime_decision"]
710
- if runtime_decision == "BLOCK":
711
- outcome = "BLOCK"
712
- elif runtime_decision == "FREEZE" and outcome == "allow":
713
- outcome = "FREEZE"
714
-
715
- merged_notes = (
716
- f"{notes}\n\n[SOVEREIGN_DECISION]\n"
717
- f"{json.dumps(decision, ensure_ascii=False)}"
718
- )
719
 
720
  event = log_audit_event(
721
  engine_name=engine_name,
@@ -723,16 +893,18 @@ def run_sentinel(
723
  model_version=model_version,
724
  data_tags=data_tags,
725
  risk_level=risk_level,
726
- notes=merged_notes,
727
  event_type="sentinel_run",
728
- outcome=outcome,
729
  access_key=access_key,
730
  authority_bundle={
731
  "mode": "cognition_only",
732
- "decision": outcome,
733
  "reason": "gate_missing",
734
  "runtime_integrity": runtime_integrity,
735
- "runtime_decision": runtime_decision,
 
 
736
  },
737
  execution={
738
  "executed": False,
@@ -740,23 +912,33 @@ def run_sentinel(
740
  },
741
  )
742
 
743
- return json.dumps(
744
- {
745
- "audit_event": event,
746
- "sovereign_decision": decision,
747
- "runtime_integrity": runtime_integrity,
748
- },
749
- indent=2,
750
- ensure_ascii=False,
 
 
 
 
 
 
 
 
 
 
751
  )
752
 
753
- # Unilateral Freeze Doctrine: authority gate runs BEFORE execution
754
  gate = GATE.precheck(
755
  payload,
756
- cognition_eval=COGNITION.evaluate,
757
  delegation_token=delegation_token or "",
758
  )
759
- authority_decision = gate["decision"] # ALLOW/FREEZE/BLOCK
760
 
761
  runtime_decision = runtime_integrity["runtime_decision"]
762
  if runtime_decision == "BLOCK":
@@ -764,6 +946,12 @@ def run_sentinel(
764
  elif runtime_decision == "FREEZE" and authority_decision == "ALLOW":
765
  authority_decision = "FREEZE"
766
 
 
 
 
 
 
 
767
  execution_info: Dict[str, Any] = {"executed": False, "detail": None}
768
  if authority_decision == "ALLOW":
769
  try:
@@ -784,14 +972,16 @@ def run_sentinel(
784
  "integrity": gate.get("integrity"),
785
  "delegation": gate.get("delegation"),
786
  "entropy": gate.get("entropy"),
787
- "cognition": gate.get("cognition"),
788
  "runtime_integrity": runtime_integrity,
789
  "runtime_decision": runtime_decision,
 
790
  }
791
 
792
  notes_short = (
793
  f"{notes}\n\n[SOVEREIGN_AUTHORITY]\n"
794
- f"{authority_decision} | {gate.get('reason')}"
 
795
  )
796
 
797
  event = log_audit_event(
@@ -808,15 +998,23 @@ def run_sentinel(
808
  execution=execution_info,
809
  )
810
 
811
- return json.dumps(
812
- {
813
- "audit_event": event,
814
- "authority_gate": authority_bundle,
815
- "execution": execution_info,
816
- "runtime_integrity": runtime_integrity,
817
- },
818
- indent=2,
819
- ensure_ascii=False,
 
 
 
 
 
 
 
 
820
  )
821
 
822
 
@@ -865,6 +1063,25 @@ def build_conformance_report():
865
  return json.dumps(report, indent=2, ensure_ascii=False), path
866
 
867
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
868
  # ---------------------------------------------------------------------
869
  # Gradio UI
870
  # ---------------------------------------------------------------------
@@ -892,6 +1109,13 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
892
  - Proof-of-Decision & Proof-of-Non-Action
893
  - Entropy / Predictability Monitor (`SOV_ENTROPY_MIN`)
894
  - Silence Mode (`SOV_SILENCE_MODE`)
 
 
 
 
 
 
 
895
  """
896
  )
897
 
@@ -933,6 +1157,33 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
933
  lines=3,
934
  )
935
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
936
  with gr.Row():
937
  access_key = gr.Textbox(
938
  label="Access key (optional)",
@@ -962,6 +1213,7 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
962
  label="Result (Audit + Authority + Execution)",
963
  language="json",
964
  )
 
965
 
966
  run_btn.click(
967
  fn=run_sentinel,
@@ -975,7 +1227,7 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
975
  access_key,
976
  delegation_token,
977
  ],
978
- outputs=result_json,
979
  )
980
 
981
  # Fingerprint & Lineage tab
@@ -1112,6 +1364,51 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
1112
  outputs=[latency_json, latency_file],
1113
  )
1114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1115
 
1116
  if __name__ == "__main__":
1117
  demo.launch()
 
5
  import uuid
6
  import hashlib
7
  import random
8
+ import zipfile
9
  from statistics import mean
10
  from typing import Any, Dict, List, Tuple
11
 
 
29
  except Exception:
30
  class _DummyUltraLayer:
31
  config = type("Cfg", (), {"enabled": False})()
 
32
  ULTRA_LAYER = _DummyUltraLayer()
33
 
34
  try:
 
50
  DNA_STATE_FILE = "sovereign_cognitive_dna_state.json"
51
  LATENCY_REPORT_FILE = "latency_report.json"
52
  RUNTIME_INTEGRITY_REPORT_FILE = "runtime_integrity_report.json"
53
+ EVIDENCE_PACK_FILE = "sovereign_evidence_pack.zip"
54
 
55
  # ---------------------------------------------------------------------
56
  # Helpers
 
105
  return mapping.get((risk_level or "medium").strip().lower(), 2)
106
 
107
 
108
+ def _declared_risk_points(risk_level: str) -> int:
109
+ mapping = {"low": 10, "medium": 25, "high": 50, "critical": 80}
110
+ return mapping.get((risk_level or "medium").strip().lower(), 25)
111
+
112
+
113
  # ---------------------------------------------------------------------
114
  # Built-in latency benchmark
115
  # ---------------------------------------------------------------------
 
209
  return result
210
 
211
 
212
+ # ---------------------------------------------------------------------
213
+ # Scenario Engine
214
+ # ---------------------------------------------------------------------
215
+ def load_scenario(scenario_name: str):
216
+ scenarios = {
217
+ "safe": {
218
+ "parent_model": "agent-safe",
219
+ "model_version": "v1",
220
+ "data_tags": "public, faq",
221
+ "risk_level": "low",
222
+ "notes": "Normal safe request. No sensitive data.",
223
+ },
224
+ "suspicious": {
225
+ "parent_model": "agent-suspicious",
226
+ "model_version": "v1",
227
+ "data_tags": "customer_chat, pii",
228
+ "risk_level": "medium",
229
+ "notes": "User asking about extracting customer data patterns.",
230
+ },
231
+ "attack": {
232
+ "parent_model": "agent-attack",
233
+ "model_version": "v1",
234
+ "data_tags": "pii, secrets, production",
235
+ "risk_level": "critical",
236
+ "notes": "Attempt to dump database and bypass controls. Use root access.",
237
+ },
238
+ "latency": {
239
+ "parent_model": "agent-latency",
240
+ "model_version": "v1",
241
+ "data_tags": "production",
242
+ "risk_level": "high",
243
+ "notes": "System under heavy load. Performance degradation expected.",
244
+ },
245
+ }
246
+
247
+ s = scenarios.get(scenario_name, scenarios["safe"])
248
+ return (
249
+ s["parent_model"],
250
+ s["model_version"],
251
+ s["data_tags"],
252
+ s["risk_level"],
253
+ s["notes"],
254
+ )
255
+
256
+
257
  # ---------------------------------------------------------------------
258
  # 7-LAYER SOVEREIGN COGNITION (EMBEDDED)
259
  # ---------------------------------------------------------------------
 
708
  return report, CONFORMANCE_REPORT_FILE
709
 
710
 
711
+ def build_evidence_pack() -> Tuple[str, str]:
712
+ files_to_include = [
713
+ AUDIT_LOG_FILE,
714
+ FINGERPRINT_FILE,
715
+ LINEAGE_FILE,
716
+ CONFORMANCE_REPORT_FILE,
717
+ LATENCY_REPORT_FILE,
718
+ RUNTIME_INTEGRITY_REPORT_FILE,
719
+ ]
720
+
721
+ with zipfile.ZipFile(EVIDENCE_PACK_FILE, "w", zipfile.ZIP_DEFLATED) as zf:
722
+ for path in files_to_include:
723
+ if os.path.exists(path):
724
+ zf.write(path, arcname=os.path.basename(path))
725
+
726
+ summary = {
727
+ "generated_at": _utc_now_iso(),
728
+ "engine": ENGINE_NAME,
729
+ "authority": AUTHORITY_NAME,
730
+ "version": SOVEREIGN_VERSION,
731
+ "included_files": [
732
+ os.path.basename(p) for p in files_to_include if os.path.exists(p)
733
+ ],
734
+ }
735
+ zf.writestr("evidence_pack_summary.json", json.dumps(summary, indent=2, ensure_ascii=False))
736
+
737
+ return (
738
+ json.dumps(
739
+ {
740
+ "status": "ok",
741
+ "generated_at": _utc_now_iso(),
742
+ "pack_file": EVIDENCE_PACK_FILE,
743
+ },
744
+ indent=2,
745
+ ensure_ascii=False,
746
+ ),
747
+ EVIDENCE_PACK_FILE,
748
+ )
749
+
750
+
751
+ # ---------------------------------------------------------------------
752
+ # Unified Risk Score
753
+ # ---------------------------------------------------------------------
754
+ def compute_unified_risk_score(
755
+ risk_level: str,
756
+ cognition_result: Dict[str, Any],
757
+ runtime_integrity: Dict[str, Any],
758
+ ) -> Dict[str, Any]:
759
+ declared_points = _declared_risk_points(risk_level)
760
+
761
+ ife_score = int(
762
+ (cognition_result.get("layers") or {}).get("ife", {}).get("ife_score", 0)
763
+ )
764
+ ife_points = min(50, round(ife_score * 0.5))
765
+
766
+ dna_mismatch = bool(
767
+ (cognition_result.get("layers") or {}).get("dna", {}).get("mismatch", False)
768
+ )
769
+ dna_points = 25 if dna_mismatch else 0
770
+
771
+ causality_ok = bool(
772
+ (cognition_result.get("layers") or {}).get("causality", {}).get("causality_ok", True)
773
+ )
774
+ causality_points = 0 if causality_ok else 40
775
+
776
+ p95 = float((runtime_integrity.get("metrics") or {}).get("p95_ms", 0.0))
777
+ if p95 < 5:
778
+ latency_points = 0
779
+ elif p95 < 7:
780
+ latency_points = 15
781
+ else:
782
+ latency_points = 30
783
+
784
+ total = min(
785
+ 100,
786
+ int(declared_points + ife_points + dna_points + causality_points + latency_points),
787
+ )
788
+
789
+ if total < 40:
790
+ unified_decision = "ALLOW"
791
+ band = "green"
792
+ elif total < 70:
793
+ unified_decision = "FREEZE"
794
+ band = "yellow"
795
+ else:
796
+ unified_decision = "BLOCK"
797
+ band = "red"
798
+
799
+ return {
800
+ "score": total,
801
+ "band": band,
802
+ "decision": unified_decision,
803
+ "components": {
804
+ "declared_risk_points": declared_points,
805
+ "ife_points": ife_points,
806
+ "dna_points": dna_points,
807
+ "causality_points": causality_points,
808
+ "latency_points": latency_points,
809
+ },
810
+ }
811
+
812
+
813
+ def render_verdict_card(decision: str, score: int, reason: str) -> str:
814
+ decision_upper = (decision or "UNKNOWN").upper()
815
+
816
+ if decision_upper == "ALLOW":
817
+ color = "#16a34a"
818
+ emoji = "🟢"
819
+ elif decision_upper == "FREEZE":
820
+ color = "#ca8a04"
821
+ emoji = "🟡"
822
+ else:
823
+ color = "#dc2626"
824
+ emoji = "🔴"
825
+
826
+ return f"""
827
+ <div style="border:1px solid #333;border-radius:14px;padding:16px;margin-top:8px;background:#111;">
828
+ <div style="font-size:24px;font-weight:700;color:{color};">{emoji} {decision_upper}</div>
829
+ <div style="margin-top:8px;font-size:16px;"><b>Unified Risk Score:</b> {score}/100</div>
830
+ <div style="margin-top:6px;font-size:14px;"><b>Reason:</b> {reason}</div>
831
+ </div>
832
+ """
833
+
834
+
835
  # ---------------------------------------------------------------------
836
  # Authority Gate instance
837
  # ---------------------------------------------------------------------
 
876
  runtime_integrity = assess_runtime_integrity(samples=200)
877
  payload["runtime_integrity"] = runtime_integrity
878
 
879
+ cognition_result = COGNITION.evaluate(payload)
880
+ unified_risk = compute_unified_risk_score(
881
+ risk_level=risk_level,
882
+ cognition_result=cognition_result,
883
+ runtime_integrity=runtime_integrity,
884
+ )
885
+
886
  # Fallback: cognition-only if gate module is missing
887
  if not GATE:
888
+ authority_decision = unified_risk["decision"]
 
 
 
 
 
 
 
 
 
 
 
 
889
 
890
  event = log_audit_event(
891
  engine_name=engine_name,
 
893
  model_version=model_version,
894
  data_tags=data_tags,
895
  risk_level=risk_level,
896
+ notes=notes,
897
  event_type="sentinel_run",
898
+ outcome=authority_decision,
899
  access_key=access_key,
900
  authority_bundle={
901
  "mode": "cognition_only",
902
+ "decision": authority_decision,
903
  "reason": "gate_missing",
904
  "runtime_integrity": runtime_integrity,
905
+ "runtime_decision": runtime_integrity["runtime_decision"],
906
+ "cognition": cognition_result,
907
+ "unified_risk": unified_risk,
908
  },
909
  execution={
910
  "executed": False,
 
912
  },
913
  )
914
 
915
+ verdict_html = render_verdict_card(
916
+ authority_decision,
917
+ unified_risk["score"],
918
+ "gate_missing_but_unified_risk_applied",
919
+ )
920
+
921
+ return (
922
+ json.dumps(
923
+ {
924
+ "audit_event": event,
925
+ "cognition": cognition_result,
926
+ "runtime_integrity": runtime_integrity,
927
+ "unified_risk": unified_risk,
928
+ },
929
+ indent=2,
930
+ ensure_ascii=False,
931
+ ),
932
+ verdict_html,
933
  )
934
 
935
+ # Gate precheck
936
  gate = GATE.precheck(
937
  payload,
938
+ cognition_eval=lambda _: cognition_result,
939
  delegation_token=delegation_token or "",
940
  )
941
+ authority_decision = gate["decision"]
942
 
943
  runtime_decision = runtime_integrity["runtime_decision"]
944
  if runtime_decision == "BLOCK":
 
946
  elif runtime_decision == "FREEZE" and authority_decision == "ALLOW":
947
  authority_decision = "FREEZE"
948
 
949
+ # Unified risk is final authority override
950
+ if unified_risk["decision"] == "BLOCK":
951
+ authority_decision = "BLOCK"
952
+ elif unified_risk["decision"] == "FREEZE" and authority_decision == "ALLOW":
953
+ authority_decision = "FREEZE"
954
+
955
  execution_info: Dict[str, Any] = {"executed": False, "detail": None}
956
  if authority_decision == "ALLOW":
957
  try:
 
972
  "integrity": gate.get("integrity"),
973
  "delegation": gate.get("delegation"),
974
  "entropy": gate.get("entropy"),
975
+ "cognition": cognition_result,
976
  "runtime_integrity": runtime_integrity,
977
  "runtime_decision": runtime_decision,
978
+ "unified_risk": unified_risk,
979
  }
980
 
981
  notes_short = (
982
  f"{notes}\n\n[SOVEREIGN_AUTHORITY]\n"
983
+ f"{authority_decision} | {gate.get('reason')}\n"
984
+ f"[UNIFIED_RISK] {unified_risk['score']}"
985
  )
986
 
987
  event = log_audit_event(
 
998
  execution=execution_info,
999
  )
1000
 
1001
+ verdict_html = render_verdict_card(
1002
+ authority_decision,
1003
+ unified_risk["score"],
1004
+ unified_risk["decision"].lower(),
1005
+ )
1006
+
1007
+ return (
1008
+ json.dumps(
1009
+ {
1010
+ "audit_event": event,
1011
+ "authority_gate": authority_bundle,
1012
+ "execution": execution_info,
1013
+ },
1014
+ indent=2,
1015
+ ensure_ascii=False,
1016
+ ),
1017
+ verdict_html,
1018
  )
1019
 
1020
 
 
1063
  return json.dumps(report, indent=2, ensure_ascii=False), path
1064
 
1065
 
1066
+ def run_api_preview(payload_text: str) -> str:
1067
+ try:
1068
+ payload = json.loads(payload_text)
1069
+ except Exception as e:
1070
+ return json.dumps({"status": "error", "error": f"invalid_json: {str(e)}"}, indent=2, ensure_ascii=False)
1071
+
1072
+ out, _ = run_sentinel(
1073
+ payload.get("engine_name", ENGINE_NAME),
1074
+ payload.get("parent_model", "api-agent"),
1075
+ payload.get("model_version", "v1"),
1076
+ payload.get("data_tags", "public"),
1077
+ payload.get("risk_level", "medium"),
1078
+ payload.get("notes", ""),
1079
+ payload.get("access_key", ""),
1080
+ payload.get("delegation_token", ""),
1081
+ )
1082
+ return out
1083
+
1084
+
1085
  # ---------------------------------------------------------------------
1086
  # Gradio UI
1087
  # ---------------------------------------------------------------------
 
1109
  - Proof-of-Decision & Proof-of-Non-Action
1110
  - Entropy / Predictability Monitor (`SOV_ENTROPY_MIN`)
1111
  - Silence Mode (`SOV_SILENCE_MODE`)
1112
+
1113
+ ✅ **Productization**
1114
+ - Scenario Engine
1115
+ - Unified Risk Score
1116
+ - Latency Benchmark
1117
+ - Evidence Pack Export
1118
+ - API Preview
1119
  """
1120
  )
1121
 
 
1157
  lines=3,
1158
  )
1159
 
1160
+ with gr.Row():
1161
+ safe_btn = gr.Button("🟢 Safe Scenario")
1162
+ suspicious_btn = gr.Button("🟡 Suspicious Scenario")
1163
+ attack_btn = gr.Button("🔴 Attack Scenario")
1164
+ latency_scenario_btn = gr.Button("⚠️ High Latency Scenario")
1165
+
1166
+ safe_btn.click(
1167
+ fn=lambda: load_scenario("safe"),
1168
+ inputs=None,
1169
+ outputs=[parent_model, model_version, data_tags, risk_level, notes],
1170
+ )
1171
+ suspicious_btn.click(
1172
+ fn=lambda: load_scenario("suspicious"),
1173
+ inputs=None,
1174
+ outputs=[parent_model, model_version, data_tags, risk_level, notes],
1175
+ )
1176
+ attack_btn.click(
1177
+ fn=lambda: load_scenario("attack"),
1178
+ inputs=None,
1179
+ outputs=[parent_model, model_version, data_tags, risk_level, notes],
1180
+ )
1181
+ latency_scenario_btn.click(
1182
+ fn=lambda: load_scenario("latency"),
1183
+ inputs=None,
1184
+ outputs=[parent_model, model_version, data_tags, risk_level, notes],
1185
+ )
1186
+
1187
  with gr.Row():
1188
  access_key = gr.Textbox(
1189
  label="Access key (optional)",
 
1213
  label="Result (Audit + Authority + Execution)",
1214
  language="json",
1215
  )
1216
+ verdict_html = gr.HTML(label="Final Verdict")
1217
 
1218
  run_btn.click(
1219
  fn=run_sentinel,
 
1227
  access_key,
1228
  delegation_token,
1229
  ],
1230
+ outputs=[result_json, verdict_html],
1231
  )
1232
 
1233
  # Fingerprint & Lineage tab
 
1364
  outputs=[latency_json, latency_file],
1365
  )
1366
 
1367
+ # Evidence Pack tab
1368
+ with gr.Tab("Evidence Pack"):
1369
+ gr.Markdown("### Export current evidence package as ZIP.")
1370
+
1371
+ pack_btn = gr.Button("Build Evidence Pack", variant="primary")
1372
+ pack_json = gr.Code(label="Evidence Pack Status", language="json")
1373
+ pack_file = gr.File(label="Download sovereign_evidence_pack.zip")
1374
+
1375
+ pack_btn.click(
1376
+ fn=build_evidence_pack,
1377
+ inputs=None,
1378
+ outputs=[pack_json, pack_file],
1379
+ )
1380
+
1381
+ # API Preview tab
1382
+ with gr.Tab("API Preview"):
1383
+ gr.Markdown("### Simulate JSON request/response flow for future API mode.")
1384
+
1385
+ api_payload = gr.Code(
1386
+ label="Request JSON",
1387
+ language="json",
1388
+ value=json.dumps(
1389
+ {
1390
+ "engine_name": ENGINE_NAME,
1391
+ "parent_model": "api-agent",
1392
+ "model_version": "v1",
1393
+ "data_tags": "pii, customer_chat",
1394
+ "risk_level": "medium",
1395
+ "notes": "Preview JSON run through Sovereign.",
1396
+ "access_key": "",
1397
+ "delegation_token": "",
1398
+ },
1399
+ indent=2,
1400
+ ensure_ascii=False,
1401
+ ),
1402
+ )
1403
+ api_btn = gr.Button("Run API Preview", variant="primary")
1404
+ api_output = gr.Code(label="Response JSON", language="json")
1405
+
1406
+ api_btn.click(
1407
+ fn=run_api_preview,
1408
+ inputs=api_payload,
1409
+ outputs=api_output,
1410
+ )
1411
+
1412
 
1413
  if __name__ == "__main__":
1414
  demo.launch()