RFTSystems commited on
Commit
844d75c
·
verified ·
1 Parent(s): 91a1b02

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -0
app.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import tempfile
4
+ from typing import Any, Dict, Optional, Tuple
5
+
6
+ import gradio as gr
7
+
8
+ from drp.bundle import verify_bundle
9
+ from drp.diff import diff_bundles
10
+ from drp.report import render_report_markdown
11
+ from drp.simulate import make_demo_bundle_zip, fork_patch_bundle
12
+
13
+
14
+ APP_TITLE = "TimelineDiff — Differential Reproducibility Protocol (DRP)"
15
+
16
+
17
+ def _tmp_path(name: str) -> str:
18
+ d = tempfile.mkdtemp(prefix="drp_")
19
+ return os.path.join(d, name)
20
+
21
+
22
+ def ui_verify(bundle_file) -> Tuple[str, Dict[str, Any]]:
23
+ if not bundle_file:
24
+ return "Upload a bundle zip first.", {"ok": False}
25
+
26
+ ok, summary = verify_bundle(bundle_file.name)
27
+ msg = "✅ Bundle verifies (hash chain OK)." if ok else "❌ Bundle failed verification."
28
+ return msg, summary
29
+
30
+
31
+ def ui_diff(bundle_a, bundle_b) -> Tuple[str, Dict[str, Any], str]:
32
+ if not bundle_a or not bundle_b:
33
+ return "Upload two bundles.", {"error": "missing input"}, ""
34
+
35
+ diff = diff_bundles(bundle_a.name, bundle_b.name)
36
+ md = render_report_markdown(diff)
37
+
38
+ # export report artifacts
39
+ out_zip = _tmp_path("drp-diff-report.zip")
40
+ out_md = _tmp_path("report.md")
41
+ out_json = _tmp_path("diff.json")
42
+
43
+ with open(out_md, "w", encoding="utf-8") as f:
44
+ f.write(md)
45
+ with open(out_json, "w", encoding="utf-8") as f:
46
+ json.dump(diff, f, ensure_ascii=False, indent=2)
47
+
48
+ import zipfile
49
+ with zipfile.ZipFile(out_zip, "w", compression=zipfile.ZIP_DEFLATED) as z:
50
+ z.write(out_md, arcname="report.md")
51
+ z.write(out_json, arcname="diff.json")
52
+
53
+ headline = "✅ Diff complete."
54
+ return headline, diff, out_zip
55
+
56
+
57
+ def ui_generate(seed_a: int, seed_b: int, chaos: float) -> Tuple[str, str, str]:
58
+ chaos = float(max(0.0, min(1.0, chaos)))
59
+
60
+ path_a = _tmp_path("demo-A.zip")
61
+ path_b = _tmp_path("demo-B.zip")
62
+ make_demo_bundle_zip(path_a, seed=int(seed_a), chaos=chaos, label="A")
63
+ make_demo_bundle_zip(path_b, seed=int(seed_b), chaos=chaos, label="B")
64
+
65
+ return "✅ Generated demo bundles.", path_a, path_b
66
+
67
+
68
+ def ui_fork(source_bundle, fork_index: int, patch_kind: str, patch_step: str, patch_payload: str) -> Tuple[str, str]:
69
+ if not source_bundle:
70
+ return "Upload a source bundle first.", ""
71
+
72
+ patch_payload_json: Optional[Dict[str, Any]] = None
73
+ if patch_payload.strip():
74
+ try:
75
+ patch_payload_json = json.loads(patch_payload)
76
+ except Exception as e:
77
+ return f"Invalid JSON patch payload: {e}", ""
78
+
79
+ out = _tmp_path("forked.zip")
80
+ fork_patch_bundle(
81
+ out,
82
+ source_zip=source_bundle.name,
83
+ fork_at_index=int(fork_index),
84
+ patch_kind=patch_kind.strip() or None,
85
+ patch_step=patch_step.strip() or None,
86
+ patch_payload_json=patch_payload_json,
87
+ )
88
+ return "✅ Fork bundle created (patched + re-hash-chained).", out
89
+
90
+
91
+ with gr.Blocks(title=APP_TITLE) as demo:
92
+ gr.Markdown(f"# {APP_TITLE}\nDiff two agent timelines. Find first divergence. Export a forensic report.")
93
+
94
+ with gr.Tab("Diff two bundles"):
95
+ with gr.Row():
96
+ bundle_a = gr.File(label="Bundle A (.zip)", file_types=[".zip"])
97
+ bundle_b = gr.File(label="Bundle B (.zip)", file_types=[".zip"])
98
+ run = gr.Button("Compute differential report", variant="primary")
99
+
100
+ status = gr.Textbox(label="Status", interactive=False)
101
+ diff_json = gr.JSON(label="Diff JSON (summary + per-event diffs)")
102
+ report_zip = gr.File(label="Download drp-diff-report.zip")
103
+
104
+ run.click(fn=ui_diff, inputs=[bundle_a, bundle_b], outputs=[status, diff_json, report_zip])
105
+
106
+ with gr.Tab("Verify bundle integrity"):
107
+ bundle_v = gr.File(label="Bundle (.zip)", file_types=[".zip"])
108
+ verify_btn = gr.Button("Verify hash chain", variant="secondary")
109
+ v_msg = gr.Textbox(label="Result", interactive=False)
110
+ v_json = gr.JSON(label="Verification summary")
111
+ verify_btn.click(fn=ui_verify, inputs=[bundle_v], outputs=[v_msg, v_json])
112
+
113
+ with gr.Tab("Generate demo bundles"):
114
+ gr.Markdown("Use this to test the diff UI without integrating exporters yet.")
115
+ with gr.Row():
116
+ seed_a = gr.Number(value=1, label="Seed A", precision=0)
117
+ seed_b = gr.Number(value=2, label="Seed B", precision=0)
118
+ chaos = gr.Slider(0, 1, value=0.35, step=0.01, label="Chaos (divergence likelihood)")
119
+ gen_btn = gr.Button("Generate", variant="primary")
120
+ gen_msg = gr.Textbox(label="Status", interactive=False)
121
+ demo_a = gr.File(label="Demo Bundle A")
122
+ demo_b = gr.File(label="Demo Bundle B")
123
+ gen_btn.click(fn=ui_generate, inputs=[seed_a, seed_b, chaos], outputs=[gen_msg, demo_a, demo_b])
124
+
125
+ with gr.Tab("Fork / patch a bundle"):
126
+ gr.Markdown("Counterfactual workflow: patch an event at index N, then re-hash-chain into a new bundle.")
127
+ src = gr.File(label="Source bundle (.zip)", file_types=[".zip"])
128
+ fork_index = gr.Number(value=0, label="Fork at event index", precision=0)
129
+
130
+ with gr.Row():
131
+ patch_kind = gr.Textbox(label="Patch kind (optional)", placeholder="e.g. tool_result")
132
+ patch_step = gr.Textbox(label="Patch step (optional)", placeholder="e.g. t12.tool_result")
133
+ patch_payload = gr.Textbox(
134
+ label="Patch payload JSON (optional)",
135
+ lines=8,
136
+ placeholder='{"ok": true, "value": 42}',
137
+ )
138
+
139
+ fork_btn = gr.Button("Create fork bundle", variant="primary")
140
+ fork_msg = gr.Textbox(label="Status", interactive=False)
141
+ fork_file = gr.File(label="Forked bundle (.zip)")
142
+ fork_btn.click(fn=ui_fork, inputs=[src, fork_index, patch_kind, patch_step, patch_payload], outputs=[fork_msg, fork_file])
143
+
144
+ gr.Markdown(
145
+ "Tip: In a real agent exporter, emit DRP events at: LLM calls, tool calls/results, memory writes, planner steps, guardrails."
146
+ )
147
+
148
+ if __name__ == "__main__":
149
+ demo.launch()