core/generate/stream.py

51 lines
1.7 KiB
Python

"""
Generation loop — token streaming from the versor manifold.
Every token: nearest word to current F via CGA inner product.
Every step: F <- versor_apply(V, F) where V is the edge rotor.
No confidence gates. No IDK fallback. No attractor clamping.
F is always on the manifold. nearest() is always exact.
"""
import numpy as np
from field.state import FieldState
from field.propagate import propagate_step
def generate(state: FieldState, vocab, persona, max_tokens: int = 128) -> list:
"""
Generate a token sequence from an initial FieldState.
Loop:
1. Apply persona motor to current field
2. Find nearest vocab node via CGA inner product
3. Emit token
4. Get edge rotor from current node to nearest node
5. Propagate: F <- versor_apply(V, F)
6. Advance node pointer
"""
tokens = []
current = state
for _ in range(max_tokens):
F_voiced = persona.apply(current.F)
word, word_idx = vocab.nearest(F_voiced)
tokens.append(word)
V = vocab.edge_rotor(current.node, word_idx)
current = propagate_step(current, V)
current = FieldState(F=current.F, node=word_idx, step=current.step)
return tokens
async def agenerate(state: FieldState, vocab, persona, max_tokens: int = 128):
"""Async streaming version — yields one token at a time."""
current = state
for _ in range(max_tokens):
F_voiced = persona.apply(current.F)
word, word_idx = vocab.nearest(F_voiced)
yield word
V = vocab.edge_rotor(current.node, word_idx)
current = propagate_step(current, V)
current = FieldState(F=current.F, node=word_idx, step=current.step)