feat: expose structured context during execution
This commit is contained in:
@@ -161,10 +161,22 @@ def _foreach_ancestor_ids(run: RunState, frame: ExecutionFrame) -> list[str]:
|
||||
def finalize_run(workflow: Workflow, run: RunState) -> RunState:
|
||||
if run.outcome is None:
|
||||
run.outcome = "ok"
|
||||
# Root workflow output keeps standard root facts consistent by projecting
|
||||
# against the root frame's derived context rather than an empty mapping.
|
||||
from wf_core.run_state import ROOT_FRAME_ID
|
||||
from wf_core.runtime.ops.frames import frame_context_view
|
||||
|
||||
root_frame = run.frames.get(ROOT_FRAME_ID)
|
||||
root_context: dict[str, Any] = (
|
||||
dict(frame_context_view(run, root_frame).graph)
|
||||
if root_frame is not None
|
||||
else {}
|
||||
)
|
||||
run.output = project_output(
|
||||
workflow,
|
||||
run.state,
|
||||
workflow_input=run.workflow_input,
|
||||
context=root_context,
|
||||
)
|
||||
validate_payload_against_schema(
|
||||
workflow.output_schema, run.output, "workflow output"
|
||||
|
||||
@@ -23,7 +23,7 @@ from wf_core.runtime.lineage import (
|
||||
scope_input_for_frame,
|
||||
)
|
||||
from wf_core.runtime.ops.flow import advance_frame, append_step_result_trace
|
||||
from wf_core.runtime.ops.frames import frame_context_values
|
||||
from wf_core.runtime.ops.frames import frame_context_view
|
||||
from wf_core.runtime.ops.index import WorkflowIndex
|
||||
from wf_core.runtime.ops.merges import ReducerDefinition
|
||||
from wf_core.runtime.ops.overlays import state_view_for_frame
|
||||
@@ -174,7 +174,7 @@ def _resolve_foreach_iterable(
|
||||
str(step.over),
|
||||
state=state_view_for_frame(run, frame),
|
||||
workflow_input=scope_input_for_frame(run, frame),
|
||||
context=frame_context_values(frame),
|
||||
context=frame_context_view(run, frame).graph,
|
||||
)
|
||||
if not isinstance(iterable, list):
|
||||
raise WorkflowExecutionError(
|
||||
|
||||
@@ -14,7 +14,7 @@ from wf_core.run_state import (
|
||||
)
|
||||
from wf_core.runtime.lineage import scope_input_for_frame
|
||||
from wf_core.runtime.ops.flow import append_trace
|
||||
from wf_core.runtime.ops.frames import frame_context_values
|
||||
from wf_core.runtime.ops.frames import frame_context_view
|
||||
from wf_core.runtime.ops.interrupts import build_interrupt_request
|
||||
from wf_core.runtime.ops.overlays import state_view_for_frame
|
||||
|
||||
@@ -75,7 +75,7 @@ def handle_interrupt_step(
|
||||
frame_id=frame.id,
|
||||
state=state_view_for_frame(run, frame),
|
||||
workflow_input=scope_input_for_frame(run, frame),
|
||||
context=frame_context_values(frame),
|
||||
context=dict(frame_context_view(run, frame).graph),
|
||||
public_frame_id=public_frame.id,
|
||||
public_node_id=public_frame.node_id,
|
||||
route=route,
|
||||
|
||||
@@ -20,7 +20,7 @@ from wf_core.runtime.lineage import (
|
||||
commit_foreach_aware_patch,
|
||||
scope_input_for_frame,
|
||||
)
|
||||
from wf_core.runtime.ops.frames import frame_context_values
|
||||
from wf_core.runtime.ops.frames import frame_context_view
|
||||
from wf_core.runtime.ops.merges import ReducerDefinition
|
||||
from wf_core.runtime.ops.overlays import state_view_for_frame
|
||||
from wf_core.runtime.ops.schemas import validate_payload_against_schema
|
||||
@@ -54,7 +54,8 @@ def _resolve_node_execution(
|
||||
node_def: NodeDef,
|
||||
platform: object | None = None,
|
||||
) -> tuple[dict[str, Any], RuntimeContext, dict[str, Any]]:
|
||||
context_values = frame_context_values(frame)
|
||||
context_view = frame_context_view(run, frame)
|
||||
context_values = context_view.graph
|
||||
state_view = state_view_for_frame(run, frame)
|
||||
resolved_input = resolve_step_input_bindings(
|
||||
node.input,
|
||||
@@ -76,6 +77,7 @@ def _resolve_node_execution(
|
||||
prior_outcome=frame.prior_outcome,
|
||||
activated_incoming_edge=frame.activated_incoming_edge,
|
||||
metadata=dict(frame.metadata),
|
||||
foreach=dict(context_view.foreach),
|
||||
platform=platform,
|
||||
)
|
||||
return resolved_input, context, state_view
|
||||
|
||||
@@ -18,7 +18,7 @@ from wf_core.run_state import (
|
||||
)
|
||||
from wf_core.runtime.input_bindings import resolve_step_input_bindings
|
||||
from wf_core.runtime.lineage import commit_foreach_aware_patch
|
||||
from wf_core.runtime.ops.frames import frame_context_values
|
||||
from wf_core.runtime.ops.frames import frame_context_view
|
||||
from wf_core.runtime.ops.merges import ReducerDefinition
|
||||
from wf_core.runtime.ops.overlays import state_view_for_frame
|
||||
from wf_core.runtime.ops.runs import initial_state
|
||||
@@ -140,7 +140,7 @@ def _start_subgraph(
|
||||
step.input,
|
||||
state=state_view_for_frame(run, frame),
|
||||
workflow_input=parent_scope.workflow_input,
|
||||
context=frame_context_values(frame),
|
||||
context=frame_context_view(run, frame).graph,
|
||||
label=f"subgraph {step.id!r}",
|
||||
)
|
||||
validate_payload_against_schema(
|
||||
@@ -218,7 +218,7 @@ def _finish_subgraph(
|
||||
prepared.workflow,
|
||||
child_scope.committed_state,
|
||||
workflow_input=child_scope.workflow_input,
|
||||
context=frame_context_values(child_frame),
|
||||
context=frame_context_view(run, child_frame).graph,
|
||||
)
|
||||
validate_payload_against_schema(
|
||||
prepared.workflow.output_schema,
|
||||
|
||||
@@ -329,7 +329,12 @@ def validate_foreach_node(
|
||||
input_root_fields: set[str],
|
||||
workflow: Workflow,
|
||||
) -> None:
|
||||
if not is_valid_source_path(node.over, state_root_fields, input_root_fields):
|
||||
# Interim permissive gate: context-rooted `over` paths reach runtime, where
|
||||
# structured ancestry resolution handles them. Task 5 replaces this with
|
||||
# location-aware validation against the consuming node's context schema.
|
||||
if not is_valid_source_path(
|
||||
node.over, state_root_fields, input_root_fields, allow_context=True
|
||||
):
|
||||
report.add(
|
||||
ValidationIssueCode.INVALID_FOREACH_SOURCE,
|
||||
f"nodes[{index}].over",
|
||||
|
||||
Reference in New Issue
Block a user