Files
Software Orchestrator 5769c1cd22 Initial commit: a0_software_orchestrator v1.0
- Auto-Registration-Bug behoben (register_project/get_project_id/resolve_project Trennung)
- 25 Tests gruen (Pytest)
- block_compactor-Tool refactored (Option B: Soft-Check statt Hard-Block)
- 4 Restbaustellen gefixt
- DB-Schema: plugin_settings-Tabelle hinzugefuegt
- 3 Schattenprojekte aus DB geloescht
- Plan v3 + Refactor-Plan + Worklog dokumentiert
2026-06-16 22:13:06 +00:00

146 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Briefing helpers for specialist handover DB-backed.
Vorher: persistierte als .md-Datei in <project_root>/.a0proj/handover/.
Jetzt: append-only in der Tabelle `orch_briefings` (patterns.db).
Kompatible Rückgabe-Schemata, aber statt "path" jetzt "briefing_id".
"""
from __future__ import annotations
import os
from typing import Any, Dict, List, Optional
from usr.plugins.a0_software_orchestrator.helpers.db_state_store import (
get_project_id,
append_briefing,
get_briefing,
list_briefings,
)
from usr.plugins.a0_software_orchestrator.helpers.handover_protocol import is_known_specialist
def ensure_handover_dir(project_root: str = "", project_name: str = "") -> Dict[str, Any]:
"""No-op in DB-mode. Wird für Rückwärtskompatibilität gehalten und
gibt statt eines Pfads einfach einen Marker-Dict zurück.
"""
return {"kind": "db", "project_name": project_name or None}
def write_initial_briefing(
*,
project_name: str = "",
project_root: str = "",
specialist: str,
topic: str,
summary: str,
decisions: List[str],
artifacts: List[str],
recent_turns: List[str],
return_condition: str,
handover_reason: str,
) -> Dict[str, Any]:
"""Hängt eine neue Briefing-Section an `orch_briefings` an.
Returns dict mit:
- briefing_id (DB-PK)
- project_id
- project_name
- specialist
- topic
- created_at
- newly_created (immer True es gibt keine "vorhanden" Files mehr)
- existed_before (deprecated, immer False für neue Einträge)
- size_bytes (Größe des section_md-Texts in Bytes)
"""
if not is_known_specialist(specialist):
raise ValueError(f"Unknown specialist profile: {specialist!r}")
# Projekt-Name ableiten: project_name ist Pflicht (basename-Fallback
# entfernt würde ungültige/Phantom-Namen erzeugen).
if not project_name or not project_name.strip():
raise ValueError(
"project_name is required (basename-fallback removed; "
"pass explicit project_name or registered name)"
)
name = project_name.strip()
pid = get_project_id(name)
if pid is None:
raise LookupError(f"project '{name}' is not registered")
# Section-Markdown aufbauen (aus handover_protocol)
from .handover_protocol import render_briefing_section
section_md = render_briefing_section(
specialist=specialist,
topic=topic,
summary=summary,
decisions=decisions,
artifacts=artifacts,
recent_turns=recent_turns,
return_condition=return_condition,
handover_reason=handover_reason,
)
briefing_id = append_briefing(
project_id=pid,
specialist=specialist,
topic=topic,
section_md=section_md,
summary=summary,
decisions=decisions,
artifacts=artifacts,
recent_turns=recent_turns,
return_condition=return_condition,
handover_reason=handover_reason,
)
return {
"briefing_id": briefing_id,
"project_id": pid,
"project_name": name,
"specialist": specialist,
"topic": topic,
"newly_created": True,
"existed_before": False,
"size_bytes": len(section_md.encode("utf-8")),
}
def read_briefing(
briefing_id: int,
max_bytes: int = 32_000,
) -> str:
"""Liest den Markdown-Text eines Briefings aus der DB.
Returns "" wenn nicht gefunden. Truncated mit Marker wenn zu lang.
"""
full = get_briefing(int(briefing_id))
if not full:
return ""
content = full.get("section_md") or ""
if len(content.encode("utf-8")) <= max_bytes:
return content
truncated = content.encode("utf-8")[:max_bytes].decode("utf-8", errors="ignore")
return truncated + "\n\n_…[truncated, use a smaller max_bytes or split topic]…_\n"
def list_briefings_for(
project_name: str = "",
project_root: str = "",
specialist: Optional[str] = None,
limit: int = 50,
) -> List[Dict[str, Any]]:
"""Listet alle Briefings (latest first) eines Projekts.
Komfort-Wrapper um db_state_store.list_briefings mit
project_name/project_root-Auflösung.
"""
# Bug-Fix: basename-Fallback entfernt würde ungültige/Phantom-Namen
# erzeugen. project_name ist Pflicht; ohne Name → leere Liste.
if not project_name or not project_name.strip():
return []
name = project_name.strip()
pid = get_project_id(name)
if pid is None:
return []
return list_briefings(pid, specialist=specialist, limit=limit)