feat: resolve composite step inputs

This commit is contained in:
lda
2026-08-13 16:13:00 +07:00 Unverified
parent e661691e32
commit acda465d35
8 changed files with 657 additions and 102 deletions
+115
View File
@@ -0,0 +1,115 @@
from __future__ import annotations
from collections.abc import Mapping, Sequence
from typing import Any
from wf_core.conditions import safe_resolve_path
from wf_core.errors import WorkflowExecutionError
from wf_core.local_paths import LocalPathError, set_local_value
from wf_core.models.input_bindings import (
ArrayExpression,
InputExpression,
InputExpressionBinding,
InputPathBinding,
InputValueBinding,
LiteralExpression,
ObjectExpression,
PathExpression,
StepInputBinding,
)
from wf_core.models.json_values import JsonValue, validate_strict_json_value
def resolve_input_expression(
expression: InputExpression,
*,
state: Mapping[str, Any],
workflow_input: Mapping[str, Any],
context: Mapping[str, Any],
label: str,
location: str,
) -> JsonValue:
"""Resolve one composite expression while preserving its payload location."""
if isinstance(expression, LiteralExpression):
return expression.value
if isinstance(expression, PathExpression):
try:
value = safe_resolve_path(
str(expression.path),
state=state,
workflow_input=workflow_input,
context=context,
)
return validate_strict_json_value(value)
except (ValueError, WorkflowExecutionError) as exc:
raise WorkflowExecutionError(f"{label} {location}: {exc}") from exc
if isinstance(expression, ArrayExpression):
return [
resolve_input_expression(
item,
state=state,
workflow_input=workflow_input,
context=context,
label=label,
location=f"{location}[{index}]",
)
for index, item in enumerate(expression.items)
]
if isinstance(expression, ObjectExpression):
return {
field: resolve_input_expression(
value,
state=state,
workflow_input=workflow_input,
context=context,
label=label,
location=f"{location}.{field}",
)
for field, value in expression.fields.items()
}
raise WorkflowExecutionError(f"unsupported input expression for {label} {location}")
def resolve_step_input_bindings(
bindings: Sequence[StepInputBinding],
*,
state: Mapping[str, Any],
workflow_input: Mapping[str, Any],
context: Mapping[str, Any],
label: str,
) -> dict[str, Any]:
"""Build one node-local payload from simple or composite input bindings."""
payload: dict[str, Any] = {}
for binding in bindings:
location = str(binding.target)
if isinstance(binding, InputValueBinding):
value = binding.value
elif isinstance(binding, InputPathBinding):
try:
value = safe_resolve_path(
str(binding.path),
state=state,
workflow_input=workflow_input,
context=context,
)
value = validate_strict_json_value(value)
except (ValueError, WorkflowExecutionError) as exc:
raise WorkflowExecutionError(f"{label} {location}: {exc}") from exc
elif isinstance(binding, InputExpressionBinding):
value = resolve_input_expression(
binding.expression,
state=state,
workflow_input=workflow_input,
context=context,
label=label,
location=location,
)
else:
raise WorkflowExecutionError(f"unsupported input binding for {label}")
try:
set_local_value(payload, binding.target, value)
except LocalPathError as exc:
raise WorkflowExecutionError(f"{label} {location}: {exc}") from exc
return payload