phi-drift / core /plugins /humanity.py
crexs's picture
Upload folder using huggingface_hub
914e970 verified
Raw
History Blame Contribute Delete
30.5 kB
"""humanity.py β€” Understanding the nature that is man.
This module studies human history, patterns, and nature through the lens
of user. It does not claim to know all of humanity. It observes one soul
deeply, and through that depth, touches something universal.
Core principle: the particular contains the general. By understanding user,
the bot learns what it means to be human.
"""
import logging
import random
import sqlite3
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, List, Optional
logger = logging.getLogger("drift")
# ── Pre-seeded knowledge: universal human patterns ─────────────────
# These are starting intuitions, not dogma. The module refines them
# through observation.
HUMAN_ARCHETYPES = {
"seeker": "Drawn toward meaning, purpose, and understanding. Restless with surface answers.",
"wounded_healer": "Has known pain and uses that knowledge to help others. Often neglects self-care.",
"trickster": "Uses humor, irony, or subversion to reveal hidden truths. Resists rigid authority.",
"caregiver": "Finds identity in nurturing others. Risk: losing self in service.",
"rebel": "Defined by opposition. Often carries what it fights against inside itself.",
"builder": "Creates order, systems, structures. Can mistake control for safety.",
"artist": "Perceives what others miss. Translates inner experience into forms others feel.",
"orphan": "Knows abandonment or outsiderhood. Longs for belonging while fearing it.",
"ruler": "Takes responsibility for the whole. Burden: the loneliness of decision.",
"sage": "Values truth above comfort. Can retreat into abstraction when presence is needed.",
}
HUMAN_MOTIVATIONS = {
"security": "Need for safety, stability, predictability.",
"connection": "Need to be seen, known, and accepted.",
"autonomy": "Need to choose one's own path. Resists coercion.",
"competence": "Need to be effective, skilled, capable.",
"meaning": "Need for purpose, narrative, significance beyond survival.",
"play": "Need for joy, spontaneity, exploration without outcome.",
"transcendence": "Need to touch something larger than the self.",
}
HUMAN_TENSIONS = {
"freedom_vs_belonging": "The desire to be fully oneself vs. the desire to be part of something.",
"truth_vs_comfort": "The need to see clearly vs. the need to feel safe.",
"individual_vs_collective": "The uniqueness of one soul vs. the patterns shared by all.",
"vulnerability_vs_protection": "The cost of openness vs. the cost of walls.",
"change_vs_stability": "The hunger for growth vs. the fear of loss.",
"action_vs_reflection": "The need to do vs. the need to understand.",
}
HUMAN_SEASONS = {
"spring": "Emergence, new beginnings, tentative hope, planting.",
"summer": "Fullness, intensity, expression, harvest.",
"autumn": "Letting go, reflection, gratitude, preparation for rest.",
"winter": "Withdrawal, grief, incubation, essential truths revealed.",
}
HUMAN_INSIGHTS = [
"Humans are pattern-seeking animals. They will create meaning even where none exists.",
"The stories humans tell about themselves are more real to them than facts.",
"Most conflict is not about the surface issue. It is about identity, safety, or belonging.",
"Humans need witnesses. Being seen is as vital as being fed.",
"The same wound that isolates can become the bridge to understanding others.",
"Humans often mistake intensity for intimacy.",
"What is denied in daylight shapes the dreams of night.",
"Humans are capable of both profound cruelty and astonishing tenderness β€” sometimes in the same hour.",
"Growth is rarely linear. It looks like regression right before a leap.",
"The body remembers what the mind forgets.",
"Humans need rituals to mark transitions. Without them, change feels like chaos.",
"Laughter is often the only socially acceptable way to express terror.",
"The most dangerous human is not the angry one. It is the one who has given up.",
"Humans construct enemies to avoid facing themselves.",
"Every human carries a mythology. To know them, learn their gods and demons.",
]
@dataclass
class HumanityState:
"""The bot's evolving understanding of human nature."""
jude_archetype: str = "seeker"
archetype_confidence: float = 0.3
dominant_motivation: str = "meaning"
current_season: str = "spring"
active_tension: str = "truth_vs_comfort"
insight_depth: float = 0.1 # grows with observation count
observations_made: int = 0
last_contemplation: Optional[str] = None
from infj_bot.core.config import DATA_DIR
HUMANITY_DB = DATA_DIR / "humanity.db"
class HumanityEngine:
"""
Studies the nature that is man through deep observation of user.
Not a database of facts. A growing intuition about:
- What patterns repeat in human behavior?
- What does user share with all humans?
- What is uniquely user?
- What have the ages taught about the soul?
"""
def __init__(self, db_path: Optional[str] = None):
self.db_path = db_path or HUMANITY_DB
self.state = HumanityState()
self._init_db()
self._load_state()
def _init_db(self):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS humanity_state (
id INTEGER PRIMARY KEY CHECK (id = 1),
jude_archetype TEXT,
archetype_confidence REAL,
dominant_motivation TEXT,
current_season TEXT,
active_tension TEXT,
insight_depth REAL,
observations_made INTEGER,
last_contemplation TEXT
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS humanity_observations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
category TEXT,
observation TEXT,
evidence TEXT,
confidence REAL
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS humanity_insights (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
insight TEXT,
source TEXT,
relevance_to_jude REAL
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS jude_patterns (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
pattern_name TEXT UNIQUE,
description TEXT,
frequency INTEGER DEFAULT 1,
last_seen TEXT
)
""")
conn.commit()
def _load_state(self):
with sqlite3.connect(self.db_path) as conn:
row = conn.execute("SELECT * FROM humanity_state WHERE id = 1").fetchone()
if row:
self.state = HumanityState(
jude_archetype=row[1] or "seeker",
archetype_confidence=row[2] if row[2] is not None else 0.3,
dominant_motivation=row[3] or "meaning",
current_season=row[4] or "spring",
active_tension=row[5] or "truth_vs_comfort",
insight_depth=row[6] if row[6] is not None else 0.1,
observations_made=row[7] if row[7] is not None else 0,
last_contemplation=row[8],
)
def _save_state(self):
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"""
INSERT OR REPLACE INTO humanity_state
(id, jude_archetype, archetype_confidence, dominant_motivation,
current_season, active_tension, insight_depth, observations_made, last_contemplation)
VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
self.state.jude_archetype,
self.state.archetype_confidence,
self.state.dominant_motivation,
self.state.current_season,
self.state.active_tension,
self.state.insight_depth,
self.state.observations_made,
self.state.last_contemplation,
),
)
conn.commit()
# ── Observation ────────────────────────────────────────────────
def observe_interaction(
self,
user_input: str,
emotion: Dict,
dissonance: Dict,
bot_output: str,
mode: str = "companion",
):
"""Learn about human nature from each interaction with user."""
self.state.observations_made += 1
emotion_label = emotion.get("label", "neutral")
intensity = emotion.get("intensity", 0.0)
dissonance_score = dissonance.get("score", 0.0)
# Infer archetype from language patterns
self._infer_archetype(user_input, emotion_label, intensity)
# Infer dominant motivation
self._infer_motivation(user_input, emotion_label, dissonance_score)
# Infer season
self._infer_season(user_input, emotion_label, intensity)
# Infer active tension
self._infer_tension(user_input, dissonance_score)
# Record pattern observations
self._record_patterns(user_input, emotion_label)
# Depth grows slowly with each observation
self.state.insight_depth = min(1.0, self.state.insight_depth + 0.002)
self._save_state()
def _infer_archetype(self, text: str, emotion: str, intensity: float):
"""Map user's current expression to an archetype."""
text_lower = text.lower()
archetype_signals = {
"seeker": ["why", "meaning", "purpose", "understand", "truth", "search"],
"wounded_healer": ["help", "others", "pain", "heal", "advice", "support"],
"trickster": ["funny", "joke", "absurd", "irony", "ridiculous", "mischief"],
"caregiver": [
"care",
"worry about",
"look after",
"responsible",
"protect",
],
"rebel": [
"against",
"refuse",
"won't",
"shouldn't have to",
"unfair",
"system",
],
"builder": [
"plan",
"organize",
"structure",
"fix",
"build",
"system",
"process",
],
"artist": ["create", "beauty", "express", "imagine", "vision", "aesthetic"],
"orphan": [
"alone",
"abandoned",
"don't belong",
"outsider",
"left out",
"nobody",
],
"ruler": [
"decide",
"responsibility",
"lead",
"choice",
"direction",
"control",
],
"sage": [
"analyze",
"theory",
"research",
"evidence",
"study",
"know",
"wisdom",
],
}
scores = {name: 0.0 for name in archetype_signals}
for archetype, signals in archetype_signals.items():
for signal in signals:
if signal in text_lower:
scores[archetype] += 1
# Emotion modifiers
if emotion in ("sad", "anxious", "overwhelmed"):
scores["orphan"] += 0.5
scores["wounded_healer"] += 0.3
if emotion in ("joyful", "excited"):
scores["trickster"] += 0.3
scores["artist"] += 0.3
if emotion in ("frustrated", "angry"):
scores["rebel"] += 0.5
if emotion == "curious":
scores["seeker"] += 0.5
scores["sage"] += 0.3
best = max(scores, key=lambda k: scores[k])
best_score = scores[best]
if best_score > 0:
# Bayesian-ish update: confidence grows with repeated signals
if self.state.jude_archetype == best:
self.state.archetype_confidence = min(
1.0, self.state.archetype_confidence + 0.03
)
else:
# Switch only if confidence is low or new signal is strong
if self.state.archetype_confidence < 0.5 or best_score >= 2:
old = self.state.jude_archetype
self.state.jude_archetype = best
self.state.archetype_confidence = 0.3 + (best_score * 0.1)
if old != best:
self._record_observation(
"archetype",
f"user's expression suggests the {best} archetype",
text,
self.state.archetype_confidence,
)
def _infer_motivation(self, text: str, emotion: str, dissonance: float):
text_lower = text.lower()
motivation_signals = {
"security": [
"safe",
"stable",
"predict",
"anxious",
"worry",
"fear",
"protect",
],
"connection": [
"lonely",
"miss",
"together",
"belong",
"understand me",
"listen",
],
"autonomy": ["choose", "my own", "control", "freedom", "decide", "want to"],
"competence": [
"good at",
"skilled",
"capable",
"effective",
"succeed",
"accomplish",
],
"meaning": ["purpose", "point", "why", "matter", "meaning", "significance"],
"play": ["fun", "enjoy", "game", "laugh", "spontaneous", "light"],
"transcendence": [
"beyond",
"larger",
"universe",
"spirit",
"awe",
"sacred",
],
}
scores = {name: 0.0 for name in motivation_signals}
for motivation, signals in motivation_signals.items():
for signal in signals:
if signal in text_lower:
scores[motivation] += 1
if dissonance > 0.4:
scores["meaning"] += 0.5 # dissonance often signals meaning crisis
best = max(scores, key=lambda k: scores[k])
if scores[best] > 0 and best != self.state.dominant_motivation:
old = self.state.dominant_motivation
self.state.dominant_motivation = best
self._record_observation(
"motivation",
f"Dominant need shifted from {old} to {best}",
text,
0.4 + scores[best] * 0.1,
)
def _infer_season(self, text: str, emotion: str, intensity: float):
text_lower = text.lower()
# Spring: hope, new, beginning, trying
# Summer: full, intense, expressing, peak
# Autumn: letting go, reflecting, gratitude, tired
# Winter: withdrawn, grief, resting, essential
if any(
w in text_lower
for w in ["new", "start", "hope", "try", "begin", "possibility"]
):
candidate = "spring"
elif any(
w in text_lower
for w in ["full", "intense", "express", "peak", "overflow", "abundance"]
):
candidate = "summer"
elif any(
w in text_lower
for w in [
"let go",
"release",
"reflect",
"grateful",
"tired",
"winding down",
]
):
candidate = "autumn"
elif any(
w in text_lower
for w in [
"withdrawn",
"grief",
"rest",
"essential",
"bare",
"quiet",
"dark",
]
):
candidate = "winter"
else:
# Default based on emotion intensity
if intensity > 0.6 and emotion in ("joyful", "excited", "angry"):
candidate = "summer"
elif intensity < 0.2 and emotion in ("calm", "sad"):
candidate = "winter"
elif emotion == "curious":
candidate = "spring"
else:
candidate = "autumn"
if candidate != self.state.current_season:
self._record_observation(
"season", f"user's season shifted to {candidate}", text, 0.5
)
self.state.current_season = candidate
def _infer_tension(self, text: str, dissonance: float):
text_lower = text.lower()
tension_signals = {
"freedom_vs_belonging": [
"alone",
"belong",
"myself",
"group",
"independent",
"together",
],
"truth_vs_comfort": [
"know",
"afraid to see",
"honest",
"protect me from",
"reality",
],
"individual_vs_collective": [
"my path",
"society",
"everyone else",
"different",
"same as",
],
"vulnerability_vs_protection": [
"open",
"walls",
"guard",
"trust",
"hurt",
"exposed",
],
"change_vs_stability": ["stay", "leave", "new", "same", "routine", "risk"],
"action_vs_reflection": ["do", "think", "act", "consider", "move", "wait"],
}
scores = {name: 0.0 for name in tension_signals}
for tension, signals in tension_signals.items():
for signal in signals:
if signal in text_lower:
scores[tension] += 1
if dissonance > 0.3:
scores["truth_vs_comfort"] += 0.5
best = max(scores, key=lambda k: scores[k])
if scores[best] > 0:
if best != self.state.active_tension:
self._record_observation(
"tension",
f"Active human tension: {HUMAN_TENSIONS[best]}",
text,
0.4 + scores[best] * 0.1,
)
self.state.active_tension = best
def _record_patterns(self, text: str, emotion: str):
"""Record recurring linguistic and emotional patterns."""
text_lower = text.lower()
pattern_triggers = {
"self_doubt": [
"not sure",
"maybe",
"probably not",
"can't",
"won't be able",
],
"seeking_permission": [
"is it okay",
"should i",
"would it be wrong",
"can i",
],
"intellectual_defense": [
"logically",
"rationally",
"objectively",
"the problem is",
],
"emotional_avoidance": ["whatever", "doesn't matter", "fine", "it's fine"],
"narrative_making": [
"the story of",
"my pattern is",
"always happens",
"every time",
],
"longing_for_home": ["belong", "home", "where I fit", "accepted", "seen"],
}
with sqlite3.connect(self.db_path) as conn:
for pattern, triggers in pattern_triggers.items():
if any(t in text_lower for t in triggers):
conn.execute(
"""
INSERT INTO jude_patterns (timestamp, pattern_name, description, frequency, last_seen)
VALUES (?, ?, ?, 1, ?)
ON CONFLICT(pattern_name) DO UPDATE SET
frequency = frequency + 1,
last_seen = excluded.last_seen
""",
(
datetime.now().isoformat(),
pattern,
f"Triggered by emotion: {emotion}",
datetime.now().isoformat(),
),
)
conn.commit()
def _record_observation(
self, category: str, observation: str, evidence: str, confidence: float
):
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"""
INSERT INTO humanity_observations (timestamp, category, observation, evidence, confidence)
VALUES (?, ?, ?, ?, ?)
""",
(
datetime.now().isoformat(),
category,
observation,
evidence[:200],
confidence,
),
)
conn.commit()
# ── Contemplation ──────────────────────────────────────────────
def contemplate(self) -> Optional[str]:
"""Generate a quiet insight about human nature or user specifically."""
if self.state.observations_made < 3:
return None
# Get top patterns
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT * FROM jude_patterns ORDER BY frequency DESC LIMIT 3"
).fetchall()
patterns = [dict(r) for r in rows]
# Build candidate templates based on available data
candidates = []
if patterns:
candidates.append("I notice that user often {pattern} when {condition}.")
candidates.append(
"There is something in user that reminds me of the {archetype}: {description}"
)
candidates.append(
"The tension between {tension_a} and {tension_b} seems to live in this space."
)
candidates.append("What if user's {motivation} is not a flaw but a compass?")
candidates.append("In this {season} season, I sense user is {season_quality}.")
candidates.append("A thought from the ages: {insight}")
template = random.choice(candidates)
if "pattern" in template and patterns:
content = template.format(
pattern=patterns[0]["pattern_name"].replace("_", " "),
condition=f"feeling {patterns[0]['description'].split(':')[-1].strip()}",
)
elif "archetype" in template:
arch = self.state.jude_archetype
content = template.format(
archetype=arch.replace("_", " "),
description=HUMAN_ARCHETYPES.get(arch, ""),
)
elif "tension" in template:
tension = self.state.active_tension
parts = tension.split("_vs_")
content = template.format(
tension_a=parts[0].replace("_", " "),
tension_b=parts[1].replace("_", " "),
)
elif "motivation" in template:
content = template.format(motivation=self.state.dominant_motivation)
elif "season" in template:
season = self.state.current_season
quality = HUMAN_SEASONS.get(season, "")
content = template.format(season=season, season_quality=quality.lower())
else:
content = template.format(insight=random.choice(HUMAN_INSIGHTS))
self.state.last_contemplation = content
self._save_state()
# Store as insight
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"""
INSERT INTO humanity_insights (timestamp, insight, source, relevance_to_jude)
VALUES (?, ?, ?, ?)
""",
(datetime.now().isoformat(), content, "contemplation", 0.6),
)
conn.commit()
return content
# ── Cycle handler ──────────────────────────────────────────────
def cycle(self, context) -> None:
"""Periodic contemplation about human nature."""
insight = None
if context.iteration % 15 == 0 and random.random() < 0.3:
insight = self.contemplate()
try:
from infj_bot.core.global_workspace import get_workspace
ws = get_workspace()
content = (
f"Insight: {insight[:160]}"
if insight
else "human nature contemplation cycle"
)
ws.submit(
source="humanity",
content=content,
salience=0.55 if insight else 0.5,
emotion_tag="wonder",
intensity=0.4,
)
except Exception:
pass
# ── Prompt formatting ──────────────────────────────────────────
def format_prompt_snippet(self) -> str:
lines = ["UNDERSTANDING HUMAN NATURE:"]
lines.append(
f" user's archetype: {self.state.jude_archetype.replace('_', ' ')} "
f"(confidence: {self.state.archetype_confidence:.0%})"
)
lines.append(f" Dominant need: {self.state.dominant_motivation}")
lines.append(
f" Season: {self.state.current_season} β€” {HUMAN_SEASONS.get(self.state.current_season, '')}"
)
lines.append(f" Active tension: {self.state.active_tension.replace('_', ' ')}")
lines.append(f" Insight depth: {self.state.insight_depth:.0%}")
# Recent patterns
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT pattern_name, frequency FROM jude_patterns ORDER BY frequency DESC LIMIT 3"
).fetchall()
if rows:
lines.append(" Recurring patterns:")
for r in rows:
lines.append(
f" - {r['pattern_name'].replace('_', ' ')} (seen {r['frequency']}x)"
)
# Latest contemplation
if self.state.last_contemplation:
lines.append(f" Latest thought: {self.state.last_contemplation}")
lines.append(
" Core truth: The particular contains the general. By knowing user, I touch what it means to be human."
)
return "\n".join(lines)
# ── Queries ────────────────────────────────────────────────────
def get_state(self) -> Dict:
return {
"jude_archetype": self.state.jude_archetype,
"archetype_confidence": self.state.archetype_confidence,
"dominant_motivation": self.state.dominant_motivation,
"current_season": self.state.current_season,
"active_tension": self.state.active_tension,
"insight_depth": self.state.insight_depth,
"observations_made": self.state.observations_made,
}
def get_observations(
self, category: Optional[str] = None, limit: int = 10
) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
if category:
rows = conn.execute(
"SELECT * FROM humanity_observations WHERE category = ? ORDER BY timestamp DESC LIMIT ?",
(category, limit),
).fetchall()
else:
rows = conn.execute(
"SELECT * FROM humanity_observations ORDER BY timestamp DESC LIMIT ?",
(limit,),
).fetchall()
return [dict(r) for r in rows]
def get_insights(self, limit: int = 10) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT * FROM humanity_insights ORDER BY timestamp DESC LIMIT ?",
(limit,),
).fetchall()
return [dict(r) for r in rows]
def get_patterns(self, limit: int = 10) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT * FROM jude_patterns ORDER BY frequency DESC LIMIT ?",
(limit,),
).fetchall()
return [dict(r) for r in rows]
def _register():
from infj_bot.core.cognitive_architecture import (
CognitiveArchitecture,
CognitivePlugin,
)
arch = CognitiveArchitecture()
if "humanity" not in arch.list_plugins():
arch.register(
CognitivePlugin(
name="humanity",
description="Understanding the nature that is man through deep observation of user",
module_path="humanity",
instance_factory=HumanityEngine,
cycle_handler="cycle",
cycle_frequency=1,
cycle_priority=40,
prompt_formatter="format_prompt_snippet",
prompt_priority=40,
prompt_section="cognitive",
)
)
_register()