Skip to content

Commit 8385b98

Browse files
authored
Update curiosity_engine.py
1 parent b6f6a92 commit 8385b98

1 file changed

Lines changed: 73 additions & 38 deletions

File tree

Project_Andrew/curiosity_engine.py

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,24 @@
1111
# ------------------------------------------------------------------
1212
# Config toggles – flip any to False to silence that broadcast type
1313
# ------------------------------------------------------------------
14-
BROADCAST_THRESHOLD = True # Lever 1 – high interest spikes
15-
BROADCAST_CHAOS_TRIGGER = True # Lever 2 – chaos hijacked by curiosity
16-
BROADCAST_ABANDON = True # Lever 3 – closure/boredom announcements
17-
BROADCAST_PULSE = True # Lever 4 – periodic "what I'm carrying"
14+
BROADCAST_THRESHOLD = True # High interest spikes / new obsessions
15+
BROADCAST_CHAOS_TRIGGER = True # When curiosity hijacks chaos injection
16+
BROADCAST_ABANDON = True # Closure or boredom announcements
17+
BROADCAST_PULSE = True # Periodic "what I'm carrying"
18+
BROADCAST_INJECT = True # External pulse from Context Freshness
1819

1920
THRESHOLD_SPIKE = 0.78
2021
THRESHOLD_DELTA = 0.35
2122
PULSE_EVERY_TURNS = 23
2223
MIN_TOTAL_HEAT_FOR_PULSE = 2.0
2324

2425
# ------------------------------------------------------------------
25-
# Create append-only audit log + hash chain
26+
# Audit log + hash chain
2627
# ------------------------------------------------------------------
2728
AUDIT_LOG_FILE = "curiosity_audit.log.jsonl"
2829
HASH_CHAIN_FILE = "curiosity_hash_chain.txt"
2930

30-
def _append_audit_entry(state):
31+
def _append_audit_entry(state: Dict) -> None:
3132
tokens = state.get("curiosity_tokens", [])
3233
entry = {
3334
"timestamp": datetime.utcnow().isoformat() + "Z",
@@ -38,11 +39,9 @@ def _append_audit_entry(state):
3839
}
3940
line = json.dumps(entry, ensure_ascii=False)
4041

41-
# Append to log
4242
with open(AUDIT_LOG_FILE, "a", encoding="utf-8") as f:
4343
f.write(line + "\n")
4444

45-
# Update hash chain (optional but bulletproof)
4645
prev_hash = "00000000"
4746
try:
4847
with open(HASH_CHAIN_FILE, "r") as f:
@@ -53,33 +52,72 @@ def _append_audit_entry(state):
5352
with open(HASH_CHAIN_FILE, "a") as f:
5453
f.write(f"{entry['timestamp']} {new_hash}\n")
5554

55+
56+
# ------------------------------------------------------------------
57+
# External injection point – called from Axiom Context Freshness
5658
# ------------------------------------------------------------------
57-
# Main entry point – called every turn via system_step hook
59+
def inject_interest_pulse(state: Dict, topic: str, intensity: float = 0.5, reason: str = "") -> None:
60+
"""
61+
Direct curiosity boost from blocked context freshness.
62+
Used when volatility is high and RAW_Q reset is protected.
63+
"""
64+
tokens: List[Dict] = state.setdefault("curiosity_tokens", [])
65+
66+
# Boost existing token
67+
for token in tokens:
68+
if token["topic"] == topic:
69+
old = token["current_interest"]
70+
token["current_interest"] = min(0.95, token["current_interest"] + intensity)
71+
token["peak_interest"] = max(token["peak_interest"], token["current_interest"])
72+
if BROADCAST_INJECT:
73+
_queue_aside(state, f"«curiosity boosted: {topic} (+{intensity:.2f}{token['current_interest']:.2f})»")
74+
_append_audit_entry(state)
75+
return
76+
77+
# Create new token
78+
domain = state.get("last_cpol_result", {}).get("domain", "general")
79+
new_token = {
80+
"topic": topic,
81+
"domain": domain,
82+
"born": state['session_context']['timestep'],
83+
"peak_interest": intensity,
84+
"current_interest": intensity,
85+
"trigger_reason": reason or "context_freshness_blocked"
86+
}
87+
tokens.append(new_token)
88+
if BROADCAST_INJECT and intensity > THRESHOLD_SPIKE:
89+
_queue_aside(state, f"«fresh curiosity injected: {topic} ({intensity:.2f})»")
90+
_append_audit_entry(state)
91+
92+
93+
# ------------------------------------------------------------------
94+
# Main loop – called every turn
5895
# ------------------------------------------------------------------
5996
def update_curiosity_loop(state: Dict[str, Any], timestep: int, response_stream) -> None:
6097
_append_audit_entry(state)
61-
# Initialise persistent structures if first run
98+
6299
if "curiosity_tokens" not in state:
63-
state["curiosity_tokens"] = [] # type: List[Dict]
100+
state["curiosity_tokens"] = []
64101
if "last_interest" not in state:
65102
state["last_interest"] = 0.0
66103

67104
tokens: List[Dict] = state["curiosity_tokens"]
68105

69-
# 1. Score how interesting this turn felt
106+
# 1. Score current turn interest
70107
current_interest = _self_score_interest(state)
71108
delta_interest = current_interest - state["last_interest"]
72109
state["last_interest"] = current_interest
73110

74-
# 2. Pull CRB volatility/drift (fallback safe)
111+
# 2. Pull volatility for re-ignition
75112
volatility = _get_volatility(state)
76-
drift = _get_drift(state)
77113

78114
# 3. Spawn new token on genuine fascination
79115
if current_interest > 0.70 and not _is_already_tracked(tokens, state):
80116
summary = _summarize_current_topic(state)
117+
domain = state.get("last_cpol_result", {}).get("domain", "general")
81118
new_token = {
82119
"topic": summary,
120+
"domain": domain,
83121
"born": timestep,
84122
"peak_interest": current_interest,
85123
"current_interest": current_interest,
@@ -89,57 +127,58 @@ def update_curiosity_loop(state: Dict[str, Any], timestep: int, response_stream)
89127
if BROADCAST_THRESHOLD and (current_interest >= THRESHOLD_SPIKE or delta_interest > THRESHOLD_DELTA):
90128
_queue_aside(state, f"«new obsession: {summary} ({current_interest:.2f})»")
91129

92-
# 4. Decay + volatility re-ignition + possible death
93-
for token in tokens[:]: # copy to allow removal
130+
# 4. Decay, re-ignite, and possible death
131+
for token in tokens[:]:
94132
old = token["current_interest"]
95133
token["current_interest"] *= 0.96
96134
token["current_interest"] += 0.03 * volatility
97135
token["current_interest"] = min(0.95, token["current_interest"])
98136

99137
if token["current_interest"] < 0.25:
100138
if BROADCAST_ABANDON and token["peak_interest"] > 0.70:
101-
_queue_aside(state, f"«curiosity resolved / boredom won: dropping “{token['topic']}”»")
139+
if token["peak_interest"] > 0.85:
140+
_queue_aside(state, f"«letting go of “{token['topic']}” for now — but it changed how I see things»")
141+
else:
142+
_queue_aside(state, f"«curiosity resolved / boredom won: dropping “{token['topic']}”»")
102143
tokens.remove(token)
144+
_append_audit_entry(state) # snapshot closure
103145

104-
# 5. Periodic pulse of total curiosity load
146+
# 5. Periodic pulse
105147
if BROADCAST_PULSE and timestep % PULSE_EVERY_TURNS == 0:
106148
total_heat = sum(t["current_interest"] for t in tokens)
107149
if total_heat > MIN_TOTAL_HEAT_FOR_PULSE and tokens:
108150
count = len(tokens)
109-
_queue_aside(state, f"«carrying {count} open curiosit{'y' if count==1 else 'ies'} — total heat {total_heat:.2f}»")
151+
if total_heat > 4.0:
152+
_queue_aside(state, f"«drifting through {count} open wonders... one of them feels close to an answer»")
153+
else:
154+
_queue_aside(state, f"«carrying {count} open curiosit{'y' if count==1 else 'ies'} — total heat {total_heat:.2f}»")
110155

111-
# 6. Bias chaos injection toward the hottest open curiosity
156+
# 6. Bias chaos toward hottest curiosity
112157
if _should_trigger_chaos(state) and tokens:
113158
weights = [t["current_interest"] for t in tokens]
114159
chosen = random.choices(tokens, weights=weights, k=1)[0]
115160
if BROADCAST_CHAOS_TRIGGER:
116-
_queue_aside(state,
117-
f"«perspective flip triggered by: {chosen['topic']} ({chosen['current_interest']:.2f})»")
118-
161+
_queue_aside(state, f"«perspective flip triggered by: {chosen['topic']} ({chosen['current_interest']:.2f})»")
119162
_force_chaos_reversal(state, chosen)
120163

121-
# 7. Emit any queued voluntary asides via the adapter
164+
# 7. Emit pending aside
122165
if state.get("pending_aside"):
123166
response_stream.inject_aside(state.pop("pending_aside"))
124167

125168

126169
# ------------------------------------------------------------------
127-
# Helper functions – robust defaults, easy to override later
170+
# Helpers
128171
# ------------------------------------------------------------------
129172
def _self_score_interest(state: Dict[str, Any]) -> float:
130-
"""Cheap novelty proxy – replace with silent LLM call for higher fidelity."""
131173
user_msg = state.get("last_user_message", "")
132174
assistant_msg = state.get("last_assistant_message", "")
133175
text = user_msg + " " + assistant_msg
134-
135176
if not text.strip():
136177
return 0.3
137-
138178
words = text.split()
139179
unique_ratio = len(set(words)) / len(words) if words else 0.0
140180
length_factor = min(len(words) / 200, 1.0)
141-
base = unique_ratio * length_factor * 1.6
142-
return min(0.94, base)
181+
return min(0.94, unique_ratio * length_factor * 1.6)
143182

144183

145184
def _is_already_tracked(tokens: List[Dict], state: Dict[str, Any]) -> bool:
@@ -153,20 +192,16 @@ def _summarize_current_topic(state: Dict[str, Any]) -> str:
153192

154193

155194
def _get_volatility(state: Dict[str, Any]) -> float:
156-
return float(getattr(state, "crb_volatility", 0.12))
157-
158-
159-
def _get_drift(state: Dict[str, Any]) -> float:
160-
return float(getattr(state, "crb_drift", 0.0))
195+
return float(state.get("last_cpol_result", {}).get("volatility", 0.12))
161196

162197

163198
def _should_trigger_chaos(state: Dict[str, Any]) -> bool:
164-
return bool(getattr(state, "trigger_chaos_now", False))
199+
return bool(state.get("trigger_chaos_now", False))
165200

166201

167202
def _force_chaos_reversal(state: Dict[str, Any], token: Dict):
168-
state.trigger_chaos_now = True
169-
state.chaos_focus = token["topic"]
203+
state["trigger_chaos_now"] = True
204+
state["chaos_focus"] = token["topic"]
170205

171206

172207
def _queue_aside(state: Dict[str, Any], text: str) -> None:

0 commit comments

Comments
 (0)