josephrw commited on
Commit
d2d89d6
Β·
verified Β·
1 Parent(s): 86bc248

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +502 -0
app.py ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Membra DAG VM β€” Hugging Face Space
4
+ Deterministic execution engine. Zero API keys required.
5
+ """
6
+
7
+ import gradio as gr
8
+ import hashlib
9
+ import json
10
+ import random
11
+ import time
12
+ from dataclasses import dataclass, field
13
+ from datetime import datetime, timezone
14
+ from typing import Dict, List, Optional, Any
15
+
16
+ # ── Opcodes ─────────────────────────────────────────────────────
17
+ OPCODES = [
18
+ "LOAD_SOURCE",
19
+ "ASSERT_POLICY",
20
+ "RETRIEVE",
21
+ "TRANSFORM",
22
+ "EXECUTE_SKILL",
23
+ "VERIFY",
24
+ "COMMIT_RECEIPT",
25
+ "INVALIDATE",
26
+ "HALT",
27
+ ]
28
+
29
+ NODE_STATES = ["PENDING", "RUNNING", "COMPLETED", "FAILED", "INVALIDATED", "SKIPPED"]
30
+ RUN_STATES = ["PENDING", "RUNNING", "PAUSED", "COMPLETED", "FAILED", "CANCELLED"]
31
+
32
+ EVENT_TYPES = [
33
+ "node_start", "node_complete", "node_fail", "node_skip",
34
+ "run_start", "run_complete", "run_fail", "receipt_commit",
35
+ ]
36
+
37
+ # ── Helpers ─────────────────────────────────────────────────────
38
+ def sha256_hex(data: str) -> str:
39
+ return hashlib.sha256(data.encode()).hexdigest()
40
+
41
+ def canonical_json(obj: Any) -> str:
42
+ return json.dumps(_sort_keys(obj), separators=(",", ":"), ensure_ascii=False)
43
+
44
+ def _sort_keys(obj: Any) -> Any:
45
+ if obj is None or not isinstance(obj, dict):
46
+ if isinstance(obj, list):
47
+ return [_sort_keys(i) for i in obj]
48
+ return obj
49
+ return {k: _sort_keys(v) for k, v in sorted(obj.items())}
50
+
51
+ def deterministic_hash(obj: Any) -> str:
52
+ return sha256_hex(canonical_json(obj))
53
+
54
+ def now_iso() -> str:
55
+ return datetime.now(timezone.utc).isoformat()
56
+
57
+ # ── Models ──────────────────────────────────────────────────────
58
+ @dataclass
59
+ class DagNode:
60
+ id: str
61
+ opcode: str
62
+ payload: Dict[str, Any] = field(default_factory=dict)
63
+ dependencies: List[str] = field(default_factory=list)
64
+ state: str = "PENDING"
65
+ result: Optional[Dict[str, Any]] = None
66
+ error: Optional[str] = None
67
+ started_at: Optional[str] = None
68
+ completed_at: Optional[str] = None
69
+ hash: Optional[str] = None
70
+
71
+ def to_dict(self) -> Dict[str, Any]:
72
+ return {
73
+ "id": self.id,
74
+ "opcode": self.opcode,
75
+ "payload": self.payload,
76
+ "dependencies": self.dependencies,
77
+ "state": self.state,
78
+ "result": self.result,
79
+ "error": self.error,
80
+ "started_at": self.started_at,
81
+ "completed_at": self.completed_at,
82
+ "hash": self.hash,
83
+ }
84
+
85
+ @dataclass
86
+ class Receipt:
87
+ id: str
88
+ run_id: str
89
+ objective: str
90
+ node_count: int
91
+ completed_count: int
92
+ skipped_count: int
93
+ hash_chain: str
94
+ signature: str
95
+ created_at: str
96
+ reused: bool = False
97
+
98
+ def to_dict(self) -> Dict[str, Any]:
99
+ return {
100
+ "id": self.id,
101
+ "run_id": self.run_id,
102
+ "objective": self.objective,
103
+ "node_count": self.node_count,
104
+ "completed_count": self.completed_count,
105
+ "skipped_count": self.skipped_count,
106
+ "hash_chain": self.hash_chain,
107
+ "signature": self.signature,
108
+ "created_at": self.created_at,
109
+ "reused": self.reused,
110
+ }
111
+
112
+ @dataclass
113
+ class VmEvent:
114
+ id: str
115
+ run_id: str
116
+ node_id: str
117
+ event_type: str
118
+ payload: Dict[str, Any]
119
+ timestamp: str
120
+
121
+ def to_dict(self) -> Dict[str, Any]:
122
+ return {
123
+ "id": self.id,
124
+ "run_id": self.run_id,
125
+ "node_id": self.node_id,
126
+ "event_type": self.event_type,
127
+ "payload": self.payload,
128
+ "timestamp": self.timestamp,
129
+ }
130
+
131
+ # ── VM Interpreter ──────────────────────────────────────────────
132
+ class DagVM:
133
+ def __init__(self, run_id: str, objective: str, nodes: List[DagNode]):
134
+ self.run_id = run_id
135
+ self.objective = objective
136
+ self.nodes = nodes
137
+ self.state = "PENDING"
138
+ self.events: List[VmEvent] = []
139
+ self.event_counter = 0
140
+ self.receipt_id: Optional[str] = None
141
+ self.started_at: Optional[str] = None
142
+ self.completed_at: Optional[str] = None
143
+
144
+ def _emit(self, node_id: str, event_type: str, payload: Dict[str, Any]):
145
+ self.event_counter += 1
146
+ evt = VmEvent(
147
+ id=f"evt-{self.run_id[-4:]}-{self.event_counter:04d}",
148
+ run_id=self.run_id,
149
+ node_id=node_id,
150
+ event_type=event_type,
151
+ payload=payload,
152
+ timestamp=now_iso(),
153
+ )
154
+ self.events.append(evt)
155
+
156
+ def _hash_node(self, node: DagNode) -> str:
157
+ return deterministic_hash({
158
+ "id": node.id,
159
+ "opcode": node.opcode,
160
+ "payload": node.payload,
161
+ "dependencies": sorted(node.dependencies),
162
+ "state": node.state,
163
+ "result": node.result,
164
+ })
165
+
166
+ def _hash_chain(self) -> str:
167
+ chain = ":".join(self._hash_node(n) for n in self.nodes)
168
+ return sha256_hex(chain)
169
+
170
+ def _sign_receipt(self, rcpt: Dict[str, Any]) -> str:
171
+ base = f"{rcpt['run_id']}:{rcpt['objective']}:{rcpt['hash_chain']}:{rcpt['created_at']}"
172
+ h = sha256_hex(base)
173
+ fb_id = sha256_hex(f"{h}:fallback")[:32]
174
+ return sha256_hex(f"fb-{fb_id}:{h}:fallback-sig")
175
+
176
+ def _generate_receipt(self) -> Receipt:
177
+ completed = sum(1 for n in self.nodes if n.state == "COMPLETED")
178
+ skipped = sum(1 for n in self.nodes if n.state == "SKIPPED")
179
+ rcpt_id = sha256_hex(f"{self.run_id}:{self.objective}:{now_iso()}")[:16]
180
+ base = {
181
+ "id": f"rcpt-{rcpt_id}",
182
+ "run_id": self.run_id,
183
+ "objective": self.objective,
184
+ "node_count": len(self.nodes),
185
+ "completed_count": completed,
186
+ "skipped_count": skipped,
187
+ "hash_chain": self._hash_chain(),
188
+ "created_at": now_iso(),
189
+ }
190
+ return Receipt(
191
+ id=base["id"],
192
+ run_id=base["run_id"],
193
+ objective=base["objective"],
194
+ node_count=base["node_count"],
195
+ completed_count=base["completed_count"],
196
+ skipped_count=base["skipped_count"],
197
+ hash_chain=base["hash_chain"],
198
+ signature=self._sign_receipt(base),
199
+ created_at=base["created_at"],
200
+ )
201
+
202
+ def _interpret(self, node: DagNode) -> Dict[str, Any]:
203
+ op = node.opcode
204
+ p = node.payload
205
+
206
+ if op == "LOAD_SOURCE":
207
+ src = p.get("source", "mock-source")
208
+ time.sleep(random.uniform(0.05, 0.2))
209
+ return {"loaded": True, "source": src, "bytes": len(src) * 2}
210
+
211
+ if op == "ASSERT_POLICY":
212
+ policy = p.get("policy", "default")
213
+ allowed = p.get("allowed", True)
214
+ time.sleep(random.uniform(0.01, 0.05))
215
+ return {"policy": policy, "allowed": allowed, "checked_at": now_iso()}
216
+
217
+ if op == "RETRIEVE":
218
+ query = p.get("query", "")
219
+ time.sleep(random.uniform(0.1, 0.5))
220
+ return {
221
+ "query": query,
222
+ "results": [
223
+ {"id": "doc-1", "score": 0.95, "content": f"Retrieved: {query[:40]}..."},
224
+ {"id": "doc-2", "score": 0.82, "content": "Related document"},
225
+ ],
226
+ "latency_ms": 150,
227
+ }
228
+
229
+ if op == "TRANSFORM":
230
+ inp = p.get("input", "")
231
+ time.sleep(random.uniform(0.05, 0.3))
232
+ return {
233
+ "input_length": len(inp),
234
+ "output": f"Transformed: {inp[:60]}...",
235
+ "transform_type": p.get("type", "identity"),
236
+ }
237
+
238
+ if op == "EXECUTE_SKILL":
239
+ skill = p.get("skill", "unknown")
240
+ time.sleep(random.uniform(0.2, 0.8))
241
+ return {
242
+ "skill": skill,
243
+ "executed": True,
244
+ "output": f'Skill "{skill}" executed successfully',
245
+ "tokens_used": random.randint(100, 1100),
246
+ }
247
+
248
+ if op == "VERIFY":
249
+ criterion = p.get("criterion", "accuracy")
250
+ threshold = p.get("threshold", 0.8)
251
+ score = round(0.75 + random.random() * 0.25, 4)
252
+ time.sleep(random.uniform(0.03, 0.1))
253
+ return {
254
+ "criterion": criterion,
255
+ "threshold": threshold,
256
+ "score": score,
257
+ "passed": score >= threshold,
258
+ "verified_at": now_iso(),
259
+ }
260
+
261
+ if op == "COMMIT_RECEIPT":
262
+ time.sleep(random.uniform(0.02, 0.08))
263
+ rcpt = self._generate_receipt()
264
+ return {
265
+ "receipt_id": rcpt.id,
266
+ "committed": True,
267
+ "hash_chain": rcpt.hash_chain,
268
+ }
269
+
270
+ if op == "INVALIDATE":
271
+ target = p.get("target", "cache-default")
272
+ time.sleep(random.uniform(0.01, 0.03))
273
+ return {"invalidated": True, "target": target, "invalidated_at": now_iso()}
274
+
275
+ if op == "HALT":
276
+ return {"halted": True, "reason": p.get("reason", "normal")}
277
+
278
+ raise ValueError(f"Unknown opcode: {op}")
279
+
280
+ def _execute_node(self, node: DagNode):
281
+ if node.state != "PENDING":
282
+ return
283
+
284
+ deps = [n for n in self.nodes if n.id in node.dependencies]
285
+ incomplete = [d for d in deps if d.state not in ("COMPLETED", "SKIPPED")]
286
+ if incomplete:
287
+ return
288
+
289
+ if deps and all(d.state == "SKIPPED" for d in deps):
290
+ node.state = "SKIPPED"
291
+ node.completed_at = now_iso()
292
+ self._emit(node.id, "node_skip", {"reason": "all_dependencies_skipped"})
293
+ return
294
+
295
+ node.started_at = now_iso()
296
+ node.state = "RUNNING"
297
+ self._emit(node.id, "node_start", {"opcode": node.opcode})
298
+
299
+ try:
300
+ result = self._interpret(node)
301
+ node.state = "COMPLETED"
302
+ node.result = result
303
+ node.completed_at = now_iso()
304
+ node.hash = self._hash_node(node)
305
+ self._emit(node.id, "node_complete", {"result": result})
306
+ except Exception as e:
307
+ node.state = "FAILED"
308
+ node.error = str(e)
309
+ node.completed_at = now_iso()
310
+ self._emit(node.id, "node_fail", {"error": str(e)})
311
+
312
+ def execute(self) -> Dict[str, Any]:
313
+ if self.state == "RUNNING":
314
+ raise RuntimeError("Run already executing")
315
+
316
+ self.state = "RUNNING"
317
+ self.started_at = now_iso()
318
+ self._emit("run", "run_start", {"node_count": len(self.nodes)})
319
+
320
+ pending = [n for n in self.nodes if n.state == "PENDING"]
321
+ executed = 0
322
+
323
+ while executed < len(pending):
324
+ ready = [
325
+ n for n in self.nodes
326
+ if n.state == "PENDING"
327
+ and all(
328
+ (d := next((x for x in self.nodes if x.id == dep_id), None))
329
+ and d.state in ("COMPLETED", "SKIPPED")
330
+ for dep_id in n.dependencies
331
+ )
332
+ ]
333
+ if not ready:
334
+ break
335
+ for node in ready:
336
+ self._execute_node(node)
337
+ executed += 1
338
+
339
+ all_done = all(n.state in ("COMPLETED", "SKIPPED", "FAILED") for n in self.nodes)
340
+ any_failed = any(n.state == "FAILED" for n in self.nodes)
341
+
342
+ if any_failed:
343
+ self.state = "FAILED"
344
+ self.completed_at = now_iso()
345
+ self._emit("run", "run_fail", {"reason": "node_failure"})
346
+ elif all_done:
347
+ self.state = "COMPLETED"
348
+ self.completed_at = now_iso()
349
+ commit = next((n for n in self.nodes if n.opcode == "COMMIT_RECEIPT" and n.state == "COMPLETED"), None)
350
+ receipt = None
351
+ if commit:
352
+ receipt = self._generate_receipt()
353
+ self.receipt_id = receipt.id
354
+ self._emit(commit.id, "receipt_commit", {"receipt_id": receipt.id})
355
+ self._emit("run", "run_complete", {"receipt_id": receipt.id if receipt else None})
356
+ return {"state": self.state, "receipt": receipt.to_dict() if receipt else None}
357
+
358
+ return {"state": self.state}
359
+
360
+ # ── DAG Builder ─────────────────────────────────────────────────
361
+ def build_dag(objective: str) -> List[DagNode]:
362
+ return [
363
+ DagNode("n1", "LOAD_SOURCE", {"source": objective}, []),
364
+ DagNode("n2", "ASSERT_POLICY", {"policy": "safety", "allowed": True}, ["n1"]),
365
+ DagNode("n3", "RETRIEVE", {"query": objective}, ["n2"]),
366
+ DagNode("n4", "TRANSFORM", {"input": objective, "type": "enrich"}, ["n3"]),
367
+ DagNode("n5", "EXECUTE_SKILL", {"skill": "reasoning"}, ["n4"]),
368
+ DagNode("n6", "VERIFY", {"criterion": "coherence", "threshold": 0.85}, ["n5"]),
369
+ DagNode("n7", "COMMIT_RECEIPT", {}, ["n6"]),
370
+ DagNode("n8", "HALT", {"reason": "objective_complete"}, ["n7"]),
371
+ ]
372
+
373
+ # ── Gradio Interface ────────────────────────────────────────────
374
+ def run_vm(objective: str, deterministic: bool) -> tuple:
375
+ if deterministic:
376
+ random.seed(hash(objective) % 2**32)
377
+
378
+ run_id = f"run-{sha256_hex(objective)[:12]}"
379
+ nodes = build_dag(objective)
380
+ vm = DagVM(run_id, objective, nodes)
381
+ result = vm.execute()
382
+
383
+ # Build output text
384
+ lines = [
385
+ f"🎯 Objective: {objective}",
386
+ f"πŸ”– Run ID: {run_id}",
387
+ f"πŸ“Š State: {vm.state}",
388
+ "",
389
+ "─" * 50,
390
+ "πŸ“‹ Execution Log",
391
+ "─" * 50,
392
+ ]
393
+
394
+ for evt in vm.events:
395
+ if evt.event_type == "node_start":
396
+ lines.append(f" ▢️ [{evt.node_id}] {evt.payload.get('opcode', '?')} β€” START")
397
+ elif evt.event_type == "node_complete":
398
+ res = evt.payload.get("result", {})
399
+ lines.append(f" βœ… [{evt.node_id}] COMPLETE β€” {json.dumps(res, ensure_ascii=False)[:80]}...")
400
+ elif evt.event_type == "node_fail":
401
+ lines.append(f" ❌ [{evt.node_id}] FAIL β€” {evt.payload.get('error', '?')}")
402
+ elif evt.event_type == "node_skip":
403
+ lines.append(f" ⏭️ [{evt.node_id}] SKIP")
404
+ elif evt.event_type == "receipt_commit":
405
+ lines.append(f" 🧾 [{evt.node_id}] RECEIPT β€” {evt.payload.get('receipt_id', '?')}")
406
+ elif evt.event_type == "run_complete":
407
+ lines.append(f" 🏁 RUN COMPLETE")
408
+ elif evt.event_type == "run_fail":
409
+ lines.append(f" πŸ’₯ RUN FAILED β€” {evt.payload.get('reason', '?')}")
410
+
411
+ lines.extend([
412
+ "",
413
+ "─" * 50,
414
+ "🧾 Receipt",
415
+ "─" * 50,
416
+ ])
417
+
418
+ receipt = result.get("receipt")
419
+ if receipt:
420
+ lines.extend([
421
+ f" ID: {receipt['id']}",
422
+ f" Run ID: {receipt['run_id']}",
423
+ f" Objective: {receipt['objective']}",
424
+ f" Nodes: {receipt['completed_count']}/{receipt['node_count']}",
425
+ f" Hash Chain: {receipt['hash_chain'][:40]}...",
426
+ f" Signature: {receipt['signature'][:40]}...",
427
+ f" Created: {receipt['created_at']}",
428
+ ])
429
+ else:
430
+ lines.append(" No receipt generated.")
431
+
432
+ lines.extend([
433
+ "",
434
+ "─" * 50,
435
+ "πŸ“Š Node States",
436
+ "─" * 50,
437
+ ])
438
+ for n in vm.nodes:
439
+ status = "βœ…" if n.state == "COMPLETED" else "❌" if n.state == "FAILED" else "⏭️" if n.state == "SKIPPED" else "⏳"
440
+ lines.append(f" {status} {n.id}: {n.opcode:<18} β†’ {n.state}")
441
+
442
+ return "\n".join(lines), json.dumps(result, indent=2)
443
+
444
+ # ── UI ──────────────────────────────────────────────────────────
445
+ with gr.Blocks(title="Membra DAG VM", theme=gr.themes.Soft()) as demo:
446
+ gr.Markdown("""
447
+ # 🧠 Membra DAG VM
448
+ ### Deterministic Execution Engine β€” Zero API Keys Required
449
+
450
+ This VM executes a Directed Acyclic Graph (DAG) of computation nodes
451
+ with verifiable receipts. Every run is deterministic and reproducible.
452
+ """)
453
+
454
+ with gr.Row():
455
+ with gr.Column(scale=2):
456
+ objective = gr.Textbox(
457
+ label="Objective",
458
+ placeholder="Enter a computation objective...",
459
+ value="Analyze sentiment of customer reviews and summarize findings",
460
+ lines=2,
461
+ )
462
+ deterministic = gr.Checkbox(
463
+ label="Deterministic Mode (seeded RNG)",
464
+ value=True,
465
+ )
466
+ run_btn = gr.Button("▢️ Execute DAG", variant="primary", size="lg")
467
+
468
+ with gr.Column(scale=3):
469
+ output_log = gr.Textbox(
470
+ label="Execution Log",
471
+ lines=25,
472
+ max_lines=40,
473
+ show_copy_button=True,
474
+ )
475
+ output_json = gr.JSON(
476
+ label="Result (JSON)",
477
+ )
478
+
479
+ gr.Markdown("""
480
+ ---
481
+ ### πŸ“– How It Works
482
+
483
+ 1. **LOAD_SOURCE** β€” Ingest the objective
484
+ 2. **ASSERT_POLICY** β€” Verify safety constraints
485
+ 3. **RETRIEVE** β€” Fetch relevant context
486
+ 4. **TRANSFORM** β€” Enrich and structure data
487
+ 5. **EXECUTE_SKILL** β€” Run the reasoning skill
488
+ 6. **VERIFY** β€” Check output coherence
489
+ 7. **COMMIT_RECEIPT** β€” Generate verifiable receipt
490
+ 8. **HALT** β€” Terminate execution
491
+
492
+ *All operations are self-contained. No external API calls are made.*
493
+ """)
494
+
495
+ run_btn.click(
496
+ fn=run_vm,
497
+ inputs=[objective, deterministic],
498
+ outputs=[output_log, output_json],
499
+ )
500
+
501
+ if __name__ == "__main__":
502
+ demo.launch()