decompress / engine /traces.py
squaredcuber's picture
Deploy Decompress MiniCPM demo
bcbb8c5 verified
Raw
History Blame Contribute Delete
6.36 kB
from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
from typing import Sequence
import numpy as np
from engine.brain import BrainSignals, ReplayBrain
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_MODAL_DUMP = ROOT / "eval" / "probe_dump_modal.npz"
DEFAULT_AGENTS = ("investor_a", "investor_b")
@dataclass(frozen=True)
class TraceStep:
signals_by_agent: dict[str, BrainSignals]
floor_holder: str = "human"
note: str = ""
@dataclass(frozen=True)
class SignalTrace:
name: str
steps: list[TraceStep]
expected: dict[str, object] = field(default_factory=dict)
@property
def agent_ids(self) -> list[str]:
return list(self.steps[0].signals_by_agent.keys()) if self.steps else []
def synthetic_traces() -> list[SignalTrace]:
return [
clean_monologue_trace(),
surprising_claim_trace(),
topic_shift_trace(),
rambling_pause_trace(),
]
def load_modal_trace(path: str | Path = DEFAULT_MODAL_DUMP, agent_ids: Sequence[str] = DEFAULT_AGENTS) -> SignalTrace:
path = Path(path)
replay = ReplayBrain.from_npz(path, name="modal_probe_replay")
samples = list(replay)
steps: list[TraceStep] = []
for index, sample in enumerate(samples):
signals: dict[str, BrainSignals] = {}
for offset, agent_id in enumerate(agent_ids):
readiness = max(0.0, sample.readiness - 0.08 * offset)
signals[agent_id] = BrainSignals(
surprise=sample.surprise,
hidden=sample.hidden,
readiness=readiness,
p_end=sample.p_end,
)
steps.append(TraceStep(signals_by_agent=signals, note=f"modal step {index + 1}"))
return SignalTrace(
name="modal_probe_replay",
steps=steps,
expected={"source": str(path), "n_steps": len(steps)},
)
def all_traces() -> list[SignalTrace]:
traces = synthetic_traces()
if DEFAULT_MODAL_DUMP.exists():
traces.append(load_modal_trace(DEFAULT_MODAL_DUMP))
return traces
def clean_monologue_trace() -> SignalTrace:
base = _unit([1, 0, 0, 0, 0, 0, 0, 0])
steps = _trace_from_series(
name="clean_monologue_take_floor",
hidden_series=[_nudge(base, index, 0.01) for index in range(6)],
surprise=[2.0, 2.1, 2.0, 2.2, 2.1, 2.45],
readiness_a=[0.25, 0.30, 0.35, 0.40, 0.45, 0.78],
readiness_b=[0.20, 0.25, 0.30, 0.32, 0.35, 0.52],
p_end=[0.02, 0.03, 0.04, 0.05, 0.10, 0.95],
notes=["setup", "details", "still talking", "more context", "closing", "turn complete"],
)
return SignalTrace(name="clean_monologue_take_floor", steps=steps, expected={"take_floor_step": 6})
def surprising_claim_trace() -> SignalTrace:
base = _unit([1, 0, 0, 0, 0, 0, 0, 0])
steps = _trace_from_series(
name="surprising_claim_interrupt",
hidden_series=[_nudge(base, index, 0.01) for index in range(6)],
surprise=[2.0, 2.1, 7.3, 3.0, 2.4, 2.2],
readiness_a=[0.30, 0.42, 0.92, 0.82, 0.55, 0.45],
readiness_b=[0.25, 0.32, 0.35, 0.36, 0.38, 0.40],
p_end=[0.02, 0.04, 0.18, 0.20, 0.30, 0.55],
notes=["setup", "build", "wild claim", "continues", "settles", "handoff"],
)
return SignalTrace(name="surprising_claim_interrupt", steps=steps, expected={"interrupt_step": 3})
def topic_shift_trace() -> SignalTrace:
topic_a = _unit([1, 0, 0, 0, 0, 0, 0, 0])
topic_b = _unit([0, 1, 0, 0, 0, 0, 0, 0])
steps = _trace_from_series(
name="topic_shift_backchannel",
hidden_series=[
_nudge(topic_a, 0, 0.01),
_nudge(topic_a, 1, 0.01),
_nudge(topic_a, 2, 0.01),
_nudge(topic_a, 3, 0.01),
_nudge(topic_b, 4, 0.01),
_nudge(topic_b, 5, 0.01),
_nudge(topic_b, 6, 0.01),
],
surprise=[2.0, 2.1, 2.0, 2.1, 2.12, 2.08, 2.06],
readiness_a=[0.25, 0.30, 0.35, 0.38, 0.50, 0.45, 0.40],
readiness_b=[0.20, 0.25, 0.28, 0.30, 0.35, 0.34, 0.34],
p_end=[0.02, 0.04, 0.06, 0.08, 0.22, 0.25, 0.28],
notes=["topic a", "topic a", "topic a", "topic a", "topic b shift", "topic b", "topic b"],
)
return SignalTrace(name="topic_shift_backchannel", steps=steps, expected={"backchannel_step": 5})
def rambling_pause_trace() -> SignalTrace:
base = _unit([0, 0, 1, 0, 0, 0, 0, 0])
steps = _trace_from_series(
name="rambling_pause_take_floor",
hidden_series=[_nudge(base, index, 0.015) for index in range(7)],
surprise=[2.1, 2.0, 2.2, 2.1, 2.0, 2.1, 2.45],
readiness_a=[0.20, 0.25, 0.30, 0.38, 0.42, 0.42, 0.80],
readiness_b=[0.18, 0.22, 0.25, 0.30, 0.32, 0.35, 0.50],
p_end=[0.02, 0.05, 0.10, 0.38, 0.42, 0.44, 0.96],
notes=["start", "ramble", "ramble", "awkward pause", "holds", "still unsure", "complete"],
)
return SignalTrace(name="rambling_pause_take_floor", steps=steps, expected={"hold_step": 4, "take_floor_step": 7})
def _trace_from_series(
*,
name: str,
hidden_series: Sequence[np.ndarray],
surprise: Sequence[float],
readiness_a: Sequence[float],
readiness_b: Sequence[float],
p_end: Sequence[float],
notes: Sequence[str],
) -> list[TraceStep]:
steps: list[TraceStep] = []
for index, hidden in enumerate(hidden_series):
signals = {
"investor_a": BrainSignals(
surprise=surprise[index],
hidden=hidden,
readiness=readiness_a[index],
p_end=p_end[index],
),
"investor_b": BrainSignals(
surprise=max(0.0, surprise[index] - 0.2),
hidden=hidden,
readiness=readiness_b[index],
p_end=p_end[index],
),
}
steps.append(TraceStep(signals_by_agent=signals, note=notes[index]))
return steps
def _unit(values: Sequence[float]) -> np.ndarray:
vector = np.asarray(values, dtype=np.float32)
norm = np.linalg.norm(vector)
if norm == 0:
return vector
return vector / norm
def _nudge(base: np.ndarray, index: int, scale: float) -> np.ndarray:
vector = base.astype(np.float32, copy=True)
vector[(index % (len(vector) - 1)) + 1] += scale
return _unit(vector)