feat(workflows): allow resume to accept updated workflow inputs (#2815)

`workflow resume` now accepts `--input key=value` (the same flag and
parsing as `workflow run`, via a shared `_parse_input_values` helper).
Supplied values are merged over the run's persisted inputs and
re-resolved through the existing typed-validation path
(`_resolve_inputs`), so a resumed/re-run step sees the updated inputs
and ill-typed values fail fast. Keys not supplied keep their persisted
values; resuming without `--input` is unchanged. Reference docs updated.

Distinct from #2405 (file-reference inputs at run time): this is about
supplying inputs at resume time, reusing the existing input model.

Closes #2812.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huy Do
2026-06-04 00:04:07 +07:00
committed by GitHub
parent 1f9eaf3ff3
commit 1732b9b62e
4 changed files with 167 additions and 11 deletions

View File

@@ -507,8 +507,19 @@ class WorkflowEngine:
state.save()
return state
def resume(self, run_id: str) -> RunState:
"""Resume a paused or failed workflow run."""
def resume(
self,
run_id: str,
inputs: dict[str, Any] | None = None,
) -> RunState:
"""Resume a paused or failed workflow run.
When ``inputs`` is provided, the values are merged over the run's
persisted inputs and re-resolved through the same typed validation
path used by :meth:`execute`, so the resumed step sees updated
workflow inputs. Keys not supplied keep their persisted values; an
empty/``None`` ``inputs`` leaves the run's inputs unchanged.
"""
state = RunState.load(run_id, self.project_root)
if state.status not in (RunStatus.PAUSED, RunStatus.FAILED):
msg = f"Cannot resume run {run_id!r} with status {state.status.value!r}."
@@ -524,6 +535,12 @@ class WorkflowEngine:
else:
definition = self.load_workflow(state.workflow_id)
# Merge any newly-supplied inputs over the persisted ones and
# re-validate through the same typing path as the initial run.
if inputs:
merged = {**state.inputs, **inputs}
state.inputs = self._resolve_inputs(definition, merged)
# Restore context
context = StepContext(
inputs=state.inputs,