feat: Implement mathematically rigid Token Clock coupling
This commit is contained in:
@@ -100,6 +100,8 @@ class TemporalConfig:
|
|||||||
coherence_threshold: float = 0.95 # I_c for collapse
|
coherence_threshold: float = 0.95 # I_c for collapse
|
||||||
history_size: int = 10000 # States to retain
|
history_size: int = 10000 # States to retain
|
||||||
dampening: float = 0.999 # Coherence dampening per cycle
|
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:
|
class PhaseIntegrator:
|
||||||
@@ -367,7 +369,17 @@ class KAIROSTemporalEngine:
|
|||||||
... state = await engine.temporalize(phrase)
|
... state = await engine.temporalize(phrase)
|
||||||
... print(f"Coherence: {state.coherence:.3f}")
|
... 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 {}
|
metadata = metadata or {}
|
||||||
|
|
||||||
# Convert input to phase
|
# Convert input to phase
|
||||||
@@ -418,6 +430,46 @@ class KAIROSTemporalEngine:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return state
|
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]]:
|
def _input_to_phase(self, input_phrase: str) -> tuple[complex, list[float]]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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"
|
||||||
Reference in New Issue
Block a user