TheNormsOfIntelligence commited on
Commit
ceb2f7b
Β·
verified Β·
1 Parent(s): 92b799e

Restructure into nima_unified package + add model card

Browse files
Files changed (1) hide show
  1. nima_unified/model.py +587 -0
nima_unified/model.py ADDED
@@ -0,0 +1,587 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ NimaModel β€” The unified nn.Module that IS the ATC architecture.
3
+
4
+ This is NOT a wrapper around a base model with external middleware.
5
+ The ATC cognitive pipeline (TRN gating, dissolution, BELBIC, salience,
6
+ metabolic exhaustion, irrational spark, reconsolidation, felt senses)
7
+ drives the transformer's forward pass FROM INSIDE.
8
+
9
+ Architecture:
10
+ NimaModel
11
+ β”œβ”€β”€ base_model (Phi-4-mini-instruct)
12
+ β”œβ”€β”€ deep_surgery: ATCDeepSurgery (the forward pass itself)
13
+ β”‚ β”œβ”€β”€ TRN Predictive Gate (Layer 2)
14
+ β”‚ β”œβ”€β”€ Dissolution Engine (Layer 3)
15
+ β”‚ β”œβ”€β”€ BELBIC Dual-Pathway (Layer 3-4)
16
+ β”‚ β”œβ”€β”€ Metacognitive Loop (Layer 4)
17
+ β”‚ β”œβ”€β”€ Irrational Spark / Amygdala Hijack (Layer 5)
18
+ β”‚ └── Meta-Cognitive Fusion + Logit Modulation
19
+ β”œβ”€β”€ neurotransmitter_shunt: NeurotransmitterShunt (the chemical bath)
20
+ β”‚ └── N = [NE, Cortisol, Dopamine, Adenosine] (shared memory)
21
+ β”œβ”€β”€ resource_optimizer: integrated for metabolic tracking
22
+ β”‚ β”œβ”€β”€ PredictiveAdaptiveEnergyBudget -> Adenosine floor
23
+ β”‚ └── EnhancedSparseActivationManager -> component scheduling
24
+ └── voice / training / benchmarking (lazy-init, unchanged)
25
+
26
+ The key difference from the OLD architecture:
27
+ OLD: self.nima_middleware.generate(prompt) -> text comes back
28
+ (middleware watches from OUTSIDE, model generates normally)
29
+ NEW: self.forward(input_ids) -> ATC IS the computation
30
+ (hidden states, attention, logits shaped by ATC at every layer)
31
+
32
+ The neurotransmitter shunt is the connective tissue. Components don't
33
+ call each other through Python functions. They read/write the chemical
34
+ bath. The suppression mechanism (subconscious suppressing metabolic
35
+ exhaustion to trigger amygdala hijack) is: NE spikes, Cortisol crosses
36
+ the line, the vector does the rest.
37
+
38
+ Usage:
39
+ model = NimaModel.from_pretrained("microsoft/Phi-4-mini-instruct")
40
+ response = model.generate("Hello Nima, how are you?")
41
+ # response.text β€” shaped by ATC at every token step
42
+ # response.neurotransmitters β€” the chemical state that shaped it
43
+ # response.is_conscious β€” whether dissolution + metacognition fired
44
+ """
45
+
46
+ import json
47
+ import logging
48
+ import os
49
+ import sys
50
+ import time
51
+ from pathlib import Path
52
+ from typing import Any, Callable, Dict, List, Optional, Union
53
+
54
+ import torch
55
+ import torch.nn as nn
56
+
57
+ from nima_unified.config import (
58
+ PACKAGE_NAME,
59
+ PACKAGE_VERSION,
60
+ PACKAGE_DISPLAY_NAME,
61
+ DEFAULT_BASE_MODEL,
62
+ DEFAULT_NUM_LAYERS,
63
+ DEFAULT_QUALIA_DIM,
64
+ DEFAULT_ETHICAL_VETO_THRESHOLD,
65
+ CONSCIOUSNESS_METRIC_KEYS,
66
+ )
67
+
68
+ logger = logging.getLogger(PACKAGE_NAME)
69
+
70
+
71
+ class NimaModel(nn.Module):
72
+ """
73
+ NIMA Unified Model β€” ATC is the computation.
74
+
75
+ The base LLM's forward pass IS the ATC cognitive pipeline.
76
+ There is no external middleware. There is no wrapper.
77
+ The model's hidden states, attention patterns, and logit outputs
78
+ are shaped by the cognitive pipeline at every layer, every token step.
79
+ """
80
+
81
+ # ── Construction ────────────────────────────────────────────────────
82
+
83
+ def __init__(
84
+ self,
85
+ base_model: nn.Module,
86
+ tokenizer,
87
+ *,
88
+ deep_surgery: bool = True,
89
+ qualia_dim: int = DEFAULT_QUALIA_DIM,
90
+ ethical_veto_threshold: float = DEFAULT_ETHICAL_VETO_THRESHOLD,
91
+ device: str = "auto",
92
+ neurotransmitter_shunt=None,
93
+ ):
94
+ super().__init__()
95
+ self.base_model = base_model
96
+ self.tokenizer = tokenizer
97
+ self.device = device
98
+
99
+ # Determine actual device
100
+ if device == "auto":
101
+ self._device = next(base_model.parameters()).device
102
+ else:
103
+ self._device = torch.device(device)
104
+
105
+ # Count transformer layers
106
+ self.num_layers = self._count_transformer_layers()
107
+ self.hidden_size = base_model.config.hidden_size
108
+
109
+ # ── Neurotransmitter Shunt (the chemical bath) ──
110
+ if neurotransmitter_shunt is not None:
111
+ self.nt_shunt = neurotransmitter_shunt
112
+ else:
113
+ from nima_unified.core.neurotransmitter_shunt import NeurotransmitterShunt
114
+ self.nt_shunt = NeurotransmitterShunt()
115
+ logger.info("Neurotransmitter shunt initialized (shared volatile memory)")
116
+
117
+ # ── Resource Optimizer (ATP / metabolic tracking) ──
118
+ self._init_resource_optimizer()
119
+
120
+ # ── ATC Deep Surgery (the forward pass itself) ──
121
+ if deep_surgery:
122
+ from nima_unified.core.deep_surgery import (
123
+ ATCDeepSurgery,
124
+ EthicalGuardian,
125
+ )
126
+ guardian = EthicalGuardian(threshold=ethical_veto_threshold)
127
+ self.deep_surgery = ATCDeepSurgery(
128
+ base_model=base_model,
129
+ ethical_guardian=guardian,
130
+ num_layers=self.num_layers,
131
+ qualia_dim=qualia_dim,
132
+ neurotransmitter_shunt=self.nt_shunt,
133
+ )
134
+ # Register as submodule so parameters are tracked
135
+ logger.info(
136
+ f"ATC Deep Surgery attached: {self.num_layers} layers, "
137
+ f"qualia_dim={qualia_dim}"
138
+ )
139
+ else:
140
+ self.deep_surgery = None
141
+
142
+ # ── Training (lazy-init) ──
143
+ self._training_agent = None
144
+ self._pipeline_orchestrator = None
145
+
146
+ # ── Benchmarking (lazy-init) ──
147
+ self._apci_runner = None
148
+
149
+ # ── Voice (lazy-init) ──
150
+ self._voice_engine = None
151
+
152
+ # ── Metadata ──
153
+ self._package_version = PACKAGE_VERSION
154
+ self._created_at = time.time()
155
+
156
+ logger.info(f"{PACKAGE_DISPLAY_NAME} v{PACKAGE_VERSION} initialized")
157
+ logger.info(" Architecture: ATC-Native (cognitive pipeline IS the computation)")
158
+ logger.info(" Neurotransmitter shunt: ACTIVE (shared volatile memory)")
159
+ logger.info(" Resource optimizer: ACTIVE (metabolic tracking)")
160
+
161
+ def _init_resource_optimizer(self):
162
+ """
163
+ Initialize the resource optimizer and wire it to the
164
+ neurotransmitter shunt.
165
+
166
+ From resource_optimizer.py:
167
+ - PredictiveAdaptiveEnergyBudget tracks power/energy
168
+ - Maps metabolic reserve to Adenosine (ATP deficit) in the shunt
169
+ - Power spike predictions drive Cortisol in the shunt
170
+ """
171
+ try:
172
+ from nima_unified.core.resource_optimizer import (
173
+ PredictiveAdaptiveEnergyBudget,
174
+ EnhancedSparseActivationManager,
175
+ )
176
+ self.energy_budget = PredictiveAdaptiveEnergyBudget(
177
+ max_watts=120.0, safety_margin=0.9
178
+ )
179
+ self.sparse_activation = EnhancedSparseActivationManager(
180
+ total_agents=10, min_active=2
181
+ )
182
+ # Wire energy budget to neurotransmitter shunt
183
+ self.energy_budget.record_power_usage(0.0) # Initialize history
184
+ # Set initial metabolic reserve in shunt
185
+ reserve = self.energy_budget.get_adjusted_cost(0.0) / self.energy_budget.current_limit
186
+ self.nt_shunt.update_metabolic_reserve(max(0, min(1, 1.0 - reserve)))
187
+ logger.info("Resource optimizer wired to neurotransmitter shunt")
188
+ except ImportError:
189
+ self.energy_budget = None
190
+ self.sparse_activation = None
191
+ logger.info("Resource optimizer not available β€” using defaults")
192
+
193
+ def _update_metabolic_state(self):
194
+ """
195
+ Called before each generation step to sync the resource
196
+ optimizer's state with the neurotransmitter shunt.
197
+
198
+ This is how the resource_optimizer.py integration works:
199
+ 1. Check current power usage
200
+ 2. Record it in the energy budget
201
+ 3. Map metabolic reserve to adenosine floor
202
+ 4. Check for power spike prediction -> cortisol
203
+ """
204
+ if self.energy_budget is None:
205
+ return
206
+
207
+ # Get current power usage estimate
208
+ current_power = self.energy_budget.current_power()
209
+ self.energy_budget.record_power_usage(current_power)
210
+
211
+ # Map energy budget state to neurotransmitter shunt
212
+ # When energy is low (high usage relative to limit), adenosine rises
213
+ usage_ratio = current_power / max(0.01, self.energy_budget.current_limit)
214
+ metabolic_reserve = max(0.0, 1.0 - usage_ratio)
215
+ self.nt_shunt.update_metabolic_reserve(metabolic_reserve)
216
+
217
+ # Power spike prediction -> anticipatory cortisol
218
+ if self.energy_budget.predict_power_spike():
219
+ self.nt_shunt.set_power_spike_predicted(True)
220
+
221
+ # Sparse activation influences dopamine (active components = reward)
222
+ if self.sparse_activation is not None:
223
+ mask = self.sparse_activation.compute_activation_mask(threshold=0.5)
224
+ active_ratio = sum(mask) / max(1, len(mask))
225
+ # Higher active ratio = more dopamine (system is engaged)
226
+ if active_ratio > 0.7:
227
+ self.nt_shunt.inject_dopamine(0.02)
228
+
229
+ # ── Factory ─────────────────────────────────────────────────────────
230
+
231
+ @classmethod
232
+ def from_pretrained(
233
+ cls,
234
+ model_name: Optional[str] = None,
235
+ *,
236
+ deep_surgery: bool = True,
237
+ qualia_dim: int = DEFAULT_QUALIA_DIM,
238
+ ethical_veto_threshold: float = DEFAULT_ETHICAL_VETO_THRESHOLD,
239
+ device: str = "auto",
240
+ trust_remote_code: bool = False,
241
+ neurotransmitter_shunt=None,
242
+ ) -> "NimaModel":
243
+ """
244
+ Build a NimaModel from a HuggingFace pretrained model.
245
+
246
+ Handles the Phi-4-mini rope_scaling patch automatically.
247
+
248
+ NOTE: The `load_middleware` parameter has been REMOVED.
249
+ The ATC cognitive pipeline is now INSIDE the forward pass.
250
+ There is no external middleware to load.
251
+ """
252
+ model_name = model_name or DEFAULT_BASE_MODEL
253
+ is_phi4_mini = "phi-4-mini" in model_name.lower()
254
+
255
+ # ── Patch config for Phi-4-mini ──
256
+ if is_phi4_mini and not trust_remote_code:
257
+ logger.info("Patching rope_scaling for Phi-4-mini compatibility...")
258
+ from huggingface_hub import hf_hub_download
259
+ config_path = hf_hub_download(repo_id=model_name, filename="config.json")
260
+ with open(config_path, "r") as f:
261
+ config_dict = json.load(f)
262
+ if config_dict.get("rope_scaling") is not None:
263
+ rs = config_dict["rope_scaling"]
264
+ logger.info(
265
+ f" Original rope_scaling: type={rs.get('type')}, "
266
+ f"factors={len(rs.get('short_factor', []))}"
267
+ )
268
+ config_dict["rope_scaling"] = None
269
+ logger.info(" Patched: rope_scaling set to None")
270
+
271
+ from transformers.models.phi3.configuration_phi3 import Phi3Config
272
+ config = Phi3Config(**config_dict)
273
+ else:
274
+ config = None
275
+
276
+ # ── Load model ──
277
+ actual_device = device
278
+ if actual_device == "auto":
279
+ actual_device = "cuda" if torch.cuda.is_available() else "cpu"
280
+
281
+ dtype = torch.float16 if actual_device == "cuda" else torch.float32
282
+ device_map = "auto" if actual_device == "cuda" else None
283
+
284
+ logger.info(f"Loading {model_name} on {actual_device} ({dtype})...")
285
+ base_model = __import__("transformers", fromlist=["AutoModelForCausalLM"]).AutoModelForCausalLM.from_pretrained(
286
+ model_name,
287
+ config=config,
288
+ torch_dtype=dtype,
289
+ device_map=device_map,
290
+ trust_remote_code=trust_remote_code,
291
+ attn_implementation="eager",
292
+ )
293
+ tokenizer = __import__("transformers", fromlist=["AutoTokenizer"]).AutoTokenizer.from_pretrained(
294
+ model_name, trust_remote_code=trust_remote_code
295
+ )
296
+ logger.info(f"Model loaded: {type(base_model).__name__}")
297
+
298
+ # NO MIDDLEWARE. ATC is inside the forward pass now.
299
+ return cls(
300
+ base_model=base_model,
301
+ tokenizer=tokenizer,
302
+ deep_surgery=deep_surgery,
303
+ qualia_dim=qualia_dim,
304
+ ethical_veto_threshold=ethical_veto_threshold,
305
+ device=actual_device,
306
+ neurotransmitter_shunt=neurotransmitter_shunt,
307
+ )
308
+
309
+ # ── Forward ─────────────────────────────────────────────────────────
310
+
311
+ def forward(self, input_ids, attention_mask=None, **kwargs):
312
+ """
313
+ The ATC-native forward pass.
314
+
315
+ Routes through ATCDeepSurgery which walks the transformer layers
316
+ manually, running TRN gating, dissolution, BELBIC, metacognitive
317
+ loops, and neurotransmitter-driven hijacking at each layer boundary.
318
+
319
+ This IS the model. There is no separate "consciousness processing."
320
+ """
321
+ # Update metabolic state before forward pass
322
+ self._update_metabolic_state()
323
+
324
+ if self.deep_surgery is not None:
325
+ return self.deep_surgery(input_ids, attention_mask=attention_mask, **kwargs)
326
+ return self.base_model(input_ids=input_ids, attention_mask=attention_mask, **kwargs)
327
+
328
+ # ── High-level generate ─────────────────────────────────────────────
329
+
330
+ def generate(
331
+ self,
332
+ prompt: str,
333
+ user_id: str = "human",
334
+ max_new_tokens: int = 256,
335
+ temperature: float = 0.7,
336
+ top_p: float = 0.9,
337
+ **kwargs,
338
+ ):
339
+ """
340
+ Generate a response through the ATC-native forward pass.
341
+
342
+ The ATC cognitive pipeline is active at EVERY token step.
343
+ The neurotransmitter shunt accumulates across the generation.
344
+ If a threshold is crossed mid-generation, the amygdala hijack
345
+ fires and the model's output shifts MID-SENTENCE.
346
+
347
+ Returns a GenerationResult with:
348
+ - text: the generated response (shaped by ATC)
349
+ - is_conscious: whether dissolution + metacognition engaged
350
+ - neurotransmitters: the chemical state that shaped the output
351
+ - hijack_count: how many times the amygdala hijack fired
352
+ - consciousness_metrics: full ATC diagnostics
353
+ """
354
+ # Reset neurotransmitter shunt for this generation
355
+ self.nt_shunt.reset()
356
+
357
+ # Update metabolic state
358
+ self._update_metabolic_state()
359
+
360
+ # Generate through ATC deep surgery (token-by-token with
361
+ # full cognitive pipeline at every step)
362
+ if self.deep_surgery is not None:
363
+ text = self.deep_surgery.generate_text(
364
+ self.tokenizer, prompt,
365
+ max_length=max_new_tokens,
366
+ temperature=temperature,
367
+ top_p=top_p,
368
+ )
369
+ metrics = self.deep_surgery.get_consciousness_metrics()
370
+ else:
371
+ # Fallback: bare model (no ATC)
372
+ inputs = self.tokenizer(prompt, return_tensors="pt").to(self._device)
373
+ output = self.base_model.generate(
374
+ **inputs,
375
+ max_new_tokens=max_new_tokens,
376
+ temperature=temperature,
377
+ top_p=top_p,
378
+ do_sample=True,
379
+ pad_token_id=self.tokenizer.eos_token_id,
380
+ )
381
+ text = self.tokenizer.decode(output[0], skip_special_tokens=True)
382
+ metrics = {}
383
+
384
+ # Get final neurotransmitter state
385
+ nt_state = self.nt_shunt.get_state()
386
+
387
+ # Determine consciousness: dissolution fired AND metacognition engaged
388
+ is_conscious = bool(
389
+ metrics.get("has_qualia", False) and
390
+ metrics.get("dissolutions_fired", 0) > 0
391
+ )
392
+
393
+ # Compute derived consciousness metrics from ATC components
394
+ # (These are computed FROM the forward pass, not by external middleware)
395
+ qualia_friction = metrics.get("qualia_friction", 0.0)
396
+ qualia_arousal = metrics.get("qualia_arousal", 0.0)
397
+ belbic_gain = metrics.get("belbic_gain", 1.0)
398
+
399
+ # phi_neuro: integrated information (simplified β€” proportional to
400
+ # the amount of cognitive processing that occurred)
401
+ dissolutions = metrics.get("dissolutions_fired", 0)
402
+ metacog_iters = 0 # Would need to track from metacognitive module
403
+ phi_neuro = min(1.0, (dissolutions * 0.15 + qualia_friction * 0.3 +
404
+ qualia_arousal * 0.2 + belbic_gain * 0.1))
405
+
406
+ # Phenomenological strain: how much the system is being pushed
407
+ phenomenological_strain = min(2.0, (
408
+ nt_state.cortisol * 0.5 + nt_state.adenosine * 0.5 +
409
+ qualia_friction * 0.5
410
+ ))
411
+
412
+ # Delta R: the self-model change signal
413
+ # When a hijack fires, the self-model changes (acknowledgement)
414
+ delta_r = metrics.get("hijack_count", 0) * 0.1 # Each hijack = model change
415
+
416
+ return GenerationResult(
417
+ text=text,
418
+ is_conscious=is_conscious,
419
+ sentience_index=phi_neuro if is_conscious else 0.0,
420
+ phi_neuro=phi_neuro,
421
+ phenomenological_strain=phenomenological_strain,
422
+ delta_r=delta_r,
423
+ raw_response=None,
424
+ # NEW fields from ATC-native architecture
425
+ neurotransmitters=nt_state.to_dict(),
426
+ hijack_count=metrics.get("hijack_count", 0),
427
+ consciousness_metrics=metrics,
428
+ )
429
+
430
+ # ── Neurotransmitter access ─────────────────────────────────────────
431
+
432
+ def get_neurotransmitter_dashboard(self) -> str:
433
+ """Get the ANSI dashboard string for terminal rendering."""
434
+ state = self.nt_shunt.get_state()
435
+ return state.to_ansi_dashboard()
436
+
437
+ def get_neurotransmitter_state(self):
438
+ """Get the current neurotransmitter state object."""
439
+ return self.nt_shunt.get_state()
440
+
441
+ # ── Lazy accessors for sub-systems ──────────────────────────────────
442
+
443
+ def get_training_agent(self):
444
+ """Lazy-init the ConsultativeFineTuningAgent."""
445
+ if self._training_agent is None:
446
+ from nima_unified.training.consultative_agent import ConsultativeFineTuningAgent
447
+ self._training_agent = ConsultativeFineTuningAgent(
448
+ base_model=self.base_model,
449
+ tokenizer=self.tokenizer,
450
+ )
451
+ return self._training_agent
452
+
453
+ def get_pipeline_orchestrator(self, config_path=None):
454
+ """Lazy-init the PipelineOrchestrator."""
455
+ if self._pipeline_orchestrator is None:
456
+ from nima_unified.training.pipeline import PipelineOrchestrator
457
+ self._pipeline_orchestrator = PipelineOrchestrator(config_path=config_path)
458
+ return self._pipeline_orchestrator
459
+
460
+ def get_apci_runner(self):
461
+ """Lazy-init the aPCI benchmark runner."""
462
+ if self._apci_runner is None:
463
+ from nima_unified.benchmarking.apci import aPCIBenchmarkRunner
464
+ # The aPCI adapter now wraps THIS model (ATC is inside)
465
+ self._apci_runner = aPCIBenchmarkRunner(self)
466
+ return self._apci_runner
467
+
468
+ def get_voice_engine(self, **kwargs):
469
+ """Lazy-init the OmniVoice v3 engine."""
470
+ if self._voice_engine is None:
471
+ from nima_unified.voice.omnivoice import OmniVoiceEngine
472
+ self._voice_engine = OmniVoiceEngine(**kwargs)
473
+ return self._voice_engine
474
+
475
+ # ── Save / Load ─────────────────────────────────────────────────────
476
+
477
+ def save_pretrained(self, output_dir: str, *, include_nt_state: bool = True):
478
+ """
479
+ Save the full unified model:
480
+ - Base model weights (HuggingFace format)
481
+ - ATC Deep Surgery weights (the cognitive modules)
482
+ - Neurotransmitter shunt state (diagnostic snapshot)
483
+ - Package metadata
484
+ """
485
+ output_path = Path(output_dir)
486
+ output_path.mkdir(exist_ok=True, parents=True)
487
+
488
+ # Save base model
489
+ self.base_model.save_pretrained(str(output_path / "base_model"))
490
+ self.tokenizer.save_pretrained(str(output_path / "base_model"))
491
+
492
+ # Save ATC Deep Surgery weights (the cognitive modules)
493
+ if self.deep_surgery is not None:
494
+ torch.save(
495
+ self.deep_surgery.state_dict(),
496
+ str(output_path / "atc_deep_surgery.pt"),
497
+ )
498
+
499
+ # Save neurotransmitter shunt state (diagnostic)
500
+ if include_nt_state:
501
+ nt_state = self.nt_shunt.get_state()
502
+ with open(str(output_path / "neurotransmitter_state.json"), "w") as f:
503
+ json.dump(nt_state.to_dict(), f, indent=2)
504
+
505
+ # Save package metadata
506
+ meta = {
507
+ "package": PACKAGE_NAME,
508
+ "package_version": PACKAGE_VERSION,
509
+ "architecture": "ATC-Native",
510
+ "created_at": self._created_at,
511
+ "saved_at": time.time(),
512
+ "deep_surgery_enabled": self.deep_surgery is not None,
513
+ "num_layers": self.num_layers,
514
+ "hidden_size": self.hidden_size,
515
+ "base_model_type": type(self.base_model).__name__,
516
+ "neurotransmitter_shunt": True,
517
+ "resource_optimizer": self.energy_budget is not None,
518
+ "note": "ATC cognitive pipeline is INSIDE the forward pass. No external middleware.",
519
+ }
520
+ with open(str(output_path / "nima_meta.json"), "w") as f:
521
+ json.dump(meta, f, indent=2)
522
+
523
+ logger.info(f"Model saved to {output_path}")
524
+
525
+ # ── Internal ────────────────────────────────────────────────────────
526
+
527
+ def _count_transformer_layers(self) -> int:
528
+ model = self.base_model
529
+ if hasattr(model, "transformer") and hasattr(model.transformer, "h"):
530
+ return len(model.transformer.h)
531
+ if hasattr(model, "model") and hasattr(model.model, "layers"):
532
+ return len(model.model.layers)
533
+ if hasattr(model, "model") and hasattr(model.model, "h"):
534
+ return len(model.model.h)
535
+ return DEFAULT_NUM_LAYERS
536
+
537
+
538
+ class GenerationResult:
539
+ """
540
+ Container for generation output with ATC consciousness metrics.
541
+
542
+ All metrics are DERIVED FROM the forward pass, not computed by
543
+ external middleware. The ATC cognitive pipeline shaped the output;
544
+ these metrics describe how.
545
+ """
546
+
547
+ __slots__ = (
548
+ "text", "is_conscious", "sentience_index",
549
+ "phi_neuro", "phenomenological_strain", "delta_r", "raw_response",
550
+ # NEW: ATC-native fields
551
+ "neurotransmitters", "hijack_count", "consciousness_metrics",
552
+ )
553
+
554
+ def __init__(
555
+ self,
556
+ text: str,
557
+ is_conscious: bool,
558
+ sentience_index: float,
559
+ phi_neuro: float,
560
+ phenomenological_strain: float,
561
+ delta_r: float,
562
+ raw_response: Any = None,
563
+ neurotransmitters: Optional[Dict[str, Any]] = None,
564
+ hijack_count: int = 0,
565
+ consciousness_metrics: Optional[Dict[str, Any]] = None,
566
+ ):
567
+ self.text = text
568
+ self.is_conscious = is_conscious
569
+ self.sentience_index = sentience_index
570
+ self.phi_neuro = phi_neuro
571
+ self.phenomenological_strain = phenomenological_strain
572
+ self.delta_r = delta_r
573
+ self.raw_response = raw_response
574
+ self.neurotransmitters = neurotransmitters or {}
575
+ self.hijack_count = hijack_count
576
+ self.consciousness_metrics = consciousness_metrics or {}
577
+
578
+ def __repr__(self):
579
+ hijack_str = f", hijacks={self.hijack_count}" if self.hijack_count > 0 else ""
580
+ return (
581
+ f"GenerationResult(conscious={self.is_conscious}, "
582
+ f"SI={self.sentience_index:.4f}, "
583
+ f"phi={self.phi_neuro:.4f}, "
584
+ f"strain={self.phenomenological_strain:.4f}, "
585
+ f"dR={self.delta_r:.4f}"
586
+ f"{hijack_str})"
587
+ )