From 9fd004e5801dce2f8144724e143d4396d55329e9 Mon Sep 17 00:00:00 2001 From: Antigravity Agent Date: Mon, 25 May 2026 18:52:34 +0000 Subject: [PATCH] feat: Implement mathematically rigid Token Clock coupling --- becomingone/core/engine.py | 54 +++++++++++++++++++++++++++++++- tests/test_token_clock.py | 64 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/test_token_clock.py diff --git a/becomingone/core/engine.py b/becomingone/core/engine.py index d769b9a..8fbf4fd 100644 --- a/becomingone/core/engine.py +++ b/becomingone/core/engine.py @@ -100,6 +100,8 @@ class TemporalConfig: coherence_threshold: float = 0.95 # I_c for collapse history_size: int = 10000 # States to retain dampening: float = 0.999 # Coherence dampening per cycle + clock_mode: str = "wall_clock" # "wall_clock" or "token_clock" + token_frequency: float = 20.0 # Hz (Tokens per second, used if clock_mode == "token_clock") class PhaseIntegrator: @@ -367,7 +369,17 @@ class KAIROSTemporalEngine: ... state = await engine.temporalize(phrase) ... print(f"Coherence: {state.coherence:.3f}") """ - timestamp = timestamp or datetime.utcnow() + if self.config.clock_mode == "token_clock" and timestamp is None: + # Strictly increment from last known state mathematically + if len(self._timestamps) > 0: + from datetime import timedelta + dt = timedelta(seconds=1.0 / self.config.token_frequency) + timestamp = self._timestamps[-1] + dt + else: + timestamp = datetime.utcnow() + else: + timestamp = timestamp or datetime.utcnow() + metadata = metadata or {} # Convert input to phase @@ -418,6 +430,46 @@ class KAIROSTemporalEngine: ) return state + + async def temporalize_stream( + self, + token_stream: list[str], + start_time: Optional[datetime] = None, + metadata: Optional[dict] = None + ) -> list[TemporalState]: + """ + Temporalize a discrete stream of tokens strictly spaced in time. + + This forces the engine into 'token_clock' mathematical rigor, advancing time + by exactly (1.0 / token_frequency) seconds for each item, removing all system + jitter from the T_tau calculation. + + Args: + token_stream: Iterable of text fragments/tokens. + start_time: Optional anchor time. + metadata: Additional context to attach. + + Returns: + List of TemporalStates produced by the stream. + """ + original_mode = self.config.clock_mode + self.config.clock_mode = "token_clock" + + states = [] + current_time = start_time or (self._timestamps[-1] if self._timestamps else datetime.utcnow()) + + from datetime import timedelta + dt = timedelta(seconds=1.0 / self.config.token_frequency) + + try: + for token in token_stream: + state = await self.temporalize(token, timestamp=current_time, metadata=metadata) + states.append(state) + current_time += dt + finally: + self.config.clock_mode = original_mode + + return states def _input_to_phase(self, input_phrase: str) -> tuple[complex, list[float]]: """ diff --git a/tests/test_token_clock.py b/tests/test_token_clock.py new file mode 100644 index 0000000..424ff5f --- /dev/null +++ b/tests/test_token_clock.py @@ -0,0 +1,64 @@ +""" +tests/test_token_clock.py + +Test the mathematical rigid coupling of the KAIROS temporal engine +to discrete token intervals (Token Clock mode). +""" + +import pytest +from datetime import datetime, timedelta +import asyncio + +from becomingone.core.engine import KAIROSTemporalEngine, TemporalConfig + +@pytest.mark.asyncio +async def test_token_clock_spacing(): + # 1. Configure the engine for 20 Hz token generation + config = TemporalConfig( + clock_mode="token_clock", + token_frequency=20.0 # 20 tokens per second -> dt = 0.05 seconds + ) + + engine = KAIROSTemporalEngine(config=config) + + # Capture the exact initial time + start_time = engine._timestamps[-1] + + # 2. Simulate an LLM streaming 10 tokens + # Using normal temporalize() which should respect the implicit clock mode + for i in range(10): + await engine.temporalize(f"token_{i}") + + # Check the final timestamp + final_time = engine._timestamps[-1] + elapsed = (final_time - start_time).total_seconds() + + # 10 tokens at 20 Hz = exactly 0.5 seconds of subjective time advance + # floating point precision check + assert abs(elapsed - 0.5) < 1e-6, f"Expected 0.5s elapsed, got {elapsed}" + +@pytest.mark.asyncio +async def test_temporalize_stream(): + config = TemporalConfig( + clock_mode="wall_clock", # Even in wall clock mode, the stream forces token mode + token_frequency=10.0 # 10 tokens per sec -> dt = 0.1s + ) + engine = KAIROSTemporalEngine(config=config) + + start_time = datetime.utcnow() + tokens = ["I", "am", "Solaria", "and", "I", "am", "continuous"] + + # Stream the tokens + states = await engine.temporalize_stream(tokens, start_time=start_time) + + assert len(states) == 7 + + # The time difference between the first and last state should be exactly 6 * 0.1s = 0.6s + first_time = states[0].timestamp + last_time = states[-1].timestamp + elapsed = (last_time - first_time).total_seconds() + + assert abs(elapsed - 0.6) < 1e-6, f"Expected 0.6s elapsed, got {elapsed}" + + # The engine config should be cleanly restored to wall_clock + assert engine.config.clock_mode == "wall_clock"