88from typing import Any
99
1010from ..core .llm import reasoning_call
11- from ..core .models import Event , SimulationConfig , TimelineEvent
11+ from ..core .models import Event , SimulationConfig , TimelineEvent , TimestepUnit
1212
1313logger = logging .getLogger (__name__ )
1414
2323 "evolving = developments over time (crisis, campaign, adoption)"
2424 ),
2525 },
26+ "timestep_unit" : {
27+ "type" : "string" ,
28+ "enum" : ["minute" , "hour" , "day" ],
29+ "description" : (
30+ "The natural time unit for this scenario. Choose based on how "
31+ "the scenario description frames duration: '7 days' → day, "
32+ "'48 hours' → hour, '30 minutes' → minute."
33+ ),
34+ },
35+ "max_timesteps" : {
36+ "type" : "integer" ,
37+ "minimum" : 1 ,
38+ "description" : (
39+ "Total number of timesteps for the simulation. Should match "
40+ "the scenario duration in the chosen unit (e.g. 7 days → 7)."
41+ ),
42+ },
2643 "background_context" : {
2744 "type" : "string" ,
2845 "description" : (
7996 ),
8097 },
8198 },
82- "required" : ["scenario_type" , "background_context" ],
99+ "required" : ["scenario_type" , "timestep_unit" , "max_timesteps" , " background_context" ],
83100}
84101
85102
@@ -107,7 +124,10 @@ def _build_timeline_prompt(
107124 "" ,
108125 "## Simulation Parameters" ,
109126 "" ,
110- f"Duration: { simulation_config .max_timesteps } { simulation_config .timestep_unit .value } s" ,
127+ "Determine the appropriate timestep_unit (minute, hour, or day) and max_timesteps "
128+ "based on the scenario description. If the description mentions a specific duration "
129+ "(e.g. '7 days', '48 hours'), use the matching unit and count. "
130+ "Timeline event timesteps must use the same unit." ,
111131 "" ,
112132 "## Your Task" ,
113133 "" ,
@@ -174,7 +194,7 @@ def generate_timeline(
174194 base_event : Event ,
175195 simulation_config : SimulationConfig ,
176196 timeline_mode : str | None = None ,
177- ) -> tuple [list [TimelineEvent ], str | None ]:
197+ ) -> tuple [list [TimelineEvent ], str | None , SimulationConfig ]:
178198 """Generate timeline events and background context.
179199
180200 Args:
@@ -186,7 +206,7 @@ def generate_timeline(
186206 - "evolving": Multi-event timeline (ASI-style)
187207
188208 Returns:
189- Tuple of (timeline_events, background_context)
209+ Tuple of (timeline_events, background_context, updated_simulation_config )
190210 timeline_events will be empty for static scenarios
191211 """
192212 prompt = _build_timeline_prompt (
@@ -206,12 +226,32 @@ def generate_timeline(
206226
207227 if not response :
208228 logger .warning ("[TIMELINE] LLM returned empty response, using defaults" )
209- return [], None
229+ return [], None , simulation_config
210230
211231 scenario_type = response .get ("scenario_type" , "static" )
212232 background_context = response .get ("background_context" )
213233 raw_events = response .get ("timeline_events" , [])
214234
235+ # Update simulation config with LLM's chosen unit and duration
236+ llm_unit = response .get ("timestep_unit" )
237+ llm_max = response .get ("max_timesteps" )
238+ if llm_unit :
239+ unit_map = {"minute" : TimestepUnit .MINUTE , "hour" : TimestepUnit .HOUR , "day" : TimestepUnit .DAY }
240+ resolved_unit = unit_map .get (llm_unit , simulation_config .timestep_unit )
241+ simulation_config = SimulationConfig (
242+ max_timesteps = llm_max if llm_max else simulation_config .max_timesteps ,
243+ timestep_unit = resolved_unit ,
244+ stop_conditions = simulation_config .stop_conditions ,
245+ seed = simulation_config .seed ,
246+ )
247+ elif llm_max :
248+ simulation_config = SimulationConfig (
249+ max_timesteps = llm_max ,
250+ timestep_unit = simulation_config .timestep_unit ,
251+ stop_conditions = simulation_config .stop_conditions ,
252+ seed = simulation_config .seed ,
253+ )
254+
215255 # Honor explicit mode override
216256 if timeline_mode == "static" :
217257 scenario_type = "static"
@@ -255,4 +295,4 @@ def generate_timeline(
255295 # Sort by timestep
256296 timeline_events .sort (key = lambda te : te .timestep )
257297
258- return timeline_events , background_context
298+ return timeline_events , background_context , simulation_config
0 commit comments