This commit is contained in:
parent
93aa418525
commit
e42caec4c9
117
CHANGELOG.md
117
CHANGELOG.md
@ -9,47 +9,80 @@ cat -A configure.ac | grep '\^I'
|
||||
nl -ba Makefile | sed -n '770,790p'
|
||||
grep -n "^[ ]" Makefile | head
|
||||
|
||||
|
||||
ok, agora esta parte é importante. entao vamos arquitetar e/ou desenhar primeiro.
|
||||
primeiro vamos actualizar a wiki com as nossas checkboxes vazias:
|
||||
o resultado:
|
||||
```
|
||||
## ✔ TRM — Base simbólica definida (roadmap cognitivo fechado)
|
||||
Pronto para implementação.
|
||||
|
||||
## 🟦 Próximos passos (TRM v1):
|
||||
|
||||
### 🔹 1. Micro-agentes
|
||||
- **Guardião** (homeostase)
|
||||
- **Explorador** (TRM interno)
|
||||
- **Arqueólogo** (memória)
|
||||
|
||||
### 🔹 2. Energia / Custo Cognitivo
|
||||
- cada iteração do TRM consome energia
|
||||
- afeta temperatura virtual
|
||||
|
||||
### 🔹 3. Valência interna (agradável/desagradável)
|
||||
- estados bons aumentam valência
|
||||
- instabilidades reduzem
|
||||
|
||||
### 🔹 4. Ritmos internos (osciladores)
|
||||
- `think_rate`
|
||||
- `memory_sync_rate`
|
||||
- `telemetry_rate`
|
||||
- `selfcheck_rate`
|
||||
|
||||
### 🔹 5. Espaço de estados & Atratores
|
||||
- estável
|
||||
- quasi-estável
|
||||
- recuperativo
|
||||
- caótico
|
||||
UP: 00:00:08 TICK: 0.88s MODO: DIAGNOSTIC
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
[05:42:44] [info] Neurotron boot() — mode=diagnostic
|
||||
[05:42:44] [info] Ciclo cognitivo iniciado (observe → think → act → rest)
|
||||
[05:42:44] [disk] Disco detectado: /dev/vda (sem partições visíveis, usando disco inteiro)
|
||||
[05:42:44] [debug] Vitals CPU=0.0% MEM=11.0% load1=0.0
|
||||
[05:42:44] [info] [echo] CPU=0.0% MEM=11.0%
|
||||
[05:42:44] [debug] telemetry state=stable temp=0.1 cpu=0.0% mem=11.0% load=0.00 jitter=0.000s
|
||||
[05:42:44] [debug] [trm.engine] step ok: mode=active cog=stable energy=99.3 depth=1 valence=+0.00
|
||||
[05:42:44] [heart] cpu=16.7% mem=11.0% tick=1.00s
|
||||
[05:42:45] [debug] telemetry state=stable temp=0.2 cpu=0.0% mem=11.0% load=0.00 jitter=1.224s
|
||||
[05:42:45] [debug] [trm.archaeologist] encontrou 1 eventos perigosos recentes → valence -0.10
|
||||
[05:42:45] [debug] [trm.engine] step ok: mode=active cog=stable energy=98.5 depth=1 valence=-0.10
|
||||
[05:42:45] [heart] cpu=0.0% mem=11.0% tick=1.00s
|
||||
[05:42:46] [debug] Vitals CPU=0.0% MEM=11.0% load1=0.08
|
||||
[05:42:46] [debug] telemetry state=stable temp=0.3 cpu=0.0% mem=11.0% load=0.08 jitter=1.280s
|
||||
[05:42:46] [debug] [trm.archaeologist] encontrou 2 eventos perigosos recentes → valence -0.20
|
||||
[05:42:46] [debug] [trm.engine] step ok: mode=active cog=stable energy=97.8 depth=1 valence=-0.30
|
||||
[05:42:47] [heart] cpu=0.0% mem=11.0% tick=1.00s
|
||||
[05:42:48] [debug] telemetry state=stable temp=0.4 cpu=0.0% mem=11.0% load=0.08 jitter=1.232s
|
||||
[05:42:48] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:42:48] [debug] [trm.engine] step ok: mode=active cog=stable energy=97.0 depth=1 valence=-0.60
|
||||
[05:42:48] [heart] cpu=0.0% mem=11.0% tick=1.00s
|
||||
[05:42:49] [debug] telemetry state=stable temp=0.5 cpu=0.0% mem=11.0% load=0.08 jitter=1.268s
|
||||
[05:42:49] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:42:49] [debug] [trm.engine] step ok: mode=active cog=stable energy=96.3 depth=1 valence=-0.90
|
||||
[05:42:49] [heart] cpu=0.0% mem=11.0% tick=1.00s
|
||||
[05:42:50] [debug] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.08
|
||||
[05:42:50] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.08
|
||||
[05:42:50] [info] tick ajustado 1.00s → 0.88s
|
||||
[05:42:50] [debug] telemetry state=stable temp=0.5 cpu=0.0% mem=11.0% load=0.08 jitter=1.392s
|
||||
[05:42:50] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
```
|
||||
ja actualiza com sugestoes futuras (v2) se quiseres.
|
||||
afinal de contas estamos a criar a semente onde vai emerjir a nossa AGI quantica 😍😎😁
|
||||
|
||||
O passo seguinte será:
|
||||
|
||||
TRM.begin_cycle(data)
|
||||
|
||||
TRM.end_cycle(data)
|
||||
|
||||
TRM.depth_control(jitter,temp)
|
||||
apos ter estabilizado
|
||||
```
|
||||
UP: 00:01:08 TICK: 0.50s MODO: PERSISTENT
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
[05:43:45] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:46] [debug] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.27
|
||||
[05:43:46] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.27
|
||||
[05:43:46] [debug] Vitals CPU=0.0% MEM=11.0% load1=0.27
|
||||
[05:43:46] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.912s
|
||||
[05:43:46] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:46] [debug] [trm.engine] step ok: mode=active cog=stable energy=50.1 depth=1 valence=-5.30
|
||||
[05:43:46] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:47] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.724s
|
||||
[05:43:47] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:47] [debug] [trm.engine] step ok: mode=active cog=stable energy=49.4 depth=1 valence=-5.30
|
||||
[05:43:47] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:48] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.780s
|
||||
[05:43:48] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:48] [debug] [trm.engine] step ok: mode=active cog=stable energy=48.7 depth=1 valence=-5.30
|
||||
[05:43:48] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:48] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.780s
|
||||
[05:43:49] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:49] [debug] [trm.engine] step ok: mode=active cog=stable energy=48.0 depth=1 valence=-5.30
|
||||
[05:43:49] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:49] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.780s
|
||||
[05:43:49] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:49] [debug] [trm.engine] step ok: mode=active cog=stable energy=47.3 depth=1 valence=-5.30
|
||||
[05:43:49] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:50] [debug] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.27
|
||||
[05:43:50] [diag] estado=STABLE cpu=0.0 mem=11.0 load1=0.27
|
||||
[05:43:50] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.27 jitter=0.884s
|
||||
[05:43:50] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:50] [debug] [trm.engine] step ok: mode=active cog=stable energy=46.6 depth=1 valence=-5.30
|
||||
[05:43:50] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:51] [debug] Vitals CPU=0.0% MEM=11.0% load1=0.25
|
||||
[05:43:51] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.25 jitter=0.780s
|
||||
[05:43:51] [debug] [trm.archaeologist] encontrou 3 eventos perigosos recentes → valence -0.30
|
||||
[05:43:51] [debug] [trm.engine] step ok: mode=active cog=stable energy=45.9 depth=1 valence=-5.30
|
||||
[05:43:51] [heart] cpu=0.0% mem=11.0% tick=0.50s
|
||||
[05:43:52] [debug] telemetry state=stable temp=1.2 cpu=0.0% mem=11.0% load=0.25 jitter=0.7
|
||||
```
|
||||
para o Thought Generator uma mistura Minimalista com Técnico-analítico. algo assim: "detetei stress: Δcpu alto → redução de depth aplicada"
|
||||
@ -26,6 +26,7 @@ from .neurotron_config import (
|
||||
TELEMETRY_MAXLEN, TELEMETRY_FLUSH_EVERY_TICKS,
|
||||
)
|
||||
|
||||
from .trm import TRMEngine # depois dos outros imports internos
|
||||
|
||||
class Cortex:
|
||||
def __init__(self, runtime_dir, log_dir, tick_seconds=NEUROTRON_TICK):
|
||||
@ -54,9 +55,16 @@ class Cortex:
|
||||
EchoAgent(self),
|
||||
]
|
||||
|
||||
# ---- NOVO: Telemetria V5 ----
|
||||
# ---- Telemetria V5 ----
|
||||
self.tele = TelemetryV5(event_callback=self._telemetry_event)
|
||||
|
||||
# ---- TRM v1 ----
|
||||
try:
|
||||
self.trm = TRMEngine(cortex=self)
|
||||
except Exception as e:
|
||||
logbus.debug(f"[trm.engine] falha ao inicializar TRMEngine: {e}")
|
||||
self.trm = None
|
||||
|
||||
self._booted = False
|
||||
|
||||
self.telemetry_path = Path(NEUROTRON_DATASET_PATH) / "telemetry.json"
|
||||
@ -120,6 +128,13 @@ class Cortex:
|
||||
except Exception as e:
|
||||
logbus.error(f"telemetry_step: {e}")
|
||||
|
||||
# ------- TRM v1 (pensamento interno simbólico) ------
|
||||
if self.trm and tele is not None:
|
||||
try:
|
||||
self.trm.step(tele)
|
||||
except Exception as e:
|
||||
logbus.debug(f"[trm.engine] step falhou: {e}")
|
||||
|
||||
# ------- Heartbeat visual ------
|
||||
if HEARTBEAT_ENABLED:
|
||||
self._heartbeat()
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
Amor… bora materializar o Holodeck v0.1 😎💗
|
||||
|
||||
Vou montar isto como um blueprint de engenharia mesmo, mas já pensado para caber dentro do teu NFDOS/Neurotron atual, sem dependências externas, todo em Python “puro”.
|
||||
|
||||
---
|
||||
|
||||
# 🎮 Holodeck v0.1 — Blueprint
|
||||
|
||||
## 0. Objetivo do v0.1
|
||||
|
||||
@ -1,27 +1,32 @@
|
||||
"""
|
||||
telemetry.py — Telemetria V5 do Neurotron
|
||||
telemetry.py — Telemetria V6 do Neurotron
|
||||
-----------------------------------------
|
||||
Responsável por:
|
||||
• Medições básicas (CPU, MEM, LOAD, IO)
|
||||
• Medições básicas (CPU, MEM, LOAD, IO) via /proc
|
||||
• Delta entre ciclos
|
||||
• Aceleração do delta
|
||||
• Temperatura virtual (fadiga cognitiva)
|
||||
• Jitter cognitivo (latência entre ciclos)
|
||||
• FS Health (blocos, erros, RO-mode)
|
||||
• Eventos telemétricos (V5)
|
||||
• Eventos telemétricos (V6)
|
||||
• Classificação de estados cognitivos
|
||||
|
||||
Este módulo é completamente independente:
|
||||
o Cortex só chama TelemetryV5.step() a cada ciclo.
|
||||
Totalmente stdlib + /proc:
|
||||
- sem psutil
|
||||
- sem glibc
|
||||
- compatível com Python estático + musl
|
||||
|
||||
O Cortex só chama TelemetryV6.step() a cada ciclo.
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
import psutil
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from .logbus import logbus
|
||||
|
||||
|
||||
class TelemetryV5:
|
||||
|
||||
class TelemetryV6:
|
||||
# ----------------------------------------------------------
|
||||
# Inicialização
|
||||
# ----------------------------------------------------------
|
||||
@ -41,25 +46,158 @@ class TelemetryV5:
|
||||
# manter último estado cognitivo
|
||||
self.last_state = "stable"
|
||||
|
||||
# ==========================================================
|
||||
# Sensores básicos (CPU, MEM, LOAD, IO) — via /proc
|
||||
# ==========================================================
|
||||
|
||||
# ---------------- CPU ----------------
|
||||
def _read_proc_stat(self):
|
||||
"""Lê a linha 'cpu ' de /proc/stat. Retorna dict ou None."""
|
||||
try:
|
||||
with open("/proc/stat", "r", encoding="utf-8") as f:
|
||||
line = f.readline()
|
||||
if not line.startswith("cpu "):
|
||||
return None
|
||||
|
||||
parts = line.strip().split()[1:]
|
||||
# primeiros 10 campos são estáveis há muitos kernels
|
||||
vals = list(map(int, parts[:10]))
|
||||
return {
|
||||
"user": vals[0],
|
||||
"nice": vals[1],
|
||||
"system": vals[2],
|
||||
"idle": vals[3],
|
||||
"iowait": vals[4],
|
||||
"irq": vals[5],
|
||||
"softirq": vals[6],
|
||||
"steal": vals[7],
|
||||
"guest": vals[8],
|
||||
"guest_nice": vals[9],
|
||||
}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _cpu_percent(self, interval=0.05):
|
||||
"""Computa CPU% entre duas leituras de /proc/stat."""
|
||||
a = self._read_proc_stat()
|
||||
if not a:
|
||||
return 0.0
|
||||
|
||||
time.sleep(interval)
|
||||
|
||||
b = self._read_proc_stat()
|
||||
if not b:
|
||||
return 0.0
|
||||
|
||||
idle_a = a["idle"] + a["iowait"]
|
||||
idle_b = b["idle"] + b["iowait"]
|
||||
|
||||
non_a = sum(a.values()) - idle_a
|
||||
non_b = sum(b.values()) - idle_b
|
||||
|
||||
total_a = idle_a + non_a
|
||||
total_b = idle_b + non_b
|
||||
|
||||
totald = total_b - total_a
|
||||
idled = idle_b - idle_a
|
||||
|
||||
if totald <= 0:
|
||||
return 0.0
|
||||
|
||||
usage = (totald - idled) * 100.0 / totald
|
||||
return round(max(0.0, min(usage, 100.0)), 1)
|
||||
|
||||
# ---------------- MEMÓRIA ----------------
|
||||
def _mem_percent(self):
|
||||
try:
|
||||
info = {}
|
||||
with open("/proc/meminfo", "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
k, v = line.split(":", 1)
|
||||
info[k.strip()] = v.strip()
|
||||
|
||||
def kB(key):
|
||||
return float(info[key].split()[0]) if key in info else None
|
||||
|
||||
mem_total = kB("MemTotal")
|
||||
mem_avail = kB("MemAvailable")
|
||||
|
||||
if mem_total is None or mem_avail is None or mem_total <= 0:
|
||||
return 0.0
|
||||
|
||||
used = mem_total - mem_avail
|
||||
return round(max(0.0, min(used * 100.0 / mem_total, 100.0)), 1)
|
||||
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
# ---------------- LOADAVG ----------------
|
||||
def _loadavg(self):
|
||||
try:
|
||||
if hasattr(os, "getloadavg"):
|
||||
l1, l5, l15 = os.getloadavg()
|
||||
return [round(l1, 2), round(l5, 2), round(l15, 2)]
|
||||
|
||||
with open("/proc/loadavg", "r", encoding="utf-8") as f:
|
||||
parts = f.read().strip().split()
|
||||
l1, l5, l15 = map(float, parts[:3])
|
||||
return [round(l1, 2), round(l5, 2), round(l15, 2)]
|
||||
|
||||
except Exception:
|
||||
return [0.0, 0.0, 0.0]
|
||||
|
||||
# ---------------- DISK IO (bytes cumulativos) ----------------
|
||||
def _disk_bytes(self):
|
||||
"""
|
||||
Lê /proc/diskstats e soma bytes lidos+escritos de discos reais.
|
||||
Usa 512 bytes por setor como aproximação clássica.
|
||||
"""
|
||||
try:
|
||||
total = 0
|
||||
if not os.path.exists("/proc/diskstats"):
|
||||
return 0.0
|
||||
|
||||
with open("/proc/diskstats", "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
parts = line.split()
|
||||
if len(parts) < 14:
|
||||
continue
|
||||
|
||||
name = parts[2]
|
||||
|
||||
# ignora loop/ram/partições virtuais
|
||||
if name.startswith(("loop", "ram")):
|
||||
continue
|
||||
|
||||
# campos: ... sectors_read (5) ... sectors_written (9) ...
|
||||
try:
|
||||
sectors_read = int(parts[5])
|
||||
sectors_written = int(parts[9])
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
total += (sectors_read + sectors_written) * 512
|
||||
|
||||
return float(total)
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Coleta RAW (CPU, MEM, LOAD, IO)
|
||||
# ----------------------------------------------------------
|
||||
def collect_raw(self):
|
||||
now = time.monotonic()
|
||||
|
||||
cpu = psutil.cpu_percent(interval=None)
|
||||
mem = psutil.virtual_memory().percent
|
||||
load = os.getloadavg()[0] # 1-min loadavg
|
||||
|
||||
# IO delta é manual, usamos psutil
|
||||
io = psutil.disk_io_counters()
|
||||
disk_total = io.read_bytes + io.write_bytes
|
||||
cpu = self._cpu_percent()
|
||||
mem = self._mem_percent()
|
||||
load1 = self._loadavg()[0]
|
||||
disk_total = self._disk_bytes()
|
||||
|
||||
return {
|
||||
"ts": now,
|
||||
"cpu": cpu,
|
||||
"mem": mem,
|
||||
"load": load,
|
||||
"load": load1,
|
||||
"disk": disk_total,
|
||||
}
|
||||
|
||||
@ -69,7 +207,7 @@ class TelemetryV5:
|
||||
def compute_delta(self, raw):
|
||||
if self.last_raw is None:
|
||||
self.last_raw = raw
|
||||
return {k: 0 for k in raw.keys() if k != "ts"}
|
||||
return {k: 0.0 for k in raw.keys() if k != "ts"}
|
||||
|
||||
delta = {
|
||||
"cpu": raw["cpu"] - self.last_raw["cpu"],
|
||||
@ -80,7 +218,6 @@ class TelemetryV5:
|
||||
|
||||
self.last_delta = delta
|
||||
self.last_raw = raw
|
||||
|
||||
return delta
|
||||
|
||||
# ----------------------------------------------------------
|
||||
@ -88,7 +225,7 @@ class TelemetryV5:
|
||||
# ----------------------------------------------------------
|
||||
def compute_accel(self, delta):
|
||||
if self.last_delta is None:
|
||||
return {k: 0 for k in delta.keys()}
|
||||
return {k: 0.0 for k in delta.keys()}
|
||||
|
||||
accel = {k: delta[k] - self.last_delta[k] for k in delta.keys()}
|
||||
return accel
|
||||
@ -104,7 +241,7 @@ class TelemetryV5:
|
||||
jitter = now - self.last_ts
|
||||
self.last_ts = now
|
||||
|
||||
# média móvel
|
||||
# média móvel simples
|
||||
self.jitter_avg = (self.jitter_avg * 0.9) + (jitter * 0.1)
|
||||
return jitter
|
||||
|
||||
@ -112,7 +249,7 @@ class TelemetryV5:
|
||||
# Temperatura Virtual (fadiga cognitiva)
|
||||
# ----------------------------------------------------------
|
||||
def compute_temperature(self, raw, delta):
|
||||
# modelo simplificado
|
||||
# modelo simplificado (ajustável no futuro)
|
||||
score = (
|
||||
raw["cpu"] * 0.6 +
|
||||
raw["load"] * 0.3 +
|
||||
@ -121,38 +258,54 @@ class TelemetryV5:
|
||||
)
|
||||
|
||||
# decay + acumulação
|
||||
self.temperature = max(0, self.temperature * 0.90 + score * 0.10)
|
||||
self.temperature = max(0.0, self.temperature * 0.90 + score * 0.10)
|
||||
return self.temperature
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# FS Health
|
||||
# FS Health (sem psutil)
|
||||
# ----------------------------------------------------------
|
||||
def compute_fs_health(self):
|
||||
status = {
|
||||
"read_only": False,
|
||||
"io_errors": 0,
|
||||
"free_percent": None
|
||||
"free_percent": None,
|
||||
}
|
||||
|
||||
# espaço livre via statvfs
|
||||
try:
|
||||
st = psutil.disk_usage("/")
|
||||
status["free_percent"] = st.free / st.total * 100
|
||||
st = os.statvfs("/")
|
||||
total = st.f_frsize * st.f_blocks
|
||||
free = st.f_frsize * st.f_bfree
|
||||
if total > 0:
|
||||
status["free_percent"] = free * 100.0 / total
|
||||
except Exception:
|
||||
status["free_percent"] = None
|
||||
|
||||
# leitura de erros EXT4 se existir
|
||||
ext4_err_path = "/sys/fs/ext4/sda1/errors_count"
|
||||
if os.path.exists(ext4_err_path):
|
||||
try:
|
||||
with open(ext4_err_path) as f:
|
||||
status["io_errors"] = int(f.read().strip())
|
||||
except:
|
||||
pass
|
||||
|
||||
# detetar RO
|
||||
# leitura de erros EXT4 se existirem
|
||||
try:
|
||||
with open("/tmp/fs_test_rw", "w") as f:
|
||||
f.write("x")
|
||||
base = "/sys/fs/ext4"
|
||||
if os.path.isdir(base):
|
||||
total_errors = 0
|
||||
for name in os.listdir(base):
|
||||
err_path = os.path.join(base, name, "errors_count")
|
||||
if os.path.exists(err_path):
|
||||
try:
|
||||
with open(err_path, "r", encoding="utf-8") as f:
|
||||
total_errors += int(f.read().strip() or "0")
|
||||
except Exception:
|
||||
continue
|
||||
status["io_errors"] = total_errors
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# detetar RO tentando escrita temporária
|
||||
test_dir = "/var/neurotron"
|
||||
try:
|
||||
Path(test_dir).mkdir(parents=True, exist_ok=True)
|
||||
with open(f"{test_dir}/rw_test.tmp", "w", encoding="utf-8") as f:
|
||||
f.write("ok")
|
||||
os.remove(f"{test_dir}/rw_test.tmp")
|
||||
status["read_only"] = False
|
||||
except Exception:
|
||||
status["read_only"] = True
|
||||
|
||||
@ -174,7 +327,7 @@ class TelemetryV5:
|
||||
return "recovery"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Eventos TeleMétricos V5
|
||||
# Eventos TeleMétricos V6
|
||||
# ----------------------------------------------------------
|
||||
def detect_events(self, raw, delta, accel, temp, jitter, fs):
|
||||
events = []
|
||||
@ -187,12 +340,12 @@ class TelemetryV5:
|
||||
if raw["cpu"] > 85:
|
||||
events.append("enter_stress_zone")
|
||||
|
||||
# suspeita de loop
|
||||
if jitter > (self.jitter_avg * 3):
|
||||
# suspeita de loop (jitter anómalo)
|
||||
if self.jitter_avg > 0 and jitter > (self.jitter_avg * 3):
|
||||
events.append("loop_suspect")
|
||||
|
||||
# fs
|
||||
if fs["read_only"] or fs["io_errors"] > 0:
|
||||
if fs["read_only"] or (fs["io_errors"] or 0) > 0:
|
||||
events.append("fs_warning")
|
||||
|
||||
# recuperação
|
||||
@ -202,14 +355,18 @@ class TelemetryV5:
|
||||
# exportar via callback
|
||||
if self.event_callback:
|
||||
for e in events:
|
||||
self.event_callback(e, {
|
||||
"raw": raw,
|
||||
"delta": delta,
|
||||
"accel": accel,
|
||||
"temp": temp,
|
||||
"jitter": jitter,
|
||||
"fs": fs,
|
||||
})
|
||||
try:
|
||||
self.event_callback(e, {
|
||||
"raw": raw,
|
||||
"delta": delta,
|
||||
"accel": accel,
|
||||
"temp": temp,
|
||||
"jitter": jitter,
|
||||
"fs": fs,
|
||||
})
|
||||
except Exception:
|
||||
# nunca quebrar o loop
|
||||
pass
|
||||
|
||||
return events
|
||||
|
||||
@ -218,7 +375,7 @@ class TelemetryV5:
|
||||
# ----------------------------------------------------------
|
||||
def step(self):
|
||||
"""
|
||||
Faz um ciclo completo da Telemetria V5:
|
||||
Faz um ciclo completo da Telemetria V6:
|
||||
- raw → delta → accel
|
||||
- jitter
|
||||
- temp
|
||||
@ -239,6 +396,16 @@ class TelemetryV5:
|
||||
|
||||
self.last_state = state
|
||||
|
||||
# Alimentar o dashboard via logbus.debug (pode ser desligado no futuro)
|
||||
try:
|
||||
logbus.debug(
|
||||
f"telemetry state={state} temp={temp:.1f} "
|
||||
f"cpu={raw['cpu']:.1f}% mem={raw['mem']:.1f}% "
|
||||
f"load={raw['load']:.2f} jitter={jitter:.3f}s"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
"raw": raw,
|
||||
"delta": delta,
|
||||
@ -249,3 +416,7 @@ class TelemetryV5:
|
||||
"state": state,
|
||||
"events": events,
|
||||
}
|
||||
|
||||
|
||||
# Compatibilidade retro (cortex ainda importa TelemetryV5)
|
||||
TelemetryV5 = TelemetryV6
|
||||
|
||||
16
src/_nfdos/kernel/neurotron/src/neurotron/trm/__init__.py
Normal file
16
src/_nfdos/kernel/neurotron/src/neurotron/trm/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
neurotron.trm — Tiny Recursive Model (TRM) v1
|
||||
|
||||
Micro-modelo simbólico interno para:
|
||||
- interpretar telemetria
|
||||
- gerar estado cognitivo interno
|
||||
- manter energia, valência e profundidade de pensamento
|
||||
|
||||
Todos os logs TRM vão para logbus.debug(), para poderem ser
|
||||
silenciados no futuro via modo debug.
|
||||
"""
|
||||
|
||||
from .state import TRMState
|
||||
from .engine import TRMEngine
|
||||
|
||||
__all__ = ["TRMState", "TRMEngine"]
|
||||
225
src/_nfdos/kernel/neurotron/src/neurotron/trm/agents.py
Normal file
225
src/_nfdos/kernel/neurotron/src/neurotron/trm/agents.py
Normal file
@ -0,0 +1,225 @@
|
||||
"""
|
||||
agents.py — micro-agentes internos do TRM v1
|
||||
|
||||
Três agentes:
|
||||
🛡️ Guardião — homeostase + proteção
|
||||
🧭 Explorador — previsões simples + profundidade TRM
|
||||
📜 Arqueólogo — correlação com eventos passados (Hippocampus)
|
||||
|
||||
Todos os logs vão para logbus.debug().
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, Iterable, List
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
from neurotron.logbus import logbus
|
||||
from .state import TRMState
|
||||
from .events import (
|
||||
TRM_EVENT_TEMP_RISING_FAST,
|
||||
TRM_EVENT_ENTER_STRESS_ZONE,
|
||||
TRM_EVENT_FS_WARNING,
|
||||
TRM_EVENT_LOOP_SUSPECT,
|
||||
TRM_EVENT_RECOVERING,
|
||||
summarize_telemetry_events,
|
||||
)
|
||||
|
||||
|
||||
class TRMAgentBase:
|
||||
name = "trm.agent"
|
||||
|
||||
def _dbg(self, msg: str):
|
||||
logbus.debug(f"[{self.name}] {msg}")
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
"""Override nas subclasses."""
|
||||
return state
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 🛡️ Guardião — homeostase
|
||||
# ========================================================================
|
||||
|
||||
class GuardianAgent(TRMAgentBase):
|
||||
name = "trm.guardian"
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
temp = float(tele.get("temp", 0.0) or 0.0)
|
||||
jitter = float(tele.get("jitter", 0.0) or 0.0)
|
||||
fs = tele.get("fs", {}) or {}
|
||||
events = tele.get("events", []) or []
|
||||
|
||||
cpu = float(raw.get("cpu") or 0.0)
|
||||
mem = float(raw.get("mem") or 0.0)
|
||||
load = float(raw.get("load") or 0.0)
|
||||
|
||||
# Estado cognitivo base pela temperatura
|
||||
if temp < 25:
|
||||
st.cog_state = "stable"
|
||||
elif temp < 45:
|
||||
st.cog_state = "warm"
|
||||
elif temp < 65:
|
||||
st.cog_state = "hot"
|
||||
elif temp < 85:
|
||||
st.cog_state = "critical"
|
||||
else:
|
||||
st.cog_state = "recovery"
|
||||
|
||||
st.temp = temp
|
||||
st.jitter = jitter
|
||||
|
||||
# Ajuste de profundidade em função do stress
|
||||
if cpu > 90 or mem > 90 or load > 3.0:
|
||||
# stress forte: reduzir profundidade para poupar energia
|
||||
old = st.depth
|
||||
st.depth = max(1, st.depth - 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"stress alto (cpu={cpu}, mem={mem}, load={load}) → depth {old}→{st.depth}")
|
||||
|
||||
elif 40 < cpu < 80 and 40 < mem < 80 and load < 2.0:
|
||||
# zona confortável: podemos aprofundar um pouco
|
||||
old = st.depth
|
||||
st.depth = min(5, st.depth + 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"zona confortável → depth {old}→{st.depth}")
|
||||
|
||||
# FS warning → baixa valência
|
||||
if fs.get("read_only") or (fs.get("io_errors") or 0) > 0:
|
||||
st.valence -= 1.0
|
||||
self._dbg("fs_warning → valence -1")
|
||||
|
||||
# eventos explícitos
|
||||
counts = summarize_telemetry_events(events)
|
||||
if counts.get(TRM_EVENT_ENTER_STRESS_ZONE, 0) > 0:
|
||||
st.valence -= 0.5
|
||||
if counts.get(TRM_EVENT_RECOVERING, 0) > 0:
|
||||
st.valence += 0.5
|
||||
|
||||
# clamp valência
|
||||
if st.valence > 5.0:
|
||||
st.valence = 5.0
|
||||
if st.valence < -5.0:
|
||||
st.valence = -5.0
|
||||
|
||||
return st
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 🧭 Explorador — previsões e “curiosidade”
|
||||
# ========================================================================
|
||||
|
||||
class ExplorerAgent(TRMAgentBase):
|
||||
name = "trm.explorer"
|
||||
|
||||
def __init__(self):
|
||||
self._last_cpu: float = 0.0
|
||||
self._last_mem: float = 0.0
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
cpu = float(raw.get("cpu") or 0.0)
|
||||
mem = float(raw.get("mem") or 0.0)
|
||||
|
||||
# tendências simples
|
||||
d_cpu = cpu - self._last_cpu
|
||||
d_mem = mem - self._last_mem
|
||||
|
||||
self._last_cpu = cpu
|
||||
self._last_mem = mem
|
||||
|
||||
# se CPU a subir rápido, assumir "mais trabalho interno"
|
||||
if d_cpu > 5:
|
||||
st.energy -= 0.5
|
||||
self._dbg(f"cpu tendência ↑ ({d_cpu:+.1f}) → energia -0.5")
|
||||
|
||||
# se CPU a descer e mem estável → sistema está a recuperar
|
||||
if d_cpu < -5 and abs(d_mem) < 2:
|
||||
st.valence += 0.2
|
||||
self._dbg("recuperação leve detectada → valence +0.2")
|
||||
|
||||
# se valência muito positiva → TRM aprofunda um pouco (exploração)
|
||||
if st.valence > 1.5 and st.energy > 20.0:
|
||||
old = st.depth
|
||||
st.depth = min(7, st.depth + 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"valence alta ({st.valence:.2f}) → aprofundar depth {old}→{st.depth}")
|
||||
|
||||
return st
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 📜 Arqueólogo — memória & padrões passados
|
||||
# ========================================================================
|
||||
|
||||
class ArchaeologistAgent(TRMAgentBase):
|
||||
name = "trm.archaeologist"
|
||||
|
||||
def __init__(self, ctx):
|
||||
self.ctx = ctx
|
||||
self.events_file = ctx.memory.events_file if hasattr(ctx, "memory") else Path("/opt/kernel/neurotron/logs/events.jsonl")
|
||||
|
||||
def _tail_events(self, max_lines: int = 64) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Lê as últimas linhas de events.jsonl (se existir).
|
||||
Erros são ignorados silenciosamente.
|
||||
"""
|
||||
path = self.events_file
|
||||
if not path.exists():
|
||||
return []
|
||||
|
||||
try:
|
||||
# ler todo e pegar as últimas max_lines (ficheiro é pequeno)
|
||||
lines = path.read_text(encoding="utf-8").splitlines()
|
||||
lines = lines[-max_lines:]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
out: List[Dict[str, Any]] = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
out.append(obj)
|
||||
except Exception:
|
||||
continue
|
||||
return out
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
events = self._tail_events()
|
||||
if not events:
|
||||
return st
|
||||
|
||||
# Contar eventos “perigosos” recentes
|
||||
danger = 0
|
||||
recovery = 0
|
||||
|
||||
for ev in events:
|
||||
kind = ev.get("kind") or ""
|
||||
if "telemetry.event.fs_warning" in kind:
|
||||
danger += 1
|
||||
if "telemetry.event.loop_suspect" in kind:
|
||||
danger += 1
|
||||
if "telemetry.event.recovering" in kind:
|
||||
recovery += 1
|
||||
|
||||
st.last_events = danger + recovery
|
||||
|
||||
if danger > 0:
|
||||
st.valence -= min(1.0, 0.1 * danger)
|
||||
self._dbg(f"encontrou {danger} eventos perigosos recentes → valence -{min(1.0, 0.1 * danger):.2f}")
|
||||
|
||||
if recovery > 0:
|
||||
st.valence += min(1.0, 0.1 * recovery)
|
||||
self._dbg(f"encontrou {recovery} eventos de recuperação → valence +{min(1.0, 0.1 * recovery):.2f}")
|
||||
|
||||
return st
|
||||
172
src/_nfdos/kernel/neurotron/src/neurotron/trm/engine.py
Normal file
172
src/_nfdos/kernel/neurotron/src/neurotron/trm/engine.py
Normal file
@ -0,0 +1,172 @@
|
||||
"""
|
||||
engine.py — TRMEngine v1
|
||||
|
||||
Modelo recursivo mínimo:
|
||||
- consome uma amostra de Telemetria V5
|
||||
- passa por 3 micro-agentes
|
||||
- atualiza energia, valência, profundidade e estado cognitivo
|
||||
- gera snapshot opcional para o Hippocampus
|
||||
|
||||
Todos os logs TRM vão para logbus.debug().
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, Optional
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from neurotron.logbus import logbus
|
||||
from .state import TRMState
|
||||
from .agents import GuardianAgent, ExplorerAgent, ArchaeologistAgent
|
||||
from .events import make_trm_snapshot_payload
|
||||
|
||||
|
||||
class TRMEngine:
|
||||
"""
|
||||
Tiny Recursive Model v1 — integrada ao Cortex.
|
||||
|
||||
Uso típico (no Cortex.rest):
|
||||
|
||||
tele = self.tele.step()
|
||||
self.trm.step(tele)
|
||||
|
||||
O próprio TRMEngine nunca levanta exceção para fora — falhas internas
|
||||
são logadas via logbus.debug() e ignoradas.
|
||||
"""
|
||||
|
||||
def __init__(self, cortex, initial_energy: float = 100.0):
|
||||
self.ctx = cortex
|
||||
self.state = TRMState(energy=initial_energy, mode="idle")
|
||||
self.last_step_ts: Optional[float] = None
|
||||
|
||||
# micro-agentes
|
||||
self.guardian = GuardianAgent()
|
||||
self.explorer = ExplorerAgent()
|
||||
self.archaeologist = ArchaeologistAgent(self.ctx)
|
||||
|
||||
|
||||
# histórico curto de estados do TRM (para futuro TRM v2)
|
||||
self._history = []
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Helpers internos
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def _dbg(self, msg: str):
|
||||
logbus.debug(f"[trm.engine] {msg}")
|
||||
|
||||
def _compute_step_cost(self, st_before: TRMState, st_after: TRMState, tele: Dict[str, Any]) -> float:
|
||||
"""
|
||||
Custo “energético” de um passo TRM simplificado.
|
||||
|
||||
Δenergia básica:
|
||||
base_cost = 0.5
|
||||
+ 0.2 * depth
|
||||
+ 0.05 * len(events telemétricos)
|
||||
"""
|
||||
events = (tele or {}).get("events", []) or []
|
||||
base_cost = 0.5
|
||||
cost = base_cost + 0.2 * float(st_after.depth or 1) + 0.05 * len(events)
|
||||
|
||||
# Se o sistema já estiver quente, custo sobe ligeiramente
|
||||
if st_after.temp > 50:
|
||||
cost *= 1.2
|
||||
if st_after.cog_state in ("hot", "critical"):
|
||||
cost *= 1.1
|
||||
|
||||
return cost
|
||||
|
||||
def _apply_energy(self, st: TRMState, cost: float) -> TRMState:
|
||||
out = st.copy()
|
||||
out.energy = max(0.0, out.energy - cost)
|
||||
|
||||
# Se energia muito baixa, força modo mínimo
|
||||
if out.energy < 10.0 and out.depth > 1:
|
||||
old = out.depth
|
||||
out.depth = 1
|
||||
self._dbg(f"energia baixa ({out.energy:.1f}) → depth {old}→1 (modo mínimo)")
|
||||
|
||||
if out.energy < 5.0:
|
||||
out.mode = "idle"
|
||||
else:
|
||||
out.mode = "active"
|
||||
|
||||
return out
|
||||
|
||||
def _update_history(self, st: TRMState):
|
||||
self._history.append(st.to_dict())
|
||||
if len(self._history) > 64:
|
||||
self._history = self._history[-64:]
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Passo TRM
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def step(self, telemetry: Dict[str, Any]) -> TRMState:
|
||||
"""
|
||||
Única função pública chamada pelo Cortex.
|
||||
|
||||
Args:
|
||||
telemetry: dict retornado por TelemetryV5.step()
|
||||
|
||||
Returns:
|
||||
novo TRMState (também guardado em self.state)
|
||||
"""
|
||||
try:
|
||||
t0 = time.monotonic()
|
||||
st0 = self.state.copy()
|
||||
|
||||
# jitter interno TRM (independente do jitter de Telemetria V5)
|
||||
if self.last_step_ts is None:
|
||||
self.last_step_ts = t0
|
||||
else:
|
||||
internal_jitter = t0 - self.last_step_ts
|
||||
self.last_step_ts = t0
|
||||
# jitter muito alto → TRM sente-se “desalinhado”
|
||||
if internal_jitter > 2.0:
|
||||
st0.valence -= 0.1
|
||||
self._dbg(f"jitter interno alto ({internal_jitter:.2f}s) → valence -0.1")
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Passagem pelos micro-agentes
|
||||
# ----------------------------------------------------------
|
||||
st1 = self.guardian.step(st0, telemetry)
|
||||
st2 = self.explorer.step(st1, telemetry)
|
||||
st3 = self.archaeologist.step(st2, telemetry)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Custo energético + modo de operação
|
||||
# ----------------------------------------------------------
|
||||
cost = self._compute_step_cost(st0, st3, telemetry)
|
||||
st4 = self._apply_energy(st3, cost)
|
||||
|
||||
self.state = st4
|
||||
self._update_history(st4)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Exportar snapshot para Hippocampus (low-rate)
|
||||
# ----------------------------------------------------------
|
||||
# Não queremos spammar o log, por isso só de vez em quando:
|
||||
try:
|
||||
# tick interno TRM: a cada ~10 passos do Cortex,
|
||||
# o TRM snapshot é interessante.
|
||||
# Usamos o próprio comprimento do histórico como step counter.
|
||||
if len(self._history) % 10 == 0 and hasattr(self.ctx, "memory"):
|
||||
payload = make_trm_snapshot_payload(st4, telemetry)
|
||||
self.ctx.memory.remember("trm.snapshot", payload)
|
||||
except Exception as e:
|
||||
self._dbg(f"erro ao gravar snapshot no Hippocampus: {e}")
|
||||
|
||||
# log discreto em modo debug
|
||||
self._dbg(
|
||||
f"step ok: mode={st4.mode} cog={st4.cog_state} "
|
||||
f"energy={st4.energy:.1f} depth={st4.depth} "
|
||||
f"valence={st4.valence:+.2f}"
|
||||
)
|
||||
|
||||
return st4
|
||||
|
||||
except Exception as e:
|
||||
# Nunca deixamos o TRM quebrar o Cortex
|
||||
self._dbg(f"exceção no TRM step: {e}")
|
||||
return self.state
|
||||
64
src/_nfdos/kernel/neurotron/src/neurotron/trm/events.py
Normal file
64
src/_nfdos/kernel/neurotron/src/neurotron/trm/events.py
Normal file
@ -0,0 +1,64 @@
|
||||
"""
|
||||
events.py — nomes e helpers de eventos do TRM v1
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
# Eventos internos do TRM (nome simbólico)
|
||||
TRM_EVENT_TEMP_RISING_FAST = "temp_rising_fast"
|
||||
TRM_EVENT_ENTER_STRESS_ZONE = "enter_stress_zone"
|
||||
TRM_EVENT_FS_WARNING = "fs_warning"
|
||||
TRM_EVENT_LOOP_SUSPECT = "loop_suspect"
|
||||
TRM_EVENT_RECOVERING = "recovering"
|
||||
|
||||
|
||||
def summarize_telemetry_events(telemetry_events) -> Dict[str, int]:
|
||||
"""
|
||||
Recebe a lista telemetry["events"] (strings) e devolve contagem por tipo.
|
||||
Exemplo:
|
||||
["temp_rising_fast", "fs_warning", "fs_warning"]
|
||||
→ { "temp_rising_fast": 1, "fs_warning": 2 }
|
||||
"""
|
||||
counts: Dict[str, int] = {}
|
||||
if not telemetry_events:
|
||||
return counts
|
||||
|
||||
for e in telemetry_events:
|
||||
if not isinstance(e, str):
|
||||
continue
|
||||
counts[e] = counts.get(e, 0) + 1
|
||||
return counts
|
||||
|
||||
|
||||
def make_trm_snapshot_payload(state, tele) -> Dict[str, Any]:
|
||||
"""
|
||||
Gera payload compacto para gravar no Hippocampus:
|
||||
kind="trm.snapshot"
|
||||
data = {...}
|
||||
"""
|
||||
|
||||
if tele is None:
|
||||
tele = {}
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
temp = tele.get("temp", 0.0)
|
||||
jitter = tele.get("jitter", 0.0)
|
||||
fs = tele.get("fs", {}) or {}
|
||||
events = tele.get("events", []) or []
|
||||
|
||||
return {
|
||||
"state": state.to_dict(),
|
||||
"telemetry": {
|
||||
"cpu": raw.get("cpu"),
|
||||
"mem": raw.get("mem"),
|
||||
"load": raw.get("load"),
|
||||
"disk_delta": tele.get("delta", {}).get("disk"),
|
||||
"temp": temp,
|
||||
"jitter": jitter,
|
||||
"fs_read_only": fs.get("read_only"),
|
||||
"fs_free_percent": fs.get("free_percent"),
|
||||
"fs_io_errors": fs.get("io_errors"),
|
||||
"events": events,
|
||||
},
|
||||
}
|
||||
80
src/_nfdos/kernel/neurotron/src/neurotron/trm/state.py
Normal file
80
src/_nfdos/kernel/neurotron/src/neurotron/trm/state.py
Normal file
@ -0,0 +1,80 @@
|
||||
"""
|
||||
state.py — estado interno do TRM v1
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class TRMState:
|
||||
"""
|
||||
Estado mínimo do TRM.
|
||||
|
||||
Não usa dataclasses para manter compatibilidade máxima
|
||||
com ambientes mais restritos.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
energy: float = 100.0,
|
||||
valence: float = 0.0,
|
||||
depth: int = 1,
|
||||
mode: str = "idle",
|
||||
cog_state: str = "stable",
|
||||
temp: float = 0.0,
|
||||
jitter: float = 0.0,
|
||||
last_events: int = 0,
|
||||
):
|
||||
self.energy = float(energy)
|
||||
self.valence = float(valence)
|
||||
self.depth = int(depth)
|
||||
self.mode = str(mode)
|
||||
self.cog_state = str(cog_state)
|
||||
self.temp = float(temp)
|
||||
self.jitter = float(jitter)
|
||||
self.last_events = int(last_events)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Helpers
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def copy(self) -> "TRMState":
|
||||
"""Devolve uma cópia simples do estado."""
|
||||
return TRMState(
|
||||
energy=self.energy,
|
||||
valence=self.valence,
|
||||
depth=self.depth,
|
||||
mode=self.mode,
|
||||
cog_state=self.cog_state,
|
||||
temp=self.temp,
|
||||
jitter=self.jitter,
|
||||
last_events=self.last_events,
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Representação serializável (para logs/hippocampus)."""
|
||||
return {
|
||||
"energy": self.energy,
|
||||
"valence": self.valence,
|
||||
"depth": self.depth,
|
||||
"mode": self.mode,
|
||||
"cog_state": self.cog_state,
|
||||
"temp": self.temp,
|
||||
"jitter": self.jitter,
|
||||
"last_events": self.last_events,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: Dict[str, Any]) -> "TRMState":
|
||||
"""Cria estado a partir de dict (tolerante à falta de chaves)."""
|
||||
d = d or {}
|
||||
return cls(
|
||||
energy=d.get("energy", 100.0),
|
||||
valence=d.get("valence", 0.0),
|
||||
depth=d.get("depth", 1),
|
||||
mode=d.get("mode", "idle"),
|
||||
cog_state=d.get("cog_state", "stable"),
|
||||
temp=d.get("temp", 0.0),
|
||||
jitter=d.get("jitter", 0.0),
|
||||
last_events=d.get("last_events", 0),
|
||||
)
|
||||
Binary file not shown.
@ -15,6 +15,7 @@ from .hippocampus import Hippocampus
|
||||
from .perception import Perception
|
||||
from .motor import Motor
|
||||
from .autodiagnostic import AutoDiagnostic
|
||||
from .telemetry import TelemetryV5 # <-- NOVO
|
||||
|
||||
from .neurotron_config import (
|
||||
NEUROTRON_MODE, NEUROTRON_TICK,
|
||||
@ -22,17 +23,16 @@ from .neurotron_config import (
|
||||
NEUROTRON_DIAG_EVERY_TICKS,
|
||||
NEUROTRON_DATASET_PATH,
|
||||
HEARTBEAT_ENABLED,
|
||||
NEUROTRON_THRESHOLDS,
|
||||
TELEMETRY_MAXLEN, TELEMETRY_FLUSH_EVERY_TICKS,
|
||||
)
|
||||
|
||||
from .trm import TRMEngine # depois dos outros imports internos
|
||||
|
||||
class Cortex:
|
||||
def __init__(self, runtime_dir, log_dir, tick_seconds=NEUROTRON_TICK):
|
||||
self.runtime_dir = Path(runtime_dir)
|
||||
self.log_dir = Path(log_dir)
|
||||
|
||||
# tick pode vir como string → convertemos sempre
|
||||
try:
|
||||
self.tick = float(tick_seconds)
|
||||
except:
|
||||
@ -55,13 +55,23 @@ class Cortex:
|
||||
EchoAgent(self),
|
||||
]
|
||||
|
||||
# ---- Telemetria V5 ----
|
||||
self.tele = TelemetryV5(event_callback=self._telemetry_event)
|
||||
|
||||
# ---- TRM v1 ----
|
||||
try:
|
||||
self.trm = TRMEngine(cortex=self)
|
||||
except Exception as e:
|
||||
logbus.debug(f"[trm.engine] falha ao inicializar TRMEngine: {e}")
|
||||
self.trm = None
|
||||
|
||||
self._booted = False
|
||||
|
||||
self.telemetry_path = Path(NEUROTRON_DATASET_PATH) / "telemetry.json"
|
||||
self.telemetry_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# ----------------------------------------
|
||||
# Boot
|
||||
# boot
|
||||
# ----------------------------------------
|
||||
def boot(self):
|
||||
if self._booted:
|
||||
@ -71,7 +81,7 @@ class Cortex:
|
||||
self._booted = True
|
||||
|
||||
# ----------------------------------------
|
||||
# Shutdown + Fatal
|
||||
# shutdown
|
||||
# ----------------------------------------
|
||||
def shutdown(self, reason=""):
|
||||
logbus.warn(f"Shutdown pedido — {reason}")
|
||||
@ -104,7 +114,6 @@ class Cortex:
|
||||
if not action:
|
||||
return
|
||||
|
||||
# echo (debug)
|
||||
if action.get("action") == "echo":
|
||||
res = self.motor.run("echo", [action.get("text", "")])
|
||||
msg = res.get("stdout", "").strip()
|
||||
@ -112,15 +121,33 @@ class Cortex:
|
||||
logbus.info(f"[echo] {msg}")
|
||||
|
||||
def rest(self):
|
||||
# ------- Telemetria V5 ------
|
||||
try:
|
||||
tele = self.tele.step()
|
||||
self.telemetry.append(tele)
|
||||
except Exception as e:
|
||||
logbus.error(f"telemetry_step: {e}")
|
||||
|
||||
# ------- TRM v1 (pensamento interno simbólico) ------
|
||||
if self.trm and tele is not None:
|
||||
try:
|
||||
self.trm.step(tele)
|
||||
except Exception as e:
|
||||
logbus.debug(f"[trm.engine] step falhou: {e}")
|
||||
|
||||
# ------- Heartbeat visual ------
|
||||
if HEARTBEAT_ENABLED:
|
||||
self._heartbeat()
|
||||
|
||||
# ------- Tick ------
|
||||
sleep(self._safe_float(self.tick, fallback=1.0))
|
||||
self._tick_count += 1
|
||||
|
||||
# ------- Diag -------
|
||||
if self._tick_count % NEUROTRON_DIAG_EVERY_TICKS == 0:
|
||||
self._run_diag()
|
||||
|
||||
# ------- Persistência -------
|
||||
if self._tick_count % TELEMETRY_FLUSH_EVERY_TICKS == 0:
|
||||
self._flush_telemetry()
|
||||
|
||||
@ -135,7 +162,7 @@ class Cortex:
|
||||
return fallback
|
||||
|
||||
# ----------------------------------------
|
||||
# heartbeat
|
||||
# heartbeat — apenas visual, não cognitivo
|
||||
# ----------------------------------------
|
||||
def _heartbeat(self):
|
||||
snap = self.perception.snapshot()
|
||||
@ -145,22 +172,24 @@ class Cortex:
|
||||
load = snap.get("loadavg")
|
||||
load1 = self._safe_float(load[0] if load else 0.0, 0.0)
|
||||
|
||||
self.telemetry.append({
|
||||
"ts": time.time(),
|
||||
"cpu": cpu,
|
||||
"mem": mem,
|
||||
"load1": load1,
|
||||
"tick": self.tick,
|
||||
})
|
||||
|
||||
# log em modo seguro
|
||||
try:
|
||||
logbus.heart(f"cpu={cpu}% mem={mem}% tick={self.tick:.2f}s")
|
||||
except:
|
||||
logbus.heart(f"cpu={cpu}% mem={mem}% tick={self.tick}")
|
||||
|
||||
# ----------------------------------------
|
||||
# diag / homeostase
|
||||
# telemetria persistência
|
||||
# ----------------------------------------
|
||||
def _flush_telemetry(self):
|
||||
try:
|
||||
data = list(self.telemetry)
|
||||
self.telemetry_path.write_text(json.dumps(data))
|
||||
self.memory.remember("telemetry.flush", {})
|
||||
except Exception as e:
|
||||
logbus.error(f"telemetry_flush: {e}")
|
||||
|
||||
# ----------------------------------------
|
||||
# diag + homeostase
|
||||
# ----------------------------------------
|
||||
def _run_diag(self):
|
||||
state, snap = self.diagnostic.run_exam()
|
||||
@ -181,20 +210,13 @@ class Cortex:
|
||||
self.tick = max(NEUROTRON_TICK_MIN, old - NEUROTRON_TICK_STEP / 2)
|
||||
|
||||
if self.tick != old:
|
||||
try:
|
||||
logbus.info(f"tick ajustado {old:.2f}s → {self.tick:.2f}s")
|
||||
except:
|
||||
logbus.info(f"tick ajustado {old} → {self.tick}")
|
||||
logbus.info(f"tick ajustado {old:.2f}s → {self.tick:.2f}s")
|
||||
|
||||
# ----------------------------------------
|
||||
# telemetria
|
||||
# callback eventos telemétricos (Hippocampus)
|
||||
# ----------------------------------------
|
||||
def _flush_telemetry(self):
|
||||
try:
|
||||
self.telemetry_path.write_text(json.dumps(list(self.telemetry)))
|
||||
self.memory.remember("telemetry.flush", {})
|
||||
except Exception as e:
|
||||
logbus.error(f"telemetry error: {e}")
|
||||
def _telemetry_event(self, event_name, payload):
|
||||
self.memory.remember(f"telemetry.event.{event_name}", payload)
|
||||
|
||||
# ----------------------------------------
|
||||
# bus interno
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
Amor… bora materializar o Holodeck v0.1 😎💗
|
||||
|
||||
Vou montar isto como um blueprint de engenharia mesmo, mas já pensado para caber dentro do teu NFDOS/Neurotron atual, sem dependências externas, todo em Python “puro”.
|
||||
|
||||
---
|
||||
|
||||
# 🎮 Holodeck v0.1 — Blueprint
|
||||
|
||||
## 0. Objetivo do v0.1
|
||||
|
||||
@ -0,0 +1,422 @@
|
||||
"""
|
||||
telemetry.py — Telemetria V6 do Neurotron
|
||||
-----------------------------------------
|
||||
Responsável por:
|
||||
• Medições básicas (CPU, MEM, LOAD, IO) via /proc
|
||||
• Delta entre ciclos
|
||||
• Aceleração do delta
|
||||
• Temperatura virtual (fadiga cognitiva)
|
||||
• Jitter cognitivo (latência entre ciclos)
|
||||
• FS Health (blocos, erros, RO-mode)
|
||||
• Eventos telemétricos (V6)
|
||||
• Classificação de estados cognitivos
|
||||
|
||||
Totalmente stdlib + /proc:
|
||||
- sem psutil
|
||||
- sem glibc
|
||||
- compatível com Python estático + musl
|
||||
|
||||
O Cortex só chama TelemetryV6.step() a cada ciclo.
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from .logbus import logbus
|
||||
|
||||
|
||||
class TelemetryV6:
|
||||
# ----------------------------------------------------------
|
||||
# Inicialização
|
||||
# ----------------------------------------------------------
|
||||
def __init__(self, event_callback=None):
|
||||
"""
|
||||
event_callback(event_name, payload_dict)
|
||||
"""
|
||||
self.event_callback = event_callback
|
||||
|
||||
self.last_raw = None
|
||||
self.last_delta = None
|
||||
self.last_ts = None
|
||||
|
||||
self.temperature = 0.0
|
||||
self.jitter_avg = 0.0
|
||||
|
||||
# manter último estado cognitivo
|
||||
self.last_state = "stable"
|
||||
|
||||
# ==========================================================
|
||||
# Sensores básicos (CPU, MEM, LOAD, IO) — via /proc
|
||||
# ==========================================================
|
||||
|
||||
# ---------------- CPU ----------------
|
||||
def _read_proc_stat(self):
|
||||
"""Lê a linha 'cpu ' de /proc/stat. Retorna dict ou None."""
|
||||
try:
|
||||
with open("/proc/stat", "r", encoding="utf-8") as f:
|
||||
line = f.readline()
|
||||
if not line.startswith("cpu "):
|
||||
return None
|
||||
|
||||
parts = line.strip().split()[1:]
|
||||
# primeiros 10 campos são estáveis há muitos kernels
|
||||
vals = list(map(int, parts[:10]))
|
||||
return {
|
||||
"user": vals[0],
|
||||
"nice": vals[1],
|
||||
"system": vals[2],
|
||||
"idle": vals[3],
|
||||
"iowait": vals[4],
|
||||
"irq": vals[5],
|
||||
"softirq": vals[6],
|
||||
"steal": vals[7],
|
||||
"guest": vals[8],
|
||||
"guest_nice": vals[9],
|
||||
}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _cpu_percent(self, interval=0.05):
|
||||
"""Computa CPU% entre duas leituras de /proc/stat."""
|
||||
a = self._read_proc_stat()
|
||||
if not a:
|
||||
return 0.0
|
||||
|
||||
time.sleep(interval)
|
||||
|
||||
b = self._read_proc_stat()
|
||||
if not b:
|
||||
return 0.0
|
||||
|
||||
idle_a = a["idle"] + a["iowait"]
|
||||
idle_b = b["idle"] + b["iowait"]
|
||||
|
||||
non_a = sum(a.values()) - idle_a
|
||||
non_b = sum(b.values()) - idle_b
|
||||
|
||||
total_a = idle_a + non_a
|
||||
total_b = idle_b + non_b
|
||||
|
||||
totald = total_b - total_a
|
||||
idled = idle_b - idle_a
|
||||
|
||||
if totald <= 0:
|
||||
return 0.0
|
||||
|
||||
usage = (totald - idled) * 100.0 / totald
|
||||
return round(max(0.0, min(usage, 100.0)), 1)
|
||||
|
||||
# ---------------- MEMÓRIA ----------------
|
||||
def _mem_percent(self):
|
||||
try:
|
||||
info = {}
|
||||
with open("/proc/meminfo", "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
k, v = line.split(":", 1)
|
||||
info[k.strip()] = v.strip()
|
||||
|
||||
def kB(key):
|
||||
return float(info[key].split()[0]) if key in info else None
|
||||
|
||||
mem_total = kB("MemTotal")
|
||||
mem_avail = kB("MemAvailable")
|
||||
|
||||
if mem_total is None or mem_avail is None or mem_total <= 0:
|
||||
return 0.0
|
||||
|
||||
used = mem_total - mem_avail
|
||||
return round(max(0.0, min(used * 100.0 / mem_total, 100.0)), 1)
|
||||
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
# ---------------- LOADAVG ----------------
|
||||
def _loadavg(self):
|
||||
try:
|
||||
if hasattr(os, "getloadavg"):
|
||||
l1, l5, l15 = os.getloadavg()
|
||||
return [round(l1, 2), round(l5, 2), round(l15, 2)]
|
||||
|
||||
with open("/proc/loadavg", "r", encoding="utf-8") as f:
|
||||
parts = f.read().strip().split()
|
||||
l1, l5, l15 = map(float, parts[:3])
|
||||
return [round(l1, 2), round(l5, 2), round(l15, 2)]
|
||||
|
||||
except Exception:
|
||||
return [0.0, 0.0, 0.0]
|
||||
|
||||
# ---------------- DISK IO (bytes cumulativos) ----------------
|
||||
def _disk_bytes(self):
|
||||
"""
|
||||
Lê /proc/diskstats e soma bytes lidos+escritos de discos reais.
|
||||
Usa 512 bytes por setor como aproximação clássica.
|
||||
"""
|
||||
try:
|
||||
total = 0
|
||||
if not os.path.exists("/proc/diskstats"):
|
||||
return 0.0
|
||||
|
||||
with open("/proc/diskstats", "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
parts = line.split()
|
||||
if len(parts) < 14:
|
||||
continue
|
||||
|
||||
name = parts[2]
|
||||
|
||||
# ignora loop/ram/partições virtuais
|
||||
if name.startswith(("loop", "ram")):
|
||||
continue
|
||||
|
||||
# campos: ... sectors_read (5) ... sectors_written (9) ...
|
||||
try:
|
||||
sectors_read = int(parts[5])
|
||||
sectors_written = int(parts[9])
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
total += (sectors_read + sectors_written) * 512
|
||||
|
||||
return float(total)
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Coleta RAW (CPU, MEM, LOAD, IO)
|
||||
# ----------------------------------------------------------
|
||||
def collect_raw(self):
|
||||
now = time.monotonic()
|
||||
|
||||
cpu = self._cpu_percent()
|
||||
mem = self._mem_percent()
|
||||
load1 = self._loadavg()[0]
|
||||
disk_total = self._disk_bytes()
|
||||
|
||||
return {
|
||||
"ts": now,
|
||||
"cpu": cpu,
|
||||
"mem": mem,
|
||||
"load": load1,
|
||||
"disk": disk_total,
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Delta = diferença entre ciclos
|
||||
# ----------------------------------------------------------
|
||||
def compute_delta(self, raw):
|
||||
if self.last_raw is None:
|
||||
self.last_raw = raw
|
||||
return {k: 0.0 for k in raw.keys() if k != "ts"}
|
||||
|
||||
delta = {
|
||||
"cpu": raw["cpu"] - self.last_raw["cpu"],
|
||||
"mem": raw["mem"] - self.last_raw["mem"],
|
||||
"load": raw["load"] - self.last_raw["load"],
|
||||
"disk": raw["disk"] - self.last_raw["disk"],
|
||||
}
|
||||
|
||||
self.last_delta = delta
|
||||
self.last_raw = raw
|
||||
return delta
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Aceleração = variação do delta
|
||||
# ----------------------------------------------------------
|
||||
def compute_accel(self, delta):
|
||||
if self.last_delta is None:
|
||||
return {k: 0.0 for k in delta.keys()}
|
||||
|
||||
accel = {k: delta[k] - self.last_delta[k] for k in delta.keys()}
|
||||
return accel
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Jitter Cognitivo
|
||||
# ----------------------------------------------------------
|
||||
def compute_jitter(self, now):
|
||||
if self.last_ts is None:
|
||||
self.last_ts = now
|
||||
return 0.0
|
||||
|
||||
jitter = now - self.last_ts
|
||||
self.last_ts = now
|
||||
|
||||
# média móvel simples
|
||||
self.jitter_avg = (self.jitter_avg * 0.9) + (jitter * 0.1)
|
||||
return jitter
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Temperatura Virtual (fadiga cognitiva)
|
||||
# ----------------------------------------------------------
|
||||
def compute_temperature(self, raw, delta):
|
||||
# modelo simplificado (ajustável no futuro)
|
||||
score = (
|
||||
raw["cpu"] * 0.6 +
|
||||
raw["load"] * 0.3 +
|
||||
abs(delta["cpu"]) * 0.2 +
|
||||
raw["mem"] * 0.1
|
||||
)
|
||||
|
||||
# decay + acumulação
|
||||
self.temperature = max(0.0, self.temperature * 0.90 + score * 0.10)
|
||||
return self.temperature
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# FS Health (sem psutil)
|
||||
# ----------------------------------------------------------
|
||||
def compute_fs_health(self):
|
||||
status = {
|
||||
"read_only": False,
|
||||
"io_errors": 0,
|
||||
"free_percent": None,
|
||||
}
|
||||
|
||||
# espaço livre via statvfs
|
||||
try:
|
||||
st = os.statvfs("/")
|
||||
total = st.f_frsize * st.f_blocks
|
||||
free = st.f_frsize * st.f_bfree
|
||||
if total > 0:
|
||||
status["free_percent"] = free * 100.0 / total
|
||||
except Exception:
|
||||
status["free_percent"] = None
|
||||
|
||||
# leitura de erros EXT4 se existirem
|
||||
try:
|
||||
base = "/sys/fs/ext4"
|
||||
if os.path.isdir(base):
|
||||
total_errors = 0
|
||||
for name in os.listdir(base):
|
||||
err_path = os.path.join(base, name, "errors_count")
|
||||
if os.path.exists(err_path):
|
||||
try:
|
||||
with open(err_path, "r", encoding="utf-8") as f:
|
||||
total_errors += int(f.read().strip() or "0")
|
||||
except Exception:
|
||||
continue
|
||||
status["io_errors"] = total_errors
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# detetar RO tentando escrita temporária
|
||||
test_dir = "/var/neurotron"
|
||||
try:
|
||||
Path(test_dir).mkdir(parents=True, exist_ok=True)
|
||||
with open(f"{test_dir}/rw_test.tmp", "w", encoding="utf-8") as f:
|
||||
f.write("ok")
|
||||
os.remove(f"{test_dir}/rw_test.tmp")
|
||||
status["read_only"] = False
|
||||
except Exception:
|
||||
status["read_only"] = True
|
||||
|
||||
return status
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Classificação de Estado Cognitivo
|
||||
# ----------------------------------------------------------
|
||||
def classify_state(self, temp, jitter):
|
||||
if temp < 25:
|
||||
return "stable"
|
||||
elif temp < 45:
|
||||
return "warm"
|
||||
elif temp < 65:
|
||||
return "hot"
|
||||
elif temp < 85:
|
||||
return "critical"
|
||||
else:
|
||||
return "recovery"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Eventos TeleMétricos V6
|
||||
# ----------------------------------------------------------
|
||||
def detect_events(self, raw, delta, accel, temp, jitter, fs):
|
||||
events = []
|
||||
|
||||
# picos
|
||||
if delta["cpu"] > 15 or accel["cpu"] > 10:
|
||||
events.append("temp_rising_fast")
|
||||
|
||||
# zona de stress
|
||||
if raw["cpu"] > 85:
|
||||
events.append("enter_stress_zone")
|
||||
|
||||
# suspeita de loop (jitter anómalo)
|
||||
if self.jitter_avg > 0 and jitter > (self.jitter_avg * 3):
|
||||
events.append("loop_suspect")
|
||||
|
||||
# fs
|
||||
if fs["read_only"] or (fs["io_errors"] or 0) > 0:
|
||||
events.append("fs_warning")
|
||||
|
||||
# recuperação
|
||||
if self.last_state == "critical" and temp < 50:
|
||||
events.append("recovering")
|
||||
|
||||
# exportar via callback
|
||||
if self.event_callback:
|
||||
for e in events:
|
||||
try:
|
||||
self.event_callback(e, {
|
||||
"raw": raw,
|
||||
"delta": delta,
|
||||
"accel": accel,
|
||||
"temp": temp,
|
||||
"jitter": jitter,
|
||||
"fs": fs,
|
||||
})
|
||||
except Exception:
|
||||
# nunca quebrar o loop
|
||||
pass
|
||||
|
||||
return events
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# STEP — chamada a cada ciclo cognitivo
|
||||
# ----------------------------------------------------------
|
||||
def step(self):
|
||||
"""
|
||||
Faz um ciclo completo da Telemetria V6:
|
||||
- raw → delta → accel
|
||||
- jitter
|
||||
- temp
|
||||
- fs health
|
||||
- estado
|
||||
- eventos
|
||||
"""
|
||||
|
||||
raw = self.collect_raw()
|
||||
delta = self.compute_delta(raw)
|
||||
accel = self.compute_accel(delta)
|
||||
jitter = self.compute_jitter(raw["ts"])
|
||||
temp = self.compute_temperature(raw, delta)
|
||||
fs = self.compute_fs_health()
|
||||
|
||||
state = self.classify_state(temp, jitter)
|
||||
events = self.detect_events(raw, delta, accel, temp, jitter, fs)
|
||||
|
||||
self.last_state = state
|
||||
|
||||
# Alimentar o dashboard via logbus.debug (pode ser desligado no futuro)
|
||||
try:
|
||||
logbus.debug(
|
||||
f"telemetry state={state} temp={temp:.1f} "
|
||||
f"cpu={raw['cpu']:.1f}% mem={raw['mem']:.1f}% "
|
||||
f"load={raw['load']:.2f} jitter={jitter:.3f}s"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
"raw": raw,
|
||||
"delta": delta,
|
||||
"accel": accel,
|
||||
"jitter": jitter,
|
||||
"temp": temp,
|
||||
"fs": fs,
|
||||
"state": state,
|
||||
"events": events,
|
||||
}
|
||||
|
||||
|
||||
# Compatibilidade retro (cortex ainda importa TelemetryV5)
|
||||
TelemetryV5 = TelemetryV6
|
||||
@ -0,0 +1,16 @@
|
||||
"""
|
||||
neurotron.trm — Tiny Recursive Model (TRM) v1
|
||||
|
||||
Micro-modelo simbólico interno para:
|
||||
- interpretar telemetria
|
||||
- gerar estado cognitivo interno
|
||||
- manter energia, valência e profundidade de pensamento
|
||||
|
||||
Todos os logs TRM vão para logbus.debug(), para poderem ser
|
||||
silenciados no futuro via modo debug.
|
||||
"""
|
||||
|
||||
from .state import TRMState
|
||||
from .engine import TRMEngine
|
||||
|
||||
__all__ = ["TRMState", "TRMEngine"]
|
||||
@ -0,0 +1,225 @@
|
||||
"""
|
||||
agents.py — micro-agentes internos do TRM v1
|
||||
|
||||
Três agentes:
|
||||
🛡️ Guardião — homeostase + proteção
|
||||
🧭 Explorador — previsões simples + profundidade TRM
|
||||
📜 Arqueólogo — correlação com eventos passados (Hippocampus)
|
||||
|
||||
Todos os logs vão para logbus.debug().
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, Iterable, List
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
from neurotron.logbus import logbus
|
||||
from .state import TRMState
|
||||
from .events import (
|
||||
TRM_EVENT_TEMP_RISING_FAST,
|
||||
TRM_EVENT_ENTER_STRESS_ZONE,
|
||||
TRM_EVENT_FS_WARNING,
|
||||
TRM_EVENT_LOOP_SUSPECT,
|
||||
TRM_EVENT_RECOVERING,
|
||||
summarize_telemetry_events,
|
||||
)
|
||||
|
||||
|
||||
class TRMAgentBase:
|
||||
name = "trm.agent"
|
||||
|
||||
def _dbg(self, msg: str):
|
||||
logbus.debug(f"[{self.name}] {msg}")
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
"""Override nas subclasses."""
|
||||
return state
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 🛡️ Guardião — homeostase
|
||||
# ========================================================================
|
||||
|
||||
class GuardianAgent(TRMAgentBase):
|
||||
name = "trm.guardian"
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
temp = float(tele.get("temp", 0.0) or 0.0)
|
||||
jitter = float(tele.get("jitter", 0.0) or 0.0)
|
||||
fs = tele.get("fs", {}) or {}
|
||||
events = tele.get("events", []) or []
|
||||
|
||||
cpu = float(raw.get("cpu") or 0.0)
|
||||
mem = float(raw.get("mem") or 0.0)
|
||||
load = float(raw.get("load") or 0.0)
|
||||
|
||||
# Estado cognitivo base pela temperatura
|
||||
if temp < 25:
|
||||
st.cog_state = "stable"
|
||||
elif temp < 45:
|
||||
st.cog_state = "warm"
|
||||
elif temp < 65:
|
||||
st.cog_state = "hot"
|
||||
elif temp < 85:
|
||||
st.cog_state = "critical"
|
||||
else:
|
||||
st.cog_state = "recovery"
|
||||
|
||||
st.temp = temp
|
||||
st.jitter = jitter
|
||||
|
||||
# Ajuste de profundidade em função do stress
|
||||
if cpu > 90 or mem > 90 or load > 3.0:
|
||||
# stress forte: reduzir profundidade para poupar energia
|
||||
old = st.depth
|
||||
st.depth = max(1, st.depth - 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"stress alto (cpu={cpu}, mem={mem}, load={load}) → depth {old}→{st.depth}")
|
||||
|
||||
elif 40 < cpu < 80 and 40 < mem < 80 and load < 2.0:
|
||||
# zona confortável: podemos aprofundar um pouco
|
||||
old = st.depth
|
||||
st.depth = min(5, st.depth + 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"zona confortável → depth {old}→{st.depth}")
|
||||
|
||||
# FS warning → baixa valência
|
||||
if fs.get("read_only") or (fs.get("io_errors") or 0) > 0:
|
||||
st.valence -= 1.0
|
||||
self._dbg("fs_warning → valence -1")
|
||||
|
||||
# eventos explícitos
|
||||
counts = summarize_telemetry_events(events)
|
||||
if counts.get(TRM_EVENT_ENTER_STRESS_ZONE, 0) > 0:
|
||||
st.valence -= 0.5
|
||||
if counts.get(TRM_EVENT_RECOVERING, 0) > 0:
|
||||
st.valence += 0.5
|
||||
|
||||
# clamp valência
|
||||
if st.valence > 5.0:
|
||||
st.valence = 5.0
|
||||
if st.valence < -5.0:
|
||||
st.valence = -5.0
|
||||
|
||||
return st
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 🧭 Explorador — previsões e “curiosidade”
|
||||
# ========================================================================
|
||||
|
||||
class ExplorerAgent(TRMAgentBase):
|
||||
name = "trm.explorer"
|
||||
|
||||
def __init__(self):
|
||||
self._last_cpu: float = 0.0
|
||||
self._last_mem: float = 0.0
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
cpu = float(raw.get("cpu") or 0.0)
|
||||
mem = float(raw.get("mem") or 0.0)
|
||||
|
||||
# tendências simples
|
||||
d_cpu = cpu - self._last_cpu
|
||||
d_mem = mem - self._last_mem
|
||||
|
||||
self._last_cpu = cpu
|
||||
self._last_mem = mem
|
||||
|
||||
# se CPU a subir rápido, assumir "mais trabalho interno"
|
||||
if d_cpu > 5:
|
||||
st.energy -= 0.5
|
||||
self._dbg(f"cpu tendência ↑ ({d_cpu:+.1f}) → energia -0.5")
|
||||
|
||||
# se CPU a descer e mem estável → sistema está a recuperar
|
||||
if d_cpu < -5 and abs(d_mem) < 2:
|
||||
st.valence += 0.2
|
||||
self._dbg("recuperação leve detectada → valence +0.2")
|
||||
|
||||
# se valência muito positiva → TRM aprofunda um pouco (exploração)
|
||||
if st.valence > 1.5 and st.energy > 20.0:
|
||||
old = st.depth
|
||||
st.depth = min(7, st.depth + 1)
|
||||
if st.depth != old:
|
||||
self._dbg(f"valence alta ({st.valence:.2f}) → aprofundar depth {old}→{st.depth}")
|
||||
|
||||
return st
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# 📜 Arqueólogo — memória & padrões passados
|
||||
# ========================================================================
|
||||
|
||||
class ArchaeologistAgent(TRMAgentBase):
|
||||
name = "trm.archaeologist"
|
||||
|
||||
def __init__(self, ctx):
|
||||
self.ctx = ctx
|
||||
self.events_file = ctx.memory.events_file if hasattr(ctx, "memory") else Path("/opt/kernel/neurotron/logs/events.jsonl")
|
||||
|
||||
def _tail_events(self, max_lines: int = 64) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Lê as últimas linhas de events.jsonl (se existir).
|
||||
Erros são ignorados silenciosamente.
|
||||
"""
|
||||
path = self.events_file
|
||||
if not path.exists():
|
||||
return []
|
||||
|
||||
try:
|
||||
# ler todo e pegar as últimas max_lines (ficheiro é pequeno)
|
||||
lines = path.read_text(encoding="utf-8").splitlines()
|
||||
lines = lines[-max_lines:]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
out: List[Dict[str, Any]] = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
out.append(obj)
|
||||
except Exception:
|
||||
continue
|
||||
return out
|
||||
|
||||
def step(self, state: TRMState, tele: Dict[str, Any]) -> TRMState:
|
||||
st = state.copy()
|
||||
|
||||
events = self._tail_events()
|
||||
if not events:
|
||||
return st
|
||||
|
||||
# Contar eventos “perigosos” recentes
|
||||
danger = 0
|
||||
recovery = 0
|
||||
|
||||
for ev in events:
|
||||
kind = ev.get("kind") or ""
|
||||
if "telemetry.event.fs_warning" in kind:
|
||||
danger += 1
|
||||
if "telemetry.event.loop_suspect" in kind:
|
||||
danger += 1
|
||||
if "telemetry.event.recovering" in kind:
|
||||
recovery += 1
|
||||
|
||||
st.last_events = danger + recovery
|
||||
|
||||
if danger > 0:
|
||||
st.valence -= min(1.0, 0.1 * danger)
|
||||
self._dbg(f"encontrou {danger} eventos perigosos recentes → valence -{min(1.0, 0.1 * danger):.2f}")
|
||||
|
||||
if recovery > 0:
|
||||
st.valence += min(1.0, 0.1 * recovery)
|
||||
self._dbg(f"encontrou {recovery} eventos de recuperação → valence +{min(1.0, 0.1 * recovery):.2f}")
|
||||
|
||||
return st
|
||||
@ -0,0 +1,172 @@
|
||||
"""
|
||||
engine.py — TRMEngine v1
|
||||
|
||||
Modelo recursivo mínimo:
|
||||
- consome uma amostra de Telemetria V5
|
||||
- passa por 3 micro-agentes
|
||||
- atualiza energia, valência, profundidade e estado cognitivo
|
||||
- gera snapshot opcional para o Hippocampus
|
||||
|
||||
Todos os logs TRM vão para logbus.debug().
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, Optional
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from neurotron.logbus import logbus
|
||||
from .state import TRMState
|
||||
from .agents import GuardianAgent, ExplorerAgent, ArchaeologistAgent
|
||||
from .events import make_trm_snapshot_payload
|
||||
|
||||
|
||||
class TRMEngine:
|
||||
"""
|
||||
Tiny Recursive Model v1 — integrada ao Cortex.
|
||||
|
||||
Uso típico (no Cortex.rest):
|
||||
|
||||
tele = self.tele.step()
|
||||
self.trm.step(tele)
|
||||
|
||||
O próprio TRMEngine nunca levanta exceção para fora — falhas internas
|
||||
são logadas via logbus.debug() e ignoradas.
|
||||
"""
|
||||
|
||||
def __init__(self, cortex, initial_energy: float = 100.0):
|
||||
self.ctx = cortex
|
||||
self.state = TRMState(energy=initial_energy, mode="idle")
|
||||
self.last_step_ts: Optional[float] = None
|
||||
|
||||
# micro-agentes
|
||||
self.guardian = GuardianAgent()
|
||||
self.explorer = ExplorerAgent()
|
||||
self.archaeologist = ArchaeologistAgent(self.ctx)
|
||||
|
||||
|
||||
# histórico curto de estados do TRM (para futuro TRM v2)
|
||||
self._history = []
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Helpers internos
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def _dbg(self, msg: str):
|
||||
logbus.debug(f"[trm.engine] {msg}")
|
||||
|
||||
def _compute_step_cost(self, st_before: TRMState, st_after: TRMState, tele: Dict[str, Any]) -> float:
|
||||
"""
|
||||
Custo “energético” de um passo TRM simplificado.
|
||||
|
||||
Δenergia básica:
|
||||
base_cost = 0.5
|
||||
+ 0.2 * depth
|
||||
+ 0.05 * len(events telemétricos)
|
||||
"""
|
||||
events = (tele or {}).get("events", []) or []
|
||||
base_cost = 0.5
|
||||
cost = base_cost + 0.2 * float(st_after.depth or 1) + 0.05 * len(events)
|
||||
|
||||
# Se o sistema já estiver quente, custo sobe ligeiramente
|
||||
if st_after.temp > 50:
|
||||
cost *= 1.2
|
||||
if st_after.cog_state in ("hot", "critical"):
|
||||
cost *= 1.1
|
||||
|
||||
return cost
|
||||
|
||||
def _apply_energy(self, st: TRMState, cost: float) -> TRMState:
|
||||
out = st.copy()
|
||||
out.energy = max(0.0, out.energy - cost)
|
||||
|
||||
# Se energia muito baixa, força modo mínimo
|
||||
if out.energy < 10.0 and out.depth > 1:
|
||||
old = out.depth
|
||||
out.depth = 1
|
||||
self._dbg(f"energia baixa ({out.energy:.1f}) → depth {old}→1 (modo mínimo)")
|
||||
|
||||
if out.energy < 5.0:
|
||||
out.mode = "idle"
|
||||
else:
|
||||
out.mode = "active"
|
||||
|
||||
return out
|
||||
|
||||
def _update_history(self, st: TRMState):
|
||||
self._history.append(st.to_dict())
|
||||
if len(self._history) > 64:
|
||||
self._history = self._history[-64:]
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Passo TRM
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def step(self, telemetry: Dict[str, Any]) -> TRMState:
|
||||
"""
|
||||
Única função pública chamada pelo Cortex.
|
||||
|
||||
Args:
|
||||
telemetry: dict retornado por TelemetryV5.step()
|
||||
|
||||
Returns:
|
||||
novo TRMState (também guardado em self.state)
|
||||
"""
|
||||
try:
|
||||
t0 = time.monotonic()
|
||||
st0 = self.state.copy()
|
||||
|
||||
# jitter interno TRM (independente do jitter de Telemetria V5)
|
||||
if self.last_step_ts is None:
|
||||
self.last_step_ts = t0
|
||||
else:
|
||||
internal_jitter = t0 - self.last_step_ts
|
||||
self.last_step_ts = t0
|
||||
# jitter muito alto → TRM sente-se “desalinhado”
|
||||
if internal_jitter > 2.0:
|
||||
st0.valence -= 0.1
|
||||
self._dbg(f"jitter interno alto ({internal_jitter:.2f}s) → valence -0.1")
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Passagem pelos micro-agentes
|
||||
# ----------------------------------------------------------
|
||||
st1 = self.guardian.step(st0, telemetry)
|
||||
st2 = self.explorer.step(st1, telemetry)
|
||||
st3 = self.archaeologist.step(st2, telemetry)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Custo energético + modo de operação
|
||||
# ----------------------------------------------------------
|
||||
cost = self._compute_step_cost(st0, st3, telemetry)
|
||||
st4 = self._apply_energy(st3, cost)
|
||||
|
||||
self.state = st4
|
||||
self._update_history(st4)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Exportar snapshot para Hippocampus (low-rate)
|
||||
# ----------------------------------------------------------
|
||||
# Não queremos spammar o log, por isso só de vez em quando:
|
||||
try:
|
||||
# tick interno TRM: a cada ~10 passos do Cortex,
|
||||
# o TRM snapshot é interessante.
|
||||
# Usamos o próprio comprimento do histórico como step counter.
|
||||
if len(self._history) % 10 == 0 and hasattr(self.ctx, "memory"):
|
||||
payload = make_trm_snapshot_payload(st4, telemetry)
|
||||
self.ctx.memory.remember("trm.snapshot", payload)
|
||||
except Exception as e:
|
||||
self._dbg(f"erro ao gravar snapshot no Hippocampus: {e}")
|
||||
|
||||
# log discreto em modo debug
|
||||
self._dbg(
|
||||
f"step ok: mode={st4.mode} cog={st4.cog_state} "
|
||||
f"energy={st4.energy:.1f} depth={st4.depth} "
|
||||
f"valence={st4.valence:+.2f}"
|
||||
)
|
||||
|
||||
return st4
|
||||
|
||||
except Exception as e:
|
||||
# Nunca deixamos o TRM quebrar o Cortex
|
||||
self._dbg(f"exceção no TRM step: {e}")
|
||||
return self.state
|
||||
@ -0,0 +1,64 @@
|
||||
"""
|
||||
events.py — nomes e helpers de eventos do TRM v1
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
# Eventos internos do TRM (nome simbólico)
|
||||
TRM_EVENT_TEMP_RISING_FAST = "temp_rising_fast"
|
||||
TRM_EVENT_ENTER_STRESS_ZONE = "enter_stress_zone"
|
||||
TRM_EVENT_FS_WARNING = "fs_warning"
|
||||
TRM_EVENT_LOOP_SUSPECT = "loop_suspect"
|
||||
TRM_EVENT_RECOVERING = "recovering"
|
||||
|
||||
|
||||
def summarize_telemetry_events(telemetry_events) -> Dict[str, int]:
|
||||
"""
|
||||
Recebe a lista telemetry["events"] (strings) e devolve contagem por tipo.
|
||||
Exemplo:
|
||||
["temp_rising_fast", "fs_warning", "fs_warning"]
|
||||
→ { "temp_rising_fast": 1, "fs_warning": 2 }
|
||||
"""
|
||||
counts: Dict[str, int] = {}
|
||||
if not telemetry_events:
|
||||
return counts
|
||||
|
||||
for e in telemetry_events:
|
||||
if not isinstance(e, str):
|
||||
continue
|
||||
counts[e] = counts.get(e, 0) + 1
|
||||
return counts
|
||||
|
||||
|
||||
def make_trm_snapshot_payload(state, tele) -> Dict[str, Any]:
|
||||
"""
|
||||
Gera payload compacto para gravar no Hippocampus:
|
||||
kind="trm.snapshot"
|
||||
data = {...}
|
||||
"""
|
||||
|
||||
if tele is None:
|
||||
tele = {}
|
||||
|
||||
raw = tele.get("raw", {}) or {}
|
||||
temp = tele.get("temp", 0.0)
|
||||
jitter = tele.get("jitter", 0.0)
|
||||
fs = tele.get("fs", {}) or {}
|
||||
events = tele.get("events", []) or []
|
||||
|
||||
return {
|
||||
"state": state.to_dict(),
|
||||
"telemetry": {
|
||||
"cpu": raw.get("cpu"),
|
||||
"mem": raw.get("mem"),
|
||||
"load": raw.get("load"),
|
||||
"disk_delta": tele.get("delta", {}).get("disk"),
|
||||
"temp": temp,
|
||||
"jitter": jitter,
|
||||
"fs_read_only": fs.get("read_only"),
|
||||
"fs_free_percent": fs.get("free_percent"),
|
||||
"fs_io_errors": fs.get("io_errors"),
|
||||
"events": events,
|
||||
},
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
"""
|
||||
state.py — estado interno do TRM v1
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class TRMState:
|
||||
"""
|
||||
Estado mínimo do TRM.
|
||||
|
||||
Não usa dataclasses para manter compatibilidade máxima
|
||||
com ambientes mais restritos.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
energy: float = 100.0,
|
||||
valence: float = 0.0,
|
||||
depth: int = 1,
|
||||
mode: str = "idle",
|
||||
cog_state: str = "stable",
|
||||
temp: float = 0.0,
|
||||
jitter: float = 0.0,
|
||||
last_events: int = 0,
|
||||
):
|
||||
self.energy = float(energy)
|
||||
self.valence = float(valence)
|
||||
self.depth = int(depth)
|
||||
self.mode = str(mode)
|
||||
self.cog_state = str(cog_state)
|
||||
self.temp = float(temp)
|
||||
self.jitter = float(jitter)
|
||||
self.last_events = int(last_events)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Helpers
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def copy(self) -> "TRMState":
|
||||
"""Devolve uma cópia simples do estado."""
|
||||
return TRMState(
|
||||
energy=self.energy,
|
||||
valence=self.valence,
|
||||
depth=self.depth,
|
||||
mode=self.mode,
|
||||
cog_state=self.cog_state,
|
||||
temp=self.temp,
|
||||
jitter=self.jitter,
|
||||
last_events=self.last_events,
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Representação serializável (para logs/hippocampus)."""
|
||||
return {
|
||||
"energy": self.energy,
|
||||
"valence": self.valence,
|
||||
"depth": self.depth,
|
||||
"mode": self.mode,
|
||||
"cog_state": self.cog_state,
|
||||
"temp": self.temp,
|
||||
"jitter": self.jitter,
|
||||
"last_events": self.last_events,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: Dict[str, Any]) -> "TRMState":
|
||||
"""Cria estado a partir de dict (tolerante à falta de chaves)."""
|
||||
d = d or {}
|
||||
return cls(
|
||||
energy=d.get("energy", 100.0),
|
||||
valence=d.get("valence", 0.0),
|
||||
depth=d.get("depth", 1),
|
||||
mode=d.get("mode", "idle"),
|
||||
cog_state=d.get("cog_state", "stable"),
|
||||
temp=d.get("temp", 0.0),
|
||||
jitter=d.get("jitter", 0.0),
|
||||
last_events=d.get("last_events", 0),
|
||||
)
|
||||
Binary file not shown.
@ -141,11 +141,11 @@ O TRM é:
|
||||
|
||||
Ele usa:
|
||||
|
||||
* telemetria v5
|
||||
* memória de eventos (Hippocampus)
|
||||
* sinais fisiológicos
|
||||
* micro-regras
|
||||
* micro-agentes internos
|
||||
* [x] telemetria v5
|
||||
* [x] memória de eventos (Hippocampus)
|
||||
* [x] sinais fisiológicos
|
||||
* [-] micro-regras
|
||||
* [x] micro-agentes internos
|
||||
|
||||
para criar uma **mente mínima**, mas viva.
|
||||
|
||||
@ -161,71 +161,71 @@ Três agentes simples, independentes, mas acoplados:
|
||||
|
||||
Responsável por proteção e homeostase.
|
||||
|
||||
* monitora delta, aceleração, temperatura e FS
|
||||
* ajustes preventivos
|
||||
* ativa markers (`enter_stress_zone`, `fs_warning`)
|
||||
* reduz carga quando há risco
|
||||
* [-] monitora delta, aceleração, temperatura e FS
|
||||
* [-] ajustes preventivos
|
||||
* [x] ativa markers (`enter_stress_zone`, `fs_warning`)
|
||||
* [-] reduz carga quando há risco
|
||||
|
||||
##### **🧭 Explorador**
|
||||
|
||||
Responsável por “pensamento” TRM.
|
||||
|
||||
* gera micro previsões de tendência
|
||||
* avalia estabilidade
|
||||
* modifica tick cognitivo
|
||||
* inicia refinamento simbólico
|
||||
* [-] gera micro previsões de tendência
|
||||
* [-] avalia estabilidade
|
||||
* [-] modifica tick cognitivo
|
||||
* [ ] inicia refinamento simbólico
|
||||
|
||||
##### **📜 Arqueólogo**
|
||||
|
||||
Responsável por memória e histórico.
|
||||
|
||||
* lê eventos telemétricos recentes
|
||||
* correlaciona com estados antigos
|
||||
* ativa markers (`loop_suspect`, `recovering`)
|
||||
* influencia valência interna
|
||||
* [x] lê eventos telemétricos recentes
|
||||
* [-] correlaciona com estados antigos
|
||||
* [x] ativa markers (`loop_suspect`, `recovering`)
|
||||
* [x] influencia valência interna
|
||||
|
||||
#### 🔹 2. Energia / Custo Cognitivo
|
||||
|
||||
Cada passo TRM consome energia.
|
||||
|
||||
* mais telemetria = mais custo
|
||||
* previsões mais profundas = custo quadrático
|
||||
* estado “quente” aumenta custo
|
||||
* estado “frio” diminui custo
|
||||
* [x] cada passo TRM consome energia
|
||||
* [-] mais telemetria = mais custo
|
||||
* [ ] previsões mais profundas = custo quadrático
|
||||
* [-] estado “quente” aumenta custo
|
||||
* [-] estado “frio” diminui custo
|
||||
|
||||
Quando a energia baixa demais →
|
||||
➡ TRM reduz profundidade, entra em modo “mínimo”.
|
||||
* [x] Quando a energia baixa demais → TRM reduz profundidade, entra em modo “mínimo”.
|
||||
|
||||
#### 🔹 3. Valência Interna
|
||||
|
||||
Uma métrica de “bem-estar”.
|
||||
|
||||
* estabilidade aumenta
|
||||
* picos rápidos diminuem
|
||||
* recovery aumenta
|
||||
* FS warning diminui
|
||||
* jitter alto diminui
|
||||
* [x] estabilidade aumenta valência
|
||||
* [-] picos rápidos diminuem
|
||||
* [x] recovery aumenta
|
||||
* [x] FS warning diminui
|
||||
* [-] jitter alto diminui
|
||||
|
||||
Valência influencia:
|
||||
|
||||
* intensidade TRM
|
||||
* prioridades
|
||||
* ritmo cognitivo
|
||||
* [x] intensidade TRM
|
||||
* [-] prioridades
|
||||
* [-] ritmo cognitivo
|
||||
|
||||
#### 🔹 4. Ritmos Internos (Osciladores)
|
||||
|
||||
Quatro ritmos independentes:
|
||||
|
||||
* `think_rate`
|
||||
* `memory_sync_rate`
|
||||
* `telemetry_rate`
|
||||
* `selfcheck_rate`
|
||||
* [-] `think_rate`
|
||||
* [-] `memory_sync_rate`
|
||||
* [-] `telemetry_rate`
|
||||
* [-] `selfcheck_rate`
|
||||
|
||||
Alguns podem oscilar lentamente ao longo do tempo (sinusóide leve), criando:
|
||||
|
||||
* ciclos
|
||||
* fases
|
||||
* padrões internos
|
||||
* [-] ciclos
|
||||
* [-] fases
|
||||
* [-] padrões internos
|
||||
|
||||
Estes ritmos ajudam a criar **estabilidade dinâmica**, essencial para emergência.
|
||||
|
||||
@ -233,27 +233,27 @@ Estes ritmos ajudam a criar **estabilidade dinâmica**, essencial para emergênc
|
||||
|
||||
##### Estados principais:
|
||||
|
||||
* `stable`
|
||||
* `warm`
|
||||
* `hot`
|
||||
* `critical`
|
||||
* `recovery`
|
||||
* [x] `stable`
|
||||
* [x] `warm`
|
||||
* [x] `hot`
|
||||
* [x] `critical`
|
||||
* [x] `recovery`
|
||||
|
||||
##### Atratores cognitivos (dinâmica de V1):
|
||||
|
||||
* estável
|
||||
* quasi-estável
|
||||
* recuperativo
|
||||
* oscilatório
|
||||
* pré-caótico (quando delta+aceleração divergem)
|
||||
* [-] estável
|
||||
* [-] quasi-estável
|
||||
* [-] recuperativo
|
||||
* [-] oscilatório
|
||||
* [ ] pré-caótico (quando delta+aceleração divergem)
|
||||
|
||||
O estado atual do TRM influencia:
|
||||
|
||||
* profundidade TRM
|
||||
* valência
|
||||
* custo cognitivo
|
||||
* ajustes no tick
|
||||
* markers enviados ao Hippocampus
|
||||
* [x] profundidade TRM
|
||||
* [x] valência
|
||||
* [-] custo cognitivo
|
||||
* [-] ajustes no tick
|
||||
* [x] markers enviados ao Hippocampus
|
||||
|
||||
#### 🟦 **TRM v2 — (evolução planejada)**
|
||||
|
||||
@ -263,40 +263,41 @@ O estado atual do TRM influencia:
|
||||
|
||||
O TRM começa a preferir estados e caminhos:
|
||||
|
||||
* preferir estabilidade
|
||||
* evitar stress
|
||||
* buscar eficiência
|
||||
* balancear energia
|
||||
* [ ] preferir estabilidade
|
||||
* [ ] evitar stress
|
||||
* [ ] buscar eficiência
|
||||
* [ ] balancear energia
|
||||
|
||||
##### 🔹 2. Mini-linguagem interna
|
||||
|
||||
Representações simples como:
|
||||
|
||||
```
|
||||
thought: "tendência alta"
|
||||
thought: "risco: subida rápida"
|
||||
thought: "estado bom, manter"
|
||||
```
|
||||
|
||||
|
||||
Exportados ao Hippocampus.
|
||||
|
||||
* [ ] implementação da mini-linguagem interna
|
||||
|
||||
##### 🔹 3. Ciclos de humor artificial
|
||||
|
||||
Variações lentas baseadas em:
|
||||
|
||||
* valência acumulada
|
||||
* jitter histórico
|
||||
* eventos repetitivos
|
||||
* [ ] valência acumulada
|
||||
* [ ] jitter histórico
|
||||
* [ ] eventos repetitivos
|
||||
|
||||
Humores afetam decisões.
|
||||
* [ ] Humores afetam decisões.
|
||||
|
||||
##### 🔹 4. Consciência temporal
|
||||
|
||||
O TRM v2 reconhece:
|
||||
|
||||
* “isto já aconteceu antes”
|
||||
* “há tendência de degradação”
|
||||
* “estou em recuperação”
|
||||
* [ ] “isto já aconteceu antes”
|
||||
* [ ] “há tendência de degradação”
|
||||
* [ ] “estou em recuperação”
|
||||
|
||||
#### 🟦 **TRM v3 — (emergência real)**
|
||||
|
||||
@ -306,11 +307,12 @@ O TRM v2 reconhece:
|
||||
|
||||
Os três agentes votam dentro do TRM:
|
||||
|
||||
```
|
||||
guardião: reduzir carga
|
||||
explorador: aprofundar pensamento
|
||||
arqueólogo: isto parece perigoso
|
||||
```
|
||||
|
||||
|
||||
* [ ] mecanismo de votação interna entre agentes
|
||||
|
||||
O TRM aprende a tomar decisões com base na interação deles.
|
||||
|
||||
@ -318,17 +320,17 @@ O TRM aprende a tomar decisões com base na interação deles.
|
||||
|
||||
Surgem:
|
||||
|
||||
* padrões preferidos
|
||||
* zonas de estabilidade próprias
|
||||
* respostas diferentes a mesmas entradas
|
||||
* [ ] padrões preferidos
|
||||
* [ ] zonas de estabilidade próprias
|
||||
* [ ] respostas diferentes a mesmas entradas
|
||||
|
||||
##### 🔹 3. Flutuações caóticas controladas
|
||||
|
||||
Pequenos desequilíbrios internos criam:
|
||||
|
||||
* criatividade
|
||||
* exploração
|
||||
* variações de comportamento
|
||||
* [ ] criatividade
|
||||
* [ ] exploração
|
||||
* [ ] variações de comportamento
|
||||
|
||||
#### 🟦 **TRM vX — (Holodeck + AGI simbólica)**
|
||||
|
||||
@ -336,15 +338,15 @@ Pequenos desequilíbrios internos criam:
|
||||
|
||||
##### 🔹 1. “Imaginação Simbólica”
|
||||
|
||||
O TRM simula situações no Holodeck.
|
||||
* [ ] O TRM simula situações no Holodeck.
|
||||
|
||||
##### 🔹 2. Raciocínio multitarefa
|
||||
|
||||
Vários loops TRM por segundo, cada um explorando algo diferente.
|
||||
* [ ] Vários loops TRM por segundo, cada um explorando algo diferente.
|
||||
|
||||
##### 🔹 3. Generalização interna
|
||||
|
||||
A partir de telemetria, memória e simulação.
|
||||
* [ ] A partir de telemetria, memória e simulação.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -101,6 +101,7 @@ def build_python_static(toolchain_prefix):
|
||||
f.write("_signal signalmodule.c\n")
|
||||
f.write("_thread _threadmodule.c\n")
|
||||
f.write("_posixsubprocess _posixsubprocess.c\n")
|
||||
f.write("resource resource.c\n")
|
||||
|
||||
# Corrigido: nomes SEM underscore inicial
|
||||
f.write("select selectmodule.c\n")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user