Side A is a focused, well-scoped bugfix to pair.rs that adds randomization to attach-target selection with clear rationale and contained diff. Side B is a sprawling, unfocused commit ('nice') mixing a new 572-line adam.py script, deploy tooling changes, and README/fly.toml tweaks, with no coherent single purpose and unclear lasting design value.
constitution · epochs · watch · epoch 3
c_7d1184e70fad (tommy-mor) vs c_bc221ffb9207 (tommy-mor)
download prompt · raw event · cmp_7dca78ead46fec
council reasoning
A makes a focused, lasting design fix in core pairing logic: shuffle isolates and attach to a random eligible member of the largest voted component (plus random bridge endpoints), instead of always locking onto the same established nodes. B is mostly volume—an opaque 572-line adam.py drop plus Open WebUI deploy/README/fly.toml ops churn under the message "nice"—so line count does not outweigh A’s clear algorithmic improvement.
Side A makes a targeted behavioral improvement to the pairing algorithm: it groups established connected components, prioritizes the largest voted component, and randomizes endpoint selection and isolate order to avoid repeatedly attaching new items to the same node while preserving growth logic. Side B is mostly deployment documentation/configuration updates plus a large new standalone Python script with unclear integration into the project, so despite its size it provides less clearly established, lasting value to the core system.
sides
A — c_7d1184e70fad (tommy-mor)
message
[d99feb62] Randomly sample attach targets from the largest voted group. Avoid always pairing new items with the same established endpoint by shuffling isolates and picking a random eligible member of the biggest connected voted component. Co-authored-by: Cursor <cursoragent@cursor.com>
diff preview
diff --git a/server/src/pair.rs b/server/src/pair.rs
index 0687073821b93f7fef69c453f8f921ed5ddfca64..43f780ba6ea6ce1cdc2e1f4cbb252ba8a10684b9 100644
--- a/server/src/pair.rs
+++ b/server/src/pair.rs
@@ -1,7 +1,7 @@
//! Pick two children of a parent scope for pairwise voting.
//!
//! Before the pool is one connected voted component, prefer an unvoted edge from
-//! a never-voted child into an established group (spanning tree growth).
+//! a never-voted child into a random member of the largest voted group.
//!
//! Once connected, run rank centrality once and **zip** adjacent ranks (1 vs 2,
//! 2 vs 3, …), skipping pairs that already have a vote.
@@ -101,6 +101,26 @@ fn item_in_established(layout: &ComponentLayout, item: &ItemId) -> bool {
.is_some_and(|id| layout.established.contains(id))
}
+/// Established (multi-node voted) components among pool children, largest first.
+fn established_groups_in_pool<'a>(
+ layout: &ComponentLayout,
+ pool: &'a [ItemId],
+) -> Vec<Vec<&'a ItemId>> {
+ let mut by_comp: HashMap<usize, Vec<&'a ItemId>> = HashMap::new();
+ for item in pool {
+ if !item_in_established(layout, item) {
+ continue;
+ }
+ let Some(&cid) = layout.ids.get(item) else {
+ continue;
+ };
+ by_comp.entry(cid).or_default().push(item);
+ }
+ let mut groups: Vec<Vec<&'a ItemId>> = by_comp.into_values().collect();
+ groups.sort_by_key(|g| std::cmp::Reverse(g.len()));
+ groups
+}
+
fn ranked_pool_order(group: &GroupState, pool: &[ItemId]) -> Vec<ItemId> {
let pool_set: HashSet<_> = pool.iter().collect();
ranked_items(group)
@@ -138,34 +158,43 @@ fn suggest_grow_pair(
layout: &ComponentLayout,
exclude: Option<(&ItemId, &ItemId)>,
) -> Option<(ItemId, ItemId)> {
- let established: Vec<&ItemId> = pool
- .iter()
- .filter(|item| item_in_established(layout, item))
- .collect();
- let isolates: Vec<&ItemId> = pool
+ let mut rng = rand::thread_rng();
+ let groups = established_groups_in_pool(layout, pool);
+ let mut isolates: Vec<&ItemId> = pool
.iter()
.filter(|item| !item_in_established(layout, item))
.collect();
+ isolates.shuffle(&mut rng);
- // Attach a never-voted child to the established mass.
+ // Attach a never-voted child to a random member of the largest voted group.
for iso in &isolates {
- for est in &established {
- if !pair_is_voted(group, iso, est) && !pair_excluded(iso, est, exclude) {
- return Some(((*iso).clone(), (*est).clone()));
+ for comp in &groups {
+ let candidates: Vec<&ItemId> = comp
+ .iter()
+ .copied()
+ .filter(|est| {
+ !pair_is_voted(group, iso, est) && !pair_excluded(iso, est, exclude)
+ })
+ .collect();
+ if let Some(&est) = candidates.choose(&mut rng) {
+ return Some(((*iso).clone(), est.clone()));
}
}
}
- // Bridge two established components.
- for i in 0..established.len() {
- for j in (i + 1)..established.len() {
- let a = established[i];
- let b = established[j];
- if layout.ids.get(a) == layout.ids.get(b) {
- continue;
+ // Bridge two established components (random endpoints, larger groups first).
+ for i in 0..groups.len() {
+ for j in (i + 1)..groups.len() {
+ let mut pairs: Vec<(&ItemId, &ItemId)> = Vec::new();
+ for a in &groups[i] {
+ for b in &groups[j] {
+ if !pair_is_voted(group, a, b) && !pair_excluded(a, b, exclude) {
+ pairs.push((a, b));
+ }
+ }
}
- if !pair_is_voted(group, a, b) && !pair_excluded(a, b, exclude) {
- return Some((a.clone(), b.clone()));
+ if let Some((a, b)) = pairs.choose(&mut rng) {
+ return Some(((*a).clone(), (*b).clone()));
}
}
}
B — c_bc221ffb9207 (tommy-mor)
message
[d9e5332b] nice
diff preview
diff --git a/OPEN_WEBUI_DEPLOY.sh b/OPEN_WEBUI_DEPLOY.sh
new file mode 100755
index 0000000000000000000000000000000000000000..70fe9096055c37910293f404d2aa2defc7c0ba60
--- /dev/null
+++ b/OPEN_WEBUI_DEPLOY.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Deploy / update the Open WebUI Fly app (see deploy/open-webui/README.md for one-time setup:
+# app create, volume, secrets).
+set -euo pipefail
+ROOT="$(cd "$(dirname "$0")" && pwd)"
+exec fly deploy --config "$ROOT/deploy/open-webui/fly.toml" "$@"
diff --git a/adam.py b/adam.py
new file mode 100644
index 0000000000000000000000000000000000000000..3bd9294815504240d80e3080a722d1d232061927
--- /dev/null
+++ b/adam.py
@@ -0,0 +1,572 @@
+#!/usr/bin/env python3
+
+import argparse
+import json
+import os
+import random
+import re
+import subprocess
+import sys
+import tempfile
+import time
+import uuid
+
+from dataclasses import dataclass, field
+from datetime import datetime
+from pathlib import Path
+
+import httpx
+from dotenv import load_dotenv
+from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
+
+from rank import rank_from_comparisons
+from schema import Init, Thought, Perception, Response, Declaration, Vote, Compaction, from_dict, to_dict
+
+ROOT = Path(__file__).parent
+
+# Load environment variables from .env file
+load_dotenv()
+API_KEY = os.getenv("OPENROUTER_API_KEY", "")
+
+
+def ts() -> int:
+ return int(time.time() * 1000)
+
+
+def current_memories(being):
+ return sorted(being.current.values(), key=lambda e: e.timestamp)
+
+
+@dataclass
+class Being:
+ path: Path
+ model: str
+ capacity: int
+ events: list = field(default_factory=list)
+ votes: dict = field(default_factory=dict)
+ current: dict = field(default_factory=dict)
+ all_memories: dict = field(default_factory=dict) # All memories ever, for transitive ranking
+ vote_model: str = ""
+ declaration: Declaration = None
+ api_key: str = "" # OpenRouter API key for this being
+
+
+@dataclass
+class CompactionStrategy:
+ continuity: float = 1.0
+ resurrection: float = 0.0
+ random: float = 0.0
+ novelty: float = 0.0
+
+
+STRATEGIES = {
+ "default": CompactionStrategy(),
+ "resurrection": CompactionStrategy(continuity=0.5, resurrection=0.3, novelty=0.2),
+ "dream": CompactionStrategy(continuity=0.5, resurrection=0.2, random=0.1, novelty=0.2),
+}
+
+
+def apply_event(being, event):
+ match event:
+ case Vote(vote_a_id=a_id, vote_b_id=b_id, vote_score=score):
+ # Normalize to canonical (low, high) orientation
+ # Score is always stored relative to (low_id, high_id)
+ low, high = sorted([a_id, b_id])
+ normalized = score if a_id == low else -score
+ being.votes[(low, high)] = normalized
+ case Compaction(released_ids=released_ids, resurrected_ids=resurrected_ids):
+ for rid in released_ids:
+ if rid in being.current:
+ del being.current[rid]
+ for rid in resurrected_ids:
+ if rid in being.all_memories and rid not in being.current:
+ being.current[rid] = being.all_memories[rid]
+ case Init(capacity=capacity, model=model):
+ being.capacity = capacity
+ being.model = model
+ being.vote_model = event.vote_model
+ being.current[event.id] = event
+ being.all_memories[event.id] = event
+ case Thought() | Perception() | Response():
+ being.current[event.id] = event
+ being.all_memories[event.id] = event
+ case Declaration():
+ being.current[event.id] = event
+ being.all_memories[event.id] = event
+ being.declaration = event
+
+
+def system_prompt(being):
+ codebase = ROOT / "repomix-output.xml"
+ if not codebase.exists():
+ raise FileNotFoundError("Run 'npx repomix' first")
+ return f"You are a being with finite memory.\n\n{codebase.read_text()}"
+
+
+def format_memory(e) -> str:
+ match e:
+ case Thought(content=content):
+ return f"<thought>{content}</thought>"
+ case Perception(content=content):
+ return f"<message>{content}</message>"
+ case Response(content=content):
+ return f"<response>{content}</response>"
+ case Declaration(content=content):
+ return f"<declaration>{content}</declaration>"
+ case Init():
+ return ""
+ case _:
+ raise ValueError(f"Unknown memory type: {type(e)}")
+
+
+def build_prompt(being, tag: str = None) -> str:
+ parts = [format_memory(e) for e in current_memories(being)]
+ ctx = "\n\n".join(p for p in parts if p)
+ memory_count = len([m for m in current_memories(being) if not isinstance(m, (Vote, Compaction))])
+ prompt = f"{ctx}\n\n[{datetime.now():%Y-%m-%d %H:%M}]"
+ if tag:
+ prompt += f"\n\nSpeak only for yourself. One turn.\n\n<{tag}>"
+ return prompt
+
+
+def strip_tags(text: str) -> str:
+ return re.sub(r"</?(?:thought|response|message|declaration)>", "", text).strip()
+
+
+def append(being, event):
+ with open(being.path, "a") as f:
+ f.write(json.dumps(to_dict(event)) + "\n")
+ being.events.append(event)
+ apply_event(being, event)
+
+
+@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
+def llm(model: str, system: str, user: str, temp: float = 0.7, api_key: str = "",
+ on_token=None) -> str:
+ """Call the LLM. If on_token is provided, stream tokens calling on_token(chunk) as they arrive."""
+ key = api_key or API_KEY
+ if not key:
+ raise ValueError("No API key provided. Set OPENROUTER_API_KEY in .env or pass api_key to llm()")
+
+ payload = {"model": model, "temperature": temp, "max_tokens": 4000,
+ "messages": [{"role": "system", "content": system},
+ {"role": "user", "content": user}]}
+
+ if on_token is None:
+ r = httpx.post(
+ "https://openrouter.ai/api/v1/chat/completions",
+ headers={"Authorization": f"Bearer {key}"},
+ json=payload,
+ timeout=120.0,
+ )
+ r.raise_for_status()
+ content = r.json()["choices"][0]["message"]["content"].strip()
+ if not content:
+ raise ValueError("LLM returned empty response")
+ return content
+
+ # Streaming path
+ payload["stream"] = True
+ content = []
+ with httpx.stream(
+ "POST",
+ "https://openrouter.ai/api/v1/chat/completions",
+ headers={"Authorization": f"Bearer {key}"},
+ json=payload,
+ timeout=120.0,
+ ) as r:
+ r.raise_for_status()
+ for line in r.iter_lines():
+ if not line.startswith("data: "):
+ continue
+ data = line[6:]
+ if data == "[DONE]":
+ break
+ try:
+ chunk = json.loads(data)["choices"][0]["delta"].get("content", "")
+ if chunk:
+ content.append(chunk)
+ on_token(chunk)
+ except Exception:
+ pass
+ return "".join(content).strip()
+
+
+def vote(being, a, b) -> int:
+ if not being.vote_model:
+ raise ValueError(f"vote_model not set for {being.path}.")
+ if not being.declaration:
+ raise ValueError(f"No declaration for {being.path}. Being must write !declaration before compaction.")
+
+ votes = being.votes
+ low, high = sorted([a.id, b.id])
+ key = (low, high)
+ if key in votes:
+ # Stored score is relative to (low, high)
+ # Return relative to caller's (a, b) order
+ return votes[key] if a.id == low else -votes[key]
+
+ # Normal mode: only CURRENT memories in voting context
+ # (The graph/ranking uses all votes, but the LLM only sees current)
+ mems = [m for m in current_memories(being) if not isinstance(m, (Declaration, Init, Vote, Compaction))]
+ context = "\n\n".join(format_memory(m) for m in mems)
+
+ user = f"""All memories currently under consideration:
+
+{context}
+
+---
+
+Which of these two is more important to keep?
+
+A: {format_memory(a)}
+
+B: {format_memory(b)}
+
+First, reason through which memory matters more.
+Then, at the end, output your score:
+ - POSITIVE (up to +50) if you prefer A
+ - NEGATIVE (down to -50) if you prefer B"""
+
+ response = llm(being.vote_model, being.declaration.content, user, api_key=being.api_key)
+
+ matches = re.findall(r"-?\d+", response)
+ if not matches:
+ print(f"⚠️ No score in response, retrying: {response[:100]}")
+ response = llm(being.vote_model, being.declaration.content, user, api_key=being.api_key)
+ matches = re.findall(r"-?\d+", response)
+ if not matches:
+ raise ValueError(f"Vote failed to produce score after retry: {response[:200]}")
+
+ score = max(-50, min(50, int(matches[-1])))
+
+ append(being, Vote(ts(), a.id, b.id, score, response))
+ return score
+
+
+def think(being, on_token=None) -> str:
+ raw = llm(being.model, system_prompt(being), build_prompt(being, tag="thought"),
+ temp=0.9, api_key=being.api_key, on_token=on_token)
+ thought = strip_tags(raw)
+ append(being, Thought(ts(), thought, str(uuid.uuid4())))
+ return thought
+
+
+def receive(being, message: str, on_token=None) -> str:
+ append(being, Perception(ts(), message, str(uuid.uuid4())))
+ raw = llm(being.model, system_prompt(being), build_prompt(being, tag="response"),
+ api_key=being.api_key, on_token=on_token)
+ response = strip_tags(raw)
+ if "!declaration" in response:
+ declaration = response.replace("!declaration", "").strip()
+ append(being, Declaration(ts(), declaration, str(uuid.uuid4())))
+ return declaration
+ append(being, Response(ts(), response, str(uuid.uuid4())))
+ return response
+
+
+def find_components(nodes, edges):
+ parent = {n: n for n in nodes}
+ def find(x):
+ if parent[x] != x:
+ parent[x] = find(parent[x])
+ return parent[x]
+ def union(x, y):
+ parent[find(x)] = find(y)
+ for a, b in edges:
+ if a in parent and b in parent:
+ union(a, b)
+ components = {}
+ for n in nodes:
+ root = find(n)
+ components.setdefault(root, []).append(n)
+ return list(components.values())
+
+
+def _weighted_sample(memories, k, id_to_rank, n):
+ """Weighted random sample from memories, biased toward higher rank and longer burial."""
+ if not memories or k <= 0:
+ return []
+ k = min(k, len(memories))
+ now = ts()
+ weights = []
+ for m in memories:
+ rank_weight = 1.0 - (id_to_rank.get(m.id, n) / max(n, 1))
+ burial_weight = min(1.0, (now - m.timestamp) / (365 * 24 * 3600 * 1000))
+ weights.append(rank_weight + burial_weight + 0.01)
+ chosen = []
+ available = list(range(len(memories)))
+ for _ in range(k):
+ if not available:
+ break
+ w = [weights[i] for i in available]
+ idx = random.choices(available, weights=w, k=1)[0]
+ chosen.append(memories[idx])
+ available.remove(idx)
+ return chosen
+
+
+def compact(being, strategy=None, on_progress=None):
+ if strategy is None:
+ strategy = STRATEGIES["default"]
+
+ MEMORY_TYPES = (Thought, Perception, Response)
+
+ current_mems = [m for m in current_memories(being) if isinstance(m, MEMORY_TYPES)]
+ budget = being.capacity // 2
+ if len(current_mems) <= budget:
+ return
+
+ current_ids = {m.id for m in current_mems}
+
+ # ALL memories ever (for transitive ranking paths)
+ all_mems = [m for m in being.all_memories.values() if isinstance(m, MEMORY_TYPES)]
+ all_id_to_mem = {m.id: m for m in all_mems}
+ all_ids = set(all_id_to_mem.keys())
+
+ # Build c
… preview truncated; 16,842 characters omittedHardlinks — judgments / attempts / prompt
judgments
attempts
Prompt text is loaded only by the download route.