Files
breakpilot-lehrer/agent-core/sessions/session_models.py
Benjamin Admin bd4b956e3c [split-required] Split final 43 files (500-668 LOC) to complete refactoring
klausur-service (11 files):
- cv_gutter_repair, ocr_pipeline_regression, upload_api
- ocr_pipeline_sessions, smart_spell, nru_worksheet_generator
- ocr_pipeline_overlays, mail/aggregator, zeugnis_api
- cv_syllable_detect, self_rag

backend-lehrer (17 files):
- classroom_engine/suggestions, generators/quiz_generator
- worksheets_api, llm_gateway/comparison, state_engine_api
- classroom/models (→ 4 submodules), services/file_processor
- alerts_agent/api/wizard+digests+routes, content_generators/pdf
- classroom/routes/sessions, llm_gateway/inference
- classroom_engine/analytics, auth/keycloak_auth
- alerts_agent/processing/rule_engine, ai_processor/print_versions

agent-core (5 files):
- brain/memory_store, brain/knowledge_graph, brain/context_manager
- orchestrator/supervisor, sessions/session_manager

admin-lehrer (5 components):
- GridOverlay, StepGridReview, DevOpsPipelineSidebar
- DataFlowDiagram, sbom/wizard/page

website (2 files):
- DependencyMap, lehrer/abitur-archiv

Other: nibis_ingestion, grid_detection_service, export-doclayout-onnx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 09:41:42 +02:00

181 lines
5.9 KiB
Python

"""
Session Models for Breakpilot Agents
Data classes for agent sessions, checkpoints, and state tracking.
"""
from dataclasses import dataclass, field
from datetime import datetime, timezone, timedelta
from typing import Dict, Any, Optional, List
from enum import Enum
import uuid
import logging
logger = logging.getLogger(__name__)
class SessionState(Enum):
"""Agent session states"""
ACTIVE = "active"
PAUSED = "paused"
COMPLETED = "completed"
FAILED = "failed"
@dataclass
class SessionCheckpoint:
"""Represents a checkpoint in an agent session"""
name: str
timestamp: datetime
data: Dict[str, Any]
def to_dict(self) -> Dict[str, Any]:
return {
"name": self.name,
"timestamp": self.timestamp.isoformat(),
"data": self.data
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "SessionCheckpoint":
return cls(
name=data["name"],
timestamp=datetime.fromisoformat(data["timestamp"]),
data=data["data"]
)
@dataclass
class AgentSession:
"""
Represents an active agent session.
Attributes:
session_id: Unique session identifier
agent_type: Type of agent (tutor, grader, quality-judge, alert, orchestrator)
user_id: Associated user ID
state: Current session state
created_at: Session creation timestamp
last_heartbeat: Last heartbeat timestamp
context: Session context data
checkpoints: List of session checkpoints for recovery
"""
session_id: str = field(default_factory=lambda: str(uuid.uuid4()))
agent_type: str = ""
user_id: str = ""
state: SessionState = SessionState.ACTIVE
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
last_heartbeat: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
context: Dict[str, Any] = field(default_factory=dict)
checkpoints: List[SessionCheckpoint] = field(default_factory=list)
metadata: Dict[str, Any] = field(default_factory=dict)
def checkpoint(self, name: str, data: Dict[str, Any]) -> SessionCheckpoint:
"""
Creates a checkpoint for recovery.
Args:
name: Checkpoint name (e.g., "task_received", "processing_complete")
data: Checkpoint data to store
Returns:
The created checkpoint
"""
checkpoint = SessionCheckpoint(
name=name,
timestamp=datetime.now(timezone.utc),
data=data
)
self.checkpoints.append(checkpoint)
logger.debug(f"Session {self.session_id}: Checkpoint '{name}' created")
return checkpoint
def heartbeat(self) -> None:
"""Updates the heartbeat timestamp"""
self.last_heartbeat = datetime.now(timezone.utc)
def pause(self) -> None:
"""Pauses the session"""
self.state = SessionState.PAUSED
self.checkpoint("session_paused", {"previous_state": "active"})
def resume(self) -> None:
"""Resumes a paused session"""
if self.state == SessionState.PAUSED:
self.state = SessionState.ACTIVE
self.heartbeat()
self.checkpoint("session_resumed", {})
def complete(self, result: Optional[Dict[str, Any]] = None) -> None:
"""Marks the session as completed"""
self.state = SessionState.COMPLETED
self.checkpoint("session_completed", {"result": result or {}})
def fail(self, error: str, error_details: Optional[Dict[str, Any]] = None) -> None:
"""Marks the session as failed"""
self.state = SessionState.FAILED
self.checkpoint("session_failed", {
"error": error,
"details": error_details or {}
})
def get_last_checkpoint(self, name: Optional[str] = None) -> Optional[SessionCheckpoint]:
"""
Gets the last checkpoint, optionally filtered by name.
Args:
name: Optional checkpoint name to filter by
Returns:
The last matching checkpoint or None
"""
if not self.checkpoints:
return None
if name:
matching = [cp for cp in self.checkpoints if cp.name == name]
return matching[-1] if matching else None
return self.checkpoints[-1]
def get_duration(self) -> timedelta:
"""Returns the session duration"""
end_time = datetime.now(timezone.utc)
if self.state in (SessionState.COMPLETED, SessionState.FAILED):
last_cp = self.get_last_checkpoint()
if last_cp:
end_time = last_cp.timestamp
return end_time - self.created_at
def to_dict(self) -> Dict[str, Any]:
"""Serializes the session to a dictionary"""
return {
"session_id": self.session_id,
"agent_type": self.agent_type,
"user_id": self.user_id,
"state": self.state.value,
"created_at": self.created_at.isoformat(),
"last_heartbeat": self.last_heartbeat.isoformat(),
"context": self.context,
"checkpoints": [cp.to_dict() for cp in self.checkpoints],
"metadata": self.metadata
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "AgentSession":
"""Deserializes a session from a dictionary"""
return cls(
session_id=data["session_id"],
agent_type=data["agent_type"],
user_id=data["user_id"],
state=SessionState(data["state"]),
created_at=datetime.fromisoformat(data["created_at"]),
last_heartbeat=datetime.fromisoformat(data["last_heartbeat"]),
context=data.get("context", {}),
checkpoints=[
SessionCheckpoint.from_dict(cp)
for cp in data.get("checkpoints", [])
],
metadata=data.get("metadata", {})
)