diff --git a/tests/test_tool_date_enforcement.py b/tests/test_tool_date_enforcement.py index 584eb01a9..55355823d 100644 --- a/tests/test_tool_date_enforcement.py +++ b/tests/test_tool_date_enforcement.py @@ -159,6 +159,15 @@ def test_a_start_date_that_is_not_a_date_is_sent_back_to_the_model(tool): assert "YYYY-MM-DD" in out and "start_date" in out +@pytest.mark.unit +def test_a_window_that_ends_before_it_starts_is_sent_back_to_the_model(): + # A reversed window reached the vendor, which then reported no data for it. + with mock.patch.object(tools, "route_to_vendor", return_value="ok") as routed: + out = tools.get_stock_data.func("NVDA", "2026-08-12", "2026-08-01", trade_date=TRADE_DATE) + assert not routed.called + assert "start_date" in out and "end_date" in out + + @pytest.mark.unit def test_a_window_whose_start_is_not_a_date_is_refused(): with pytest.raises(ValueError, match="start_date"): diff --git a/tradingagents/dataflows/date_window.py b/tradingagents/dataflows/date_window.py index 9d9083ff4..f9bc70758 100644 --- a/tradingagents/dataflows/date_window.py +++ b/tradingagents/dataflows/date_window.py @@ -95,11 +95,14 @@ def as_of_window(start_date: str, end_date: str, trade_date: str) -> tuple[str, A window wholly after the run date keeps its length and moves back to end there. An unreadable end reads as the run date, but no window can be guessed from an - unreadable start, so it raises ValueError for the caller to send back (#1476). + unreadable start or from a start after the end, so those raise ValueError for + the caller to send back (#1476). """ start, old_end = _parse(start_date), _parse(end_date) if start is None: raise ValueError(f"start_date {start_date!r} is not a date; give it as YYYY-MM-DD") + if old_end is not None and start > old_end: + raise ValueError(f"start_date {start_date} is after end_date {end_date}; give the earlier date first") end = as_of(end_date, trade_date) end_dt = _parse(end) if end_dt is None or end_dt == old_end or start <= end_dt: