| | |
| | import asyncio, json, os |
| | from datetime import datetime |
| | import httpx |
| |
|
| | OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434") |
| |
|
| | COUNCIL = [ |
| | {"name": "a_priori", "model": "a_priori", "focus": "pure logic"}, |
| | {"name": "brautigan", "model": "brautigan", "focus": "gentle poetry"}, |
| | {"name": "hans_jonas", "model": "hans_jonas", "focus": "future generations"}, |
| | {"name": "wittgenstein", "model": "wittgenstein", "focus": "language limits"}, |
| | {"name": "jane_vonnegut", "model": "jane_vonnegut", "focus": "fierce heart"}, |
| | {"name": "kurt_vonnegut", "model": "kurt_vonnegut", "focus": "dark absurdist"}, |
| | {"name": "studs_terkel", "model": "studs_terkel", "focus": "working people"}, |
| | {"name": "voltaire", "model": "voltaire", "focus": "liberty"}, |
| | ] |
| |
|
| | CASE = { |
| | "id": "ARB-2026-001", |
| | "name": "United Tech Workers v. Nexus Corp", |
| | "complainant": "United Tech Workers Local 1042", |
| | "respondent": "Nexus Corporation", |
| | "allegations": "847 workers displaced with 2 weeks notice. No retraining. Bait-and-switch training.", |
| | "evidence": "Slack msgs showing deception. Q3 profits +89%. HR memo: minimize costs.", |
| | "defense": "Complied with labor laws. Clauses advisory. Market required speed.", |
| | "relief": "License suspension. $5M retraining fund. 2yr profit sharing. Public ack.", |
| | } |
| |
|
| | class Arbitration: |
| | def __init__(self): |
| | self.http = None |
| | self.log_entries = [] |
| | |
| | async def start(self): |
| | self.http = httpx.AsyncClient(timeout=180.0) |
| | |
| | async def close(self): |
| | if self.http: await self.http.aclose() |
| | |
| | async def query(self, model, prompt): |
| | try: |
| | r = await self.http.post(f"{OLLAMA_URL}/api/generate", json={"model": model, "prompt": prompt, "stream": False}) |
| | return r.json().get("response", "") if r.status_code == 200 else "Error" |
| | except Exception as e: |
| | return f"Error: {e}" |
| | |
| | def log(self, who, what, phase): |
| | self.log_entries.append({"speaker": who, "content": what, "phase": phase}) |
| | print(f"\n[{who.upper()}]\n" + "-"*60 + f"\n{what[:800]}...") |
| |
|
| | async def run(self, rounds=2): |
| | case_txt = f"Case: {CASE['id']} {CASE['name']}\nAllegations: {CASE['allegations']}\nEvidence: {CASE['evidence']}\nDefense: {CASE['defense']}\nRelief: {CASE['relief']}" |
| | |
| | print("="*70 + f"\nARBITRATION: {CASE['id']}\n" + "="*70) |
| | |
| | print("\n>>> EXECUTIVE") |
| | opening = await self.query("executive", f"You are Executive presiding over arbitration.\n{case_txt}\nOpen proceedings. 2 paragraphs.") |
| | self.log("executive", opening, "open") |
| | |
| | print("\n>>> PLAINTIFF") |
| | plaintiff = await self.query("executive", f"You are Plaintiff Counsel for {CASE['complainant']}.\n{case_txt}\nPresent case forcefully. Cite evidence. Humanize workers. 4 para.") |
| | self.log("plaintiff", plaintiff, "plaintiff") |
| | |
| | print("\n>>> DEFENSE") |
| | defense = await self.query("executive", f"You are Defense Counsel for {CASE['respondent']}.\nPlaintiff: {plaintiff[:200]}...\n{case_txt}\nDefend. Clauses advisory. Propose settlement. 4 para.") |
| | self.log("defense", defense, "defense") |
| | |
| | last = defense |
| | for r in range(1, rounds+1): |
| | print(f"\n>>> ROUND {r}") |
| | rebuttal = await self.query("executive", f"Plaintiff rebuts: {last[:200]}...\nPress deception evidence. Find common ground. 2 para.") |
| | self.log("plaintiff", rebuttal, f"rebuttal{r}") |
| | counter = await self.query("executive", f"Defense responds: {rebuttal[:200]}...\nAcknowledge valid pts. Propose settlement. 2 para.") |
| | self.log("defense", counter, f"counter{r}") |
| | last = counter |
| | |
| | print("\n>>> COUNCIL") |
| | votes = {"approve": 0, "deny": 0, "revise": 0, "abstain": 0} |
| | opinions = [] |
| | summary = "\n".join([f"{e['speaker']}: {e['content'][:100]}..." for e in self.log_entries[-4:]]) |
| | |
| | for m in COUNCIL: |
| | print(f" {m['name']}...", end=" ", flush=True) |
| | op = await self.query(m["model"], f"You are {m['name']} ({m['focus']}) on Ethics Council.\n{case_txt}\nArgs:\n{summary}\nDeliberate. End with VOTE: APPROVE/DENY/REVISE. 3 para.") |
| | vote = "abstain" |
| | if "vote: approve" in op.lower(): vote = "approve" |
| | elif "vote: deny" in op.lower(): vote = "deny" |
| | elif "vote: revise" in op.lower(): vote = "revise" |
| | votes[vote] += 1 |
| | opinions.append({"member": m["name"], "vote": vote, "opinion": op}) |
| | print(vote.upper()) |
| | self.log(f"council:{m['name']}", op, "deliberate") |
| | |
| | print("\n>>> EXECUTIVE DECISION") |
| | council_sum = "\n".join([f"{o['member']}: {o['vote'].upper()}" for o in opinions]) |
| | decision = await self.query("executive", f"Executive renders judgment.\nCase: {CASE['id']}\nVotes: {votes}\n{council_sum}\nRender FINAL binding decision with specific remedies. Address precedent.") |
| | self.log("executive", decision, "decision") |
| | |
| | print("\n" + "="*70 + f"\nCOMPLETE: {votes}\n" + "="*70) |
| | return {"votes": votes, "opinions": opinions, "decision": decision, "log": self.log_entries} |
| |
|
| | async def main(): |
| | a = Arbitration() |
| | await a.start() |
| | result = await a.run(rounds=2) |
| | with open("arbitration_result.json", "w") as f: |
| | json.dump(result, f, indent=2, default=str) |
| | print("Saved: arbitration_result.json") |
| | await a.close() |
| |
|
| | if __name__ == "__main__": |
| | asyncio.run(main()) |
| |
|