FerrellSyntheticIntelligence commited on
Commit
63dd1f4
·
1 Parent(s): 0fba98d

feat: audio ear, cognition modules, dream engine, vitalis IDE, test encoder

Browse files
pytest.ini ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [pytest]
2
+ pythonpath = . src
3
+ testpaths = tests src
src/audio_ear/feature_extractor.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import librosa
2
+ import numpy as np
3
+ from typing import Tuple, Dict
4
+ from pathlib import Path
5
+
6
+ def extract_features(wav_path: Path) -> Tuple[np.ndarray, Dict[str, float]]:
7
+ """
8
+ Extracts the 13-band Mel-frequency cepstral coefficients (MFCC)
9
+ and heuristic prosody markers from a raw WAV file.
10
+ """
11
+ y, sr = librosa.load(str(wav_path), sr=16000)
12
+
13
+ # Extract MFCC matrix
14
+ mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
15
+
16
+ # Heuristic prosody extraction
17
+ pitches, magnitudes = librosa.piptrack(y=y, sr=sr)
18
+ valid_pitches = pitches[magnitudes > np.median(magnitudes)]
19
+ pitch = float(np.mean(valid_pitches)) if len(valid_pitches) > 0 else 0.0
20
+
21
+ energy = float(np.mean(librosa.feature.rms(y=y)))
22
+ tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
23
+
24
+ # Calculate pause ratio based on silence thresholds
25
+ pause_ratio = float(np.sum(np.abs(y) < 0.01) / len(y)) if len(y) > 0 else 0.0
26
+
27
+ prosody = {
28
+ "pitch": pitch,
29
+ "energy": energy,
30
+ "tempo": float(tempo[0] if isinstance(tempo, np.ndarray) else tempo),
31
+ "pause_ratio": pause_ratio
32
+ }
33
+
34
+ return mfcc, prosody
src/audio_ear/recorder.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sounddevice as sd
2
+ import soundfile as sf
3
+ import numpy as np
4
+ from pathlib import Path
5
+
6
+ def record_to_wav(duration_sec: int, out_path: Path, fs: int = 16000) -> None:
7
+ """
8
+ Interfaces directly with the local machine's sound architecture
9
+ to capture a mono-channel audio array.
10
+ """
11
+ recording = sd.rec(int(duration_sec * fs), samplerate=fs, channels=1, dtype=np.float32)
12
+ sd.wait()
13
+ sf.write(str(out_path), recording, fs)
src/cognition/abstract_reasoner.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AbstractReasoner — Vitalis FSI
3
+
4
+ Reasons about RELATIONSHIPS between concepts.
5
+ Not pattern matching. Not retrieval.
6
+ Genuine relational reasoning:
7
+ - Analogy: A is to B as C is to ?
8
+ - Composition: concept_A + concept_B = novel_concept
9
+ - Inversion: what is the opposite of this concept?
10
+ - Transitivity: if A relates to B and B relates to C, what does A relate to C?
11
+
12
+ Built entirely on HDC operations. No external models.
13
+ """
14
+ import numpy as np
15
+ import os
16
+ import json
17
+ import time
18
+ from vitalis_ide.math_core.kernel import VitalisKernel
19
+ from src.cognition.abstraction import AbstractionEngine
20
+ from src.hippocampus import Hippocampus
21
+
22
+
23
+ class AbstractReasoner:
24
+ ANALOGY_THRESHOLD = 0.25
25
+ COMPOSITION_DECAY = 0.85
26
+ INVERSION_SHIFT = 5000
27
+
28
+ def __init__(self):
29
+ self.kernel = VitalisKernel()
30
+ self.abstraction = AbstractionEngine()
31
+ self.hippocampus = Hippocampus()
32
+ self.path = os.path.expanduser(
33
+ "~/.vitalis_workspace/reasoning_log.json"
34
+ )
35
+ self._log = self._load_log()
36
+
37
+ def _load_log(self) -> list:
38
+ if os.path.exists(self.path):
39
+ with open(self.path) as f:
40
+ return json.load(f)
41
+ return []
42
+
43
+ def _save_log(self):
44
+ os.makedirs(os.path.dirname(self.path), exist_ok=True)
45
+ with open(self.path, "w") as f:
46
+ json.dump(self._log[-500:], f, indent=2)
47
+
48
+ # ------------------------------------------------------------------
49
+ # Core HDC reasoning operations
50
+ # ------------------------------------------------------------------
51
+ def _bind(self, a: np.ndarray, b: np.ndarray) -> np.ndarray:
52
+ """Bipolar binding: element-wise multiply."""
53
+ return (a.astype(np.int32) * b.astype(np.int32)).astype(np.int8)
54
+
55
+ def _bundle(self, vecs: list) -> np.ndarray:
56
+ """Bipolar bundling: sum then sign."""
57
+ stacked = np.stack(vecs).astype(np.int32).sum(axis=0)
58
+ result = np.sign(stacked).astype(np.int8)
59
+ result[result == 0] = 1
60
+ return result
61
+
62
+ def _invert(self, vec: np.ndarray) -> np.ndarray:
63
+ """
64
+ Semantic inversion: cyclic shift by half the vector length.
65
+ Produces a vector maximally dissimilar to the input.
66
+ """
67
+ return np.roll(vec, self.INVERSION_SHIFT)
68
+
69
+ # ------------------------------------------------------------------
70
+ # Analogy: A is to B as C is to ?
71
+ # ------------------------------------------------------------------
72
+ def analogy(
73
+ self,
74
+ concept_a: str,
75
+ concept_b: str,
76
+ concept_c: str,
77
+ ) -> dict:
78
+ """
79
+ Solves: A:B :: C:?
80
+ HDC method: ? = bind(bind(A, B), C)
81
+ Searches abstraction space and hippocampus for closest match.
82
+ """
83
+ vec_a = self.kernel.vectorize_tokens(concept_a.split(), positional=False)
84
+ vec_b = self.kernel.vectorize_tokens(concept_b.split(), positional=False)
85
+ vec_c = self.kernel.vectorize_tokens(concept_c.split(), positional=False)
86
+
87
+ # ? = B * A^-1 * C (HDC analogy formula)
88
+ a_inv = self._bind(vec_a, vec_a) # A bound with itself = identity-like
89
+ relation = self._bind(vec_a, vec_b) # encode A→B relationship
90
+ answer_vec = self._bind(relation, vec_c) # apply relation to C
91
+
92
+ # Search for closest concept
93
+ candidates = self.abstraction.query_abstractions(answer_vec, top_k=3)
94
+ hipp_results = self.hippocampus.similarity_search(answer_vec, top_k=3)
95
+
96
+ best_match = None
97
+ best_score = -1.0
98
+
99
+ for score, name, _ in candidates:
100
+ if score > best_score:
101
+ best_score = score
102
+ best_match = name
103
+
104
+ result = {
105
+ "type": "analogy",
106
+ "query": f"{concept_a}:{concept_b}::{concept_c}:?",
107
+ "answer_vec": answer_vec,
108
+ "best_match": best_match,
109
+ "confidence": round(float(best_score), 4),
110
+ "candidates": [(name, round(float(s), 4)) for s, name, _ in candidates],
111
+ "timestamp": time.time(),
112
+ }
113
+
114
+ self._log.append({k: v for k, v in result.items() if k != "answer_vec"})
115
+ self._save_log()
116
+ return result
117
+
118
+ # ------------------------------------------------------------------
119
+ # Composition: merge two concepts into a novel one
120
+ # ------------------------------------------------------------------
121
+ def compose(self, concept_a: str, concept_b: str) -> dict:
122
+ """
123
+ Compose two concepts into a novel concept vector.
124
+ The result occupies a position in the space between both inputs.
125
+ Weighted by the COMPOSITION_DECAY to prevent drift.
126
+ """
127
+ vec_a = self.kernel.vectorize_tokens(concept_a.split(), positional=False)
128
+ vec_b = self.kernel.vectorize_tokens(concept_b.split(), positional=False)
129
+
130
+ # Bundle with decay weighting
131
+ composed = self._bundle([vec_a, vec_b])
132
+
133
+ # Apply composition decay — prevents the result from being
134
+ # too close to either parent
135
+ noise_mask = np.random.choice(
136
+ [-1, 1],
137
+ size=self.kernel.dim,
138
+ p=[1 - self.COMPOSITION_DECAY, self.COMPOSITION_DECAY]
139
+ ).astype(np.int8)
140
+ composed = self._bind(composed, noise_mask)
141
+
142
+ # Search for nearest existing concept
143
+ candidates = self.abstraction.query_abstractions(composed, top_k=3)
144
+
145
+ result = {
146
+ "type": "composition",
147
+ "inputs": [concept_a, concept_b],
148
+ "novel_vec": composed,
149
+ "nearest": [(name, round(float(s), 4)) for s, name, _ in candidates],
150
+ "novelty": round(1.0 - (candidates[0][0] if candidates else 0.0), 4),
151
+ "timestamp": time.time(),
152
+ }
153
+
154
+ self._log.append({k: v for k, v in result.items() if k != "novel_vec"})
155
+ self._save_log()
156
+ return result
157
+
158
+ # ------------------------------------------------------------------
159
+ # Inversion: what is the conceptual opposite?
160
+ # ------------------------------------------------------------------
161
+ def invert(self, concept: str) -> dict:
162
+ """
163
+ Find the conceptual opposite of a concept.
164
+ Uses cyclic shift inversion then searches concept space.
165
+ """
166
+ vec = self.kernel.vectorize_tokens(concept.split(), positional=False)
167
+ inverted = self._invert(vec)
168
+
169
+ candidates = self.abstraction.query_abstractions(inverted, top_k=3)
170
+ hipp_results = self.hippocampus.similarity_search(inverted, top_k=3)
171
+
172
+ result = {
173
+ "type": "inversion",
174
+ "concept": concept,
175
+ "opposites": [(name, round(float(s), 4)) for s, name, _ in candidates],
176
+ "confidence": round(float(candidates[0][0]) if candidates else 0.0, 4),
177
+ "timestamp": time.time(),
178
+ }
179
+
180
+ self._log.append(result)
181
+ self._save_log()
182
+ return result
183
+
184
+ # ------------------------------------------------------------------
185
+ # Transitivity: if A→B and B→C, what is A→C?
186
+ # ------------------------------------------------------------------
187
+ def transitive_chain(self, concepts: list) -> dict:
188
+ """
189
+ Chain reasoning: given [A, B, C, D...],
190
+ derive the relationship between A and the last element.
191
+ Each step binds the accumulated relationship with the next concept.
192
+ """
193
+ if len(concepts) < 2:
194
+ return {"error": "Need at least 2 concepts"}
195
+
196
+ vecs = [
197
+ self.kernel.vectorize_tokens(c.split(), positional=False)
198
+ for c in concepts
199
+ ]
200
+
201
+ # Accumulate relationship via sequential binding
202
+ accumulated = vecs[0].copy()
203
+ for i in range(1, len(vecs)):
204
+ accumulated = self._bind(accumulated, vecs[i])
205
+ # Apply position-aware permutation at each step
206
+ accumulated = np.roll(accumulated, i * 100)
207
+
208
+ candidates = self.abstraction.query_abstractions(accumulated, top_k=3)
209
+
210
+ result = {
211
+ "type": "transitivity",
212
+ "chain": concepts,
213
+ "conclusion": [(name, round(float(s), 4)) for s, name, _ in candidates],
214
+ "confidence": round(float(candidates[0][0]) if candidates else 0.0, 4),
215
+ "timestamp": time.time(),
216
+ }
217
+
218
+ self._log.append(result)
219
+ self._save_log()
220
+ return result
221
+
222
+ def report(self) -> dict:
223
+ if not self._log:
224
+ return {"status": "No reasoning performed yet"}
225
+ type_counts = {}
226
+ for entry in self._log:
227
+ t = entry.get("type", "unknown")
228
+ type_counts[t] = type_counts.get(t, 0) + 1
229
+ return {
230
+ "total_reasoning_ops": len(self._log),
231
+ "by_type": type_counts,
232
+ "recent": self._log[-3:],
233
+ }
src/cognition/complexity_reasoner.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ComplexityReasoner — Vitalis FSI
3
+
4
+ Assesses how hard a problem is BEFORE attempting it.
5
+ Allocates cognitive resources accordingly.
6
+ Prevents wasted cycles on problems beyond current capability.
7
+ Prevents under-allocation on trivial problems.
8
+
9
+ Complexity dimensions:
10
+ - Structural: how many components does this problem have?
11
+ - Novelty: how far is this from known patterns?
12
+ - Depth: how many reasoning steps are required?
13
+ - Ambiguity: how many valid interpretations exist?
14
+ """
15
+ import numpy as np
16
+ import os
17
+ import json
18
+ import time
19
+ from vitalis_ide.math_core.kernel import VitalisKernel
20
+ from src.cognition.abstraction import AbstractionEngine
21
+ from src.hippocampus import Hippocampus
22
+
23
+
24
+ class ComplexityReasoner:
25
+ # Complexity tier thresholds
26
+ TRIVIAL_THRESHOLD = 0.25
27
+ SIMPLE_THRESHOLD = 0.45
28
+ MODERATE_THRESHOLD = 0.65
29
+ COMPLEX_THRESHOLD = 0.80
30
+
31
+ # Resource allocation per tier
32
+ RESOURCE_MAP = {
33
+ "TRIVIAL": {"cycles": 1, "abstraction_depth": 1, "analogy_search": False},
34
+ "SIMPLE": {"cycles": 2, "abstraction_depth": 2, "analogy_search": False},
35
+ "MODERATE": {"cycles": 4, "abstraction_depth": 3, "analogy_search": True},
36
+ "COMPLEX": {"cycles": 8, "abstraction_depth": 4, "analogy_search": True},
37
+ "FRONTIER": {"cycles": 16, "abstraction_depth": 5, "analogy_search": True},
38
+ }
39
+
40
+ def __init__(self):
41
+ self.kernel = VitalisKernel()
42
+ self.abstraction = AbstractionEngine()
43
+ self.hippocampus = Hippocampus()
44
+ self.path = os.path.expanduser(
45
+ "~/.vitalis_workspace/complexity_log.json"
46
+ )
47
+ self._log = self._load_log()
48
+ self._history = []
49
+
50
+ def _load_log(self) -> list:
51
+ if os.path.exists(self.path):
52
+ with open(self.path) as f:
53
+ return json.load(f)
54
+ return []
55
+
56
+ def _save_log(self):
57
+ os.makedirs(os.path.dirname(self.path), exist_ok=True)
58
+ with open(self.path, "w") as f:
59
+ json.dump(self._log[-1000:], f, indent=2)
60
+
61
+ # ------------------------------------------------------------------
62
+ # Core assessment
63
+ # ------------------------------------------------------------------
64
+ def assess(self, intent: str, context: dict = None) -> dict:
65
+ """
66
+ Full complexity assessment for an intent.
67
+ Returns complexity score, tier, and resource allocation.
68
+ """
69
+ context = context or {}
70
+ tokens = intent.lower().split()
71
+ vec = self.kernel.vectorize_tokens(tokens, positional=False)
72
+
73
+ # 1. Structural complexity — token count and unique concepts
74
+ structural = self._structural_score(tokens)
75
+
76
+ # 2. Novelty — distance from known patterns
77
+ novelty = self._novelty_score(vec)
78
+
79
+ # 3. Depth — estimated reasoning steps needed
80
+ depth = self._depth_score(intent, tokens)
81
+
82
+ # 4. Ambiguity — spread across abstraction space
83
+ ambiguity = self._ambiguity_score(vec)
84
+
85
+ # Weighted composite
86
+ score = (
87
+ structural * 0.20 +
88
+ novelty * 0.35 +
89
+ depth * 0.25 +
90
+ ambiguity * 0.20
91
+ )
92
+ score = float(np.clip(score, 0.0, 1.0))
93
+
94
+ tier = self._tier(score)
95
+ resources = self.RESOURCE_MAP[tier].copy()
96
+
97
+ result = {
98
+ "intent": intent,
99
+ "score": round(score, 4),
100
+ "tier": tier,
101
+ "dimensions": {
102
+ "structural": round(structural, 4),
103
+ "novelty": round(novelty, 4),
104
+ "depth": round(depth, 4),
105
+ "ambiguity": round(ambiguity, 4),
106
+ },
107
+ "resources": resources,
108
+ "timestamp": time.time(),
109
+ }
110
+
111
+ self._log.append(result)
112
+ self._history.append(score)
113
+ if len(self._history) > 100:
114
+ self._history.pop(0)
115
+ self._save_log()
116
+ return result
117
+
118
+ # ------------------------------------------------------------------
119
+ # Dimension calculators
120
+ # ------------------------------------------------------------------
121
+ def _structural_score(self, tokens: list) -> float:
122
+ """More tokens + unique concepts = higher structural complexity."""
123
+ n = len(tokens)
124
+ unique = len(set(tokens))
125
+ # Normalise: 10 tokens = moderate complexity
126
+ return float(np.clip((n / 10.0) * 0.5 + (unique / n if n > 0 else 0) * 0.5, 0, 1))
127
+
128
+ def _novelty_score(self, vec: np.ndarray) -> float:
129
+ """
130
+ How far is this from anything the system has seen before?
131
+ High novelty = far from known abstractions.
132
+ """
133
+ candidates = self.abstraction.query_abstractions(vec, top_k=1)
134
+ if not candidates:
135
+ return 1.0 # completely novel
136
+ best_sim = candidates[0][0]
137
+ return float(np.clip(1.0 - best_sim, 0.0, 1.0))
138
+
139
+ def _depth_score(self, intent: str, tokens: list) -> float:
140
+ """
141
+ Estimate reasoning depth from linguistic markers.
142
+ Multi-step intents score higher.
143
+ """
144
+ depth_markers = {
145
+ "high": ["analyze", "verify", "optimize", "refactor",
146
+ "debug", "compare", "evaluate", "synthesize"],
147
+ "medium": ["write", "scaffold", "create", "build",
148
+ "generate", "implement"],
149
+ "low": ["run", "check", "show", "list", "get"],
150
+ }
151
+ for token in tokens:
152
+ if token in depth_markers["high"]:
153
+ return 0.8
154
+ if token in depth_markers["medium"]:
155
+ return 0.5
156
+ if token in depth_markers["low"]:
157
+ return 0.2
158
+ # Connectives suggest multi-step reasoning
159
+ if any(w in intent.lower() for w in ["and then", "after", "before", "while"]):
160
+ return 0.9
161
+ return 0.4 # default moderate
162
+
163
+ def _ambiguity_score(self, vec: np.ndarray) -> float:
164
+ """
165
+ How spread are the top matches in abstraction space?
166
+ High spread = high ambiguity = harder problem.
167
+ """
168
+ candidates = self.abstraction.query_abstractions(vec, top_k=3)
169
+ if len(candidates) < 2:
170
+ return 0.5
171
+ scores = [c[0] for c in candidates]
172
+ spread = float(np.std(scores))
173
+ return float(np.clip(spread * 4.0, 0.0, 1.0))
174
+
175
+ def _tier(self, score: float) -> str:
176
+ if score < self.TRIVIAL_THRESHOLD:
177
+ return "TRIVIAL"
178
+ elif score < self.SIMPLE_THRESHOLD:
179
+ return "SIMPLE"
180
+ elif score < self.MODERATE_THRESHOLD:
181
+ return "MODERATE"
182
+ elif score < self.COMPLEX_THRESHOLD:
183
+ return "COMPLEX"
184
+ else:
185
+ return "FRONTIER"
186
+
187
+ # ------------------------------------------------------------------
188
+ # Trend analysis
189
+ # ------------------------------------------------------------------
190
+ def complexity_trend(self) -> dict:
191
+ """Is the system tackling harder or easier problems over time?"""
192
+ if len(self._history) < 5:
193
+ return {"status": "Insufficient data"}
194
+ recent = float(np.mean(self._history[-5:]))
195
+ baseline = float(np.mean(self._history))
196
+ trend = "increasing" if recent > baseline + 0.05 else \
197
+ "decreasing" if recent < baseline - 0.05 else "stable"
198
+ return {
199
+ "recent_avg": round(recent, 4),
200
+ "baseline": round(baseline, 4),
201
+ "trend": trend,
202
+ "sample_size": len(self._history),
203
+ }
204
+
205
+ def report(self) -> dict:
206
+ if not self._log:
207
+ return {"status": "No assessments yet"}
208
+ tiers = {}
209
+ for e in self._log:
210
+ t = e.get("tier", "UNKNOWN")
211
+ tiers[t] = tiers.get(t, 0) + 1
212
+ return {
213
+ "total_assessments": len(self._log),
214
+ "tier_distribution": tiers,
215
+ "avg_complexity": round(float(np.mean([e["score"] for e in self._log])), 4),
216
+ "trend": self.complexity_trend(),
217
+ }
src/cognition/self_model.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ SelfModel — Vitalis FSI
3
+
4
+ Vitalis maintains a coherent understanding of its own architecture,
5
+ capabilities, limitations, and growth trajectory.
6
+
7
+ This is not a static config file.
8
+ This is a living self-representation that updates as the system evolves.
9
+
10
+ The SelfModel answers:
11
+ - What am I capable of right now?
12
+ - What are my current limitations?
13
+ - How have I grown since initialization?
14
+ - What is the next capability boundary I should push?
15
+ - Am I operating within my identity alignment?
16
+ """
17
+ import numpy as np
18
+ import os
19
+ import json
20
+ import time
21
+ from vitalis_ide.math_core.kernel import VitalisKernel
22
+ from src.brain.resonance import ResonanceEngine
23
+ from src.hippocampus import Hippocampus
24
+
25
+
26
+ class SelfModel:
27
+ # Capability thresholds — evolve as resonance weights grow
28
+ CAPABILITY_THRESHOLD = 1.2 # resonance weight above this = capable
29
+ LIMITATION_THRESHOLD = 0.5 # resonance weight below this = limited
30
+ FRONTIER_THRESHOLD = 0.8 # between = frontier (learning zone)
31
+
32
+ def __init__(self):
33
+ self.kernel = VitalisKernel()
34
+ self.resonance = ResonanceEngine()
35
+ self.hippocampus = Hippocampus()
36
+ self.path = os.path.expanduser(
37
+ "~/.vitalis_workspace/self_model.json"
38
+ )
39
+ self._birth_time = self._load_birth_time()
40
+ self._snapshots = self._load_snapshots()
41
+
42
+ def _load_birth_time(self) -> float:
43
+ if os.path.exists(self.path):
44
+ with open(self.path) as f:
45
+ data = json.load(f)
46
+ return data.get("birth_time", time.time())
47
+ birth = time.time()
48
+ self._save({"birth_time": birth, "snapshots": []})
49
+ return birth
50
+
51
+ def _load_snapshots(self) -> list:
52
+ if os.path.exists(self.path):
53
+ with open(self.path) as f:
54
+ return json.load(f).get("snapshots", [])
55
+ return []
56
+
57
+ def _save(self, data: dict = None):
58
+ os.makedirs(os.path.dirname(self.path), exist_ok=True)
59
+ if data is None:
60
+ data = {
61
+ "birth_time": self._birth_time,
62
+ "snapshots": self._snapshots[-100:],
63
+ }
64
+ with open(self.path, "w") as f:
65
+ json.dump(data, f, indent=2)
66
+
67
+ # ------------------------------------------------------------------
68
+ # Core self-assessment
69
+ # ------------------------------------------------------------------
70
+ def assess(self) -> dict:
71
+ """
72
+ Full self-assessment. Returns current capability map,
73
+ limitations, frontier zones, and growth trajectory.
74
+ """
75
+ resonance_report = self.resonance.report()
76
+ weights = self.resonance.weights
77
+ memory_report = self.hippocampus.memory_report()
78
+
79
+ # Capability map
80
+ capabilities = []
81
+ limitations = []
82
+ frontiers = []
83
+
84
+ for pattern, weight in weights.items():
85
+ if weight >= self.CAPABILITY_THRESHOLD:
86
+ capabilities.append((pattern, round(weight, 3)))
87
+ elif weight <= self.LIMITATION_THRESHOLD:
88
+ limitations.append((pattern, round(weight, 3)))
89
+ else:
90
+ frontiers.append((pattern, round(weight, 3)))
91
+
92
+ capabilities.sort(key=lambda x: x[1], reverse=True)
93
+ limitations.sort(key=lambda x: x[1])
94
+ frontiers.sort(key=lambda x: x[1], reverse=True)
95
+
96
+ # Growth metrics
97
+ age_hours = (time.time() - self._birth_time) / 3600
98
+ mem_count = len(memory_report)
99
+ avg_strength = float(np.mean([
100
+ v["strength"] for v in memory_report.values()
101
+ ])) if memory_report else 0.0
102
+
103
+ # Next capability boundary — highest frontier item
104
+ next_boundary = frontiers[0][0] if frontiers else "unexplored"
105
+
106
+ # Identity coherence — how aligned are capabilities with identity?
107
+ identity_vec = self._load_identity_vec()
108
+ coherence = self._identity_coherence(identity_vec, capabilities)
109
+
110
+ assessment = {
111
+ "timestamp": time.time(),
112
+ "age_hours": round(age_hours, 2),
113
+ "capabilities": capabilities[:10],
114
+ "limitations": limitations[:5],
115
+ "frontiers": frontiers[:5],
116
+ "next_boundary": next_boundary,
117
+ "memory_count": mem_count,
118
+ "memory_strength": round(avg_strength, 4),
119
+ "identity_coherence": round(coherence, 4),
120
+ "total_patterns": len(weights),
121
+ "growth_index": self._growth_index(),
122
+ }
123
+
124
+ # Snapshot for trajectory tracking
125
+ self._snapshots.append({
126
+ "timestamp": assessment["timestamp"],
127
+ "capabilities": len(capabilities),
128
+ "limitations": len(limitations),
129
+ "growth_index": assessment["growth_index"],
130
+ })
131
+ self._save()
132
+
133
+ return assessment
134
+
135
+ # ------------------------------------------------------------------
136
+ # Internal
137
+ # ------------------------------------------------------------------
138
+ def _load_identity_vec(self) -> np.ndarray:
139
+ path = os.path.expanduser("~/.vitalis_workspace/identity.npy")
140
+ if os.path.exists(path):
141
+ return np.load(path)
142
+ return np.ones(self.kernel.dim, dtype=np.int8)
143
+
144
+ def _identity_coherence(
145
+ self, identity_vec: np.ndarray, capabilities: list
146
+ ) -> float:
147
+ """
148
+ How aligned are current capabilities with the system's identity?
149
+ High coherence = acting true to itself.
150
+ """
151
+ if not capabilities:
152
+ return 0.5
153
+ sims = []
154
+ for pattern, _ in capabilities[:5]:
155
+ cap_vec = self.kernel.vectorize_tokens(
156
+ pattern.split("_"), positional=False
157
+ )
158
+ sims.append(self.kernel.similarity(identity_vec, cap_vec))
159
+ return float(np.mean(sims))
160
+
161
+ def _growth_index(self) -> float:
162
+ """
163
+ Single metric for overall growth.
164
+ Combines: total patterns, avg weight, memory count.
165
+ """
166
+ weights = self.resonance.weights
167
+ if not weights:
168
+ return 0.0
169
+ avg_w = float(np.mean(list(weights.values())))
170
+ n = len(weights)
171
+ mem = len(self.hippocampus.all_slots())
172
+ # Normalised growth index
173
+ return round(float(np.log1p(n) * avg_w + np.log1p(mem) * 0.1), 4)
174
+
175
+ def growth_trajectory(self) -> dict:
176
+ """How has the system grown over time?"""
177
+ if len(self._snapshots) < 2:
178
+ return {"status": "Insufficient snapshots"}
179
+ first = self._snapshots[0]
180
+ last = self._snapshots[-1]
181
+ return {
182
+ "snapshots": len(self._snapshots),
183
+ "growth_index_delta": round(
184
+ last["growth_index"] - first["growth_index"], 4
185
+ ),
186
+ "capability_delta": last["capabilities"] - first["capabilities"],
187
+ "limitation_delta": last["limitations"] - first["limitations"],
188
+ "time_span_hours": round(
189
+ (last["timestamp"] - first["timestamp"]) / 3600, 2
190
+ ),
191
+ }
192
+
193
+ def report(self) -> dict:
194
+ assessment = self.assess()
195
+ return {
196
+ "age_hours": assessment["age_hours"],
197
+ "growth_index": assessment["growth_index"],
198
+ "capabilities": len(assessment["capabilities"]),
199
+ "limitations": len(assessment["limitations"]),
200
+ "next_boundary": assessment["next_boundary"],
201
+ "identity_coherence": assessment["identity_coherence"],
202
+ "trajectory": self.growth_trajectory(),
203
+ }
src/cognitive/reasoning_engine.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ..dream_engine.helix_memory import HelixMemory
2
+ import numpy as np
3
+
4
+ class ReasoningEngine:
5
+ MODE_MAP = {
6
+ "question": "EXECUTION",
7
+ "instruction": "RECOVERY",
8
+ "explanation": "ANALYTICAL",
9
+ "unknown": "EXPLORATORY",
10
+ }
11
+
12
+ def __init__(self, helix_path):
13
+ self.helix = HelixMemory(helix_path)
14
+
15
+ def select_mode(self, hv: np.ndarray) -> str:
16
+ prototypes = self.helix.retrieve(hv, top_k=1)
17
+ if not prototypes:
18
+ return "EXPLORATORY"
19
+ proto, meta = prototypes[0]
20
+ label = meta.get("label", "unknown")
21
+ return self.MODE_MAP.get(label, "EXPLORATORY")
src/dream_engine/helix_memory.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pickle
3
+ from pathlib import Path
4
+ from typing import List, Tuple, Dict, Optional
5
+
6
+ class HelixMemory:
7
+ def __init__(self, storage_path: Path):
8
+ self.storage_path = storage_path
9
+ self._load()
10
+
11
+ def _load(self) -> None:
12
+ if self.storage_path.exists():
13
+ with self.storage_path.open("rb") as f:
14
+ self.entries: List[Tuple[int, np.ndarray, int, dict]] = pickle.load(f)
15
+ else:
16
+ self.entries = []
17
+
18
+ def _save(self) -> None:
19
+ self.storage_path.parent.mkdir(parents=True, exist_ok=True)
20
+ with self.storage_path.open("wb") as f:
21
+ pickle.dump(self.entries, f)
22
+
23
+ def add(self, hv: np.ndarray, meta: Optional[dict] = None) -> None:
24
+ meta = meta or {}
25
+ for i, (code, proto, cnt, old_meta) in enumerate(self.entries):
26
+ sim = np.mean(hv == proto)
27
+ if sim > 0.85:
28
+ merged = {**old_meta, **meta}
29
+ self.entries[i] = (code, proto, cnt + 1, merged)
30
+ self._save()
31
+ return
32
+
33
+ new_code = len(self.entries)
34
+ self.entries.append((new_code, hv.copy(), 1, meta))
35
+ self._save()
36
+
37
+ def retrieve(self, hv: np.ndarray, top_k: int = 3) -> List[Tuple[np.ndarray, dict]]:
38
+ sims = [(np.mean(hv == proto), proto, meta) for _, proto, _, meta in self.entries]
39
+ sims.sort(key=lambda x: x[0], reverse=True)
40
+ return [(proto, meta) for _, proto, meta in sims[:top_k]]
41
+
42
+ def reconstruct(self, code_id: int) -> np.ndarray:
43
+ for cid, proto, _, _ in self.entries:
44
+ if cid == code_id:
45
+ return proto.copy()
46
+ raise KeyError(f"Helix code {code_id} not found")
47
+
48
+ def most_uncertain(self) -> Tuple[int, np.ndarray]:
49
+ if not self.entries:
50
+ raise RuntimeError("HelixMemory empty")
51
+ entry = min(self.entries, key=lambda e: e[2])
52
+ return entry[0], entry[1]
src/vitalis_ide/cli/main.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ import time
4
+ from pathlib import Path
5
+
6
+ from audio_ear.recorder import record_to_wav
7
+ from audio_ear.feature_extractor import extract_features
8
+ from hdc_encoder.encoder import encode
9
+ from dream_engine.consolidator import DreamEngine
10
+ from dream_engine.helix_memory import HelixMemory
11
+
12
+ def log_success(intent: str, details: dict) -> None:
13
+ from cognition.mind import VitalisMind
14
+ mind = VitalisMind()
15
+ mind.ledger.append({"type": "success", "intent": intent, "details": details})
16
+
17
+ def log_failure(intent: str, error: str) -> None:
18
+ from cognition.mind import VitalisMind
19
+ mind = VitalisMind()
20
+ mind.ledger.append({"type": "failure", "intent": intent, "error": error})
21
+
22
+ def cmd_listen(args: argparse.Namespace) -> None:
23
+ out_path = Path(args.output or f"/tmp/live_{int(time.time())}.wav")
24
+ print(f"🔊 Recording {args.duration}s -> {out_path}")
25
+ record_to_wav(duration_sec=args.duration, out_path=out_path)
26
+ mfcc, prosody = extract_features(out_path)
27
+ hv = encode(mfcc, prosody)
28
+
29
+ helix_path = Path.home() / ".vitalis_workspace" / "helix_memory.pkl"
30
+ helix = HelixMemory(helix_path)
31
+ dreamer = DreamEngine(helix)
32
+ dreamer.ingest(hv, meta={"source": str(out_path), "prosody": prosody})
33
+
34
+ log_success("listen_live", {"file": str(out_path)})
35
+ print("✅ Ingested into DreamEngine.")
36
+
37
+ def cmd_dream(args: argparse.Namespace) -> None:
38
+ helix_path = Path.home() / ".vitalis_workspace" / "helix_memory.pkl"
39
+ helix = HelixMemory(helix_path)
40
+ dreamer = DreamEngine(helix)
41
+ dreamer.dream(force=True)
42
+ print("💤 Consolidation complete.")
43
+
44
+ def build_parser() -> argparse.ArgumentParser:
45
+ parser = argparse.ArgumentParser(prog="vitalis")
46
+ sub = parser.add_subparsers(dest="command", required=True)
47
+
48
+ p_listen = sub.add_parser("listen")
49
+ p_listen.add_argument("-d", "--duration", type=int, default=10)
50
+ p_listen.add_argument("-o", "--output", type=str)
51
+ p_listen.set_defaults(func=cmd_listen)
52
+
53
+ p_dream = sub.add_parser("dream")
54
+ p_dream.set_defaults(func=cmd_dream)
55
+
56
+ return parser
57
+
58
+ def main(argv: list | None = None) -> None:
59
+ parser = build_parser()
60
+ args = parser.parse_args(argv)
61
+ try: args.func(args)
62
+ except Exception as exc:
63
+ log_failure(intent=args.command, error=str(exc))
64
+ print(f"❌ Failed: {exc}", file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+ if __name__ == "__main__":
68
+ main()
tests/test_encoder.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from src.hdc_encoder.encoder import encode, DIM
3
+
4
+ class TestHDCEncoder:
5
+ def setup_method(self):
6
+ """Initialize base parameters before each test to guarantee state isolation."""
7
+ self.prosody = {"pitch": 140.0, "energy": 0.25, "tempo": 115.0, "pause_ratio": 0.15}
8
+ self.frames = 40
9
+ self.mfcc = np.random.rand(13, self.frames).astype(np.float32)
10
+
11
+ def test_encoder_dimensionality(self):
12
+ """Verify the output vector matches the strict dimensional parameters."""
13
+ hv = encode(self.mfcc, self.prosody)
14
+
15
+ assert hv.shape == (DIM,), f"Dimensionality failure: Expected {DIM}, got {hv.shape[0]}"
16
+ assert hv.dtype == np.uint8, f"Type architecture failure: Expected uint8, got {hv.dtype}"
17
+
18
+ def test_temporal_sequence_asymmetry(self):
19
+ """
20
+ Verify that reversing the audio sequence produces a fundamentally different
21
+ hypervector. This proves the encoder captures the temporal direction of speech.
22
+ """
23
+ mfcc_reversed = self.mfcc[:, ::-1]
24
+
25
+ hv_forward = encode(self.mfcc, self.prosody)
26
+ hv_reversed = encode(mfcc_reversed, self.prosody)
27
+
28
+ similarity = np.mean(hv_forward == hv_reversed)
29
+
30
+ # In an orthogonal 10k dimensional space, random vectors share ~50% similarity.
31
+ # We enforce a strict threshold to ensure the temporal shift breaks vector alignment.
32
+ assert similarity < 0.60, f"Commutativity failure: Temporal sequence not isolated. Similarity: {similarity}"
33
+
34
+ def test_prosody_modulation(self):
35
+ """Verify that altering emotional/prosodic intent alters the final memory vector."""
36
+ angry_prosody = {"pitch": 240.0, "energy": 0.85, "tempo": 160.0, "pause_ratio": 0.05}
37
+
38
+ hv_base = encode(self.mfcc, self.prosody)
39
+ hv_angry = encode(self.mfcc, angry_prosody)
40
+
41
+ similarity = np.mean(hv_base == hv_angry)
42
+
43
+ assert similarity < 0.95, "Modulation failure: Prosody shifts did not impact the spatial vector."