From b01669f9aa1487a35c064c396debfb7a51b2c859 Mon Sep 17 00:00:00 2001 From: hemanth-openai Date: Fri, 6 Feb 2026 21:58:46 -0800 Subject: [PATCH] fix: restore dummy support and timeout cap --- src/gabriel/api.py | 159 +++++------------------------- src/gabriel/tasks/bucket.py | 8 -- src/gabriel/tasks/classify.py | 4 - src/gabriel/tasks/codify.py | 10 +- src/gabriel/tasks/compare.py | 4 - src/gabriel/tasks/debias.py | 13 ++- src/gabriel/tasks/deduplicate.py | 2 - src/gabriel/tasks/deidentify.py | 4 - src/gabriel/tasks/discover.py | 14 +-- src/gabriel/tasks/extract.py | 4 - src/gabriel/tasks/filter.py | 2 - src/gabriel/tasks/ideate.py | 5 - src/gabriel/tasks/merge.py | 2 - src/gabriel/tasks/rank.py | 15 --- src/gabriel/tasks/rate.py | 4 - src/gabriel/tasks/seed.py | 7 -- src/gabriel/tasks/whatever.py | 2 - src/gabriel/utils/openai_utils.py | 11 ++- 18 files changed, 40 insertions(+), 230 deletions(-) diff --git a/src/gabriel/api.py b/src/gabriel/api.py index 1796e29..c6447a1 100644 --- a/src/gabriel/api.py +++ b/src/gabriel/api.py @@ -81,11 +81,9 @@ async def rate( n_runs: int = 1, n_attributes_per_run: int = 8, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "ratings.csv", modality: str = "text", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, search_context_size: str = "medium", template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, @@ -125,16 +123,14 @@ async def rate( reset_files: When ``True`` existing outputs in ``save_dir`` are ignored and regenerated. - use_dummy: - If ``True`` use deterministic dummy responses for offline testing. file_name: Basename (without the automatic ``_raw_responses`` suffix) for saved artifacts. modality: One of ``"text"``, ``"entity"``, ``"web"``, ``"image"``, ``"audio"``, or ``"pdf"`` to control how inputs are packaged into prompts. - reasoning_effort, reasoning_summary: - Optional OpenAI metadata that tunes reasoning depth and summary capture. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. search_context_size: Size hint forwarded to web-search capable models. template_path: @@ -166,11 +162,9 @@ async def rate( n_parallels=n_parallels, n_runs=n_runs, n_attributes_per_run=n_attributes_per_run, - use_dummy=use_dummy, additional_instructions=additional_instructions, modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, search_context_size=search_context_size, **cfg_kwargs, ) @@ -194,11 +188,9 @@ async def extract( n_runs: int = 1, n_attributes_per_run: int = 8, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "extraction.csv", modality: str = "entity", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, types: Optional[Dict[str, Any]] = None, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, @@ -235,16 +227,13 @@ async def extract( split into multiple prompts when this threshold is exceeded. reset_files: When ``True`` forces regeneration of outputs in ``save_dir``. - use_dummy: - If ``True`` return deterministic dummy outputs instead of real API - calls. file_name: CSV name used when saving extraction results. modality: Indicates whether the content is ``"entity"`` text or another modality supported by the templates. - reasoning_effort, reasoning_summary: - Optional OpenAI metadata for reasoning depth and summarisation. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. types: Optional mapping of attribute names to explicit Python types for stronger downstream typing. @@ -277,11 +266,9 @@ async def extract( n_parallels=n_parallels, n_runs=n_runs, n_attributes_per_run=n_attributes_per_run, - use_dummy=use_dummy, additional_instructions=additional_instructions, modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, **cfg_kwargs, ) return await Extract(cfg, template_path=template_path).run( @@ -299,18 +286,15 @@ async def seed( *, save_dir: str, file_name: str = "seed_entities.csv", - model: str = "gpt-5.1", + model: str = "gpt-5.2", n_parallels: int = 650, num_entities: int = 1000, entities_per_generation: int = 50, entity_batch_frac: float = 0.25, existing_entities_cap: int = 100, - use_dummy: bool = False, deduplicate: bool = False, deduplicate_sample_seed: int = 42, reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, - max_timeout: Optional[float] = None, template_path: Optional[str] = None, existing_entities: Optional[List[str]] = None, reset_files: bool = False, @@ -345,8 +329,6 @@ async def seed( Fraction of generated entities to keep per batch before deduplication. existing_entities_cap: Maximum number of prior entities to consider when avoiding duplicates. - use_dummy: - If ``True`` emit deterministic dummy seeds for offline testing. deduplicate: When ``True`` over-generate and apply a shallow deduplication pass before returning results. @@ -354,9 +336,7 @@ async def seed( Random seed used when sampling a deterministic subset after deduplication. reasoning_effort: - Optional OpenAI reasoning control. - max_timeout: - Optional timeout in seconds for each API call. + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. template_path: Optional Jinja2 template override for the seeding prompt. existing_entities: @@ -393,12 +373,9 @@ async def seed( entities_per_generation=entities_per_generation, entity_batch_frac=entity_batch_frac, existing_entities_cap=existing_entities_cap, - use_dummy=use_dummy, deduplicate=deduplicate, deduplicate_sample_seed=deduplicate_sample_seed, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, - max_timeout=max_timeout, ) task = Seed(cfg, template_path=template_path) return await task.run( @@ -426,11 +403,9 @@ async def classify( n_attributes_per_run: int = 8, min_frequency: float = 0.6, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "classify_responses.csv", modality: str = "text", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, search_context_size: str = "medium", template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, @@ -473,14 +448,12 @@ async def classify( Minimum label frequency required to keep a label during aggregation. reset_files: When ``True`` overwrite any existing outputs in ``save_dir``. - use_dummy: - If ``True`` return deterministic dummy outputs for offline testing. file_name: Basename for saved classification CSVs. modality: Indicates the content modality for prompt rendering. reasoning_effort: - Optional OpenAI reasoning control. + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. search_context_size: Context size hint forwarded to the Responses API. template_path: @@ -514,10 +487,8 @@ async def classify( n_attributes_per_run=n_attributes_per_run, min_frequency=min_frequency, additional_instructions=additional_instructions or "", - use_dummy=use_dummy, modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, search_context_size=search_context_size, **cfg_kwargs, ) @@ -552,9 +523,7 @@ async def ideate( recursive_rate_first_round: bool = True, additional_instructions: Optional[str] = None, web_search: bool = False, - use_dummy: bool = False, reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, reset_files: bool = False, generation_kwargs: Optional[Dict[str, Any]] = None, rank_config_updates: Optional[Dict[str, Any]] = None, @@ -607,10 +576,8 @@ async def ideate( Extra guidance injected into prompts for both generation and ranking. web_search: Enable web search augmentation for generation. - use_dummy: - When ``True`` perform deterministic offline runs. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. reset_files: Force regeneration of outputs in ``save_dir``. *_config_updates, *_run_kwargs: @@ -654,9 +621,7 @@ async def ideate( recursive_rate_first_round=recursive_rate_first_round, additional_instructions=additional_instructions, web_search=web_search, - use_dummy=use_dummy, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, seed_deduplicate=seed_deduplicate, ) if attributes is not None: @@ -712,12 +677,10 @@ async def deidentify( mapping_column: Optional[str] = None, model: str = "gpt-5-mini", n_parallels: int = 650, - use_dummy: bool = False, file_name: str = "deidentified.csv", max_words_per_call: int = 7500, additional_instructions: Optional[str] = None, reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, n_passes: int = 1, use_existing_mappings_only: bool = False, template_path: Optional[str] = None, @@ -748,16 +711,14 @@ async def deidentify( Model name used to perform the deidentification. n_parallels: Maximum concurrent requests. - use_dummy: - When ``True`` produce deterministic dummy replacements for testing. file_name: CSV filename used when persisting deidentified text. max_words_per_call: Chunk size control for long passages. additional_instructions: Extra guidance appended to the prompt. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. n_passes: Number of deidentification passes to run over each passage. use_existing_mappings_only: @@ -789,11 +750,9 @@ async def deidentify( file_name=file_name, model=model, n_parallels=n_parallels, - use_dummy=use_dummy, max_words_per_call=max_words_per_call, additional_instructions=additional_instructions, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, n_passes=n_passes, use_existing_mappings_only=use_existing_mappings_only, **cfg_kwargs, @@ -823,12 +782,10 @@ async def rank( learning_rate: float = 0.1, n_parallels: int = 650, n_attributes_per_run: int = 8, - use_dummy: bool = False, file_name: str = "rankings", reset_files: bool = False, modality: str = "text", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, template_path: Optional[str] = None, recursive: bool = False, recursive_fraction: float = 1.0 / 3.0, @@ -879,16 +836,14 @@ async def rank( n_attributes_per_run: Maximum number of attributes to compare per prompt. Attributes are batched across prompts when this cap is exceeded. - use_dummy: - When ``True`` run deterministic offline ranking. file_name: Base filename for saved rankings (without extension). reset_files: Force regeneration of any existing outputs in ``save_dir``. modality: Content modality forwarded to the prompt. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. template_path: Path to a custom ranking prompt template. recursive_*: @@ -935,13 +890,11 @@ async def rank( model=model, n_parallels=n_parallels, n_attributes_per_run=n_attributes_per_run, - use_dummy=use_dummy, save_dir=save_dir, file_name=file_name, additional_instructions=additional_instructions or "", modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, recursive=recursive, recursive_fraction=recursive_fraction, recursive_min_remaining=recursive_min_remaining, @@ -1005,12 +958,8 @@ async def codify( file_name: str = "coding_results.csv", reset_files: bool = False, debug_print: bool = False, - use_dummy: bool = False, reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, modality: str = "text", - json_mode: bool = True, - max_timeout: Optional[float] = None, n_rounds: int = 2, completion_classifier_instructions: Optional[str] = None, template_path: Optional[str] = None, @@ -1051,16 +1000,10 @@ async def codify( When ``True`` regenerate outputs even if files exist. debug_print: Enable verbose logging of prompts and responses. - use_dummy: - Use deterministic dummy outputs for testing. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. modality: Content modality hint (text, entity, etc.). - json_mode: - Request JSON-mode responses where supported. - max_timeout: - Optional per-call timeout. n_rounds: Number of completion passes to refine codes. completion_classifier_instructions: @@ -1095,12 +1038,8 @@ async def codify( max_words_per_call=max_words_per_call, max_categories_per_call=max_categories_per_call, debug_print=debug_print, - use_dummy=use_dummy, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, modality=modality, - json_mode=json_mode, - max_timeout=max_timeout, n_rounds=n_rounds, completion_classifier_instructions=completion_classifier_instructions, **cfg_kwargs, @@ -1136,7 +1075,6 @@ async def paraphrase( reasoning_effort: Optional[str] = None, search_context_size: str = "medium", file_name: str = "paraphrase_responses.csv", - use_dummy: bool = False, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, @@ -1182,13 +1120,11 @@ async def paraphrase( json_mode: Whether to request JSON responses. reasoning_effort: - Optional OpenAI reasoning control. + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. search_context_size: Web search context size when ``modality="web"``. file_name: CSV filename for saved paraphrases. - use_dummy: - Produce deterministic dummy paraphrases. template_path: Custom template path to override the default paraphrase prompt. response_fn: @@ -1224,7 +1160,6 @@ async def paraphrase( modality=modality, n_parallels=n_parallels, search_context_size=search_context_size, - use_dummy=use_dummy, reasoning_effort=reasoning_effort, **cfg_kwargs, ) @@ -1249,11 +1184,9 @@ async def compare( n_parallels: int = 650, n_runs: int = 1, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "comparison_responses.csv", modality: str = "text", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, @@ -1285,14 +1218,12 @@ async def compare( Number of repeated comparisons to gather per pair. reset_files: When ``True`` regenerate results regardless of existing files. - use_dummy: - If ``True`` return deterministic dummy comparison outputs. file_name: CSV filename for saved comparison responses. modality: Content modality hint for prompt rendering. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. template_path: Custom template override for comparison prompts. response_fn: @@ -1321,12 +1252,10 @@ async def compare( model=model, n_parallels=n_parallels, n_runs=n_runs, - use_dummy=use_dummy, differentiate=differentiate, additional_instructions=additional_instructions or "", modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, **cfg_kwargs, ) return await Compare(cfg, template_path=template_path).run( @@ -1348,12 +1277,10 @@ async def bucket( model: str = "gpt-5-mini", n_parallels: int = 650, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "bucket_definitions.csv", bucket_count: int = 10, differentiate: bool = False, reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, @@ -1381,16 +1308,14 @@ async def bucket( Maximum number of concurrent bucket definition calls. reset_files: When ``True`` regenerate outputs despite existing files. - use_dummy: - Return deterministic dummy buckets for offline testing. file_name: Filename for saved bucket definitions. bucket_count: Target number of buckets to generate. differentiate: Whether to encourage distinctive bucket descriptions. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. template_path: Custom template path for bucket prompts. response_fn: @@ -1419,11 +1344,9 @@ async def bucket( file_name=file_name, model=model, n_parallels=n_parallels, - use_dummy=use_dummy, additional_instructions=additional_instructions, differentiate=differentiate, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, **cfg_kwargs, ) return await Bucket(cfg, template_path=template_path).run( @@ -1445,6 +1368,7 @@ async def discover( additional_instructions: Optional[str] = None, model: str = "gpt-5-mini", n_parallels: int = 650, + reset_files: bool = False, n_runs: int = 1, min_frequency: float = 0.6, bucket_count: int = 10, @@ -1457,11 +1381,8 @@ async def discover( next_round_frac: float = 0.25, top_k_per_round: int = 1, raw_term_definitions: bool = True, - use_dummy: bool = False, modality: str = "text", reasoning_effort: Optional[str] = None, - reasoning_summary: Optional[str] = None, - reset_files: bool = False, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, **cfg_kwargs, @@ -1506,12 +1427,10 @@ async def discover( Controls for carrying top-performing terms into subsequent rounds. raw_term_definitions: Whether to keep raw label definitions in the outputs. - use_dummy: - If ``True`` perform deterministic offline discovery. modality: Content modality hint forwarded to downstream tasks. - reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + reasoning_effort: + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. reset_files: When ``True`` regenerate all discovery artifacts. response_fn: @@ -1554,10 +1473,8 @@ async def discover( next_round_frac=next_round_frac, top_k_per_round=top_k_per_round, raw_term_definitions=raw_term_definitions, - use_dummy=use_dummy, modality=modality, reasoning_effort=reasoning_effort, - reasoning_summary=reasoning_summary, **cfg_kwargs, ) return await Discover(cfg).run( @@ -1583,11 +1500,9 @@ async def deduplicate( n_parallels: int = 650, n_runs: int = 3, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "deduplicate_responses.csv", use_embeddings: bool = True, group_size: int = 500, - max_timeout: Optional[float] = None, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, @@ -1621,16 +1536,12 @@ async def deduplicate( Number of passes to run; helps stabilise duplicate detection. reset_files: When ``True`` regenerate outputs regardless of existing files. - use_dummy: - Return deterministic dummy outputs for offline testing. file_name: CSV filename for saved deduplication responses. use_embeddings: Whether to use embedding-based prefiltering prior to model calls. group_size: Number of passages to evaluate per batch during deduplication. - max_timeout: - Optional timeout per API call. template_path: Custom template override for deduplication prompts. response_fn: @@ -1661,8 +1572,6 @@ async def deduplicate( model=model, n_parallels=n_parallels, n_runs=n_runs, - use_dummy=use_dummy, - max_timeout=max_timeout, additional_instructions=additional_instructions, use_embeddings=use_embeddings, group_size=group_size, @@ -1693,7 +1602,6 @@ async def merge( n_parallels: int = 650, n_runs: int = 1, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "merge_responses.csv", use_embeddings: bool = True, short_list_len: int = 16, @@ -1736,8 +1644,6 @@ async def merge( Number of repeated comparisons per candidate. reset_files: When ``True`` regenerate outputs even if files exist. - use_dummy: - If ``True`` return deterministic dummy matches. file_name: CSV filename for saved merge responses. use_embeddings: @@ -1783,7 +1689,6 @@ async def merge( model=model, n_parallels=n_parallels, n_runs=n_runs, - use_dummy=use_dummy, additional_instructions=additional_instructions, use_embeddings=use_embeddings, short_list_len=short_list_len, @@ -1823,9 +1728,7 @@ async def filter( model: str = "gpt-5-nano", n_parallels: int = 650, reset_files: bool = False, - use_dummy: bool = False, file_name: str = "filter_responses.csv", - max_timeout: Optional[float] = None, template_path: Optional[str] = None, response_fn: Optional[Callable[..., Awaitable[Any]]] = None, get_all_responses_fn: Optional[Callable[..., Awaitable[pd.DataFrame]]] = None, @@ -1865,12 +1768,8 @@ async def filter( Maximum number of concurrent filtering calls. reset_files: When ``True`` regenerate outputs even if files exist. - use_dummy: - Return deterministic dummy outputs instead of real API responses. file_name: CSV filename for saved filter responses. - max_timeout: - Optional per-call timeout. template_path: Custom prompt template path. response_fn: @@ -1904,8 +1803,6 @@ async def filter( n_runs=n_runs, threshold=threshold, additional_instructions=additional_instructions or "", - use_dummy=use_dummy, - max_timeout=max_timeout, **cfg_kwargs, ) return await Filter(cfg, template_path=template_path).run( @@ -1939,7 +1836,6 @@ async def debias( remaining_signal: bool = True, max_words_per_call: Optional[int] = 1000, n_rounds: Optional[int] = 3, - use_dummy: bool = False, robust_regression: bool = True, random_seed: int = 12345, verbose: bool = True, @@ -1997,8 +1893,6 @@ async def debias( configures the codify task's chunk size, while ``n_rounds`` controls the number of completion passes run by codify and any downstream paraphrasing steps. Defaults to 3 when not explicitly provided. - use_dummy: - If ``True`` run deterministic offline debiasing. robust_regression: Whether to use robust regression when estimating bias coefficients. random_seed: @@ -2067,7 +1961,6 @@ async def debias( measurement_kwargs=measurement_kwargs, removal_kwargs=removal_kwargs, remaining_signal=remaining_signal, - use_dummy=use_dummy, robust_regression=robust_regression, random_seed=random_seed, verbose=verbose, @@ -2096,7 +1989,6 @@ async def whatever( web_search_filters: Optional[Dict[str, Any]] = None, search_context_size: str = "medium", n_parallels: int = 650, - use_dummy: bool = False, reset_files: bool = False, return_original_columns: bool = True, drop_prompts: bool = True, @@ -2145,8 +2037,6 @@ async def whatever( Context size hint for web-search capable models. n_parallels: Maximum concurrent response requests. - use_dummy: - If ``True`` return deterministic dummy responses. reset_files: When ``True`` regenerate outputs even if files already exist. return_original_columns: @@ -2156,7 +2046,7 @@ async def whatever( When ``True`` and merging back onto ``df``, drop the prompt column before saving/returning the result. reasoning_effort, reasoning_summary: - Optional OpenAI reasoning controls. + Controls how intensely the model reasons (none/low/medium/high). Higher is smarter but slower. response_fn: Optional callable forwarded to :func:`gabriel.utils.openai_utils.get_all_responses` that replaces the per-prompt model invocation. Ignored when @@ -2216,7 +2106,6 @@ async def whatever( web_search_filters=web_search_filters, search_context_size=search_context_size, n_parallels=n_parallels, - use_dummy=use_dummy, reasoning_effort=reasoning_effort, reasoning_summary=reasoning_summary, ) diff --git a/src/gabriel/tasks/bucket.py b/src/gabriel/tasks/bucket.py index 6555187..9e8ddb6 100644 --- a/src/gabriel/tasks/bucket.py +++ b/src/gabriel/tasks/bucket.py @@ -30,7 +30,6 @@ class BucketConfig: model: str = "gpt-5-mini" n_parallels: int = 650 use_dummy: bool = False - max_timeout: Optional[float] = None additional_instructions: Optional[str] = None differentiate: bool = False n_terms_per_prompt: int = 250 @@ -40,7 +39,6 @@ class BucketConfig: top_k_per_round: int = 1 raw_term_definitions: bool = True reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None def __post_init__(self) -> None: if self.additional_instructions is not None: @@ -247,11 +245,9 @@ def persist_state() -> None: model=self.cfg.model, save_path=os.path.join(self.cfg.save_dir, "bucket_generation.csv"), use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) if not isinstance(gen_df, pd.DataFrame): @@ -336,11 +332,9 @@ def _vote_prompts(opts: List[str], selected: List[str], tag: str): self.cfg.save_dir, f"vote_reduce{round_idx}.csv" ), use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) vote_map = dict(zip(vote_df.Identifier, vote_df.Response)) @@ -385,11 +379,9 @@ def _vote_prompts(opts: List[str], selected: List[str], tag: str): self.cfg.save_dir, f"vote_final{loop_idx}.csv" ), use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) vote_map = dict(zip(vote_df.Identifier, vote_df.Response)) diff --git a/src/gabriel/tasks/classify.py b/src/gabriel/tasks/classify.py index 8cb9409..15fd51a 100644 --- a/src/gabriel/tasks/classify.py +++ b/src/gabriel/tasks/classify.py @@ -57,11 +57,9 @@ class ClassifyConfig: min_frequency: float = 0.6 additional_instructions: Optional[str] = None use_dummy: bool = False - max_timeout: Optional[float] = None modality: str = "text" n_attributes_per_run: int = 8 reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None differentiate: bool = False circle_first: Optional[bool] = None search_context_size: str = "medium" @@ -436,9 +434,7 @@ async def run( json_mode=self.cfg.modality != "audio", model=self.cfg.model, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, print_example_prompt=True, **kwargs, ) diff --git a/src/gabriel/tasks/codify.py b/src/gabriel/tasks/codify.py index 4b8b0b4..e586393 100644 --- a/src/gabriel/tasks/codify.py +++ b/src/gabriel/tasks/codify.py @@ -42,10 +42,7 @@ class CodifyConfig: debug_print: bool = False use_dummy: bool = False reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None modality: str = "text" - json_mode: bool = True - max_timeout: Optional[float] = None n_rounds: int = 2 # Total Codify passes including the initial run; set to 1 to skip completion sweeps completion_classifier_instructions: Optional[str] = None completion_max_rounds: InitVar[Optional[int]] = None @@ -760,13 +757,11 @@ async def _gather_iteration( n_parallels=self.cfg.n_parallels, save_path=os.path.join(self.cfg.save_dir, self._iteration_file_name(iteration)), reset_files=reset_files, - use_dummy=self.cfg.use_dummy, - json_mode=self.cfg.json_mode, + json_mode=True, model=self.cfg.model, - max_timeout=self.cfg.max_timeout, + use_dummy=self.cfg.use_dummy, print_example_prompt=True, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, prompt_images=prompt_images or None, prompt_audio=prompt_audio or None, prompt_pdfs=prompt_pdfs or None, @@ -878,7 +873,6 @@ async def _classify_remaining( modality=self.cfg.modality, n_attributes_per_run=self.cfg.max_categories_per_call, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, ) classifier = Classify(classify_cfg) diff --git a/src/gabriel/tasks/compare.py b/src/gabriel/tasks/compare.py index 9f7b8fb..fecc374 100644 --- a/src/gabriel/tasks/compare.py +++ b/src/gabriel/tasks/compare.py @@ -30,12 +30,10 @@ class CompareConfig: n_parallels: int = 650 n_runs: int = 1 use_dummy: bool = False - max_timeout: Optional[float] = None differentiate: bool = True additional_instructions: Optional[str] = None modality: str = "text" reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None circle_first: Optional[bool] = None def __post_init__(self) -> None: @@ -204,11 +202,9 @@ async def run( model=self.cfg.model, save_path=csv_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=self.cfg.modality != "audio", reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) if not isinstance(df_resp_all, pd.DataFrame): diff --git a/src/gabriel/tasks/debias.py b/src/gabriel/tasks/debias.py index 5436043..037306d 100644 --- a/src/gabriel/tasks/debias.py +++ b/src/gabriel/tasks/debias.py @@ -261,7 +261,6 @@ class DebiasConfig: n_parallels: int = 650 measurement_kwargs: Dict[str, Any] = field(default_factory=dict) removal_kwargs: Dict[str, Any] = field(default_factory=dict) - use_dummy: bool = False robust_regression: bool = True random_seed: int = 12345 verbose: bool = True @@ -612,7 +611,7 @@ async def _run_measurement( save_dir=save_dir, model=kwargs.pop("model", default_model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Rate(cfg, template_path=template_path) @@ -628,7 +627,7 @@ async def _run_measurement( save_dir=save_dir, model=kwargs.pop("model", default_model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Classify(cfg, template_path=template_path) @@ -644,7 +643,7 @@ async def _run_measurement( save_dir=save_dir, model=kwargs.pop("model", default_model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Extract(cfg, template_path=template_path) @@ -660,7 +659,7 @@ async def _run_measurement( save_dir=save_dir, model=kwargs.pop("model", default_model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Rank(cfg, template_path=template_path) @@ -794,7 +793,7 @@ async def _prepare_codify_variants( save_dir=save_dir, model=kwargs.pop("model", self.cfg.model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Codify(cfg) @@ -872,7 +871,7 @@ async def _prepare_paraphrase_variant( save_dir=save_dir, model=kwargs.pop("model", self.cfg.model), n_parallels=kwargs.pop("n_parallels", self.cfg.n_parallels), - use_dummy=kwargs.pop("use_dummy", self.cfg.use_dummy), + use_dummy=kwargs.pop("use_dummy", False), **kwargs, ) runner = Paraphrase(cfg) diff --git a/src/gabriel/tasks/deduplicate.py b/src/gabriel/tasks/deduplicate.py index 6665b19..fd7bf62 100644 --- a/src/gabriel/tasks/deduplicate.py +++ b/src/gabriel/tasks/deduplicate.py @@ -33,7 +33,6 @@ class DeduplicateConfig: n_parallels: int = 650 n_runs: int = 3 use_dummy: bool = False - max_timeout: Optional[float] = None additional_instructions: Optional[str] = None use_embeddings: bool = True group_size: int = 500 @@ -182,7 +181,6 @@ async def _run_once( model=self.cfg.model, save_path=save_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files, **kwargs, diff --git a/src/gabriel/tasks/deidentify.py b/src/gabriel/tasks/deidentify.py index 9452fb5..40229d6 100644 --- a/src/gabriel/tasks/deidentify.py +++ b/src/gabriel/tasks/deidentify.py @@ -29,11 +29,9 @@ class DeidentifyConfig: save_dir: str = "deidentify" file_name: str = "deidentified.csv" use_dummy: bool = False - max_timeout: Optional[float] = None max_words_per_call: int = 7500 additional_instructions: Optional[str] = None reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None n_passes: int = 1 use_existing_mappings_only: bool = False @@ -269,10 +267,8 @@ async def run( model=self.cfg.model, save_path=str(save_path), use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, reset_files=reset_files, **kwargs, ) diff --git a/src/gabriel/tasks/discover.py b/src/gabriel/tasks/discover.py index 488179a..68e7695 100644 --- a/src/gabriel/tasks/discover.py +++ b/src/gabriel/tasks/discover.py @@ -41,8 +41,6 @@ class DiscoverConfig: top_k_per_round: int = 1 raw_term_definitions: bool = True reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None - max_timeout: Optional[float] = None def __post_init__(self) -> None: if self.additional_instructions is not None: @@ -201,8 +199,6 @@ async def run( debug_print=False, use_dummy=self.cfg.use_dummy, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, - max_timeout=self.cfg.max_timeout, ) coder = Codify(coder_cfg) codify_df = await coder.run( @@ -237,12 +233,10 @@ async def run( model=self.cfg.model, n_parallels=self.cfg.n_parallels, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, differentiate=self.cfg.differentiate, additional_instructions=self.cfg.additional_instructions, modality=self.cfg.modality, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, ) cmp = Compare(cmp_cfg) compare_df = await cmp.run( @@ -287,8 +281,6 @@ async def run( top_k_per_round=self.cfg.top_k_per_round, raw_term_definitions=self.cfg.raw_term_definitions, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, - max_timeout=self.cfg.max_timeout, ) buck = Bucket(buck_cfg) bucket_df = await buck.run( @@ -318,11 +310,9 @@ async def run( "use_dummy": self.cfg.use_dummy, "modality": self.cfg.modality, "reasoning_effort": self.cfg.reasoning_effort, - "reasoning_summary": self.cfg.reasoning_summary, "n_attributes_per_run": 8, "differentiate": True, "additional_instructions": self.cfg.additional_instructions or "", - "max_timeout": self.cfg.max_timeout, } def swap_cs(text: str) -> str: @@ -480,13 +470,11 @@ def derive_base_from_combined( n_parallels=self.cfg.n_parallels, n_runs=self.cfg.n_runs, min_frequency=self.cfg.min_frequency, - additional_instructions=self.cfg.additional_instructions or "", use_dummy=self.cfg.use_dummy, + additional_instructions=self.cfg.additional_instructions or "", modality=self.cfg.modality, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, n_attributes_per_run=8, - max_timeout=self.cfg.max_timeout, ) clf = Classify(clf_cfg) classify_result = await clf.run( diff --git a/src/gabriel/tasks/extract.py b/src/gabriel/tasks/extract.py index 063365d..4dcbc38 100644 --- a/src/gabriel/tasks/extract.py +++ b/src/gabriel/tasks/extract.py @@ -32,12 +32,10 @@ class ExtractConfig: n_parallels: int = 650 n_runs: int = 1 use_dummy: bool = False - max_timeout: Optional[float] = None additional_instructions: Optional[str] = None modality: str = "entity" n_attributes_per_run: int = 8 reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None def __post_init__(self) -> None: if self.additional_instructions is not None: @@ -306,11 +304,9 @@ async def run( model=self.cfg.model, save_path=csv_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=self.cfg.modality != "audio", reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) if not isinstance(df_resp_all, pd.DataFrame): diff --git a/src/gabriel/tasks/filter.py b/src/gabriel/tasks/filter.py index 61db424..ae5e2d6 100644 --- a/src/gabriel/tasks/filter.py +++ b/src/gabriel/tasks/filter.py @@ -30,7 +30,6 @@ class FilterConfig: threshold: float = 0.5 additional_instructions: Optional[str] = None use_dummy: bool = False - max_timeout: Optional[float] = None fix_json_with_llm: bool = False json_fix_timeout: Optional[float] = 60.0 @@ -113,7 +112,6 @@ async def run( model=self.cfg.model, save_path=save_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files, **kwargs, diff --git a/src/gabriel/tasks/ideate.py b/src/gabriel/tasks/ideate.py index dc4e565..a091b43 100644 --- a/src/gabriel/tasks/ideate.py +++ b/src/gabriel/tasks/ideate.py @@ -80,7 +80,6 @@ class IdeateConfig: use_dummy: bool = False web_search: bool = False reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None use_seed_entities: bool = True seed_num_entities: Optional[int] = None seed_entities_per_generation: Optional[int] = None @@ -305,7 +304,6 @@ async def _generate_reports( reset_files=reset_files, use_dummy=self.cfg.use_dummy, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, print_example_prompt=True, ) kwargs.update(generation_kwargs) @@ -357,7 +355,6 @@ async def _generate_seed_entities( use_dummy=self.cfg.use_dummy, deduplicate=self.cfg.seed_deduplicate, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, ) if self.cfg.seed_additional_instructions: cfg_kwargs["instructions"] = ( @@ -616,7 +613,6 @@ async def _apply_rate( n_parallels=self.cfg.n_parallels, use_dummy=self.cfg.use_dummy, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, ) cfg_kwargs.update(config_updates) existing_instruction = cfg_kwargs.get("additional_instructions") @@ -661,7 +657,6 @@ async def _apply_rank( n_parallels=self.cfg.n_parallels, use_dummy=self.cfg.use_dummy, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, recursive=recursive, recursive_fraction=self.cfg.recursive_fraction, recursive_min_remaining=self.cfg.recursive_min_remaining, diff --git a/src/gabriel/tasks/merge.py b/src/gabriel/tasks/merge.py index 6c46778..2ede68b 100644 --- a/src/gabriel/tasks/merge.py +++ b/src/gabriel/tasks/merge.py @@ -32,7 +32,6 @@ class MergeConfig: n_parallels: int = 650 n_runs: int = 1 use_dummy: bool = False - max_timeout: Optional[float] = None additional_instructions: Optional[str] = None use_embeddings: bool = True short_list_len: int = 16 @@ -337,7 +336,6 @@ def _parse_response(res: Any) -> Dict[str, str]: model=self.cfg.model, save_path=save_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=True, reset_files=reset_files if attempt == 0 else False, **kwargs, diff --git a/src/gabriel/tasks/rank.py b/src/gabriel/tasks/rank.py index 9171b7e..008280a 100644 --- a/src/gabriel/tasks/rank.py +++ b/src/gabriel/tasks/rank.py @@ -104,8 +104,6 @@ class RankConfig: Name of the language model to call via ``get_all_responses``. n_parallels: Number of parallel API calls to issue. - use_dummy: - Whether to use a dummy model for testing purposes. save_dir: Directory into which result files should be saved. file_name: @@ -136,11 +134,6 @@ class RankConfig: recursive_keep_stage_columns, recursive_add_stage_suffix: Control whether intermediate stage outputs are merged into the final results and whether their columns receive stage prefixes. - max_timeout: - Optional upper bound for individual API calls when retrieving - ranking judgements. ``None`` (default) lets the timeout be - derived dynamically from observed latencies in - :func:`gabriel.utils.openai_utils.get_all_responses`. initial_rating_pass: Enables a one-off :class:`Rate` pass before standard ranking rounds. The centred scores from that pass seed the initial @@ -171,8 +164,6 @@ class RankConfig: modality: str = "text" n_attributes_per_run: int = 8 reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None - max_timeout: Optional[float] = None # Recursive execution controls recursive: bool = False recursive_fraction: float = 1.0 / 3.0 @@ -386,8 +377,6 @@ async def _run_rate_pass( modality=self.cfg.modality, n_attributes_per_run=self.cfg.n_attributes_per_run, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, - max_timeout=self.cfg.max_timeout, ) for key, value in cfg_overrides.items(): setattr(rate_cfg, key, value) @@ -984,10 +973,8 @@ async def _catch_up_existing_rounds( save_path=round_path, reset_files=reset_files, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, max_retries=1, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) resp_df["Batch"] = resp_df.Identifier.map( @@ -1926,10 +1913,8 @@ async def _coerce_dict_replay(raw: Any) -> Dict[str, Any]: save_path=round_path, reset_files=reset_files, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, max_retries=1, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) # attach metadata columns and overwrite the round CSV diff --git a/src/gabriel/tasks/rate.py b/src/gabriel/tasks/rate.py index 8472496..4f773dd 100644 --- a/src/gabriel/tasks/rate.py +++ b/src/gabriel/tasks/rate.py @@ -39,13 +39,11 @@ class RateConfig: n_parallels: int = 650 n_runs: int = 1 use_dummy: bool = False - max_timeout: Optional[float] = None rating_scale: Optional[str] = None additional_instructions: Optional[str] = None modality: str = "text" n_attributes_per_run: int = 8 reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None search_context_size: str = "medium" def __post_init__(self) -> None: @@ -271,11 +269,9 @@ async def run( model=self.cfg.model, save_path=csv_path, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, json_mode=self.cfg.modality != "audio", reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, - reasoning_summary=self.cfg.reasoning_summary, **kwargs, ) diff --git a/src/gabriel/tasks/seed.py b/src/gabriel/tasks/seed.py index 3939da5..e15fb04 100644 --- a/src/gabriel/tasks/seed.py +++ b/src/gabriel/tasks/seed.py @@ -34,9 +34,7 @@ class SeedConfig: use_dummy: bool = False deduplicate: bool = False deduplicate_sample_seed: int = 42 - max_timeout: Optional[float] = None reasoning_effort: Optional[str] = None - reasoning_summary: Optional[str] = None class Seed: @@ -282,9 +280,7 @@ async def _request_entities( kwargs.setdefault("model", self.cfg.model) kwargs.setdefault("n_parallels", self.cfg.n_parallels) kwargs.setdefault("use_dummy", self.cfg.use_dummy) - kwargs.setdefault("max_timeout", self.cfg.max_timeout) kwargs.setdefault("reasoning_effort", self.cfg.reasoning_effort) - kwargs.setdefault("reasoning_summary", self.cfg.reasoning_summary) kwargs.setdefault("json_mode", True) kwargs.setdefault("save_path", raw_save) kwargs.setdefault("reset_files", reset_files) @@ -412,7 +408,6 @@ async def _deduplicate_entities( n_parallels=self.cfg.n_parallels, n_runs=4, use_dummy=self.cfg.use_dummy, - max_timeout=self.cfg.max_timeout, group_size=100, ) dedup = Deduplicate(dedup_cfg) @@ -443,8 +438,6 @@ def _filter_dedup_response_kwargs(response_kwargs: Dict[str, Any]) -> Dict[str, "model", "n_parallels", "save_path", - "use_dummy", - "max_timeout", "json_mode", "reset_files", "prompts", diff --git a/src/gabriel/tasks/whatever.py b/src/gabriel/tasks/whatever.py index 5ee6a5f..82895c2 100644 --- a/src/gabriel/tasks/whatever.py +++ b/src/gabriel/tasks/whatever.py @@ -26,7 +26,6 @@ class WhateverConfig: web_search_filters: Optional[Dict[str, Any]] = None search_context_size: str = "medium" n_parallels: int = 650 - use_dummy: bool = False reasoning_effort: Optional[str] = None reasoning_summary: Optional[str] = None @@ -302,7 +301,6 @@ async def run( web_search_filters=global_filters, search_context_size=self.cfg.search_context_size, n_parallels=self.cfg.n_parallels, - use_dummy=self.cfg.use_dummy, reset_files=reset_files, reasoning_effort=self.cfg.reasoning_effort, reasoning_summary=self.cfg.reasoning_summary, diff --git a/src/gabriel/utils/openai_utils.py b/src/gabriel/utils/openai_utils.py index 54b451d..7b8a695 100644 --- a/src/gabriel/utils/openai_utils.py +++ b/src/gabriel/utils/openai_utils.py @@ -1551,8 +1551,10 @@ def _build_params( expected_schema: Optional JSON schema supplied when ``json_mode`` is requested. reasoning_effort, reasoning_summary: - Additional settings for modern models controlling hidden reasoning - tokens and optional summaries. + ``reasoning_effort`` controls how intensely the model reasons + (``none``, ``low``, ``medium``, ``high``). Higher values are typically + smarter but slower. ``reasoning_summary`` requests a concise reasoning + summary when supported. include: Optional list (or comma-separated string) of ``include`` fields to request from the Responses API. When ``web_search`` is enabled, the @@ -2929,8 +2931,9 @@ async def get_all_responses( initially allows unlimited time for each request, then observes how long successful responses take and sets a timeout based on the 90th percentile of observed durations. Subsequent calls use this timeout (capped by - ``max_timeout``) and it is increased if later responses are slower. Any - request exceeding the current limit is cancelled and retried. While the + ``max_timeout`` if provided) and it is increased if later responses are + slower. Any request exceeding the current limit is cancelled and retried. + While the timeout is unbounded the helper automatically submits requests in background mode and polls for completion so that connections closed by the server or networking layer do not strand in-flight prompts. You can force