diff --git a/backend/prompt_executor.py b/backend/prompt_executor.py index 3b13100..bb053ee 100644 --- a/backend/prompt_executor.py +++ b/backend/prompt_executor.py @@ -50,17 +50,24 @@ def resolve_placeholders(template: str, variables: Dict[str, Any], debug_info: O resolved_value = str(value) # Apply modifiers - if 'd' in modifiers and catalog: - # Add description from catalog - description = None - for cat_items in catalog.values(): - matching = [item for item in cat_items if item['key'] == key] - if matching: - description = matching[0].get('description', '') - break + if 'd' in modifiers: + if catalog: + # Add description from catalog + description = None + for cat_items in catalog.values(): + matching = [item for item in cat_items if item['key'] == key] + if matching: + description = matching[0].get('description', '') + break - if description: - resolved_value = f"{resolved_value} ({description})" + if description: + resolved_value = f"{resolved_value} ({description})" + else: + # Catalog not available - log warning in debug + if debug_info is not None: + if 'warnings' not in debug_info: + debug_info['warnings'] = [] + debug_info['warnings'].append(f"Modifier |d used but catalog not available for {key}") # Track resolution for debug if debug_info is not None: @@ -407,9 +414,11 @@ async def execute_prompt_with_data( # Load placeholder catalog for |d modifier support try: catalog = get_placeholder_catalog(profile_id) - variables['_catalog'] = catalog # Will be popped in execute_prompt - except Exception: + except Exception as e: catalog = None + print(f"Warning: Could not load placeholder catalog: {e}") + + variables['_catalog'] = catalog # Will be popped in execute_prompt (can be None) # Add PROCESSED placeholders (name, weight_trend, caliper_summary, etc.) # This makes old-style prompts work with the new executor diff --git a/backend/routers/prompts.py b/backend/routers/prompts.py index 139a7a2..44c7ee2 100644 --- a/backend/routers/prompts.py +++ b/backend/routers/prompts.py @@ -786,13 +786,14 @@ async def execute_unified_prompt( } # Execute with prompt_executor + # Always enable debug when saving to collect metadata for value table result = await execute_prompt_with_data( prompt_slug=prompt_slug, profile_id=profile_id, modules=modules, timeframes=timeframes, openrouter_call_func=call_openrouter, - enable_debug=debug + enable_debug=debug or save # Enable debug if saving for metadata collection ) # Save to ai_insights if requested diff --git a/frontend/src/components/UnifiedPromptModal.jsx b/frontend/src/components/UnifiedPromptModal.jsx index 24badf7..e99bd99 100644 --- a/frontend/src/components/UnifiedPromptModal.jsx +++ b/frontend/src/components/UnifiedPromptModal.jsx @@ -41,6 +41,7 @@ export default function UnifiedPromptModal({ prompt, onSave, onClose }) { const [pickerTarget, setPickerTarget] = useState(null) // 'base' or {stage, promptIdx} const [cursorPosition, setCursorPosition] = useState(null) // Track cursor position for insertion const baseTemplateRef = useRef(null) + const stageTemplateRefs = useRef({}) // Map of stage_promptIdx -> ref // Test functionality const [testing, setTesting] = useState(false) @@ -657,9 +658,18 @@ export default function UnifiedPromptModal({ prompt, onSave, onClose }) { ) : (