Spaces:
Running
Running
| """Generation state — hierarchia źródeł prawdy i helpery persystencji. | |
| Problem (audyt): stan generacji był rozproszony w ``external_context`` JSON, | |
| checkpointach LangGraph (sqlite) i GSD orchestratorze. | |
| Hierarchia odczytu (od najbardziej autorytatywnego): | |
| 1. **GSD orchestrator** — ``gsd/gsd_state.py`` + sqlite saver (aktywny run) | |
| 2. **Hybrid checkpoint** — ``external_context['orchestrator_checkpoint_v5']`` | |
| 3. **Legacy LangGraph generator** — ``data/generator_checkpoints.db`` (DEPRECATED) | |
| 4. **Pozostałe klucze w external_context** — cache / pochodne (nie źródło prawdy) | |
| Zapis: używaj ``persist_generation_checkpoint`` aby synchronizować warstwy 1↔2. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| from copy import deepcopy | |
| from typing import Any | |
| logger = logging.getLogger(__name__) | |
| CHECKPOINT_V5_KEY = "orchestrator_checkpoint_v5" | |
| GSD_STATE_KEY = "gsd_state" | |
| GENERATION_META_KEY = "generation_meta" | |
| DERIVED_CONTEXT_KEYS = frozenset( | |
| { | |
| "holistic_review", | |
| "risk_score", | |
| "blocks_export_recommendation", | |
| "v5_grounding_certificate", | |
| "compliance_checklist", | |
| "regulation_section_titles", | |
| "credibility_flags", | |
| } | |
| ) | |
| def get_authoritative_checkpoint(project) -> dict[str, Any] | None: | |
| """Zwraca hybrid checkpoint v5 z projektu lub None.""" | |
| ext = getattr(project, "external_context", None) or {} | |
| ck = ext.get(CHECKPOINT_V5_KEY) | |
| return ck if isinstance(ck, dict) else None | |
| def get_generation_meta(project) -> dict[str, Any]: | |
| """Metadane generacji (ścieżka orkiestracji, ostatnia faza).""" | |
| ext = getattr(project, "external_context", None) or {} | |
| meta = ext.get(GENERATION_META_KEY) or {} | |
| return meta if isinstance(meta, dict) else {} | |
| def persist_generation_checkpoint( | |
| db, | |
| project, | |
| checkpoint: dict[str, Any], | |
| *, | |
| orchestration_path: str = "gsd", | |
| merge_meta: dict[str, Any] | None = None, | |
| ) -> None: | |
| """Zapisuje checkpoint do ``external_context`` (single durable source w Postgres/SQLite).""" | |
| from sqlalchemy.orm.attributes import flag_modified | |
| ext = deepcopy(getattr(project, "external_context", None) or {}) | |
| ext[CHECKPOINT_V5_KEY] = checkpoint | |
| meta = dict(ext.get(GENERATION_META_KEY) or {}) | |
| meta["orchestration_path"] = orchestration_path | |
| meta["last_checkpoint_stage"] = checkpoint.get("stage") or checkpoint.get("current_orchestrator_stage") | |
| if merge_meta: | |
| meta.update(merge_meta) | |
| ext[GENERATION_META_KEY] = meta | |
| project.external_context = ext | |
| flag_modified(project, "external_context") | |
| db.commit() | |
| logger.debug( | |
| "[generation_state] Persisted checkpoint stage=%s path=%s project=%s", | |
| meta.get("last_checkpoint_stage"), | |
| orchestration_path, | |
| getattr(project, "id", "?"), | |
| ) | |
| def is_legacy_langgraph_checkpoint(config: dict[str, Any] | None) -> bool: | |
| """Czy config wskazuje na legacy LangGraph thread (generator agent).""" | |
| if not config: | |
| return False | |
| tid = config.get("configurable", {}).get("thread_id", "") | |
| return isinstance(tid, str) and tid.startswith("gen-") | |