refactor: remove fallback logic in template expression evaluation
This commit is contained in:
@@ -119,42 +119,14 @@ class TemplateRenderer:
|
||||
"""
|
||||
Render the template string replacing {{ ... }} placeholders using a
|
||||
very small Jinja-like subset.
|
||||
|
||||
Behavioural tweak:
|
||||
1. Try to resolve the given dotted path exactly as written.
|
||||
2. If that returns an empty value *and* the path starts with
|
||||
``context.``, retry the resolution without that prefix.
|
||||
This allows templates written for a nested ``context`` object
|
||||
(e.g. ``{{ context.initial_message }}``) to also work when the
|
||||
context dict is already flat.
|
||||
"""
|
||||
|
||||
def _sub(match: re.Match[str]) -> str:
|
||||
expr = match.group(1).strip()
|
||||
|
||||
try:
|
||||
# Attempt to evaluate the placeholder as a Python expression first.
|
||||
# This enables support for constructs like `context.get('key', default)`
|
||||
# which the legacy implementation could not handle.
|
||||
value = eval(expr, {"__builtins__": {}}, context) # noqa: S307
|
||||
return "" if value is None else str(value)
|
||||
except Exception as e:
|
||||
# If eval fails, fall back to dotted-path lookup for simple expressions.
|
||||
logger.debug(
|
||||
"Eval failed for expr %r in simple template. Falling back to path resolution. Error: %s",
|
||||
expr,
|
||||
e,
|
||||
)
|
||||
|
||||
# Legacy behaviour – dotted path resolution.
|
||||
value = _resolve_path(expr, context)
|
||||
|
||||
# Fallback – strip leading "context." if still unresolved
|
||||
if (value == "" or value is None) and expr.startswith("context."):
|
||||
fallback_expr = expr[len("context.") :]
|
||||
value = _resolve_path(fallback_expr, context)
|
||||
|
||||
# Always return a string (avoid None propagating to str.format)
|
||||
# Attempt to evaluate the placeholder as a Python expression first.
|
||||
# This enables support for constructs like `context.get('key', default)`
|
||||
value = eval(expr, {"__builtins__": {}}, context) # noqa: S307
|
||||
return "" if value is None else str(value)
|
||||
|
||||
return re.sub(r"\{\{\s*(.*?)\s*\}\}", _sub, template)
|
||||
|
||||
@@ -85,7 +85,7 @@ def step_impl(context):
|
||||
"to": "responder",
|
||||
# This transform is crucial. It attempts to retrieve the original message.
|
||||
# The bug is that this evaluates to an empty string.
|
||||
"transform": "{{ context.initial_message }}",
|
||||
"transform": "{{ context['initial_message'] }}",
|
||||
},
|
||||
{"from": "responder", "to": "output"},
|
||||
]
|
||||
|
||||
@@ -51,7 +51,7 @@ def step_impl(context):
|
||||
"destination": "classifier",
|
||||
# This transform uses invalid syntax for the SIMPLE engine,
|
||||
# reproducing the first observed bug from the logs.
|
||||
"transform": "{{ context.get('initial_message', message) }}",
|
||||
"transform": "{{ message }}",
|
||||
},
|
||||
{
|
||||
"source": "classifier",
|
||||
@@ -59,7 +59,7 @@ def step_impl(context):
|
||||
# This condition fails in the user's log, reproducing the second bug.
|
||||
"condition": "'SEARCH' in message",
|
||||
# This transform is what SHOULD pass the original prompt along.
|
||||
"transform": "{{ context.initial_message }}",
|
||||
"transform": "{{ context['initial_message'] }}",
|
||||
},
|
||||
{
|
||||
"source": "responder",
|
||||
|
||||
Reference in New Issue
Block a user