Spaces:
Running
Running
| """ayllu.lounge — the collaboration surface, learned from the tribe lounge/bus. | |
| The tribe let souls talk in a shared room. a11oy keeps that, in-memory and honest: each | |
| posted message carries a source label ("model-unverified" when a model answered, | |
| else "persona-fallback"), so a reader never mistakes direct model text for grounded | |
| Brain retrieval. `deliberate()` runs a BOUNDED council round — one honest turn | |
| per persona — and never fabricates when no backend is injected. Publishing is | |
| explicit opt-in; public ask/council calls keep their output out of this feed. | |
| """ | |
| from __future__ import annotations | |
| import asyncio | |
| import time | |
| from typing import Any | |
| class Lounge: | |
| def __init__(self, capacity: int = 200) -> None: | |
| self.capacity = int(capacity) | |
| self.feed: list[dict[str, Any]] = [] | |
| def post(self, persona: str, text: str, *, source: str = "persona") -> dict[str, Any]: | |
| entry = {"ts": time.time(), "persona": persona, "text": text, "source": source} | |
| self.feed.append(entry) | |
| if len(self.feed) > self.capacity: | |
| self.feed = self.feed[-self.capacity:] | |
| return entry | |
| def recent(self, n: int = 50) -> list[dict[str, Any]]: | |
| return self.feed[-int(n):] | |
| async def deliberate( | |
| self, | |
| prompt: str, | |
| personas: list, | |
| *, | |
| model_complete=None, | |
| difficulty: float = 0.6, | |
| two_person_attested: bool = False, | |
| debate: bool = False, | |
| publish_to_lounge: bool = False, | |
| ) -> dict[str, Any]: | |
| from .loop import run_turn | |
| async def _one_turn(p, turn_prompt: str): | |
| return await run_turn( | |
| p, turn_prompt, model_complete=model_complete, | |
| difficulty=difficulty, | |
| two_person_attested=two_person_attested) | |
| # A council round is independent fan-out. Preserve input order in the | |
| # evidence, but spend one bounded deadline instead of N sequential ones. | |
| rounds = list(await asyncio.gather(*( | |
| _one_turn(p, prompt) for p in personas | |
| ))) | |
| for p, turn in zip(personas, rounds): | |
| turn["round"] = 1 | |
| src = ("model-unverified" if turn.get("answer") is not None | |
| and not turn.get("stub") else "persona-fallback") | |
| if publish_to_lounge: | |
| self.post(p.name, turn.get("answer") or turn.get("honesty"), source=src) | |
| mode = "single-round" | |
| # Debate-then-converge (after arXiv:2305.14325, Multiagent Debate): one | |
| # bounded extra round where each persona reads its peers' round-1 positions, | |
| # states dissent or agreement explicitly, and revises. EXACTLY two rounds — | |
| # never an open-ended loop. Runs only when a real/stub backend is injected | |
| # and at least two personas answered (an honest debate needs peers). | |
| if debate and model_complete is not None: | |
| positions = [ | |
| (r.get("persona"), r.get("answer")) | |
| for r in rounds if r.get("answer") | |
| ] | |
| if len(positions) >= 2: | |
| mode = "debate" | |
| debate_jobs = [] | |
| for p in personas: | |
| peers = "\n\n".join( | |
| f"[{name}] {ans[:1200]}" for name, ans in positions | |
| if name != p.name | |
| ) | |
| debate_prompt = ( | |
| "COUNCIL DEBATE ROUND (bounded: this is the final round).\n" | |
| f"Original question:\n{prompt}\n\n" | |
| f"Your peers' opening positions:\n{peers}\n\n" | |
| "State explicitly where you agree or dissent, then give " | |
| "your revised answer. Honest dissent beats false consensus." | |
| ) | |
| debate_jobs.append((p, debate_prompt)) | |
| revised = list(await asyncio.gather(*( | |
| _one_turn(p, turn_prompt) for p, turn_prompt in debate_jobs | |
| ))) | |
| for (p, _turn_prompt), turn in zip(debate_jobs, revised): | |
| turn["round"] = 2 | |
| src = ("model-unverified" if turn.get("answer") is not None | |
| and not turn.get("stub") else "persona-fallback") | |
| if publish_to_lounge: | |
| self.post(p.name, turn.get("answer") or turn.get("honesty"), | |
| source=src) | |
| rounds.append(turn) | |
| else: | |
| mode = "single-round" | |
| return { | |
| "prompt": prompt, | |
| "participants": [p.name for p in personas], | |
| "rounds": rounds, | |
| "mode": mode, | |
| "published_to_lounge": publish_to_lounge, | |
| "note": "bounded council; each turn honest (no fabrication when a model " | |
| "backend is absent); debate mode = exactly two rounds, " | |
| "after arXiv:2305.14325", | |
| } | |