from __future__ import annotations import json import re from pathlib import Path from typing import Any _PROMPT_DIR = Path(__file__).resolve().parent.parent / "nemoclaw_prompts" _PLACEHOLDER_PATTERN = re.compile(r"\{(\w+)\}") _TEMPLATE_HINTS = { "pipeline": ["tpl_pipeline_board_v2", "tpl_followup_queue_v1"], "kanban": ["tpl_pipeline_board_v2"], "map": ["tpl_geo_investor_heat_v2"], "geo": ["tpl_geo_investor_heat_v2"], "trend": ["tpl_absorption_trend_v1", "tpl_campaign_lead_line_v1"], "quota": ["tpl_quota_gauge_v1", "tpl_kpi_pipeline_health_v1"], "broker": ["tpl_broker_performance_v1"], "source": ["tpl_qd_source_compare_v1", "tpl_bar_source_quality_v3"], "follow": ["tpl_followup_queue_v1", "tpl_followup_gap_v1"], "campaign": ["tpl_campaign_lead_line_v1"], } class PersonaService: def __init__(self) -> None: self.prompt_files = { "qd_calculator": _PROMPT_DIR / "qd_calculator.md", "lead_tagger": _PROMPT_DIR / "lead_tagger.md", "cctv_profiler": _PROMPT_DIR / "cctv_profiler.md", } async def health(self) -> dict[str, Any]: loaded = {} for key, path in self.prompt_files.items(): loaded[key] = path.exists() and path.read_text(encoding="utf-8").strip() != "" return { "status": "healthy" if all(loaded.values()) else "degraded", "prompts": loaded, } async def render_prompt( self, *, prompt_name: str, variables: dict[str, Any], ) -> dict[str, Any]: path = self.prompt_files.get(prompt_name) if path is None or not path.exists(): raise FileNotFoundError(f"Unknown prompt '{prompt_name}'.") template = path.read_text(encoding="utf-8") rendered = template for key, value in variables.items(): rendered = rendered.replace(f"{{{key}}}", json.dumps(value) if isinstance(value, (dict, list)) else str(value)) unresolved = sorted(set(_PLACEHOLDER_PATTERN.findall(rendered))) return { "promptName": prompt_name, "templatePath": str(path), "renderedPrompt": rendered, "unresolvedVariables": unresolved, } async def plan_for_prompt( self, *, prompt: str, tenant_id: str, actor_role: str, ) -> dict[str, Any]: lower_prompt = prompt.lower() recommended: list[str] = [] for token, template_ids in _TEMPLATE_HINTS.items(): if token in lower_prompt: recommended.extend(template_ids) if not recommended: recommended = ["tpl_kpi_pipeline_health_v1", "tpl_qd_source_compare_v1"] recommended = list(dict.fromkeys(recommended)) return { "tenantId": tenant_id, "actorRole": actor_role, "recommendedTemplates": recommended, "canvasBlocks": [ { "type": "textCanvas", "widthMode": "full", "minHeightPx": 180, "content": ( "Oracle planned a mixed response: query the CRM, reuse matching component templates, " "and synthesize missing visualization blocks if a direct template is unavailable." ), } ], "workflowIntent": "comfy_oracle_canvas", } persona_service = PersonaService()