path control flow stuff to use the struct directly!

This commit is contained in:
lda
2026-05-21 02:53:53 +07:00 Verified
parent 32c2d96c1a
commit c37be4f13c
10 changed files with 1280 additions and 56 deletions
+28 -19
View File
@@ -44,7 +44,10 @@ from .mapping import (
auto_input_map,
auto_output_map,
coerce_path,
normalize_input_mapping,
normalize_input_values,
normalize_mapping,
normalize_output_mapping,
)
from .refs import (
BranchRef,
@@ -68,28 +71,30 @@ def _condition_base(condition: CoreCondition) -> str:
def _canonical_input_bindings(
in_map: Mapping[str, str],
input_values: Mapping[str, Any],
in_map: Mapping[GraphSourcePath, LocalPath],
input_values: Mapping[LocalPath, Any],
) -> list[InputBinding]:
"""Convert authoring compatibility maps into canonical core input bindings."""
"""Convert typed authoring maps into canonical core input bindings."""
value_bindings = [
InputValueBinding(target=LocalPath.parse(target), value=value)
InputValueBinding(target=target, value=value)
for target, value in input_values.items()
]
path_bindings = [
InputPathBinding(
target=LocalPath.parse(target),
path=GraphSourcePath.parse(path),
target=target,
path=path,
)
for path, target in in_map.items()
]
return [*value_bindings, *path_bindings]
def _canonical_output_bindings(out_map: Mapping[str, str]) -> list[OutputBinding]:
"""Convert authoring compatibility maps into canonical core output bindings."""
def _canonical_output_bindings(
out_map: Mapping[LocalPath, StatePath],
) -> list[OutputBinding]:
"""Convert typed authoring maps into canonical core output bindings."""
return [
OutputBinding(source=LocalPath.parse(source), target=StatePath.parse(target))
OutputBinding(source=source, target=target)
for source, target in out_map.items()
]
@@ -118,28 +123,30 @@ class WorkflowBuilder:
*,
id: str | None = None,
in_map: MapArg | None = None,
input_values: Mapping[str, Any] | None = None,
input_values: Mapping[Any, Any] | None = None,
out_map: MapArg | None = None,
desc: str | None = None,
) -> NodeUse:
self.node_specs[spec.name] = spec
normalized_input_schema = cast(SchemaRef, self.input_schema)
normalized_state_schema = cast(StateSchema, self.state_schema)
normalized_in_map = (
raw_in_map = (
auto_input_map(
spec,
input_schema=normalized_input_schema,
state_schema=normalized_state_schema,
)
if in_map is None
else normalize_mapping(in_map)
else in_map
)
normalized_input_values = dict(input_values or {})
normalized_out_map = (
normalized_in_map = normalize_input_mapping(raw_in_map)
normalized_input_values = normalize_input_values(input_values)
raw_out_map = (
auto_output_map(spec, state_schema=normalized_state_schema)
if out_map is None
else normalize_mapping(out_map)
else out_map
)
normalized_out_map = normalize_output_mapping(raw_out_map)
node = NodeUse(
id=id or self._next_step_id(slug_id(spec.name)),
type="node",
@@ -160,7 +167,7 @@ class WorkflowBuilder:
*,
id: str | None = None,
in_map: MapArg | None = None,
input_values: Mapping[str, Any] | None = None,
input_values: Mapping[Any, Any] | None = None,
out_map: MapArg | None = None,
desc: str | None = None,
) -> NodeUse:
@@ -171,9 +178,9 @@ class WorkflowBuilder:
hatch for MCP/saved-workflow capability refs that are resolved later by
the environment runner into node definitions and registry handlers.
"""
normalized_in_map = normalize_mapping(in_map)
normalized_input_values = dict(input_values or {})
normalized_out_map = normalize_mapping(out_map)
normalized_in_map = normalize_input_mapping(in_map)
normalized_input_values = normalize_input_values(input_values)
normalized_out_map = normalize_output_mapping(out_map)
node = NodeUse(
id=id or self._next_step_id(slug_id(name)),
type="node",
@@ -254,6 +261,8 @@ class WorkflowBuilder:
mode: Literal["serial", "parallel"] = "serial",
on_item_error: Literal["fail", "collect", "skip"] = "fail",
) -> ForeachNode:
# Core foreach still stores `over` as a string. Keep this compatibility
# path isolated until ForeachNode grows a typed GraphSourcePath field.
node = ForeachNode.model_validate({
"id": id or self._next_step_id(f"foreach_{slug_id(as_)}"),
"type": "foreach",
+43
View File
@@ -4,11 +4,20 @@ from collections.abc import Mapping
from typing import Any, TypeAlias
from wf_core import SchemaRef, StateSchema
from wf_core.paths import GraphSourcePath, LocalPath, StatePath
from ..dsl import GraphPath
from ..dsl.path_inputs import (
coerce_graph_path,
coerce_local_path,
coerce_state_path,
)
from ..nodes import NodeSpec
MapArg: TypeAlias = Mapping[Any, Any]
InputMap: TypeAlias = dict[GraphSourcePath, LocalPath]
OutputMap: TypeAlias = dict[LocalPath, StatePath]
InputValues: TypeAlias = dict[LocalPath, Any]
def coerce_path(value: object) -> str:
@@ -17,6 +26,8 @@ def coerce_path(value: object) -> str:
return value
if isinstance(value, GraphPath):
return value.value
if isinstance(value, GraphSourcePath | StatePath | LocalPath):
return str(value)
raise TypeError(f"unsupported graph path value {value!r}")
@@ -30,6 +41,38 @@ def normalize_mapping(mapping: MapArg | None) -> dict[str, str]:
}
def normalize_input_mapping(mapping: MapArg | None) -> InputMap:
"""Normalize `in_map`: graph source path -> node-local input path."""
if mapping is None:
return {}
return {
coerce_graph_path(source.path if isinstance(source, GraphPath) else source): (
coerce_local_path(destination)
)
for source, destination in mapping.items()
}
def normalize_input_values(mapping: Mapping[Any, Any] | None) -> InputValues:
"""Normalize `input_values`: node-local input path -> literal value."""
if mapping is None:
return {}
return {coerce_local_path(target): value for target, value in mapping.items()}
def normalize_output_mapping(mapping: MapArg | None) -> OutputMap:
"""Normalize `out_map`: node-local output path -> workflow state path."""
if mapping is None:
return {}
return {
coerce_local_path(source): coerce_state_path(
target.path if isinstance(target, GraphPath) else target,
allow_legacy_root=True,
)
for source, target in mapping.items()
}
def auto_input_map(
spec: NodeSpec[Any, Any],
*,