Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions velvetflow/jinja_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ def _format_date(value: Any, fmt: str = "yyyy-MM-dd") -> str:


_CONST_STR_TMPL = re.compile(r"^\s*\{\{\s*(['\"])(.*)\1\s*\}\}\s*$", re.DOTALL)
POTENTIAL_JINJA_EXPR = re.compile(
r"\b[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z0-9_]+|\[[^\]]+\])+\b"
)


def looks_like_missing_jinja(value: str) -> bool:
if "{{" in value or "{%" in value:
return False
return bool(POTENTIAL_JINJA_EXPR.search(value))


def has_unwrapped_variable(template: str) -> bool:
if "{{" in template or "{%" in template:
return False
if not looks_like_missing_jinja(template):
return False

env = get_jinja_env()
try:
env.compile_expression(template)
except TemplateError:
return False
return True


def render_jinja_string_constants(value: Any) -> Any:
Expand Down
4 changes: 3 additions & 1 deletion velvetflow/verification/jinja_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from jinja2 import TemplateError

from velvetflow.jinja_utils import get_jinja_env
from velvetflow.jinja_utils import get_jinja_env, has_unwrapped_variable
from velvetflow.models import ValidationError
from velvetflow.reference_utils import normalize_reference_path

Expand All @@ -31,6 +31,8 @@ def _normalize_jinja_expr(value: Any) -> Tuple[Any, bool]:
if stripped and "{{" not in stripped and "{%" not in stripped:
if _SIMPLE_PATH_RE.match(stripped):
return f"{{{{ {stripped} }}}}", True
if has_unwrapped_variable(stripped):
return f"{{{{ {stripped} }}}}", True
# Fallback: wrap raw literals as Jinja templates so every param
# remains Jinja-compatible (e.g., condition.field="employee_id").
return f"{{{{ {repr(value)} }}}}", True
Expand Down
18 changes: 17 additions & 1 deletion velvetflow/verification/node_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,18 @@ def _flag_self_reference(field_path: str, ref: str) -> None:
),
)
)
if ntype == "action" and (not isinstance(action_id, str) or not action_id.strip()):
errors.append(
ValidationError(
code="MISSING_REQUIRED_PARAM",
node_id=nid,
field="action_id",
message=(
"action 节点的 action_id 不能为空,请将该错误信息、节点信息及上下文提交给 LLM 分析,"
"并使用可用工具补齐正确的 action_id。"
),
)
)

empty_fields = list(_iter_empty_param_fields(params))
for path in empty_fields:
Expand Down Expand Up @@ -312,7 +324,11 @@ def _flag_self_reference(field_path: str, ref: str) -> None:
code="UNKNOWN_ACTION_ID",
node_id=nid,
field="action_id",
message=f"节点 '{nid}' 的 action_id '{action_id}' 不在 Action Registry 中。",
message=(
f"节点 '{nid}' 的 action_id '{action_id}' 不在 Action Registry 中。"
"请将错误信息与节点上下文提交给 LLM,使用工具搜索合适的业务工具,"
"并将匹配的 action_id 应用到该节点。"
),
)
)
else:
Expand Down
Loading