fix: Workflow placeholder resolution + complete catalog display
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s

Backend workflow_executor.py:
- load_prompt_template() now uses modern resolve_placeholders() from prompt_executor
- Calls get_placeholder_example_values() to populate ALL registered placeholders
- Passes catalog for |d modifier support
- Fixes issue where basis prompts had empty/null placeholder values in workflows

Backend placeholder_resolver.py:
- get_placeholder_catalog() now includes ALL placeholders from PLACEHOLDER_MAP
- Uncategorized placeholders added to "Sonstiges" category
- Fixes discrepancy: 111 total placeholders but only ~30 shown in picker

Root Cause:
- Workflow used old resolve_placeholders() (only PLACEHOLDER_MAP, no variables)
- Isolated execution used modern resolve_placeholders() (full variables dict)
- Catalog excluded non-registry placeholders from PLACEHOLDER_MAP

Impact:
- All placeholders now resolve correctly in workflow execution
- PlaceholderPicker shows all 111+ placeholders (not just registry ones)

Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Bug Fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-04-09 18:10:04 +02:00
parent 1a9fb99411
commit 857c55aeb8
2 changed files with 58 additions and 4 deletions

View File

@ -1470,4 +1470,33 @@ def get_placeholder_catalog(profile_id: str) -> Dict[str, List[Dict[str, str]]]:
'example': str(example) 'example': str(example)
}) })
# Add ALL remaining placeholders from PLACEHOLDER_MAP that aren't categorized yet
# This ensures PlaceholderPicker shows all 111+ placeholders, not just registry ones
all_categorized_keys = set()
for items in catalog.values():
all_categorized_keys.update(p['key'] for p in items)
sonstige_category = 'Sonstiges'
if sonstige_category not in catalog:
catalog[sonstige_category] = []
for placeholder, resolver in PLACEHOLDER_MAP.items():
# Extract key from {{key}}
key = placeholder.replace('{{', '').replace('}}', '')
# Skip if already categorized
if key in all_categorized_keys:
continue
try:
example = resolver(profile_id)
except Exception:
example = '[Nicht verfügbar]'
catalog[sonstige_category].append({
'key': key,
'description': f'Platzhalter: {key}', # Generic description
'example': str(example)
})
return catalog return catalog

View File

@ -766,7 +766,8 @@ async def load_prompt_template(prompt_slug: str, context: Dict[str, Any]) -> str
>>> "{{name}}" not in template >>> "{{name}}" not in template
True True
""" """
from placeholder_resolver import resolve_placeholders from placeholder_resolver import get_placeholder_example_values, get_placeholder_catalog
from prompt_executor import resolve_placeholders
with get_db() as conn: with get_db() as conn:
cur = get_cursor(conn) cur = get_cursor(conn)
@ -780,13 +781,37 @@ async def load_prompt_template(prompt_slug: str, context: Dict[str, Any]) -> str
template = row['template'] template = row['template']
# Resolve Placeholders # Resolve Placeholders using modern prompt_executor method
profile_id = context.get("profile_id") profile_id = context.get("profile_id")
# Build variables dict with ALL registered placeholders
variables = {}
try:
# Get all placeholder values from registry
processed_placeholders = get_placeholder_example_values(profile_id)
# Remove {{ }} from keys (placeholder_resolver returns them with wrappers)
cleaned_placeholders = {
key.replace('{{', '').replace('}}', ''): value
for key, value in processed_placeholders.items()
}
variables.update(cleaned_placeholders)
except Exception as e:
logger.warning(f"Failed to load placeholders for workflow: {e}")
# Load catalog for |d modifier support
try:
catalog = get_placeholder_catalog(profile_id)
except Exception as e:
catalog = None
logger.warning(f"Failed to load placeholder catalog for workflow: {e}")
# Resolve with modern executor
resolved = resolve_placeholders( resolved = resolve_placeholders(
template=template, template=template,
profile_id=profile_id variables=variables,
catalog=catalog
) )
# TODO Phase 3: Support custom variables from workflow context
return resolved return resolved