website (17 pages + 3 components): - multiplayer/wizard, middleware/wizard+test-wizard, communication - builds/wizard, staff-search, voice, sbom/wizard - foerderantrag, mail/tasks, tools/communication, sbom - compliance/evidence, uni-crawler, brandbook (already done) - CollectionsTab, IngestionTab, RiskHeatmap backend-lehrer (5 files): - letters_api (641 → 2), certificates_api (636 → 2) - alerts_agent/db/models (636 → 3) - llm_gateway/communication_service (614 → 2) - game/database already done in prior batch klausur-service (2 files): - hybrid_vocab_extractor (664 → 2) - klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2) voice-service (3 files): - bqas/rag_judge (618 → 3), runner (529 → 2) - enhanced_task_orchestrator (519 → 2) studio-v2 (6 files): - korrektur/[klausurId] (578 → 4), fairness (569 → 2) - AlertsWizard (552 → 2), OnboardingWizard (513 → 2) - korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
142 lines
4.2 KiB
Python
142 lines
4.2 KiB
Python
"""
|
|
Enhanced Orchestrator Session Management
|
|
|
|
Session lifecycle methods extracted from EnhancedTaskOrchestrator.
|
|
"""
|
|
import structlog
|
|
from typing import Optional, Dict, Any
|
|
|
|
from sessions.session_manager import SessionManager, AgentSession, SessionState
|
|
from sessions.heartbeat import HeartbeatMonitor, HeartbeatClient
|
|
from brain.context_manager import ContextManager
|
|
|
|
logger = structlog.get_logger(__name__)
|
|
|
|
|
|
async def create_session(
|
|
session_manager: SessionManager,
|
|
context_manager: ContextManager,
|
|
heartbeat: HeartbeatMonitor,
|
|
voice_sessions: Dict[str, AgentSession],
|
|
heartbeat_clients: Dict[str, HeartbeatClient],
|
|
voice_session_id: str,
|
|
user_id: str = "",
|
|
metadata: Optional[Dict[str, Any]] = None,
|
|
system_prompt: str = "",
|
|
) -> AgentSession:
|
|
"""Creates a new agent session for a voice session."""
|
|
session = await session_manager.create_session(
|
|
agent_type="voice-orchestrator",
|
|
user_id=user_id,
|
|
context={"voice_session_id": voice_session_id},
|
|
metadata=metadata
|
|
)
|
|
|
|
context_manager.create_context(
|
|
session_id=session.session_id,
|
|
system_prompt=system_prompt,
|
|
max_messages=50
|
|
)
|
|
|
|
heartbeat_client = HeartbeatClient(
|
|
session_id=session.session_id,
|
|
monitor=heartbeat,
|
|
interval_seconds=10
|
|
)
|
|
await heartbeat_client.start()
|
|
heartbeat.register(session.session_id, "voice-orchestrator")
|
|
|
|
voice_sessions[voice_session_id] = session
|
|
heartbeat_clients[session.session_id] = heartbeat_client
|
|
|
|
logger.info(
|
|
"Created agent session",
|
|
session_id=session.session_id[:8],
|
|
voice_session_id=voice_session_id
|
|
)
|
|
return session
|
|
|
|
|
|
async def end_session(
|
|
session_manager: SessionManager,
|
|
heartbeat: HeartbeatMonitor,
|
|
voice_sessions: Dict[str, AgentSession],
|
|
heartbeat_clients: Dict[str, HeartbeatClient],
|
|
voice_session_id: str,
|
|
) -> None:
|
|
"""Ends an agent session."""
|
|
session = voice_sessions.get(voice_session_id)
|
|
if not session:
|
|
return
|
|
|
|
if session.session_id in heartbeat_clients:
|
|
await heartbeat_clients[session.session_id].stop()
|
|
del heartbeat_clients[session.session_id]
|
|
|
|
heartbeat.unregister(session.session_id)
|
|
session.complete()
|
|
await session_manager.update_session(session)
|
|
del voice_sessions[voice_session_id]
|
|
|
|
logger.info(
|
|
"Ended agent session",
|
|
session_id=session.session_id[:8],
|
|
duration_seconds=session.get_duration().total_seconds()
|
|
)
|
|
|
|
|
|
async def recover_session(
|
|
session_manager: SessionManager,
|
|
heartbeat: HeartbeatMonitor,
|
|
voice_sessions: Dict[str, AgentSession],
|
|
heartbeat_clients: Dict[str, HeartbeatClient],
|
|
tasks: Dict[str, Any],
|
|
process_task_fn,
|
|
voice_session_id: str,
|
|
session_id: str,
|
|
) -> Optional[AgentSession]:
|
|
"""Recovers a session from checkpoint."""
|
|
session = await session_manager.get_session(session_id)
|
|
|
|
if not session:
|
|
logger.warning("Session not found for recovery", session_id=session_id)
|
|
return None
|
|
|
|
if session.state != SessionState.ACTIVE:
|
|
logger.warning(
|
|
"Session not active for recovery",
|
|
session_id=session_id, state=session.state.value
|
|
)
|
|
return None
|
|
|
|
session.resume()
|
|
|
|
heartbeat_client = HeartbeatClient(
|
|
session_id=session.session_id,
|
|
monitor=heartbeat,
|
|
interval_seconds=10
|
|
)
|
|
await heartbeat_client.start()
|
|
heartbeat.register(session.session_id, "voice-orchestrator")
|
|
|
|
voice_sessions[voice_session_id] = session
|
|
heartbeat_clients[session.session_id] = heartbeat_client
|
|
|
|
# Recover pending tasks from checkpoints
|
|
from models.task import TaskState
|
|
for checkpoint in reversed(session.checkpoints):
|
|
if checkpoint.name == "task_queued":
|
|
task_id = checkpoint.data.get("task_id")
|
|
if task_id and task_id in tasks:
|
|
task = tasks[task_id]
|
|
if task.state == TaskState.QUEUED:
|
|
await process_task_fn(task)
|
|
logger.info("Recovered pending task", task_id=task_id[:8])
|
|
|
|
logger.info(
|
|
"Recovered session",
|
|
session_id=session.session_id[:8],
|
|
checkpoints=len(session.checkpoints)
|
|
)
|
|
return session
|