From 327d991860a8a7809e7cf95d0f8084cd196a4334 Mon Sep 17 00:00:00 2001 From: Joao Moura Date: Mon, 6 Jul 2026 17:01:17 -0700 Subject: [PATCH] fix(cli): forward reserved `id` input to flow kickoff; ruff format - Cursor: the schema filter treated an `id` key in --inputs as unknown and dropped it, regressing kickoff's persistence-restore support (inputs["id"]). Let `id` pass through untouched (test: reserved_id_input_is_forwarded). - Apply ruff format to run_declarative_flow.py (fixes the lint-run `ruff format --check` step). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh --- lib/cli/src/crewai_cli/run_declarative_flow.py | 9 ++++++--- lib/cli/tests/test_run_declarative_flow.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/cli/src/crewai_cli/run_declarative_flow.py b/lib/cli/src/crewai_cli/run_declarative_flow.py index e3f3abad1..d3c58c1cf 100644 --- a/lib/cli/src/crewai_cli/run_declarative_flow.py +++ b/lib/cli/src/crewai_cli/run_declarative_flow.py @@ -89,10 +89,11 @@ def _resolve_flow_inputs(flow: Any, provided: dict[str, Any]) -> dict[str, Any]: defaults = _flow_state_defaults(flow) # Unknown keys are almost always typos — warn and drop them (they'd fail - # structured-state validation at kickoff anyway). + # structured-state validation at kickoff anyway). ``id`` is a reserved + # kickoff key (persistence restore), so let it through untouched. collected: dict[str, Any] = {} for key, value in provided.items(): - if key in properties: + if key in properties or key == "id": collected[key] = value continue suggestion = _closest_key(key, properties) @@ -112,7 +113,9 @@ def _resolve_flow_inputs(flow: Any, provided: dict[str, Any]) -> dict[str, Any]: for name in missing: description = (properties.get(name) or {}).get("description") suffix = f" — {description}" if description else "" - click.secho(f" Missing required input '{name}'{suffix}", fg="red", err=True) + click.secho( + f" Missing required input '{name}'{suffix}", fg="red", err=True + ) raise SystemExit(1) _validate_flow_inputs(state_model, {**defaults, **collected}) diff --git a/lib/cli/tests/test_run_declarative_flow.py b/lib/cli/tests/test_run_declarative_flow.py index 396578cd6..3364135a1 100644 --- a/lib/cli/tests/test_run_declarative_flow.py +++ b/lib/cli/tests/test_run_declarative_flow.py @@ -335,3 +335,19 @@ def test_validates_input_types_before_kickoff( run_declarative_flow_module.run_declarative_flow(str(path), '{"count":"nope"}') assert "Invalid input 'count'" in capsys.readouterr().err + + +def test_reserved_id_input_is_forwarded_not_dropped( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + # `id` is a reserved kickoff key (persistence restore); it must pass through + # instead of being flagged as an unknown key and dropped. + path = _write(tmp_path, REQUIRED_FLOW_YAML) + + run_declarative_flow_module.run_declarative_flow( + str(path), '{"id":"run-123","prospect_email":"a@b.com"}' + ) + + captured = capsys.readouterr() + assert captured.out == "a@b.com\n" + assert "Ignoring unknown input 'id'" not in captured.err