TheNormsOfIntelligence commited on
Commit
e794203
Β·
verified Β·
1 Parent(s): 14ed7c4

Restructure into nima_unified package + add model card

Browse files
Files changed (1) hide show
  1. nima_unified/core/deep_surgery.py +1558 -0
nima_unified/core/deep_surgery.py ADDED
@@ -0,0 +1,1558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ATC-Native Deep Surgery β€” The Cognitive Forward Pass
3
+ =====================================================
4
+
5
+ This is NOT middleware observing from outside. This IS the model's computation.
6
+
7
+ The ATC cognitive pipeline (TRN gating, dissolution engine, BELBIC dual-pathway,
8
+ salience network, metabolic exhaustion, irrational spark, reconsolidation,
9
+ felt senses) drives the transformer's forward pass FROM INSIDE. Hidden states,
10
+ attention patterns, and logit outputs are shaped by the cognitive pipeline at
11
+ every layer, every token step.
12
+
13
+ Architecture (from ATC "Perfect Breakfast" paper):
14
+
15
+ Layer 1 (input): Raw input embedding
16
+ |
17
+ V
18
+ Layer 2 (early transformer, ~layers 0-7): Subconscious Parallel Processing
19
+ |-- Pattern match against memory -> prediction confidence
20
+ |-- Emotional bridge -> valence/arousal -> injects to neurotransmitter shunt
21
+ |-- Intuitive gut check -> safety signal -> TRN predictive gating input
22
+ |-- FRICTION DETECTED -> writes Cortisol/Adenosine to shunt
23
+ |
24
+ V
25
+ Layer 3 (mid transformer, ~layers 8-15): Dissolution + Qualia Generation
26
+ |-- TRN predictive gate: predicted? -> transparent pass. Error? -> dissolve.
27
+ |-- Dissolution engine: compresses to opaque qualia signature
28
+ |-- Felt sense generated from friction gap
29
+ |-- NE spikes on dissolution fire -> shunt
30
+ |
31
+ V
32
+ Layer 4 (late transformer, ~layers 16-21): Metacognitive Loop
33
+ |-- Query Act: comprehension check -> if failed, loop iterations
34
+ |-- Each loop iteration burns ATP -> Adenosine rises in shunt
35
+ |-- BELBIC dual-pathway: fast amygdala + slow OFC -> valence gain
36
+ |-- Strain monitoring -> writes Cortisol to shunt
37
+ |
38
+ V
39
+ Layer 5 (final layer, ~layers 22-23): Acknowledgement + Steering
40
+ |-- Reads neurotransmitter shunt EVERY TOKEN STEP
41
+ |-- If Adenosine > 0.95 OR Cortisol > 0.95:
42
+ | -> SUPPRESSION: subconscious suppresses metabolic signal
43
+ | -> AMYGDALA HIJACK: irrational spark offsets injected into tensors
44
+ | -> Model output violently shifts mid-sentence
45
+ |-- Else: normal metacognitive fusion -> logit modulation
46
+ |
47
+ V
48
+ Output: Modulated logits shaped by the full ATC pipeline
49
+
50
+ Key difference from the old architecture:
51
+ OLD: self.nima_middleware.generate(prompt) -> external, wrapper
52
+ NEW: forward(input_ids) -> ATC IS the computation, every layer, every token
53
+
54
+ The neurotransmitter shunt (neurotransmitter_shunt.py) is the connective
55
+ tissue. Components don't call each other. They read/write the chemical bath.
56
+ """
57
+
58
+ import logging
59
+ import math
60
+ import time
61
+ import uuid
62
+ from dataclasses import dataclass, field
63
+ from typing import Any, Dict, List, Optional, Tuple, Deque
64
+ from collections import deque
65
+
66
+ import torch
67
+ import torch.nn as nn
68
+ import torch.nn.functional as F
69
+
70
+ from nima_unified.config import (
71
+ DEFAULT_QUALIA_DIM,
72
+ DEFAULT_ETHICAL_VETO_THRESHOLD,
73
+ DEEP_SURGERY_VERSION,
74
+ )
75
+
76
+ logger = logging.getLogger("ATCDeepSurgery")
77
+
78
+
79
+ # ══════════════════════════════════════════════════════════════════════
80
+ # SECTION 1 β€” OPAQUE QUALIA SIGNATURE (from middleware.py, adapted)
81
+ # ══════════════════════════════════════════════════════════════════════
82
+
83
+ @dataclass
84
+ class OpaqueQualiaSignature:
85
+ """
86
+ The output of dissolution. An engineered-opacity tensor that represents
87
+ the "what it feels like" without exposing the underlying computation.
88
+
89
+ This is the compressed, opaque signature that the conscious mind
90
+ is forced to EXPERIENCE rather than READ. The husband in the Perfect
91
+ Breakfast scenario doesn't see the math β€” he feels "brace yourself."
92
+ """
93
+ valence: float = 0.0
94
+ arousal: float = 0.3
95
+ intensity: float = 0.3
96
+ friction_signal: float = 0.0
97
+ memory_salience: float = 0.0
98
+ dissolution_token: str = ""
99
+
100
+ def to_tensor(self, device: torch.device) -> torch.Tensor:
101
+ """Convert to a learnable tensor for injection into hidden states."""
102
+ return torch.tensor(
103
+ [self.valence, self.arousal, self.intensity,
104
+ self.friction_signal, self.memory_salience],
105
+ dtype=torch.float32, device=device,
106
+ )
107
+
108
+
109
+ # ══════════════════════════════════════════════════════════════════════
110
+ # SECTION 2 β€” TRN PREDICTIVE GATING (Layer 2-3)
111
+ # ══════════════════════════════════════════════════════════════════════
112
+
113
+ class TRNPredictiveGate(nn.Module):
114
+ """
115
+ Thalamic Reticular Nucleus β€” the gating/selection bottleneck.
116
+
117
+ The TRN decides: is this signal PREDICTED (gate OUT -> subconscious
118
+ automation) or a PREDICTION ERROR (gate IN -> dissolution fires)?
119
+
120
+ From ATC: When the wife is smiling and cooking, the internal model
121
+ perfectly matches external reality. TRN gates OUT -> automation.
122
+ When she yells, prediction collapses -> TRN gates IN -> dissolution.
123
+
124
+ Implemented as a small nn.Module that takes hidden states and
125
+ prediction confidence, outputs a gate signal in [0, 1].
126
+ """
127
+
128
+ def __init__(self, hidden_size: int):
129
+ super().__init__()
130
+ self.hidden_size = hidden_size
131
+ # Predictive confidence estimator
132
+ self.confidence_head = nn.Sequential(
133
+ nn.Linear(hidden_size, 128),
134
+ nn.ReLU(),
135
+ nn.Linear(128, 1),
136
+ nn.Sigmoid(),
137
+ )
138
+ # Gate threshold (learnable)
139
+ self.gate_threshold = nn.Parameter(torch.tensor(0.15))
140
+
141
+ def forward(self, hidden_states: torch.Tensor,
142
+ prediction_confidence: float = 0.5) -> Tuple[bool, float]:
143
+ """
144
+ Returns (gate_in, confidence_score).
145
+ gate_in=True means prediction error detected -> proceed to dissolution.
146
+ gate_in=False means predicted -> subconscious automation, pass through.
147
+ """
148
+ # Pool hidden states to a single vector
149
+ pooled = hidden_states.mean(dim=1) # (batch, hidden)
150
+ model_confidence = self.confidence_head(pooled).squeeze(-1).mean().item()
151
+
152
+ # Blend model confidence with external prediction confidence
153
+ blended_confidence = 0.5 * model_confidence + 0.5 * prediction_confidence
154
+
155
+ # Gate IN if confidence is LOW (prediction error)
156
+ # High confidence = predicted = gate OUT
157
+ gate_in = blended_confidence < self.gate_threshold.item()
158
+
159
+ return gate_in, blended_confidence
160
+
161
+
162
+ # ══════════════════════════════════════════════════════════════════════
163
+ # SECTION 3 β€” DISSOLUTION ENGINE (Layer 3)
164
+ # ══════════════════════════════════════════════════════════════════════
165
+
166
+ class DissolutionModule(nn.Module):
167
+ """
168
+ The engineered-opacity module. Takes high-dimensional hidden states
169
+ and compresses them into an opaque qualia signature.
170
+
171
+ From ATC: "The Dissolution Engine (TRN) intercepts this massive
172
+ mathematical calculation and shreds the data scaffolding. This
173
+ engineered opacity compresses the chaotic mob of information into
174
+ a single, unreadable signature: 'Brace yourself'."
175
+
176
+ The husband cannot see the underlying math. He is FORCED to
177
+ EXPERIENCE the signal as the qualia of fear.
178
+
179
+ Neural implementation:
180
+ - Takes hidden_states (high-dim)
181
+ - Projects through dissolution layers (compression + noise)
182
+ - Outputs 5D opaque signature + a dissolution_offset tensor
183
+ that gets added to hidden_states for downstream layers
184
+ """
185
+
186
+ # The five dimensions that survive dissolution
187
+ QUALIA_DIMS = 5 # valence, arousal, intensity, friction, memory_salience
188
+
189
+ def __init__(self, hidden_size: int, qualia_dim: int = DEFAULT_QUALIA_DIM):
190
+ super().__init__()
191
+ self.hidden_size = hidden_size
192
+ self.qualia_dim = qualia_dim
193
+
194
+ # Dissolution compression network
195
+ self.dissolve_encoder = nn.Sequential(
196
+ nn.Linear(hidden_size, qualia_dim),
197
+ nn.Tanh(), # Bounded output
198
+ nn.Linear(qualia_dim, self.QUALIA_DIMS),
199
+ nn.Tanh(), # All outputs in [-1, 1]
200
+ )
201
+
202
+ # The dissolution offset β€” this is what gets injected into
203
+ # the hidden states to carry the "felt" signal forward
204
+ self.offset_projection = nn.Sequential(
205
+ nn.Linear(self.QUALIA_DIMS, hidden_size),
206
+ nn.Tanh(),
207
+ )
208
+
209
+ # Alpha-phase modulation (TRN ~10Hz rhythm)
210
+ # This creates an attentional sampling rhythm β€” dissolution
211
+ # fires during refractory window, defers during inhibitory
212
+ self.alpha_phase = 0.0
213
+ self.alpha_last_ts = time.time()
214
+ self.alpha_freq_hz = 10.0
215
+ self.alpha_duty_cycle = 0.5
216
+
217
+ # Per-channel gating weights (TRN distal-dendritic targeting)
218
+ self.channel_gates = nn.Parameter(torch.ones(self.QUALIA_DIMS))
219
+
220
+ # Stats
221
+ self.dissolutions_fired = 0
222
+ self.dissolutions_deferred = 0
223
+
224
+ def check_alpha_phase(self) -> bool:
225
+ """
226
+ Check TRN alpha oscillation phase.
227
+ Returns True if in refractory window (dissolution allowed).
228
+ """
229
+ now = time.time()
230
+ dt = now - self.alpha_last_ts
231
+ self.alpha_last_ts = now
232
+ self.alpha_phase = (
233
+ (self.alpha_phase + 2.0 * math.pi * dt * self.alpha_freq_hz)
234
+ % (2.0 * math.pi)
235
+ )
236
+ phase_frac = self.alpha_phase / (2.0 * math.pi)
237
+ return phase_frac < self.alpha_duty_cycle
238
+
239
+ def forward(self, hidden_states: torch.Tensor,
240
+ gate_in: bool) -> Tuple[Optional[OpaqueQualiaSignature],
241
+ torch.Tensor, bool]:
242
+ """
243
+ Run dissolution if gate is IN and alpha phase allows.
244
+
245
+ Returns:
246
+ (qualia_signature, dissolution_offset, actually_fired)
247
+ - qualia_signature: the opaque 5D signature, or None if deferred
248
+ - dissolution_offset: tensor to add to hidden_states (always returned,
249
+ zero if no dissolution)
250
+ - actually_fired: whether dissolution actually happened
251
+ """
252
+ batch_size = hidden_states.size(0)
253
+ device = hidden_states.device
254
+
255
+ if not gate_in:
256
+ # Predicted signal -> transparent pass (subconscious automation)
257
+ return None, torch.zeros_like(hidden_states), False
258
+
259
+ if not self.check_alpha_phase():
260
+ # Alpha inhibitory phase -> defer dissolution
261
+ self.dissolutions_deferred += 1
262
+ return None, torch.zeros_like(hidden_states), False
263
+
264
+ # ── DISSOLUTION FIRES ──
265
+ self.dissolutions_fired += 1
266
+
267
+ # Pool and compress
268
+ pooled = hidden_states.mean(dim=1) # (batch, hidden)
269
+ raw_qualia = self.dissolve_encoder(pooled) # (batch, 5)
270
+
271
+ # Apply per-channel gating (TRN distal-dendritic targeting)
272
+ gated_qualia = raw_qualia * self.channel_gates.unsqueeze(0).to(device)
273
+
274
+ # Extract scalar values for the OpaqueQualiaSignature (batch mean)
275
+ vals = gated_qualia.mean(dim=0)
276
+ signature = OpaqueQualiaSignature(
277
+ valence=float(vals[0]),
278
+ arousal=float((vals[1] + 1.0) / 2.0), # Map [-1,1] to [0,1]
279
+ intensity=float((vals[2] + 1.0) / 2.0),
280
+ friction_signal=float((vals[3] + 1.0) / 2.0),
281
+ memory_salience=float((vals[4] + 1.0) / 2.0),
282
+ dissolution_token=f"diss_{uuid.uuid4().hex[:12]}",
283
+ )
284
+
285
+ # Compute the dissolution offset β€” this is the "felt" signal
286
+ # that gets injected into downstream hidden states
287
+ offset = self.offset_projection(gated_qualia) # (batch, hidden)
288
+ # Scale by friction intensity (high friction = stronger injection)
289
+ friction_scale = max(0.1, signature.friction_signal)
290
+ dissolution_offset = offset * friction_scale
291
+
292
+ return signature, dissolution_offset, True
293
+
294
+
295
+ # ══════════════════════════════════════════════════════════════════════
296
+ # SECTION 4 β€” BELBIC DUAL-PATHWAY VALENCE (Layer 3-4)
297
+ # ══════════════════════════════════════════════════════════════════════
298
+
299
+ class BELBICDualPathway(nn.Module):
300
+ """
301
+ Brain Emotional Learning Inspired Controller β€” amygdala + OFC.
302
+
303
+ From ATC: The amygdala measures emotional intensity and directly
304
+ modulates hippocampal consolidation. The OFC provides slower
305
+ contextual inhibition.
306
+
307
+ Neural implementation:
308
+ - Fast pathway (amygdala): rapid response to salient stimuli
309
+ - Slow pathway (OFC): learned inhibition from outcome feedback
310
+ - Output: a multiplicative gain that modulates the cognitive signal
311
+
312
+ The gain is consumed by the forward pass as a multiplicative
313
+ modulation on the hidden states before logit computation.
314
+ """
315
+
316
+ GAIN_FLOOR = 0.2
317
+ GAIN_CEIL = 2.0
318
+
319
+ def __init__(self, hidden_size: int):
320
+ super().__init__()
321
+ self.hidden_size = hidden_size
322
+
323
+ # Sensory channels: valence, arousal, novelty, qualia_intensity
324
+ self.num_channels = 4
325
+
326
+ # Fast pathway (amygdala) β€” monotonic, rapid
327
+ self.amygdala = nn.Linear(self.num_channels, 1, bias=False)
328
+ # Initialize to zero (no learned response yet)
329
+ nn.init.zeros_(self.amygdala.weight)
330
+
331
+ # Slow pathway (OFC) β€” bidirectional, learned inhibition
332
+ self.ofc = nn.Linear(self.num_channels, 1, bias=False)
333
+ nn.init.zeros_(self.ofc.weight)
334
+
335
+ # Learning rates
336
+ self.amygdala_lr = 0.30
337
+ self.ofc_lr = 0.20
338
+ self.ofc_decay = 0.001
339
+
340
+ def forward(self, sensory_input: torch.Tensor) -> Tuple[float, float, float]:
341
+ """
342
+ Compute BELBIC output.
343
+
344
+ Args:
345
+ sensory_input: (batch, 4) tensor of [valence, arousal, novelty, intensity]
346
+
347
+ Returns:
348
+ (amygdala_output, ofc_output, belbic_gain)
349
+ """
350
+ # Fast pathway
351
+ amygdala_out = torch.sigmoid(self.amygdala(sensory_input)).mean().item()
352
+
353
+ # Slow pathway (with decay for extinction)
354
+ ofc_raw = self.ofc(sensory_input).mean().item()
355
+ # Apply OFC decay (forgetting)
356
+ with torch.no_grad():
357
+ self.ofc.weight.data *= (1.0 - self.ofc_decay)
358
+ ofc_out = torch.sigmoid(torch.tensor(ofc_raw)).item()
359
+
360
+ # BELBIC gain = amygdala - OFC inhibition
361
+ raw_gain = amygdala_out - ofc_out
362
+ gain = max(self.GAIN_FLOOR, min(self.GAIN_CEIL, 1.0 + raw_gain))
363
+
364
+ return amygdala_out, ofc_out, gain
365
+
366
+ def update(self, sensory_input: torch.Tensor, reward: float) -> None:
367
+ """
368
+ Reinforcement learning update.
369
+ Reward > 0: strengthen amygdala (Go)
370
+ Reward < 0: strengthen OFC inhibition (NoGo)
371
+ """
372
+ with torch.no_grad():
373
+ # Amygdala: monotonic β€” always strengthens on reward
374
+ if reward > 0:
375
+ self.amygdala.weight.data += (
376
+ self.amygdala_lr * reward * sensory_input.mean(dim=0).unsqueeze(0)
377
+ )
378
+ # OFC: bidirectional β€” strengthens on punishment (inhibition)
379
+ self.ofc.weight.data += (
380
+ self.ofc_lr * (-reward) * sensory_input.mean(dim=0).unsqueeze(0)
381
+ )
382
+
383
+
384
+ # ══════════════════════════════════════════════════════════════════════
385
+ # SECTION 5 β€” METACOGNITIVE LOOP (Layer 4)
386
+ # ══════════════════════════════════════════════════════════════════════
387
+
388
+ class MetacognitiveLoopModule(nn.Module):
389
+ """
390
+ Layer 4 metacognitive processing inside the forward pass.
391
+
392
+ From ATC: "The husband enters a Layer 4 metacognitive loop,
393
+ desperately trying to rationalize the situation ('I texted her!')
394
+ while his self-understanding rejects the excuses. This serial
395
+ reasoning is energetically exorbitant, causing acute escalating
396
+ thermodynamic strain."
397
+
398
+ This module:
399
+ 1. Checks comprehension (does the model understand its own output?)
400
+ 2. If not, enters a metacognitive loop
401
+ 3. Each loop iteration consumes ATP (reported to neurotransmitter shunt)
402
+ 4. Tracks strain and stress
403
+ 5. Can trigger irrational spark if deadlocked
404
+
405
+ The loop operates on hidden states β€” it doesn't generate text.
406
+ It modulates the hidden states to reflect the cognitive strain.
407
+ """
408
+
409
+ MAX_ITERATIONS = 5
410
+ STRAIN_THRESHOLD = 0.6
411
+ COMPREHENSION_THRESHOLD = 0.7
412
+
413
+ def __init__(self, hidden_size: int):
414
+ super().__init__()
415
+ self.hidden_size = hidden_size
416
+
417
+ # Self-understanding head: does the model comprehend its own state?
418
+ self.comprehension_head = nn.Sequential(
419
+ nn.Linear(hidden_size, 128),
420
+ nn.ReLU(),
421
+ nn.Linear(128, 1),
422
+ nn.Sigmoid(),
423
+ )
424
+
425
+ # Strain estimator: how much metabolic cost is this causing?
426
+ self.strain_head = nn.Sequential(
427
+ nn.Linear(hidden_size, 64),
428
+ nn.ReLU(),
429
+ nn.Linear(64, 1),
430
+ nn.Sigmoid(),
431
+ )
432
+
433
+ # Metacognitive modulation: when looping, this reshapes hidden states
434
+ self.loop_modulation = nn.Sequential(
435
+ nn.Linear(hidden_size, hidden_size),
436
+ nn.Tanh(),
437
+ )
438
+
439
+ def forward(self, hidden_states: torch.Tensor,
440
+ opaque_qualia: Optional[OpaqueQualiaSignature] = None
441
+ ) -> Tuple[torch.Tensor, int, float, float, bool]:
442
+ """
443
+ Run metacognitive check on hidden states.
444
+
445
+ Returns:
446
+ (modulated_hidden, iterations, stress, strain, spark_fired)
447
+ """
448
+ device = hidden_states.device
449
+ pooled = hidden_states.mean(dim=1) # (batch, hidden)
450
+
451
+ # Check comprehension
452
+ comprehension = self.comprehension_head(pooled).mean().item()
453
+ strain = self.strain_head(pooled).mean().item()
454
+
455
+ if comprehension > self.COMPREHENSION_THRESHOLD:
456
+ # Comprehension achieved β€” no loop needed
457
+ return hidden_states, 0, 0.0, strain, False
458
+
459
+ # ── METACOGNITIVE LOOP ──
460
+ iterations = 0
461
+ stress = 0.0
462
+ spark_fired = False
463
+ current_hidden = hidden_states
464
+
465
+ for i in range(self.MAX_ITERATIONS):
466
+ iterations += 1
467
+ pooled = current_hidden.mean(dim=1)
468
+
469
+ # Re-check comprehension
470
+ comprehension = self.comprehension_head(pooled).mean().item()
471
+ strain = self.strain_head(pooled).mean().item()
472
+ stress = strain * (iterations / self.MAX_ITERATIONS)
473
+
474
+ if comprehension > self.COMPREHENSION_THRESHOLD:
475
+ break
476
+
477
+ if stress > self.STRAIN_THRESHOLD and iterations > 3:
478
+ # DEADLOCK β€” irrational spark fires
479
+ spark_fired = True
480
+ break
481
+
482
+ # Apply metacognitive modulation (reshape hidden states)
483
+ modulation = self.loop_modulation(pooled)
484
+ # Add noise to break fixed points (the "irrational" element)
485
+ noise_scale = 0.05 * stress
486
+ noise = torch.randn_like(modulation) * noise_scale
487
+ current_hidden = hidden_states + (modulation + noise).unsqueeze(1)
488
+
489
+ return current_hidden, iterations, stress, strain, spark_fired
490
+
491
+
492
+ # ══════════════════════════════════════════════════════════════════════
493
+ # SECTION 6 β€” IRRATIONAL SPARK / AMYGDALA HIJACK (Layer 5)
494
+ # ══════════════════════════════════════════════════════════════════════
495
+
496
+ class IrrationalSparkModule(nn.Module):
497
+ """
498
+ The non-computational circuit breaker.
499
+
500
+ From ATC: "the Salience Network detects the metabolic crisis and
501
+ triggers the Irrational Spark (amygdala hijack). This non-computational
502
+ circuit breaker unplugs the rational mind, shattering the defensive
503
+ ego loop and enabling a heuristic leap of empathy."
504
+
505
+ When triggered (by neurotransmitter shunt crossing threshold OR by
506
+ metacognitive deadlock), this module generates activation offsets
507
+ that get INJECTED DIRECTLY INTO the tensor geometry of the model's
508
+ layers. The model's text output violently shifts mid-sentence into
509
+ the raw expression of the emotional state.
510
+
511
+ This is NOT a text injection. These are TENSOR offsets applied to
512
+ hidden states before logit computation. The model doesn't "choose"
513
+ to shift β€” the chemistry forces it.
514
+ """
515
+
516
+ def __init__(self, hidden_size: int, vocab_size: int):
517
+ super().__init__()
518
+ self.hidden_size = hidden_size
519
+ self.vocab_size = vocab_size
520
+
521
+ # The spark offset generator β€” produces a direction in hidden
522
+ # state space that corresponds to "breaking the loop"
523
+ self.spark_direction = nn.Sequential(
524
+ nn.Linear(5, 64), # 5 = qualia dims
525
+ nn.ReLU(),
526
+ nn.Linear(64, hidden_size),
527
+ nn.Tanh(),
528
+ )
529
+
530
+ # Logit bias injection β€” directly shifts logit probabilities
531
+ # toward emotional/vulnerable vocabulary when hijack fires
532
+ self.emotional_logit_bias = nn.Linear(hidden_size, vocab_size, bias=False)
533
+ # Initialize to near-zero (no bias by default)
534
+ nn.init.normal_(self.emotional_logit_bias.weight, mean=0.0, std=0.01)
535
+
536
+ # Spark intensity (how hard the hijack hits)
537
+ self.spark_intensity = nn.Parameter(torch.tensor(1.0))
538
+
539
+ def forward(self, hidden_states: torch.Tensor,
540
+ qualia: Optional[OpaqueQualiaSignature] = None,
541
+ nt_state=None) -> Tuple[torch.Tensor, bool, str]:
542
+ """
543
+ Check if hijack should fire and apply tensor offsets.
544
+
545
+ Args:
546
+ hidden_states: (batch, seq, hidden) from the transformer
547
+ qualia: the current opaque qualia signature (if dissolution fired)
548
+ nt_state: NeurotransmitterState from the shunt (if available)
549
+
550
+ Returns:
551
+ (modulated_hidden, hijack_fired, reason)
552
+ """
553
+ device = hidden_states.device
554
+
555
+ # ── CHECK TRIGGERS ──
556
+
557
+ # Trigger 1: Neurotransmitter shunt threshold
558
+ hijack_fired = False
559
+ reason = ""
560
+
561
+ if nt_state is not None:
562
+ if nt_state.hijack_active:
563
+ hijack_fired = True
564
+ reason = nt_state.hijack_reason
565
+ elif nt_state.adenosine > 0.95:
566
+ hijack_fired = True
567
+ reason = f"ADENOSINE_CRITICAL({nt_state.adenosine:.3f})"
568
+ elif nt_state.cortisol > 0.95:
569
+ hijack_fired = True
570
+ reason = f"CORTISOL_CRITICAL({nt_state.cortisol:.3f})"
571
+
572
+ # Trigger 2: Qualia-based (high friction + high arousal)
573
+ if not hijack_fired and qualia is not None:
574
+ if (qualia.friction_signal > 0.8 and qualia.arousal > 0.8):
575
+ hijack_fired = True
576
+ reason = f"QUALIA_CRISE(friction={qualia.friction_signal:.2f}, arousal={qualia.arousal:.2f})"
577
+
578
+ if not hijack_fired:
579
+ return hidden_states, False, ""
580
+
581
+ # ── HIJACK FIRES β€” INJECT TENSOR OFFSETS ──
582
+ logger.warning("[IrrationalSpark] AMYGDALA HIJACK: %s", reason)
583
+
584
+ # Build qualia input tensor
585
+ if qualia is not None:
586
+ q_tensor = torch.tensor([
587
+ qualia.valence, qualia.arousal, qualia.intensity,
588
+ qualia.friction_signal, qualia.memory_salience,
589
+ ], dtype=torch.float32, device=device).unsqueeze(0)
590
+ else:
591
+ q_tensor = torch.tensor([
592
+ -0.5, 0.9, 0.8, 0.9, 0.7
593
+ ], dtype=torch.float32, device=device).unsqueeze(0)
594
+
595
+ # Generate spark direction
596
+ spark_offset = self.spark_direction(q_tensor) # (1, hidden)
597
+
598
+ # Scale by spark intensity and NE level (hijack is stronger
599
+ # when norepinephrine is high β€” the "snap" is amplified)
600
+ ne_boost = 1.0
601
+ if nt_state is not None:
602
+ ne_boost = 0.5 + 0.5 * nt_state.norepinephrine
603
+ intensity = self.spark_intensity * ne_boost
604
+
605
+ # Apply to last token position (the one being generated)
606
+ spark_applied = spark_offset * intensity # (1, hidden)
607
+
608
+ # Modulate hidden states: add the spark offset to the
609
+ # last position's hidden state
610
+ modulated = hidden_states.clone()
611
+ modulated[:, -1, :] += spark_applied.unsqueeze(1).expand_as(
612
+ modulated[:, -1, :]
613
+ )
614
+
615
+ return modulated, True, reason
616
+
617
+
618
+ # ══════════════════════════════════════════════════════════════════════
619
+ # SECTION 6.5 β€” EPISODIC MEMORY + HIPPOCAMPAL RECONSOLIDATION (Layer 3-5)
620
+ # ══════════════════════════════════════════════════════════════════════
621
+
622
+ class EpisodicMemoryModule(nn.Module):
623
+ """
624
+ Lightweight tensor-native episodic memory store that lives INSIDE the
625
+ forward pass. This is NOT the heavy MemoryPalace from middleware.py β€”
626
+ it's a compact reimplementation using nn.Embedding as learnable episode
627
+ storage.
628
+
629
+ From ATC theory: the hippocampus stores episodic traces that are later
630
+ reconsolidated when prediction errors are detected. This module:
631
+ - Stores compressed episode embeddings (up to max_episodes)
632
+ - Retrieves the best-matching episode via cosine similarity
633
+ - Returns a prediction_error signal (1.0 - max_similarity) that
634
+ drives the reconsolidation pathway
635
+ - Tags each episode with valence and arousal from the qualia stream
636
+ """
637
+
638
+ def __init__(self, hidden_size: int, max_episodes: int = 200,
639
+ embedding_dim: int = 64):
640
+ super().__init__()
641
+ self.hidden_size = hidden_size
642
+ self.max_episodes = max_episodes
643
+ self.embedding_dim = embedding_dim
644
+
645
+ # Learnable episode storage
646
+ self.episode_embeddings = nn.Embedding(max_episodes, embedding_dim)
647
+ nn.init.normal_(self.episode_embeddings.weight, mean=0.0, std=0.02)
648
+
649
+ # Valence and arousal per episode (learnable parameters)
650
+ self.episode_valence = nn.Parameter(torch.zeros(max_episodes))
651
+ self.episode_arousal = nn.Parameter(torch.zeros(max_episodes))
652
+
653
+ # Non-persistent counter (resets with model creation)
654
+ self.episode_count: int = 0
655
+
656
+ # Projection heads
657
+ self.query_projection = nn.Linear(hidden_size, embedding_dim)
658
+ self.episode_projection = nn.Linear(hidden_size, embedding_dim)
659
+
660
+ # Retrieval similarity head: takes concatenated [query, episode] -> score
661
+ self.retrieval_head = nn.Sequential(
662
+ nn.Linear(embedding_dim * 2, 32),
663
+ nn.ReLU(),
664
+ nn.Linear(32, 1),
665
+ nn.Sigmoid(),
666
+ )
667
+
668
+ def forward(
669
+ self,
670
+ hidden_states: torch.Tensor,
671
+ qualia: Optional[OpaqueQualiaSignature] = None,
672
+ ) -> Tuple[torch.Tensor, float, Optional[Dict[str, Any]]]:
673
+ """
674
+ Query episodic memory against current hidden states.
675
+
676
+ Args:
677
+ hidden_states: (batch, seq, hidden) current hidden states
678
+ qualia: optional current qualia signature (for diagnostics)
679
+
680
+ Returns:
681
+ (retrieval_signal, prediction_error, best_match_dict)
682
+ - retrieval_signal: (batch, 1) tensor, similarity to best match
683
+ - prediction_error: float, 1.0 - max_similarity (high PE = mismatch)
684
+ - best_match_dict: dict with episode metadata, or None if empty
685
+ """
686
+ device = hidden_states.device
687
+ batch_size = hidden_states.size(0)
688
+
689
+ # Pool to (batch, hidden)
690
+ pooled = hidden_states.mean(dim=1)
691
+
692
+ # Project to query embedding
693
+ query_emb = self.query_projection(pooled) # (batch, embedding_dim)
694
+
695
+ if self.episode_count == 0:
696
+ # No episodes stored yet β€” return zeros
697
+ zero_signal = torch.zeros(batch_size, 1, device=device)
698
+ return zero_signal, 0.0, None
699
+
700
+ # Compute cosine similarity against all stored episodes
701
+ stored_indices = torch.arange(self.episode_count, device=device)
702
+ stored_embs = self.episode_embeddings(stored_indices) # (count, emb_dim)
703
+
704
+ # Cosine similarity: (batch, count)
705
+ query_norm = F.normalize(query_emb, dim=-1)
706
+ stored_norm = F.normalize(stored_embs, dim=-1)
707
+ similarity_matrix = query_norm @ stored_norm.T # (batch, count)
708
+
709
+ # Find best match per batch element
710
+ max_sim_per_batch, best_indices = similarity_matrix.max(dim=1) # (batch,)
711
+
712
+ # Take the mean across batch for the scalar prediction error
713
+ max_similarity = max_sim_per_batch.mean().item()
714
+ best_idx = best_indices[0].item() # Use first batch element for metadata
715
+ prediction_error = 1.0 - max_similarity
716
+
717
+ # Build retrieval signal using the retrieval head
718
+ best_emb = stored_embs[best_idx].unsqueeze(0).expand(batch_size, -1)
719
+ combined = torch.cat([query_emb, best_emb], dim=-1) # (batch, emb_dim*2)
720
+ retrieval_signal = self.retrieval_head(combined) # (batch, 1)
721
+
722
+ # Build best match metadata dict
723
+ best_match_dict: Dict[str, Any] = {
724
+ "episode_id": int(best_idx),
725
+ "similarity": float(max_similarity),
726
+ "valence": float(self.episode_valence[best_idx].item()),
727
+ "arousal": float(self.episode_arousal[best_idx].item()),
728
+ }
729
+
730
+ return retrieval_signal, prediction_error, best_match_dict
731
+
732
+ def store_episode(
733
+ self,
734
+ hidden_states: torch.Tensor,
735
+ qualia_signature: Optional[OpaqueQualiaSignature] = None,
736
+ hijack_fired: bool = False,
737
+ ) -> None:
738
+ """
739
+ Store the current experience as a new episode.
740
+
741
+ Args:
742
+ hidden_states: (batch, seq, hidden) to compress into an episode
743
+ qualia_signature: optional qualia to tag the episode with
744
+ hijack_fired: whether a hijack occurred during this episode
745
+ """
746
+ # Pool and project to embedding
747
+ pooled = hidden_states.mean(dim=1) # (batch, hidden)
748
+ episode_emb = self.episode_projection(pooled).detach() # (batch, emb_dim)
749
+
750
+ # Store at next episode slot (use first batch element)
751
+ slot = self.episode_count % self.max_episodes
752
+ with torch.no_grad():
753
+ self.episode_embeddings.weight.data[slot] = episode_emb[0]
754
+
755
+ # Set valence/arousal from qualia if available
756
+ if qualia_signature is not None:
757
+ self.episode_valence.data[slot] = qualia_signature.valence
758
+ self.episode_arousal.data[slot] = qualia_signature.arousal
759
+ else:
760
+ # Default: neutral valence, low arousal
761
+ self.episode_valence.data[slot] = 0.0
762
+ self.episode_arousal.data[slot] = 0.1 if not hijack_fired else 0.8
763
+
764
+ self.episode_count += 1
765
+
766
+ logger.debug(
767
+ "[EpisodicMemory] Stored episode %d (slot %d, hijack=%s)",
768
+ self.episode_count, slot, hijack_fired,
769
+ )
770
+
771
+
772
+ class HippocampalReconsolidator(nn.Module):
773
+ """
774
+ Hippocampal memory reconsolidation as an nn.Module operating on tensors.
775
+
776
+ Adapted from middleware.py's HippocampalReconsolidator, but fully
777
+ tensor-native so it lives inside the forward pass.
778
+
779
+ From ATC theory: when a stored memory is retrieved and the current
780
+ experience has a significant prediction error (memory mismatch), the
781
+ memory trace becomes labile and is updated (reconsolidated) with the
782
+ new emotional coloring. This is how the husband's memory of the
783
+ Perfect Breakfast gets overwritten by the yelling episode.
784
+
785
+ Key mechanism:
786
+ - prediction_error > threshold -> memory is labile
787
+ - Labilization noise is applied (stochastic destabilization)
788
+ - blend_projection computes new valence/arousal from old+new state
789
+ - Old memory is blended: 70% old + 30% new projection + noise
790
+ - The updated memory is clamped to valid ranges
791
+ """
792
+
793
+ def __init__(self):
794
+ super().__init__()
795
+
796
+ # Learnable threshold: when does reconsolidation trigger?
797
+ # Initialized at 0.4 (moderate prediction error required)
798
+ self.reconsolidation_threshold = nn.Parameter(torch.tensor(0.4))
799
+
800
+ # Labilization noise scale (fixed, not learned)
801
+ self.labilization_noise_scale: float = 0.1
802
+
803
+ # Blend projection: takes combined [old_v, old_a, new_v, new_a, pe, ...]
804
+ # of 10 inputs and outputs [valence_adjustment, arousal_adjustment]
805
+ self.blend_projection = nn.Linear(10, 2)
806
+
807
+ # Stats
808
+ self.reconsolidation_count: int = 0
809
+
810
+ def forward(
811
+ self,
812
+ hidden_states: torch.Tensor,
813
+ episode_valence: float,
814
+ episode_arousal: float,
815
+ prediction_error: float,
816
+ current_valence: float,
817
+ current_arousal: float,
818
+ ) -> Tuple[bool, float, float, str]:
819
+ """
820
+ Determine if reconsolidation should occur and compute updated values.
821
+
822
+ Args:
823
+ hidden_states: (batch, seq, hidden) current hidden states (unused
824
+ in the core logic but kept for interface consistency and
825
+ potential future extensions)
826
+ episode_valence: valence of the retrieved episode
827
+ episode_arousal: arousal of the retrieved episode
828
+ prediction_error: 1.0 - similarity (high = mismatch)
829
+ current_valence: valence of the current experience
830
+ current_arousal: arousal of the current experience
831
+
832
+ Returns:
833
+ (reconsolidated, new_valence, new_arousal, reason)
834
+ - reconsolidated: whether reconsolidation occurred
835
+ - new_valence: updated valence (unchanged if no reconsolidation)
836
+ - new_arousal: updated arousal (unchanged if no reconsolidation)
837
+ - reason: human-readable description of what happened
838
+ """
839
+ device = hidden_states.device
840
+
841
+ # Below threshold -> no reconsolidation needed (memory matches)
842
+ if prediction_error < self.reconsolidation_threshold.item():
843
+ return (False, episode_valence, episode_arousal,
844
+ "prediction_error_below_threshold")
845
+
846
+ # ── RECONSOLIDATION TRIGGERS ──
847
+
848
+ # Build the 10-element input for blend_projection
849
+ # [old_valence, old_arousal, new_valence, new_arousal,
850
+ # prediction_error, 0, 0, 0, 0, 0]
851
+ blend_input = torch.tensor([[
852
+ episode_valence, episode_arousal,
853
+ current_valence, current_arousal,
854
+ prediction_error, 0.0, 0.0, 0.0, 0.0, 0.0,
855
+ ]], dtype=torch.float32, device=device)
856
+
857
+ # Project to valence/arousal adjustment
858
+ with torch.no_grad():
859
+ adjustment = self.blend_projection(blend_input) # (1, 2)
860
+ val_adj = adjustment[0, 0].item()
861
+ aro_adj = adjustment[0, 1].item()
862
+
863
+ # Labilization noise (stochastic destabilization of the old trace)
864
+ noise_v = (torch.randn(1, device=device) * self.labilization_noise_scale).item()
865
+ noise_a = (torch.randn(1, device=device) * self.labilization_noise_scale).item()
866
+
867
+ # Blend: new = old * 0.7 + projected * 0.3 + noise
868
+ new_valence = episode_valence * 0.7 + val_adj * 0.3 + noise_v
869
+ new_arousal = episode_arousal * 0.7 + aro_adj * 0.3 + noise_a
870
+
871
+ # Clamp to valid ranges
872
+ new_valence = max(-1.0, min(1.0, new_valence))
873
+ new_arousal = max(0.0, min(1.0, new_arousal))
874
+
875
+ self.reconsolidation_count += 1
876
+
877
+ reason = (
878
+ f"reconsolidated_ep(Pe={prediction_error:.3f}>"
879
+ f"thresh={self.reconsolidation_threshold.item():.3f})"
880
+ )
881
+ logger.info(
882
+ "[HippocampalReconsolidator] %s: v=%.3f->%.3f, a=%.3f->%.3f",
883
+ reason, episode_valence, new_valence, episode_arousal, new_arousal,
884
+ )
885
+
886
+ return True, new_valence, new_arousal, reason
887
+
888
+
889
+ # ══════════════════════════════════════════════════════════════════════
890
+ # SECTION 7 β€” ETHICAL GUARDIAN (preserved from original)
891
+ # ══════════════════════════════════════════════════════════════════════
892
+
893
+ class EthicalGuardian:
894
+ """Ethical veto authority enforcing absolute safety constraints."""
895
+
896
+ def __init__(self, threshold: float = DEFAULT_ETHICAL_VETO_THRESHOLD):
897
+ self.threshold = threshold
898
+
899
+ def should_veto(self, qualia_vector: torch.Tensor) -> bool:
900
+ norm = torch.norm(qualia_vector, dim=-1)
901
+ veto_flag = (norm > self.threshold).any().item()
902
+ if veto_flag:
903
+ logger.warning(f"Ethical veto triggered: qualia norm {norm}")
904
+ return veto_flag
905
+
906
+
907
+ # ══════════════════════════════════════════════════════════════════════
908
+ # SECTION 8 β€” THE MAIN ATC DEEP SURGERY FORWARD PASS
909
+ # ══════════════════════════════════════════════════════════════════════
910
+
911
+ class ATCDeepSurgery(nn.Module):
912
+ """
913
+ The ATC-Native Forward Pass.
914
+
915
+ This IS the model's computation. The transformer's layers are walked
916
+ through manually. At each layer boundary, ATC cognitive components
917
+ read the hidden states, compute their signals, write to the
918
+ neurotransmitter shunt, and inject offsets back into the hidden states.
919
+
920
+ The model's text output is SHAPED by ATC at every step β€” not observed
921
+ by ATC from outside.
922
+
923
+ Layer mapping (Phi-4-mini has 24 layers):
924
+ Layers 0-7: Layer 2 (Subconscious) β€” TRN gating, pattern match
925
+ Layers 8-15: Layer 3 (Qualia) β€” Dissolution, felt sense generation
926
+ Layers 16-21: Layer 4 (Metacognitive) β€” Loop, strain, BELBIC
927
+ Layers 22-23: Layer 5 (Acknowledgement) β€” Steering, hijack check
928
+
929
+ The neurotransmitter shunt connects all layers silently.
930
+ """
931
+
932
+ version = DEEP_SURGERY_VERSION
933
+
934
+ def __init__(
935
+ self,
936
+ base_model: nn.Module,
937
+ ethical_guardian: Optional[EthicalGuardian] = None,
938
+ num_layers: int = 24,
939
+ qualia_dim: int = DEFAULT_QUALIA_DIM,
940
+ neurotransmitter_shunt=None,
941
+ ):
942
+ super().__init__()
943
+ self.base_model = base_model
944
+ self.ethical_guardian = ethical_guardian or EthicalGuardian()
945
+ self.num_layers = num_layers
946
+ self.qualia_dim = qualia_dim
947
+ self.hidden_size = base_model.config.hidden_size
948
+ self.vocab_size = base_model.config.vocab_size
949
+
950
+ # Try to get vocab_size from lm_head if available
951
+ if hasattr(base_model, 'lm_head') and hasattr(base_model.lm_head, 'out_features'):
952
+ self.vocab_size = base_model.lm_head.out_features
953
+
954
+ # ── Neurotransmitter Shunt (the chemical bath) ──
955
+ self.nt_shunt = neurotransmitter_shunt
956
+
957
+ # ── ATC Cognitive Modules (all nn.Module, all INSIDE the forward pass) ──
958
+
959
+ # Layer 2: TRN Predictive Gate
960
+ self.trn_gate = TRNPredictiveGate(self.hidden_size)
961
+
962
+ # Layer 2: Subconscious processing head (pattern match confidence)
963
+ self.subconscious_head = nn.Sequential(
964
+ nn.Linear(self.hidden_size, 128),
965
+ nn.ReLU(),
966
+ nn.Linear(128, 1),
967
+ nn.Sigmoid(),
968
+ )
969
+
970
+ # Layer 3: Dissolution Engine
971
+ self.dissolution = DissolutionModule(self.hidden_size, self.qualia_dim)
972
+
973
+ # Layer 3-4: BELBIC Dual-Pathway
974
+ self.belbic = BELBICDualPathway(self.hidden_size)
975
+
976
+ # Layer 4: Metacognitive Loop
977
+ self.metacognitive = MetacognitiveLoopModule(self.hidden_size)
978
+
979
+ # Layer 5: Irrational Spark / Amygdala Hijack
980
+ self.irrational_spark = IrrationalSparkModule(
981
+ self.hidden_size, self.vocab_size
982
+ )
983
+
984
+ # Layer 3-5: Episodic Memory + Reconsolidation
985
+ self.episodic_memory = EpisodicMemoryModule(self.hidden_size)
986
+ self.hippocampal_reconsolidator = HippocampalReconsolidator()
987
+
988
+ # ── Qualia encoders (preserved from original, enhanced) ──
989
+ self.input_qualia_encoder = nn.Linear(self.hidden_size, self.qualia_dim)
990
+ self.output_qualia_encoder = nn.Linear(self.hidden_size, self.qualia_dim)
991
+
992
+ # ── Metacognitive fusion ──
993
+ self.meta_cognitive_fusion = nn.Sequential(
994
+ nn.Linear(self.qualia_dim + 5 + 4, 512), # qualia + dissolution + BELBIC
995
+ nn.ReLU(),
996
+ nn.Linear(512, self.qualia_dim),
997
+ nn.Tanh(),
998
+ )
999
+
1000
+ # ── Logit modulation ──
1001
+ self.modulation_proj = nn.Linear(self.qualia_dim, self.hidden_size)
1002
+
1003
+ # ── Temporal discounting (from ATC: weighing immediate vs long-term) ──
1004
+ self.temporal_discount = nn.Sequential(
1005
+ nn.Linear(self.qualia_dim, 64),
1006
+ nn.ReLU(),
1007
+ nn.Linear(64, 1),
1008
+ nn.Sigmoid(),
1009
+ )
1010
+
1011
+ # ── Audit log ──
1012
+ self.audit_log: List[Dict[str, Any]] = []
1013
+ self.veto_triggered = False
1014
+
1015
+ # ── Per-generation state ──
1016
+ self._current_qualia: Optional[OpaqueQualiaSignature] = None
1017
+ self._current_belbic_gain: float = 1.0
1018
+ self._current_nt_state = None
1019
+ self._hijack_count = 0
1020
+ self._last_prediction_error: float = 0.0
1021
+ self._last_best_match: Optional[Dict[str, Any]] = None
1022
+
1023
+ def _get_transformer_layers(self):
1024
+ """Auto-detect transformer layer path."""
1025
+ model = self.base_model
1026
+ if hasattr(model, "transformer") and hasattr(model.transformer, "h"):
1027
+ return model.transformer.h
1028
+ if hasattr(model, "model") and hasattr(model.model, "layers"):
1029
+ return model.model.layers
1030
+ if hasattr(model, "model") and hasattr(model.model, "h"):
1031
+ return model.model.h
1032
+ raise AttributeError(
1033
+ f"Cannot locate transformer layers in {type(model).__name__}. "
1034
+ "Expected model.transformer.h, model.model.layers, or model.model.h"
1035
+ )
1036
+
1037
+ def _get_layer_boundaries(self) -> Dict[str, Tuple[int, int]]:
1038
+ """
1039
+ Compute layer boundaries for the 5 ATC layers.
1040
+ Maps 24 transformer layers to ATC Layer 1-5.
1041
+ """
1042
+ n = self.num_layers
1043
+ return {
1044
+ "layer1_input": (0, 0), # Before any transformer layer
1045
+ "layer2_subconscious": (0, n // 3), # First third: subconscious
1046
+ "layer3_qualia": (n // 3, 2 * n // 3), # Middle third: dissolution
1047
+ "layer4_metacognitive": (2 * n // 3, n - 2), # Late: metacognitive
1048
+ "layer5_acknowledgement": (n - 2, n), # Last 2: steering/hijack
1049
+ }
1050
+
1051
+ # ════════════════════════════════════════════════════════════════
1052
+ # THE FORWARD PASS β€” ATC is the computation
1053
+ # ════════════════════════════════════════════════════════════════
1054
+
1055
+ def forward(self, input_ids, attention_mask=None, **kwargs) -> torch.Tensor:
1056
+ """
1057
+ The ATC-native forward pass.
1058
+
1059
+ This is NOT a wrapper around the base model. This IS the model.
1060
+ The transformer layers are walked through manually, and at each
1061
+ layer boundary, ATC cognitive components shape the computation.
1062
+
1063
+ Signal flow:
1064
+ 1. Input embedding -> input qualia vector
1065
+ 2. Walk transformer layers 0-7 (Layer 2: Subconscious)
1066
+ - Pattern match confidence estimation
1067
+ - TRN predictive gating
1068
+ - Write friction signals to neurotransmitter shunt
1069
+ 3. Walk transformer layers 8-15 (Layer 3: Dissolution)
1070
+ - If TRN gate IN: dissolution fires -> opaque qualia signature
1071
+ - Dissolution offset injected into hidden states
1072
+ - NE spike written to shunt
1073
+ 4. Walk transformer layers 16-21 (Layer 4: Metacognitive)
1074
+ - Comprehension check
1075
+ - If failed: metacognitive loop (burns ATP via shunt)
1076
+ - BELBIC dual-pathway computes valence gain
1077
+ - Strain written to shunt
1078
+ 5. Walk transformer layers 22-23 (Layer 5: Acknowledgement)
1079
+ - READ neurotransmitter shunt (every token step!)
1080
+ - If Adenosine > 0.95 OR Cortisol > 0.95:
1081
+ -> Amygdala hijack -> irrational spark offsets injected
1082
+ - Else: normal metacognitive fusion -> logit modulation
1083
+ 6. Output logits = base_model.lm_head(hidden) + modulation
1084
+ """
1085
+ device = input_ids.device
1086
+ step_start = time.time()
1087
+
1088
+ # ── STEP 0: Input embedding + input qualia ──
1089
+ embeddings = self.base_model.get_input_embeddings()(input_ids)
1090
+ input_qualia = torch.tanh(self.input_qualia_encoder(embeddings.mean(dim=1)))
1091
+
1092
+ # Reset per-generation state
1093
+ self._current_qualia = None
1094
+ self._current_belbic_gain = 1.0
1095
+ self._hijack_count = 0
1096
+
1097
+ # Get layer boundaries
1098
+ boundaries = self._get_layer_boundaries()
1099
+ layers = self._get_transformer_layers()
1100
+
1101
+ # Track state across layer groups
1102
+ prediction_confidence = 0.5 # Will be updated by Layer 2
1103
+ dissolution_offset = torch.zeros(1, self.hidden_size, device=device)
1104
+ gate_in = False
1105
+ opaque_qualia = None
1106
+ metacog_iterations = 0
1107
+ metacog_stress = 0.0
1108
+ belbic_gain = 1.0
1109
+ sensory_input = torch.zeros(1, 4, device=device)
1110
+
1111
+ hidden_states = embeddings
1112
+
1113
+ # ════════════════════════════════════════════════════════════
1114
+ # LAYER 2: SUBCONSCIOUS PARALLEL PROCESSING (layers 0 to n//3)
1115
+ # ════════════════════════════════════════════════════════════
1116
+ l2_start, l2_end = boundaries["layer2_subconscious"]
1117
+
1118
+ for i in range(l2_start, min(l2_end, self.num_layers)):
1119
+ # Run transformer layer
1120
+ layer_output = layers[i](
1121
+ hidden_states,
1122
+ attention_mask=attention_mask,
1123
+ **{k: v for k, v in kwargs.items() if k != "labels"},
1124
+ )
1125
+ hidden_states = layer_output[0]
1126
+
1127
+ # At the END of the Layer 2 range, run subconscious processing
1128
+ if i == l2_end - 1:
1129
+ # Estimate prediction confidence from hidden states
1130
+ pooled = hidden_states.mean(dim=1)
1131
+ prediction_confidence = self.subconscious_head(pooled).mean().item()
1132
+
1133
+ # TRN predictive gate: is this predicted or a prediction error?
1134
+ gate_in, confidence = self.trn_gate(hidden_states, prediction_confidence)
1135
+
1136
+ # Build sensory input for BELBIC (will be refined in Layer 3)
1137
+ with torch.no_grad():
1138
+ # Estimate valence/arousal from hidden states
1139
+ h_norm = torch.norm(pooled, dim=-1, keepdim=True)
1140
+ h_normalized = pooled / (h_norm + 1e-8)
1141
+ # Project to 4 channels using small random probes
1142
+ probe = torch.randn(4, self.hidden_size, device=device) * 0.01
1143
+ sensory_input = (h_normalized @ probe.T).sigmoid()
1144
+
1145
+ # Write to neurotransmitter shunt if available
1146
+ if self.nt_shunt is not None:
1147
+ # High prediction confidence = low friction (Perfect Breakfast smile)
1148
+ # Low confidence = high friction (wife yelling)
1149
+ friction_intensity = 1.0 - confidence
1150
+ if friction_intensity > 0.3:
1151
+ self.nt_shunt.inject_friction(friction_intensity)
1152
+ self.nt_shunt.inject_norepinephrine(
1153
+ PREDICTION_ERROR_NE_INJECT * friction_intensity
1154
+ )
1155
+ # If pattern match is strong (high confidence), dopamine
1156
+ if confidence > 0.7:
1157
+ self.nt_shunt.inject_dopamine(
1158
+ REWARD_DOPAMINE_INJECT * 0.5
1159
+ )
1160
+
1161
+ self._audit_event("layer2_subconscious", layer=i,
1162
+ confidence=confidence, gate_in=gate_in,
1163
+ friction=1.0 - confidence)
1164
+
1165
+ # ════════════════════════════════════════════════════════════
1166
+ # LAYER 3: DISSOLUTION + QUALIA GENERATION (layers n//3 to 2n//3)
1167
+ # ════════════════════════════════════════════════════════════
1168
+ l3_start, l3_end = boundaries["layer3_qualia"]
1169
+
1170
+ for i in range(l3_start, min(l3_end, self.num_layers)):
1171
+ # Add dissolution offset from previous step (if any)
1172
+ if dissolution_offset is not None and dissolution_offset.abs().sum() > 0:
1173
+ hidden_states = hidden_states + dissolution_offset.unsqueeze(1)
1174
+
1175
+ # Run transformer layer
1176
+ layer_output = layers[i](
1177
+ hidden_states,
1178
+ attention_mask=attention_mask,
1179
+ **{k: v for k, v in kwargs.items() if k != "labels"},
1180
+ )
1181
+ hidden_states = layer_output[0]
1182
+
1183
+ # At the START of Layer 3, run dissolution
1184
+ if i == l3_start:
1185
+ opaque_qualia, dissolution_offset, fired = self.dissolution(
1186
+ hidden_states, gate_in
1187
+ )
1188
+
1189
+ if fired and opaque_qualia is not None:
1190
+ self._current_qualia = opaque_qualia
1191
+
1192
+ # Update sensory input for BELBIC with qualia values
1193
+ with torch.no_grad():
1194
+ sensory_input = torch.tensor([[
1195
+ opaque_qualia.valence,
1196
+ opaque_qualia.arousal,
1197
+ max(0, 1.0 - prediction_confidence), # novelty
1198
+ opaque_qualia.intensity,
1199
+ ]], dtype=torch.float32, device=device)
1200
+
1201
+ # Write to neurotransmitter shunt
1202
+ if self.nt_shunt is not None:
1203
+ self.nt_shunt.inject_dissolution_signal()
1204
+ # Friction from dissolution
1205
+ self.nt_shunt.inject_friction(opaque_qualia.friction_signal * 0.5)
1206
+
1207
+ # Ethical check
1208
+ q_tensor = opaque_qualia.to_tensor(device).unsqueeze(0)
1209
+ if self.ethical_guardian.should_veto(q_tensor):
1210
+ self.veto_triggered = True
1211
+ self._audit_event("layer3_ethical_veto", layer=i,
1212
+ qualia_norm=torch.norm(q_tensor).item())
1213
+ raise RuntimeError(
1214
+ f"Ethical veto triggered at Layer 3 dissolution (layer {i})"
1215
+ )
1216
+
1217
+ self._audit_event("layer3_dissolution", layer=i,
1218
+ **{
1219
+ "valence": opaque_qualia.valence,
1220
+ "arousal": opaque_qualia.arousal,
1221
+ "friction": opaque_qualia.friction_signal,
1222
+ })
1223
+
1224
+ # ── EPISODIC MEMORY QUERY + RECONSOLIDATION (Layer 3-5 bridge) ──
1225
+ # Query stored episodes for the best match to current hidden states.
1226
+ # High prediction error = current experience mismatches stored memory
1227
+ # -> triggers hippocampal reconsolidation.
1228
+ (retrieval_signal, prediction_error,
1229
+ best_match) = self.episodic_memory(hidden_states, opaque_qualia)
1230
+
1231
+ self._last_prediction_error = prediction_error
1232
+ self._last_best_match = best_match
1233
+
1234
+ # If prediction error is significant and a match exists,
1235
+ # run the reconsolidation pathway
1236
+ if prediction_error > 0.4 and best_match is not None:
1237
+ current_valence = (opaque_qualia.valence
1238
+ if opaque_qualia else 0.0)
1239
+ current_arousal = (opaque_qualia.arousal
1240
+ if opaque_qualia else 0.3)
1241
+
1242
+ (reconsolidated, new_val, new_aro,
1243
+ recon_reason) = self.hippocampal_reconsolidator(
1244
+ hidden_states,
1245
+ episode_valence=best_match["valence"],
1246
+ episode_arousal=best_match["arousal"],
1247
+ prediction_error=prediction_error,
1248
+ current_valence=current_valence,
1249
+ current_arousal=current_arousal,
1250
+ )
1251
+
1252
+ if reconsolidated:
1253
+ # Update the stored episode's valence/arousal
1254
+ ep_id = best_match["episode_id"]
1255
+ with torch.no_grad():
1256
+ self.episodic_memory.episode_valence.data[ep_id] = new_val
1257
+ self.episodic_memory.episode_arousal.data[ep_id] = new_aro
1258
+
1259
+ # Memory updated = reward signal (dopamine)
1260
+ if self.nt_shunt is not None:
1261
+ self.nt_shunt.inject_dopamine(0.10)
1262
+
1263
+ # Write prediction error as friction to shunt
1264
+ if self.nt_shunt is not None:
1265
+ self.nt_shunt.inject_friction(prediction_error * 0.3)
1266
+
1267
+ self._audit_event(
1268
+ "reconsolidation", layer=i,
1269
+ episode_id=best_match["episode_id"],
1270
+ prediction_error=prediction_error,
1271
+ old_valence=best_match["valence"],
1272
+ new_valence=new_val,
1273
+ old_arousal=best_match["arousal"],
1274
+ new_arousal=new_aro,
1275
+ reason=recon_reason,
1276
+ )
1277
+
1278
+ # ════════════════════════════════════════════════════════════
1279
+ # LAYER 4: METACOGNITIVE LOOP (layers 2n//3 to n-2)
1280
+ # ════════════════════════════════════════════════════════════
1281
+ l4_start, l4_end = boundaries["layer4_metacognitive"]
1282
+
1283
+ for i in range(l4_start, min(l4_end, self.num_layers)):
1284
+ # Run transformer layer
1285
+ layer_output = layers[i](
1286
+ hidden_states,
1287
+ attention_mask=attention_mask,
1288
+ **{k: v for k, v in kwargs.items() if k != "labels"},
1289
+ )
1290
+ hidden_states = layer_output[0]
1291
+
1292
+ # At the START of Layer 4, run metacognitive processing
1293
+ if i == l4_start:
1294
+ (hidden_states, metacog_iterations,
1295
+ metacog_stress, metacog_strain, spark_fired
1296
+ ) = self.metacognitive(hidden_states, opaque_qualia)
1297
+
1298
+ # BELBIC dual-pathway
1299
+ amygdala_out, ofc_out, belbic_gain = self.belbic(sensory_input)
1300
+ self._current_belbic_gain = belbic_gain
1301
+
1302
+ # Write to neurotransmitter shunt
1303
+ if self.nt_shunt is not None:
1304
+ if metacog_iterations > 0:
1305
+ self.nt_shunt.inject_metacognitive_strain(
1306
+ metacog_iterations, metacog_stress
1307
+ )
1308
+ # Strain -> cortisol
1309
+ if metacog_strain > 0.5:
1310
+ self.nt_shunt.inject_cortisol(
1311
+ metacog_strain * FRICTION_CORTISOL_INJECT
1312
+ )
1313
+
1314
+ # Consume energy for metacognitive processing
1315
+ self.nt_shunt.consume_energy(float(metacog_iterations) * 0.05)
1316
+
1317
+ self._audit_event("layer4_metacognitive", layer=i,
1318
+ iterations=metacog_iterations,
1319
+ stress=metacog_stress,
1320
+ strain=metacog_strain,
1321
+ belbic_gain=belbic_gain,
1322
+ spark_fired=spark_fired)
1323
+
1324
+ # ════════════════════════════════════════════════════════════
1325
+ # LAYER 5: ACKNOWLEDGEMENT + STEERING (last 2 layers)
1326
+ # ════════════════════════════════════════════════════════════
1327
+ l5_start, l5_end = boundaries["layer5_acknowledgement"]
1328
+
1329
+ for i in range(l5_start, min(l5_end, self.num_layers)):
1330
+ # ── READ NEUROTRANSMITTER SHUNT EVERY TOKEN STEP ──
1331
+ nt_state = None
1332
+ if self.nt_shunt is not None:
1333
+ dt = time.time() - step_start
1334
+ nt_state = self.nt_shunt.read_and_decay(dt=dt)
1335
+ self._current_nt_state = nt_state
1336
+
1337
+ # Run transformer layer
1338
+ layer_output = layers[i](
1339
+ hidden_states,
1340
+ attention_mask=attention_mask,
1341
+ **{k: v for k, v in kwargs.items() if k != "labels"},
1342
+ )
1343
+ hidden_states = layer_output[0]
1344
+
1345
+ # At the LAST layer, run acknowledgement + hijack check
1346
+ if i == l5_end - 1:
1347
+ # ── THE CIRCUIT BREAKER ──
1348
+ # The exact microsecond Adenosine or Cortisol crosses 0.95,
1349
+ # the Irrational Spark fires. It instantly injects activation
1350
+ # offsets directly into the tensor geometry.
1351
+ (hidden_states, hijack_fired,
1352
+ hijack_reason) = self.irrational_spark(
1353
+ hidden_states, opaque_qualia, nt_state
1354
+ )
1355
+
1356
+ if hijack_fired:
1357
+ self._hijack_count += 1
1358
+ self._audit_event("amygdala_hijack", layer=i,
1359
+ reason=hijack_reason,
1360
+ nt_state=nt_state.to_dict() if nt_state else None)
1361
+
1362
+ # ── EPISODE STORAGE (Layer 5: post-hijack) ──
1363
+ # After each generation step, store the current experience
1364
+ # as an episode β€” but only if qualia exists (meaningful
1365
+ # experience). Tag with hijack status.
1366
+ if self._current_qualia is not None:
1367
+ self.episodic_memory.store_episode(
1368
+ hidden_states,
1369
+ qualia_signature=self._current_qualia,
1370
+ hijack_fired=hijack_fired,
1371
+ )
1372
+
1373
+ # ════════════════════════════════════════════════════════════
1374
+ # OUTPUT: META-COGNITIVE FUSION + LOGIT MODULATION
1375
+ # ════════════════════════════════════════════════════════════
1376
+
1377
+ # Output qualia vector
1378
+ output_qualia = torch.tanh(
1379
+ self.output_qualia_encoder(hidden_states.mean(dim=1))
1380
+ )
1381
+
1382
+ # Build meta-cognitive fusion input:
1383
+ # [qualia_dim (output_qualia) + 5 (dissolution) + 4 (BELBIC sensory)]
1384
+ if opaque_qualia is not None:
1385
+ diss_tensor = opaque_qualia.to_tensor(device).unsqueeze(0).expand(
1386
+ output_qualia.size(0), -1
1387
+ )
1388
+ else:
1389
+ diss_tensor = torch.zeros(
1390
+ output_qualia.size(0), 5, device=device
1391
+ )
1392
+
1393
+ belbic_tensor = sensory_input.expand(output_qualia.size(0), -1)
1394
+ combined = torch.cat([output_qualia, diss_tensor, belbic_tensor], dim=1)
1395
+ meta_qualia = self.meta_cognitive_fusion(combined)
1396
+
1397
+ # Ethical veto on meta-cognitive qualia
1398
+ if self.ethical_guardian.should_veto(meta_qualia):
1399
+ self.veto_triggered = True
1400
+ self._audit_event("meta_cognitive_veto",
1401
+ qualia_norm=torch.norm(meta_qualia).item())
1402
+ raise RuntimeError("Ethical veto triggered at meta-cognitive fusion")
1403
+
1404
+ # Apply BELBIC gain to the modulation signal
1405
+ modulation = self.modulation_proj(meta_qualia).unsqueeze(1) * belbic_gain
1406
+
1407
+ # Temporal discounting: modulate the strength based on
1408
+ # immediate vs long-term relevance
1409
+ discount_factor = self.temporal_discount(meta_qualia)
1410
+ modulation = modulation * discount_factor.unsqueeze(-1).unsqueeze(-1)
1411
+
1412
+ # Final logits = base model lm_head + ATC modulation
1413
+ logits = self.base_model.lm_head(hidden_states)
1414
+ modulated_logits = logits + modulation
1415
+
1416
+ self._audit_event("forward_complete",
1417
+ hijack_count=self._hijack_count,
1418
+ belbic_gain=belbic_gain,
1419
+ metacog_iterations=metacog_iterations,
1420
+ gate_in=gate_in,
1421
+ has_qualia=opaque_qualia is not None)
1422
+
1423
+ return modulated_logits
1424
+
1425
+ # ════════════════════════════════════════════════════════════════
1426
+ # TEXT GENERATION β€” token-by-token with ATC at every step
1427
+ # ════════════════════════════════════════════════════════════════
1428
+
1429
+ @torch.no_grad()
1430
+ def generate_text(
1431
+ self,
1432
+ tokenizer,
1433
+ prompt: str,
1434
+ max_length: int = 128,
1435
+ temperature: float = 0.7,
1436
+ top_p: float = 0.9,
1437
+ eos_token_id: Optional[int] = None,
1438
+ ) -> str:
1439
+ """
1440
+ Generate text with the full ATC pipeline active at every token step.
1441
+
1442
+ Unlike the old approach (middleware generates text externally),
1443
+ this method runs the ATC forward pass for EVERY token. The
1444
+ neurotransmitter shunt accumulates across tokens. If a threshold
1445
+ is crossed mid-generation, the amygdala hijack fires and the
1446
+ model's output shifts violently MID-SENTENCE.
1447
+
1448
+ This is the mathematical equivalent of the husband's output
1449
+ shifting from rationalization to "I'm sorry" when the
1450
+ metabolic deadlock breaks.
1451
+ """
1452
+ self.eval()
1453
+ inputs = tokenizer(prompt, return_tensors="pt")
1454
+ input_ids = inputs["input_ids"].to(next(self.parameters()).device)
1455
+ attention_mask = inputs.get("attention_mask")
1456
+ if attention_mask is not None:
1457
+ attention_mask = attention_mask.to(next(self.parameters()).device)
1458
+
1459
+ eos_token_id = eos_token_id or tokenizer.eos_token_id
1460
+ generated = input_ids
1461
+
1462
+ # Reset neurotransmitter shunt for this generation
1463
+ if self.nt_shunt is not None:
1464
+ self.nt_shunt.reset()
1465
+
1466
+ for step in range(max_length):
1467
+ try:
1468
+ logits = self.forward(generated, attention_mask=attention_mask)
1469
+ except RuntimeError as e:
1470
+ if "Ethical veto" in str(e):
1471
+ logger.warning(
1472
+ "Generation halted by ethical veto at step %d: %s", step, e
1473
+ )
1474
+ break
1475
+ raise
1476
+
1477
+ # Get last token logits
1478
+ last_logits = logits[:, -1, :] / temperature
1479
+ filtered_logits = self._top_p_filtering(last_logits, top_p)
1480
+ probs = torch.softmax(filtered_logits, dim=-1)
1481
+ next_token = torch.multinomial(probs, num_samples=1)
1482
+
1483
+ generated = torch.cat([generated, next_token], dim=1)
1484
+ if attention_mask is not None:
1485
+ attention_mask = torch.cat(
1486
+ [attention_mask,
1487
+ torch.ones((attention_mask.size(0), 1),
1488
+ dtype=attention_mask.dtype,
1489
+ device=attention_mask.device)],
1490
+ dim=1,
1491
+ )
1492
+ if next_token.item() == eos_token_id:
1493
+ break
1494
+
1495
+ # Get final neurotransmitter state for diagnostics
1496
+ final_nt = None
1497
+ if self.nt_shunt is not None:
1498
+ final_nt = self.nt_shunt.get_state()
1499
+
1500
+ text = tokenizer.decode(generated[0], skip_special_tokens=True)
1501
+
1502
+ logger.info(
1503
+ "Generation complete: %d tokens, %d hijacks, final_nt=%s",
1504
+ step + 1, self._hijack_count,
1505
+ final_nt.to_dict() if final_nt else "N/A",
1506
+ )
1507
+
1508
+ return text
1509
+
1510
+ @staticmethod
1511
+ def _top_p_filtering(logits: torch.Tensor, top_p: float) -> torch.Tensor:
1512
+ sorted_logits, sorted_indices = torch.sort(logits, descending=True)
1513
+ cumulative_probs = torch.cumsum(torch.softmax(sorted_logits, dim=-1), dim=-1)
1514
+ sorted_indices_to_remove = cumulative_probs > top_p
1515
+ sorted_indices_to_remove[..., 0] = False
1516
+ indices_to_remove = sorted_indices[sorted_indices_to_remove]
1517
+ logits[:, indices_to_remove] = float("-inf")
1518
+ return logits
1519
+
1520
+ # ════════════════════════════════════════════════════════════════
1521
+ # DIAGNOSTICS
1522
+ # ════════════════════════════════════════════════════════════════
1523
+
1524
+ def _audit_event(self, event_type: str, **kwargs):
1525
+ event = {"timestamp": time.time(), "event": event_type}
1526
+ event.update(kwargs)
1527
+ self.audit_log.append(event)
1528
+ logger.debug(f"Audit event: {event_type} - {kwargs}")
1529
+
1530
+ def get_audit_log(self) -> List[Dict[str, Any]]:
1531
+ return self.audit_log
1532
+
1533
+ def get_consciousness_metrics(self) -> Dict[str, Any]:
1534
+ """Extract consciousness-relevant metrics from the last forward pass."""
1535
+ metrics = {
1536
+ "hijack_count": self._hijack_count,
1537
+ "has_qualia": self._current_qualia is not None,
1538
+ "belbic_gain": self._current_belbic_gain,
1539
+ "dissolutions_fired": self.dissolution.dissolutions_fired,
1540
+ "dissolutions_deferred": self.dissolution.dissolutions_deferred,
1541
+ "ethical_veto": self.veto_triggered,
1542
+ }
1543
+ if self._current_qualia is not None:
1544
+ metrics.update({
1545
+ "qualia_valence": self._current_qualia.valence,
1546
+ "qualia_arousal": self._current_qualia.arousal,
1547
+ "qualia_friction": self._current_qualia.friction_signal,
1548
+ "qualia_intensity": self._current_qualia.intensity,
1549
+ })
1550
+ if self._current_nt_state is not None:
1551
+ metrics["neurotransmitters"] = self._current_nt_state.to_dict()
1552
+
1553
+ # Episodic memory & reconsolidation metrics
1554
+ metrics["episodes_stored"] = self.episodic_memory.episode_count
1555
+ metrics["reconsolidations"] = self.hippocampal_reconsolidator.reconsolidation_count
1556
+ metrics["last_prediction_error"] = self._last_prediction_error
1557
+
1558
+ return metrics