""" Stream State — SESSION_STATE_V1 Rolling session state that tracks camera, audio, observer, and builder across the five loops. """ import time import uuid import hashlib import json from collections import deque from dataclasses import dataclass, field from typing import Any, Optional @dataclass class FrameEvidence: ts: float sha256: str phash: str entropy: float motion_score: float width: int height: int jpeg_b64: str @dataclass class AudioChunk: ts: float chunk_id: str duration_ms: int speaker: str transcript: str confidence: float sha256: str is_speech: bool @dataclass class SessionState: session_id: str = field(default_factory=lambda: str(uuid.uuid4())) created_at: float = field(default_factory=time.time) # Camera camera_source: str = "webcam" frame_rate_sampled: float = 1.0 frames: deque = field(default_factory=lambda: deque(maxlen=16)) last_frame_hash: str = "" motion_score: float = 0.0 # Audio audio_chunks: deque = field(default_factory=lambda: deque(maxlen=30)) speakers: dict = field(default_factory=dict) # Observer scene_summary: str = "" intent_summary: str = "" novelty_score: float = 0.0 code_relevance_score: float = 0.0 observer_state: dict = field(default_factory=dict) last_observer_ts: float = 0.0 # Builder current_artifact: str = "" last_patch_hash: str = "" builder_state: dict = field(default_factory=dict) last_builder_ts: float = 0.0 # QVD qvd: float = 0.0 qvd_threshold: float = 0.08 # Receipts receipt_count: int = 0 # User user_instruction: str = "" mode: str = "continuous_code" def add_frame(self, frame: FrameEvidence): self.frames.append(frame) self.last_frame_hash = frame.sha256 self.motion_score = frame.motion_score def add_audio_chunk(self, chunk: AudioChunk): self.audio_chunks.append(chunk) if chunk.speaker not in self.speakers: self.speakers[chunk.speaker] = { "transcript": "", "confidence": 0.0, "chunk_count": 0, } s = self.speakers[chunk.speaker] s["transcript"] = (s["transcript"] + " " + chunk.transcript).strip()[-2000:] s["confidence"] = chunk.confidence s["chunk_count"] += 1 def frame_hashes(self) -> list: return [f.sha256 for f in self.frames] def audio_chunk_hashes(self) -> list: return [c.sha256 for c in self.audio_chunks] def speaker_segments(self) -> list: return [ {"speaker": c.speaker, "text": c.transcript, "confidence": c.confidence} for c in self.audio_chunks if c.is_speech ] def to_dict(self) -> dict: return { "session_id": self.session_id, "created_at": self.created_at, "camera": { "source": self.camera_source, "frame_rate_sampled": self.frame_rate_sampled, "last_frame_hash": self.last_frame_hash, "motion_score": round(self.motion_score, 4), "frames_buffered": len(self.frames), }, "audio": { "chunks_buffered": len(self.audio_chunks), "speakers": self.speakers, }, "observer": { "scene_summary": self.scene_summary, "intent_summary": self.intent_summary, "novelty_score": round(self.novelty_score, 4), "code_relevance_score": round(self.code_relevance_score, 4), "state": self.observer_state, "last_ts": self.last_observer_ts, }, "builder": { "current_artifact": self.current_artifact[:500], "last_patch_hash": self.last_patch_hash, "state": self.builder_state, "last_ts": self.last_builder_ts, }, "qvd": round(self.qvd, 4), "qvd_threshold": self.qvd_threshold, "receipt_count": self.receipt_count, "user_instruction": self.user_instruction, "mode": self.mode, } def sha256_bytes(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def sha256_text(text: str) -> str: return hashlib.sha256(text.encode()).hexdigest()