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
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""Extension: Load compact project state at monologue start (DB-first, file fallback)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from usr.plugins.a0_software_orchestrator.helpers.db_state_store import (
|
||||
get_project_id,
|
||||
get_kv,
|
||||
get_status,
|
||||
list_next_steps,
|
||||
list_errors,
|
||||
get_block_compact,
|
||||
get_project_detail,
|
||||
)
|
||||
from usr.plugins.a0_software_orchestrator.helpers.state_store import read_json, get_project_files
|
||||
|
||||
|
||||
def _project_name(project_root: str) -> str:
|
||||
return os.path.basename((project_root or os.getcwd()).rstrip("/"))
|
||||
|
||||
|
||||
def get_monologue_injection(project_root: str = None) -> str:
|
||||
"""Return compact project state summary for the agent."""
|
||||
if not project_root:
|
||||
project_root = os.getcwd()
|
||||
name = _project_name(project_root)
|
||||
|
||||
# DB is the source of truth. Files are legacy fallback only.
|
||||
try:
|
||||
pid = get_project_id(name)
|
||||
if pid is None:
|
||||
raise LookupError("project not registered")
|
||||
status = get_status(pid)
|
||||
detail = get_project_detail(name) or {}
|
||||
phase = get_kv(pid, "phase", default=detail.get("phase", "unknown"))
|
||||
mode = get_kv(pid, "orchestrator_mode", default={})
|
||||
if (not isinstance(mode, dict) or not mode) and detail.get("plan_mode"):
|
||||
mode = {"mode": detail.get("plan_mode")}
|
||||
steps = list_next_steps(pid, status="pending", limit=5)
|
||||
errors = list_errors(pid, status="open", limit=5)
|
||||
bc = get_block_compact(pid)
|
||||
parts = [f"Project: {name}", f"Project-ID: {pid}", f"Phase: {phase}"]
|
||||
if isinstance(mode, dict):
|
||||
parts.append(f"Plan Mode: {mode.get('mode', 'planning_only')}")
|
||||
if status:
|
||||
parts.append(f"Status: {status[:300]}")
|
||||
parts.append(f"Pending next steps: {len(steps)}")
|
||||
parts.append(f"Open errors: {len(errors)}")
|
||||
if bc:
|
||||
parts.append(f"Last block: {bc.get('last_block_id')} → Next: {bc.get('next_block')}")
|
||||
return "\n".join(parts)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Legacy fallback: .a0 files
|
||||
files = get_project_files(project_root)
|
||||
parts = []
|
||||
if os.path.exists(files["project_state"]):
|
||||
state = read_json(files["project_state"], {})
|
||||
project = state.get("project", {})
|
||||
phase = state.get("phase", {})
|
||||
parts.append(f"Project: {project.get('name', name)}")
|
||||
parts.append(f"Phase: {phase.get('current', 'unknown')}")
|
||||
parts.append(f"Blocked: {phase.get('blocked', False)}")
|
||||
if os.path.exists(files["current_status"]):
|
||||
with open(files["current_status"], "r", encoding="utf-8") as f:
|
||||
parts.append(f"Status: {f.read()[:200]}")
|
||||
if os.path.exists(files["next_steps"]):
|
||||
with open(files["next_steps"], "r", encoding="utf-8") as f:
|
||||
parts.append(f"Next: {f.read()[:200]}")
|
||||
if os.path.exists(files["orchestrator_mode"]):
|
||||
mode_data = read_json(files["orchestrator_mode"], {})
|
||||
parts.append(f"Plan Mode: {mode_data.get('mode', 'unknown')}")
|
||||
return "\n".join(parts) if parts else "No project state loaded."
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(get_monologue_injection(os.getcwd()) or "no state")
|
||||
|
||||
|
||||
from helpers.extension import Extension
|
||||
|
||||
|
||||
class LoadProjectState(Extension):
|
||||
async def execute(self, loop_data=None, **kwargs):
|
||||
# Keep startup light: only inject a compact DB-backed summary, never broad filesystem discovery.
|
||||
if not self.agent or self.agent.config.profile != "a0_software_orchestrator":
|
||||
return
|
||||
try:
|
||||
summary = get_monologue_injection(os.getcwd())
|
||||
if summary and loop_data is not None:
|
||||
loop_data.extras_temporary["orchestrator_project_state"] = summary
|
||||
except Exception:
|
||||
return
|
||||
Reference in New Issue
Block a user