3838 ("no such model" , "Model not found. Check available models for your account." ),
3939 # Rate limiting (without retry-after)
4040 ("rate_limit" , "Rate limited. Consider reducing --max-workers or adding delays." ),
41+ # Timeout
42+ ("timed out" , "Sample timed out. Try --sample-timeout to increase, or reduce --context-length." ),
4143]
4244
4345
@@ -119,6 +121,7 @@ class RunnerConfig:
119121 max_workers : int = 1 # Number of parallel workers (1 = sequential)
120122 progress : str = "auto" # Progress display: "auto", "tqdm", "simple", "none"
121123 progress_callback : ProgressCallback | None = None # Custom progress callback
124+ sample_timeout : int = 300 # Timeout per sample in seconds (default: 5 minutes)
122125 backend_kwargs : dict [str , Any ] = field (default_factory = dict )
123126 environment_kwargs : dict [str , Any ] = field (default_factory = dict )
124127
@@ -157,6 +160,7 @@ def __init__(
157160 max_workers : int = 1 ,
158161 progress : str = "auto" ,
159162 progress_callback : ProgressCallback | None = None ,
163+ sample_timeout : int = 300 ,
160164 ** kwargs ,
161165 ):
162166 """Initialize runner with configuration.
@@ -176,6 +180,7 @@ def __init__(
176180 - "none": No progress output
177181 progress_callback: Custom callback for progress updates.
178182 Signature: (completed, total, sample_result, stats) -> None
183+ sample_timeout: Timeout per sample in seconds (default: 300 = 5 minutes).
179184 **kwargs: Additional backend or environment kwargs.
180185 """
181186 self .config = RunnerConfig (
@@ -188,6 +193,7 @@ def __init__(
188193 max_workers = max_workers ,
189194 progress = progress ,
190195 progress_callback = progress_callback ,
196+ sample_timeout = sample_timeout ,
191197 backend_kwargs = {"model_name" : model , ** kwargs .get ("backend_kwargs" , {})},
192198 environment_kwargs = kwargs .get ("environment_kwargs" , {}),
193199 )
@@ -613,14 +619,24 @@ def _run_sample(
613619 inference_fn : Callable [[BenchmarkSample ], tuple [str , dict [str , Any ]]],
614620 benchmark : Benchmark ,
615621 ) -> SampleResult :
616- """Run a single sample and evaluate."""
622+ """Run a single sample and evaluate with timeout."""
623+ from concurrent .futures import TimeoutError as FuturesTimeoutError
624+
617625 start_time = time .time ()
618626 error = None
619627 prediction = ""
620628 metadata : dict [str , Any ] = {}
629+ timeout = self .config .sample_timeout
621630
622631 try :
623- prediction , metadata = inference_fn (sample )
632+ # Use a thread pool to enforce timeout
633+ with ThreadPoolExecutor (max_workers = 1 ) as executor :
634+ future = executor .submit (inference_fn , sample )
635+ try :
636+ prediction , metadata = future .result (timeout = timeout )
637+ except FuturesTimeoutError :
638+ error = f"Sample timed out after { timeout } s. Try --sample-timeout to increase."
639+ prediction = ""
624640 except Exception as e :
625641 error = str (e )
626642 prediction = ""
0 commit comments