dsh-biocore 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +170 -27
- package/package.json +1 -1
- package/python/biocore_runtime/pipeline.py +42 -0
- package/python/biocore_runtime/rerank.py +201 -0
- package/python/mindbase/__init__.py +18 -0
- package/python/mindbase/__main__.py +3 -0
- package/python/mindbase/actions.py +56 -0
- package/python/mindbase/active_inference.py +54 -0
- package/python/mindbase/addressing.py +69 -0
- package/python/mindbase/affect.py +86 -0
- package/python/mindbase/affective.py +111 -0
- package/python/mindbase/allostasis.py +28 -0
- package/python/mindbase/appraisal.py +101 -0
- package/python/mindbase/attachment.py +49 -0
- package/python/mindbase/attention.py +30 -0
- package/python/mindbase/autonomy.py +81 -0
- package/python/mindbase/autonomy_bench.py +251 -0
- package/python/mindbase/autonomy_evolve.py +342 -0
- package/python/mindbase/autonomy_loop.py +65 -0
- package/python/mindbase/autonomy_meta.py +91 -0
- package/python/mindbase/base_only.py +28 -0
- package/python/mindbase/benchmark.py +61 -0
- package/python/mindbase/bio_adaptation.py +274 -0
- package/python/mindbase/bio_noise.py +39 -0
- package/python/mindbase/bio_semantic.py +138 -0
- package/python/mindbase/bm25.py +46 -0
- package/python/mindbase/bootstrap.py +256 -0
- package/python/mindbase/bootstrap_real.py +231 -0
- package/python/mindbase/brain.py +178 -0
- package/python/mindbase/care.py +78 -0
- package/python/mindbase/chaos_search.py +79 -0
- package/python/mindbase/character_profile.py +33 -0
- package/python/mindbase/circadian.py +38 -0
- package/python/mindbase/circuit.py +235 -0
- package/python/mindbase/clock.py +53 -0
- package/python/mindbase/companion_runtime.py +366 -0
- package/python/mindbase/companion_train.py +126 -0
- package/python/mindbase/config.py +66 -0
- package/python/mindbase/connection_state.py +76 -0
- package/python/mindbase/connectome_prior.py +35 -0
- package/python/mindbase/connectome_world.py +158 -0
- package/python/mindbase/constructs.py +88 -0
- package/python/mindbase/context_builder.py +58 -0
- package/python/mindbase/critical.py +36 -0
- package/python/mindbase/criticality.py +123 -0
- package/python/mindbase/defaults.py +27 -0
- package/python/mindbase/demo.py +163 -0
- package/python/mindbase/diary.py +116 -0
- package/python/mindbase/diary_service.py +40 -0
- package/python/mindbase/digital_prior.py +37 -0
- package/python/mindbase/diversity.py +110 -0
- package/python/mindbase/drives.py +106 -0
- package/python/mindbase/embedding.py +132 -0
- package/python/mindbase/embedding_memory.py +74 -0
- package/python/mindbase/embodiment.py +83 -0
- package/python/mindbase/emotion_calibration.py +39 -0
- package/python/mindbase/emotion_calibrator.py +50 -0
- package/python/mindbase/emotion_core.py +113 -0
- package/python/mindbase/emotion_dynamics.py +104 -0
- package/python/mindbase/emotion_intent.py +164 -0
- package/python/mindbase/emotion_layer.py +200 -0
- package/python/mindbase/emotion_schema.py +92 -0
- package/python/mindbase/engine.py +781 -0
- package/python/mindbase/episode_log.py +90 -0
- package/python/mindbase/evaluation.py +493 -0
- package/python/mindbase/event_appraisal.py +84 -0
- package/python/mindbase/evolution.py +77 -0
- package/python/mindbase/evolve_offline.py +232 -0
- package/python/mindbase/experiments.py +358 -0
- package/python/mindbase/expression.py +54 -0
- package/python/mindbase/external_brain.py +157 -0
- package/python/mindbase/fly_mb.py +159 -0
- package/python/mindbase/fly_tasks.py +45 -0
- package/python/mindbase/forage.py +179 -0
- package/python/mindbase/goal_generator.py +98 -0
- package/python/mindbase/goals.py +153 -0
- package/python/mindbase/grid_world.py +123 -0
- package/python/mindbase/group_autonomy.py +92 -0
- package/python/mindbase/group_context.py +67 -0
- package/python/mindbase/homeostatic.py +71 -0
- package/python/mindbase/homeostatic_action.py +38 -0
- package/python/mindbase/human_standard.py +53 -0
- package/python/mindbase/identity_suite.py +50 -0
- package/python/mindbase/image_context.py +27 -0
- package/python/mindbase/impression.py +119 -0
- package/python/mindbase/initiative_quota.py +145 -0
- package/python/mindbase/insight.py +51 -0
- package/python/mindbase/intelligence_search.py +108 -0
- package/python/mindbase/intention.py +76 -0
- package/python/mindbase/interaction_log.py +30 -0
- package/python/mindbase/interoception.py +67 -0
- package/python/mindbase/invariants.py +53 -0
- package/python/mindbase/iteration.py +29 -0
- package/python/mindbase/layered_memory.py +170 -0
- package/python/mindbase/layers/__init__.py +18 -0
- package/python/mindbase/layers/l0_substrate.py +39 -0
- package/python/mindbase/layers/l1_homeostasis.py +6 -0
- package/python/mindbase/layers/l2_affect.py +6 -0
- package/python/mindbase/layers/l3_attention.py +6 -0
- package/python/mindbase/layers/l4_learning.py +17 -0
- package/python/mindbase/layers/l5_self_social.py +35 -0
- package/python/mindbase/layers/l6_expression.py +23 -0
- package/python/mindbase/layers/l7_evaluation.py +45 -0
- package/python/mindbase/learner.py +196 -0
- package/python/mindbase/lexicon.py +33 -0
- package/python/mindbase/life_state.py +169 -0
- package/python/mindbase/lifecycle.py +87 -0
- package/python/mindbase/liquid_readout.py +48 -0
- package/python/mindbase/llm_adapter.py +233 -0
- package/python/mindbase/llm_cache.py +77 -0
- package/python/mindbase/llm_gate.py +85 -0
- package/python/mindbase/llm_openai.py +130 -0
- package/python/mindbase/llm_setup.py +99 -0
- package/python/mindbase/longrun.py +83 -0
- package/python/mindbase/longterm_memory.py +606 -0
- package/python/mindbase/mb/__init__.py +14 -0
- package/python/mindbase/mb/apl.py +22 -0
- package/python/mindbase/mb/dan.py +14 -0
- package/python/mindbase/mb/habituation.py +27 -0
- package/python/mindbase/mb/kc.py +28 -0
- package/python/mindbase/mb/mbon.py +23 -0
- package/python/mindbase/mb/mushroom_body.py +116 -0
- package/python/mindbase/memory.py +201 -0
- package/python/mindbase/memory_framework.py +158 -0
- package/python/mindbase/memory_retriever.py +110 -0
- package/python/mindbase/memory_summarizer.py +177 -0
- package/python/mindbase/memory_task.py +32 -0
- package/python/mindbase/memory_trace.py +46 -0
- package/python/mindbase/meta.py +32 -0
- package/python/mindbase/motivation.py +31 -0
- package/python/mindbase/multi_session.py +19 -0
- package/python/mindbase/narrative.py +87 -0
- package/python/mindbase/needs.py +77 -0
- package/python/mindbase/neural.py +45 -0
- package/python/mindbase/neuron_models.py +134 -0
- package/python/mindbase/noise.py +309 -0
- package/python/mindbase/one_on_one.py +60 -0
- package/python/mindbase/online_iteration.py +63 -0
- package/python/mindbase/ostracism.py +35 -0
- package/python/mindbase/parallel_eval.py +60 -0
- package/python/mindbase/parallel_qd.py +64 -0
- package/python/mindbase/persona.py +221 -0
- package/python/mindbase/persona_ab.py +64 -0
- package/python/mindbase/persona_bridge.py +129 -0
- package/python/mindbase/persona_compile.py +34 -0
- package/python/mindbase/persona_dsh.py +120 -0
- package/python/mindbase/persona_learner.py +157 -0
- package/python/mindbase/physiology.py +197 -0
- package/python/mindbase/population_lifecycle.py +83 -0
- package/python/mindbase/preferences.py +50 -0
- package/python/mindbase/proactive_agent.py +274 -0
- package/python/mindbase/proactive_gate.py +53 -0
- package/python/mindbase/proactive_group.py +119 -0
- package/python/mindbase/proactive_policy.py +422 -0
- package/python/mindbase/proactive_profile.py +196 -0
- package/python/mindbase/proactive_timing.py +28 -0
- package/python/mindbase/pyramid_stages.py +61 -0
- package/python/mindbase/quantum.py +132 -0
- package/python/mindbase/quantum_chaos.py +98 -0
- package/python/mindbase/reflection.py +68 -0
- package/python/mindbase/regulation_posture.py +50 -0
- package/python/mindbase/relationship_session.py +431 -0
- package/python/mindbase/relationship_suite.py +45 -0
- package/python/mindbase/relationships.py +70 -0
- package/python/mindbase/replay.py +22 -0
- package/python/mindbase/reply_diversity.py +53 -0
- package/python/mindbase/reply_gate.py +52 -0
- package/python/mindbase/rerank.py +41 -0
- package/python/mindbase/rerank_local.py +46 -0
- package/python/mindbase/ripple.py +187 -0
- package/python/mindbase/robust_search.py +68 -0
- package/python/mindbase/runtime.py +113 -0
- package/python/mindbase/scoped_identity.py +116 -0
- package/python/mindbase/self_insight.py +51 -0
- package/python/mindbase/self_model.py +116 -0
- package/python/mindbase/selftest.py +118 -0
- package/python/mindbase/semantic_memory.py +108 -0
- package/python/mindbase/session_store.py +175 -0
- package/python/mindbase/session_window.py +31 -0
- package/python/mindbase/shadow_eval.py +42 -0
- package/python/mindbase/sim_env.py +86 -0
- package/python/mindbase/social.py +138 -0
- package/python/mindbase/social_constraint.py +141 -0
- package/python/mindbase/social_feedback.py +95 -0
- package/python/mindbase/social_norm.py +225 -0
- package/python/mindbase/spiking_reservoir.py +204 -0
- package/python/mindbase/spontaneity.py +40 -0
- package/python/mindbase/story_loop.py +203 -0
- package/python/mindbase/survival_gauntlet.py +128 -0
- package/python/mindbase/symbolic.py +170 -0
- package/python/mindbase/teacher.py +244 -0
- package/python/mindbase/theory.py +42 -0
- package/python/mindbase/theory_of_mind.py +98 -0
- package/python/mindbase/translation_layer.py +80 -0
- package/python/mindbase/turn_eval.py +52 -0
- package/python/mindbase/types.py +78 -0
- package/python/mindbase/uncertainty_field.py +61 -0
- package/python/mindbase/user_loop.py +45 -0
- package/python/mindbase/user_profile.py +73 -0
- package/python/mindbase/value_model.py +64 -0
- package/python/mindbase/values.py +102 -0
- package/python/mindbase/vector_store.py +78 -0
- package/python/mindbase/viability.py +41 -0
- package/python/mindbase/virtual_body.py +90 -0
- package/python/mindbase/will.py +60 -0
- package/python/mindbase/working_memory.py +32 -0
- package/python/mindbase/workspace.py +55 -0
- package/ui/panel.css +16 -5
- package/ui/panel.html +25 -1
- package/ui/panel.js +57 -15
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from .digital_prior import FlyPrior
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class ConnectomePrior(FlyPrior):
|
|
11
|
+
"""Compressed structural prior from digital-fly connectomics.
|
|
12
|
+
|
|
13
|
+
cell_types from MaleCNS 2026; MBON/DAN counts are approximate and used only
|
|
14
|
+
as a scale, not as an exact reconstruction.
|
|
15
|
+
"""
|
|
16
|
+
cell_types: int = 11_710
|
|
17
|
+
mb_compartments: int = 15
|
|
18
|
+
mbon_count: int = 34
|
|
19
|
+
dan_count: int = 130
|
|
20
|
+
|
|
21
|
+
def summary(self) -> Dict[str, object]:
|
|
22
|
+
base = super().summary()
|
|
23
|
+
base.update(
|
|
24
|
+
{
|
|
25
|
+
"cell_types": self.cell_types,
|
|
26
|
+
"mb_compartments": self.mb_compartments,
|
|
27
|
+
"mbon_count": self.mbon_count,
|
|
28
|
+
"dan_count": self.dan_count,
|
|
29
|
+
"note": "MBON/DAN counts are approximate, used as scale only",
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
return base
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
CONNECTOME = ConnectomePrior()
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Connectome-constrained world model prototype.
|
|
2
|
+
|
|
3
|
+
A sparse recurrent reservoir (connectome-like wiring prior) + self-supervised
|
|
4
|
+
linear readout: predict the next sensory/state vector. This is a small,
|
|
5
|
+
honest prototype, not a whole-brain emulation.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import random
|
|
10
|
+
from typing import Dict, List, Sequence
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConnectomeWorldModel:
|
|
16
|
+
def __init__(self, n_neurons: int = 128, n_input: int = 6,
|
|
17
|
+
sparsity: float = 0.08, spectral_radius: float = 0.9,
|
|
18
|
+
seed: int = 1, n_action: int = 6,
|
|
19
|
+
use_action_effects: bool = False):
|
|
20
|
+
self.n = int(n_neurons)
|
|
21
|
+
self.n_input = int(n_input)
|
|
22
|
+
self.n_action = int(n_action)
|
|
23
|
+
self.use_action_effects = bool(use_action_effects)
|
|
24
|
+
self.action_dim = self.n_input if self.use_action_effects else self.n_action
|
|
25
|
+
self.action_effects = np.zeros((self.n_action, self.n_input))
|
|
26
|
+
self.rng = np.random.default_rng(int(seed))
|
|
27
|
+
w = self.rng.normal(0.0, 1.0, size=(self.n, self.n))
|
|
28
|
+
mask = self.rng.random((self.n, self.n)) < float(sparsity)
|
|
29
|
+
w = w * mask
|
|
30
|
+
# scale spectral radius for stable echo-state dynamics
|
|
31
|
+
try:
|
|
32
|
+
vals = np.linalg.eigvals(w)
|
|
33
|
+
radius = float(np.max(np.abs(vals))) if len(vals) else 1.0
|
|
34
|
+
w = w * (float(spectral_radius) / max(1e-9, radius))
|
|
35
|
+
except Exception:
|
|
36
|
+
w = w / max(1e-9, np.linalg.norm(w, 2))
|
|
37
|
+
self.W = w
|
|
38
|
+
self.B = self.rng.normal(0.0, 0.2, size=(self.n, self.n_input + self.action_dim))
|
|
39
|
+
self.C = np.zeros((self.n, self.n_input))
|
|
40
|
+
self.h = np.zeros(self.n)
|
|
41
|
+
|
|
42
|
+
def _step(self, sensory: np.ndarray, action: int | None = None) -> np.ndarray:
|
|
43
|
+
s = np.asarray(sensory, dtype=float).reshape(-1)
|
|
44
|
+
if s.shape[0] != self.n_input:
|
|
45
|
+
s = np.resize(s, self.n_input)
|
|
46
|
+
a = np.zeros(self.action_dim)
|
|
47
|
+
if action is not None:
|
|
48
|
+
ai = int(action) % self.n_action
|
|
49
|
+
if self.use_action_effects:
|
|
50
|
+
a = self.action_effects[ai].copy()
|
|
51
|
+
else:
|
|
52
|
+
a[ai] = 1.0
|
|
53
|
+
inp = np.concatenate([s, a])
|
|
54
|
+
self.h = np.tanh(self.W @ self.h + self.B @ inp)
|
|
55
|
+
return self.h
|
|
56
|
+
|
|
57
|
+
def predict_next(self, sensory: np.ndarray, action: int | None = None) -> np.ndarray:
|
|
58
|
+
h = self._step(sensory, action)
|
|
59
|
+
return np.asarray(sensory, dtype=float).reshape(-1)[:self.n_input] + h @ self.C
|
|
60
|
+
|
|
61
|
+
def fit(self, sequences: Sequence[Sequence[np.ndarray]], ridge: float = 1e-3) -> Dict[str, float]:
|
|
62
|
+
X: List[np.ndarray] = []
|
|
63
|
+
Y: List[np.ndarray] = []
|
|
64
|
+
for seq in sequences:
|
|
65
|
+
self.h = np.zeros(self.n)
|
|
66
|
+
prev = None
|
|
67
|
+
for s in seq:
|
|
68
|
+
s = np.asarray(s, dtype=float)
|
|
69
|
+
if prev is not None:
|
|
70
|
+
X.append(self.h.copy())
|
|
71
|
+
Y.append(s - prev)
|
|
72
|
+
self._step(s)
|
|
73
|
+
prev = s
|
|
74
|
+
if not X:
|
|
75
|
+
return {"n": 0, "train_mse": 0.0}
|
|
76
|
+
Xm = np.asarray(X)
|
|
77
|
+
Ym = np.asarray(Y)
|
|
78
|
+
# ridge: C^T = (X^T X + λI)^-1 X^T Y
|
|
79
|
+
A = Xm.T @ Xm + float(ridge) * np.eye(self.n)
|
|
80
|
+
self.C = np.linalg.solve(A, Xm.T @ Ym)
|
|
81
|
+
pred = Xm @ self.C
|
|
82
|
+
return {"n": int(len(X)), "train_mse": round(float(np.mean((pred - Ym) ** 2)), 6)}
|
|
83
|
+
|
|
84
|
+
def evaluate(self, sequences: Sequence[Sequence[np.ndarray]]) -> Dict[str, float]:
|
|
85
|
+
errs = []
|
|
86
|
+
base = []
|
|
87
|
+
for seq in sequences:
|
|
88
|
+
self.h = np.zeros(self.n)
|
|
89
|
+
prev = None
|
|
90
|
+
for s in seq:
|
|
91
|
+
s = np.asarray(s, dtype=float)
|
|
92
|
+
if prev is not None:
|
|
93
|
+
pred = prev + (self.h @ self.C)
|
|
94
|
+
errs.append(float(np.mean((pred - s) ** 2)))
|
|
95
|
+
base.append(float(np.mean((prev - s) ** 2)))
|
|
96
|
+
self._step(s)
|
|
97
|
+
prev = s
|
|
98
|
+
return {"n": len(errs),
|
|
99
|
+
"model_mse": round(float(np.mean(errs)) if errs else 0.0, 6),
|
|
100
|
+
"persistence_mse": round(float(np.mean(base)) if base else 0.0, 6)}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def fit_action(self, sequences: Sequence[Sequence[tuple]], ridge: float = 1e-3) -> Dict[str, float]:
|
|
104
|
+
if self.use_action_effects:
|
|
105
|
+
sums = np.zeros((self.n_action, self.n_input))
|
|
106
|
+
counts = np.zeros(self.n_action)
|
|
107
|
+
for seq in sequences:
|
|
108
|
+
for (s0, action), (s1, _a1) in zip(seq[:-1], seq[1:]):
|
|
109
|
+
ai = int(action) % self.n_action
|
|
110
|
+
sums[ai] += np.asarray(s1, dtype=float) - np.asarray(s0, dtype=float)
|
|
111
|
+
counts[ai] += 1
|
|
112
|
+
for i in range(self.n_action):
|
|
113
|
+
if counts[i] > 0:
|
|
114
|
+
self.action_effects[i] = sums[i] / counts[i]
|
|
115
|
+
X: List[np.ndarray] = []
|
|
116
|
+
Y: List[np.ndarray] = []
|
|
117
|
+
for seq in sequences:
|
|
118
|
+
self.h = np.zeros(self.n)
|
|
119
|
+
for (s, action), nxt in zip(seq[:-1], seq[1:]):
|
|
120
|
+
s_arr = np.asarray(s, dtype=float)
|
|
121
|
+
X.append(self.h.copy())
|
|
122
|
+
Y.append(np.asarray(nxt[0], dtype=float) - s_arr)
|
|
123
|
+
self._step(s_arr, int(action))
|
|
124
|
+
if not X:
|
|
125
|
+
return {"n": 0, "train_mse": 0.0}
|
|
126
|
+
Xm = np.asarray(X)
|
|
127
|
+
Ym = np.asarray(Y)
|
|
128
|
+
A = Xm.T @ Xm + float(ridge) * np.eye(self.n)
|
|
129
|
+
self.C = np.linalg.solve(A, Xm.T @ Ym)
|
|
130
|
+
pred = Xm @ self.C
|
|
131
|
+
return {"n": int(len(X)), "train_mse": round(float(np.mean((pred - Ym) ** 2)), 6)}
|
|
132
|
+
|
|
133
|
+
def evaluate_action(self, sequences: Sequence[Sequence[tuple]]) -> Dict[str, float]:
|
|
134
|
+
errs = []
|
|
135
|
+
base = []
|
|
136
|
+
for seq in sequences:
|
|
137
|
+
self.h = np.zeros(self.n)
|
|
138
|
+
for (s, action), nxt in zip(seq[:-1], seq[1:]):
|
|
139
|
+
s_arr = np.asarray(s, dtype=float)
|
|
140
|
+
nxt_arr = np.asarray(nxt[0], dtype=float)
|
|
141
|
+
pred = s_arr + (self.h @ self.C)
|
|
142
|
+
errs.append(float(np.mean((pred - nxt_arr) ** 2)))
|
|
143
|
+
base.append(float(np.mean((s_arr - nxt_arr) ** 2)))
|
|
144
|
+
self._step(s_arr, int(action))
|
|
145
|
+
return {"n": len(errs),
|
|
146
|
+
"model_mse": round(float(np.mean(errs)) if errs else 0.0, 6),
|
|
147
|
+
"persistence_mse": round(float(np.mean(base)) if base else 0.0, 6)}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def sequences_from_rows(rows: Sequence[Dict[str, object]], n_input: int = 6) -> List[np.ndarray]:
|
|
151
|
+
out = []
|
|
152
|
+
for r in rows:
|
|
153
|
+
need = float((r.get("needs") or 0.0))
|
|
154
|
+
vec = [float(r.get("energy", 0.0)), float(r.get("social", 0.0)),
|
|
155
|
+
float(r.get("stress", 0.0)), float(r.get("damage", 0.0)),
|
|
156
|
+
float(r.get("viability", 1.0)), need]
|
|
157
|
+
out.append(np.asarray(vec[:n_input], dtype=float))
|
|
158
|
+
return out
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from .noise import clip
|
|
8
|
+
|
|
9
|
+
DEFAULT_PATH = Path(__file__).with_name("constructs.json")
|
|
10
|
+
|
|
11
|
+
BOUNDS: Dict[str, Tuple[float, float]] = {
|
|
12
|
+
"O": (0.0, 1.0),
|
|
13
|
+
"C": (0.0, 1.0),
|
|
14
|
+
"E": (0.0, 1.0),
|
|
15
|
+
"A": (0.0, 1.0),
|
|
16
|
+
"N": (0.0, 1.0),
|
|
17
|
+
"baseline_v": (-1.0, 1.0),
|
|
18
|
+
"baseline_a": (0.0, 1.0),
|
|
19
|
+
"stress_reactivity": (0.0, 1.0),
|
|
20
|
+
"recovery_rate": (0.0, 1.0),
|
|
21
|
+
"social_baseline": (0.0, 1.0),
|
|
22
|
+
"energy_baseline": (0.0, 1.0),
|
|
23
|
+
"curiosity_baseline": (0.0, 1.0),
|
|
24
|
+
"safety_baseline": (0.0, 1.0),
|
|
25
|
+
"da_baseline": (0.0, 1.0),
|
|
26
|
+
"oa_baseline": (0.0, 1.0),
|
|
27
|
+
"ht_baseline": (0.0, 1.0),
|
|
28
|
+
"autonomy_gain": (0.0, 1.5),
|
|
29
|
+
"learning_rate": (0.01, 0.12),
|
|
30
|
+
"circadian_phase": (-0.10, 0.10),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ConstructRegistry:
|
|
35
|
+
"""Declarative construct -> numeric deltas.
|
|
36
|
+
|
|
37
|
+
Definitions are data (JSON), not if/else branches. Register a new construct
|
|
38
|
+
at runtime without touching the engine.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, path: Optional[Path] = None, definitions: Optional[Dict[str, dict]] = None):
|
|
42
|
+
self.constructs: Dict[str, dict] = {}
|
|
43
|
+
target = path or DEFAULT_PATH
|
|
44
|
+
if target.exists():
|
|
45
|
+
self.load(target)
|
|
46
|
+
if definitions:
|
|
47
|
+
self.register_many(definitions)
|
|
48
|
+
|
|
49
|
+
def load(self, path: Path) -> None:
|
|
50
|
+
data = json.loads(Path(path).read_text(encoding="utf-8"))
|
|
51
|
+
self.register_many(data)
|
|
52
|
+
|
|
53
|
+
def register(self, name: str, definition: dict) -> None:
|
|
54
|
+
if "deltas" not in definition or not isinstance(definition["deltas"], dict):
|
|
55
|
+
raise ValueError(f"construct {name} needs a deltas dict")
|
|
56
|
+
self.constructs[name] = dict(definition)
|
|
57
|
+
|
|
58
|
+
def register_many(self, definitions: Dict[str, dict]) -> None:
|
|
59
|
+
for name, definition in definitions.items():
|
|
60
|
+
self.register(name, definition)
|
|
61
|
+
|
|
62
|
+
def has(self, name: str) -> bool:
|
|
63
|
+
return name in self.constructs
|
|
64
|
+
|
|
65
|
+
def apply(self, numbers: Dict[str, float], scores: Dict[str, float]) -> Tuple[Dict[str, float], Dict[str, float]]:
|
|
66
|
+
out = dict(numbers)
|
|
67
|
+
extra: Dict[str, float] = {}
|
|
68
|
+
for name, raw_score in scores.items():
|
|
69
|
+
definition = self.constructs.get(name)
|
|
70
|
+
if definition is None:
|
|
71
|
+
continue
|
|
72
|
+
score = clip(float(raw_score), 0.0, 1.0)
|
|
73
|
+
for target, delta in definition["deltas"].items():
|
|
74
|
+
amount = score * float(delta)
|
|
75
|
+
if target.startswith("extra."):
|
|
76
|
+
key = target.split(".", 1)[1]
|
|
77
|
+
extra[key] = extra.get(key, 0.5) + amount
|
|
78
|
+
elif target in out:
|
|
79
|
+
out[target] = out[target] + amount
|
|
80
|
+
for key, (lo, hi) in BOUNDS.items():
|
|
81
|
+
if key in out:
|
|
82
|
+
out[key] = clip(float(out[key]), lo, hi)
|
|
83
|
+
for key in list(extra):
|
|
84
|
+
extra[key] = clip(extra[key], 0.0, 1.0)
|
|
85
|
+
return out, extra
|
|
86
|
+
|
|
87
|
+
def snapshot(self) -> Dict[str, dict]:
|
|
88
|
+
return {name: {"label": d.get("label", name), "description": d.get("description", "")} for name, d in self.constructs.items()}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Prioritized context blocks and a numeric reflection trigger.
|
|
2
|
+
|
|
3
|
+
MemGPT/Letta-style core blocks + Generative-Agents-style reflection threshold.
|
|
4
|
+
No LLM call in the decision; the LLM is only used when the trigger fires.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContextBuilder:
|
|
10
|
+
def __init__(self, max_chars: int = 1400):
|
|
11
|
+
self.max_chars = int(max_chars)
|
|
12
|
+
self.last_blocks = {}
|
|
13
|
+
|
|
14
|
+
def build(self, facts=None, loops=None, recent: str = "") -> str:
|
|
15
|
+
facts = [str(x).strip() for x in (facts or []) if str(x).strip()]
|
|
16
|
+
loops = [str(x).strip() for x in (loops or []) if str(x).strip()]
|
|
17
|
+
blocks = []
|
|
18
|
+
used = 0
|
|
19
|
+
def add(label, items):
|
|
20
|
+
nonlocal used
|
|
21
|
+
if not items:
|
|
22
|
+
return
|
|
23
|
+
body = ";".join(dict.fromkeys(items))
|
|
24
|
+
text = label + ":" + body
|
|
25
|
+
if used + len(text) > self.max_chars:
|
|
26
|
+
remain = max(0, self.max_chars - used)
|
|
27
|
+
if remain < 20:
|
|
28
|
+
return
|
|
29
|
+
text = text[:remain]
|
|
30
|
+
blocks.append(text)
|
|
31
|
+
used += len(text)
|
|
32
|
+
add("稳定事实", facts)
|
|
33
|
+
add("未闭环", loops)
|
|
34
|
+
if recent:
|
|
35
|
+
add("近期", [recent])
|
|
36
|
+
self.last_blocks = {"facts": len(facts), "loops": len(loops), "chars": used}
|
|
37
|
+
return "\n".join(blocks)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ReflectionTrigger:
|
|
41
|
+
def __init__(self, threshold: float = 8.0, min_interval_s: float = 1800.0):
|
|
42
|
+
self.threshold = float(threshold)
|
|
43
|
+
self.min_interval_s = float(min_interval_s)
|
|
44
|
+
self.accum = 0.0
|
|
45
|
+
self.last_at = 0.0
|
|
46
|
+
|
|
47
|
+
def note(self, importance: float) -> None:
|
|
48
|
+
try:
|
|
49
|
+
self.accum += max(0.0, min(1.0, float(importance)))
|
|
50
|
+
except Exception:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
def due(self, now: float) -> bool:
|
|
54
|
+
return self.accum >= self.threshold and (float(now) - self.last_at) >= self.min_interval_s
|
|
55
|
+
|
|
56
|
+
def consume(self, now: float) -> None:
|
|
57
|
+
self.accum = 0.0
|
|
58
|
+
self.last_at = float(now)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CriticalDynamics:
|
|
7
|
+
"""Recurrent dynamics near the edge of chaos (spectral radius ~= 1)."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, seed: int = 1, n: int = 64):
|
|
10
|
+
self.rng = np.random.default_rng(seed)
|
|
11
|
+
self.n = n
|
|
12
|
+
self.w = self.rng.normal(0, 1.0 / np.sqrt(n), (n, n))
|
|
13
|
+
radius = max(1e-6, float(np.max(np.abs(np.linalg.eigvals(self.w)))))
|
|
14
|
+
self.w *= 1.0 / radius
|
|
15
|
+
self.x = self.rng.normal(0, 0.1, n)
|
|
16
|
+
self.history = []
|
|
17
|
+
|
|
18
|
+
def step(self, external: float = 0.0) -> dict:
|
|
19
|
+
noise = self.rng.normal(0, 0.01, self.n)
|
|
20
|
+
self.x = np.tanh(self.w @ self.x + 0.4 * float(external) + noise)
|
|
21
|
+
self.history.append(float(np.mean(self.x)))
|
|
22
|
+
self.history = self.history[-200:]
|
|
23
|
+
self.metastability = float(np.std(self.history)) if len(self.history) > 5 else 0.0
|
|
24
|
+
return {
|
|
25
|
+
"mean": round(float(np.mean(self.x)), 4),
|
|
26
|
+
"variance": round(float(np.var(self.x)), 4),
|
|
27
|
+
"metastability": round(float(np.std(self.history)), 4) if len(self.history) > 5 else 0.0,
|
|
28
|
+
"saturation": round(float(np.mean(np.abs(self.x) > 0.95)), 4),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def flexibility(self) -> float:
|
|
32
|
+
# metastability normalized for downstream use
|
|
33
|
+
return round(min(1.0, max(0.0, float(self.step.__self__.history and 0 or 0))), 4) if False else round(min(1.0, abs(float(getattr(self, "metastability", 0.0)))), 4)
|
|
34
|
+
|
|
35
|
+
def spectral_radius(self) -> float:
|
|
36
|
+
return round(float(np.max(np.abs(np.linalg.eigvals(self.w)))), 4)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Criticality meters and controllers for endogenous noise.
|
|
2
|
+
|
|
3
|
+
Operational proxies only: branching ratio, avalanche distribution, metastability.
|
|
4
|
+
These are *not* claims of consciousness; they measure structured spontaneous activity.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
from collections import deque
|
|
10
|
+
from typing import Deque, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BranchingRatio:
|
|
14
|
+
"""Estimate sigma = E[n_{t+1} / n_t] for active steps (n_t > 0)."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, window: int = 256):
|
|
17
|
+
self.window = max(8, int(window))
|
|
18
|
+
self.history: Deque[float] = deque(maxlen=self.window)
|
|
19
|
+
self.prev = 0
|
|
20
|
+
|
|
21
|
+
def reset(self) -> None:
|
|
22
|
+
self.history.clear()
|
|
23
|
+
self.prev = 0
|
|
24
|
+
|
|
25
|
+
def update(self, activity: int) -> float:
|
|
26
|
+
n = max(0, int(activity))
|
|
27
|
+
if self.prev > 0:
|
|
28
|
+
self.history.append(float(n) / float(self.prev))
|
|
29
|
+
self.prev = n
|
|
30
|
+
return self.sigma
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def sigma(self) -> float:
|
|
34
|
+
if not self.history:
|
|
35
|
+
return 0.0
|
|
36
|
+
return float(sum(self.history) / len(self.history))
|
|
37
|
+
|
|
38
|
+
def score(self, target: float = 1.0) -> float:
|
|
39
|
+
if not self.history:
|
|
40
|
+
return 0.0
|
|
41
|
+
return max(0.0, 1.0 - min(1.0, abs(self.sigma - float(target))))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AvalancheMeter:
|
|
45
|
+
"""Collect activity counts and fit a crude power-law slope on log bins."""
|
|
46
|
+
|
|
47
|
+
def __init__(self, capacity: int = 2048):
|
|
48
|
+
self.counts: Deque[int] = deque(maxlen=max(32, int(capacity)))
|
|
49
|
+
|
|
50
|
+
def reset(self) -> None:
|
|
51
|
+
self.counts.clear()
|
|
52
|
+
|
|
53
|
+
def update(self, activity: int) -> None:
|
|
54
|
+
self.counts.append(max(0, int(activity)))
|
|
55
|
+
|
|
56
|
+
def exponent(self) -> float:
|
|
57
|
+
vals = [x for x in self.counts if x > 0]
|
|
58
|
+
if len(vals) < 16:
|
|
59
|
+
return 0.0
|
|
60
|
+
# coarse log bins
|
|
61
|
+
bins: Dict[int, int] = {}
|
|
62
|
+
for x in vals:
|
|
63
|
+
b = int(math.floor(math.log2(max(1, x))))
|
|
64
|
+
bins[b] = bins.get(b, 0) + 1
|
|
65
|
+
xs: List[float] = []
|
|
66
|
+
ys: List[float] = []
|
|
67
|
+
for b, c in sorted(bins.items()):
|
|
68
|
+
if c > 0:
|
|
69
|
+
xs.append(math.log(max(1.0, float(2 ** b))))
|
|
70
|
+
ys.append(math.log(float(c)))
|
|
71
|
+
if len(xs) < 3:
|
|
72
|
+
return 0.0
|
|
73
|
+
mx = sum(xs) / len(xs)
|
|
74
|
+
my = sum(ys) / len(ys)
|
|
75
|
+
den = sum((x - mx) ** 2 for x in xs)
|
|
76
|
+
if den <= 1e-9:
|
|
77
|
+
return 0.0
|
|
78
|
+
return float(sum((x - mx) * (y - my) for x, y in zip(xs, ys)) / den)
|
|
79
|
+
|
|
80
|
+
def score(self) -> float:
|
|
81
|
+
# target slope ~ -1.5 (classic avalanche exponent)
|
|
82
|
+
return max(0.0, 1.0 - min(1.0, abs(self.exponent() + 1.5) / 1.5))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class CriticalityController:
|
|
86
|
+
"""Homeostatic controller: adjust a gate toward a target branching ratio."""
|
|
87
|
+
|
|
88
|
+
def __init__(self, target: float = 1.0, lr: float = 0.02, gate: float = 1.0):
|
|
89
|
+
self.target = float(target)
|
|
90
|
+
self.lr = float(lr)
|
|
91
|
+
self.gate = float(gate)
|
|
92
|
+
self.last_sigma = 0.0
|
|
93
|
+
|
|
94
|
+
def update(self, sigma: float) -> float:
|
|
95
|
+
self.last_sigma = float(sigma)
|
|
96
|
+
if self.last_sigma > 0.0:
|
|
97
|
+
self.gate += self.lr * (self.last_sigma - self.target)
|
|
98
|
+
self.gate = max(0.2, min(3.0, self.gate))
|
|
99
|
+
return self.gate
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MetastabilityMeter:
|
|
103
|
+
"""Cheap state-switching / dwell-time proxy."""
|
|
104
|
+
|
|
105
|
+
def __init__(self, window: int = 256):
|
|
106
|
+
self.values: Deque[float] = deque(maxlen=max(16, int(window)))
|
|
107
|
+
|
|
108
|
+
def update(self, value: float) -> None:
|
|
109
|
+
self.values.append(float(value))
|
|
110
|
+
|
|
111
|
+
def autocorrelation(self, lag: int = 1) -> float:
|
|
112
|
+
xs = list(self.values)
|
|
113
|
+
if len(xs) <= lag + 2:
|
|
114
|
+
return 0.0
|
|
115
|
+
a = xs[:-lag]
|
|
116
|
+
b = xs[lag:]
|
|
117
|
+
ma = sum(a) / len(a)
|
|
118
|
+
mb = sum(b) / len(b)
|
|
119
|
+
va = sum((x - ma) ** 2 for x in a)
|
|
120
|
+
vb = sum((x - mb) ** 2 for x in b)
|
|
121
|
+
if va <= 1e-12 or vb <= 1e-12:
|
|
122
|
+
return 0.0
|
|
123
|
+
return float(sum((x - ma) * (y - mb) for x, y in zip(a, b)) / math.sqrt(va * vb))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Reference defaults from digital-fly literature.
|
|
2
|
+
|
|
3
|
+
These are documented starting points, not laws. Runtime knobs live in
|
|
4
|
+
MindConfig; changing a default should be a deliberate design change.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Digital fly (FlyWire / MaleCNS)
|
|
8
|
+
NEURONS = 139_255
|
|
9
|
+
SYNAPSES = 50_000_000
|
|
10
|
+
CELL_TYPES = 11_710
|
|
11
|
+
MB_COMPARTMENTS = 15
|
|
12
|
+
|
|
13
|
+
# Mushroom body compression
|
|
14
|
+
KC_COUNT = 2_000
|
|
15
|
+
KC_SPARSITY = 0.05
|
|
16
|
+
KC_SLOTS = 256
|
|
17
|
+
KC_ACTIVE = max(1, round(KC_SLOTS * KC_SPARSITY)) # 13
|
|
18
|
+
|
|
19
|
+
# Approximate scale only (used for comments / coarse priors)
|
|
20
|
+
MBON_COUNT = 34
|
|
21
|
+
DAN_COUNT = 130
|
|
22
|
+
|
|
23
|
+
# Runtime contract
|
|
24
|
+
MAX_WM_SLOTS = 5
|
|
25
|
+
MEMORY_CAPACITY = 256
|
|
26
|
+
MAX_GOALS = 3
|
|
27
|
+
MAX_LLM_CALLS_PER_STEP = 1
|