{"record":{"id":"b8f9b6195dc87fb9","repo":"VectifyAI/PageIndex","slug":"optimize-expand-is-deprecated-pass-optimize-full","errorCode":null,"errorMessage":"optimize_expand is deprecated: pass optimize='full', 'merge', or False. When optimize is not passed it maps onto it (False -> 'merge', True -> 'full'), so the optimize pass now runs where the old optimize=False default ran nothing.","messagePattern":"optimize_expand is deprecated: pass optimize='full', 'merge', or False\\. When optimize is not passed it maps onto it \\(False -> 'merge', True -> 'full'\\), so the optimize pass now runs where the old optimize=False default ran nothing\\.","errorType":"console","errorClass":"DeprecationWarning","httpStatus":null,"severity":"warning","filePath":"pageindex/flash/api.py","lineNumber":105,"sourceCode":"             for page_text in page_texts]\n    outcome = asyncio.run(optimize(structure, page_texts, lines, model=model,\n                                   do_expand=do_expand,\n                                   page_count=len(page_texts)))\n    return {\"merges\": outcome[\"merges\"], \"expands\": outcome[\"expands\"],\n            \"same_page_merges\": outcome[\"same_page_merges\"],\n            \"same_page_dropped\": outcome[\"same_page_dropped\"],\n            \"kept_collapsed\": outcome[\"kept_collapsed\"],\n            \"before\": outcome[\"before\"], \"after\": outcome[\"after\"]}\n\n\ndef page_index_flash(pdf, summary=True, summary_model=None,\n                     optimize: str | bool | None = None, optimize_expand=None,\n                     optimize_model=None, summary_concurrency=None,\n                     use_embedded_toc=True) -> dict:\n    \"\"\"Build a PageIndex tree structure from a PDF using layout statistics. The tree extraction itself uses no LLM; by default an LLM writes node summaries and expands the tree (``summary=False, optimize=False`` runs fully LLM-free). Args: pdf: path to a PDF file (``str`` or ``pathlib.Path``) or an in-memory binary stream (``io.BytesIO``). summary: if True, generate LLM summaries for each node (requires ``summary_model``). summary_model: the LLM model identifier to use for summary generation. optimize: ``\"full\"`` for merge + LLM expand (a model unreachable after the retry ladder — a missing credential included — fails the run loudly from expand itself; a per-prompt rejection leaves just that node collapsed), ``\"merge\"`` for deterministic merge only, ``False`` to disable. ``True`` is accepted as ``\"full\"`` for backward compatibility; defaults to ``\"full\"``. Expand needs readable page text, so a bookmark-only or scanned PDF runs the merge half only (``expands`` reports 0). optimize_expand: deprecated — use ``optimize``. Honored only when ``optimize`` is not passed (or is the legacy ``True``): ``False`` maps to ``\"merge\"``, ``True`` to ``\"full\"``. optimize_model: the LLM model for expand (defaults to the summary model). summary_concurrency: maximum simultaneous summary model calls; None uses the library default. use_embedded_toc: if True, consume the PDF's embedded bookmarks when trustworthy: deep bookmarks become the frame and the detected sections they lack are grafted back in after noise filtering, coarse ones become the chapter frame with detected nodes re-hung under them (deeper sparse entries are filled in when the page text confirms them, and garbled extracted titles are repaired from the bookmark strings), garbage ones are ignored; adds a ``toc_source`` key to the result. On by default; pass False for the pure detected structure. Returns: dict with keys ``doc_name``, ``doc_title``, ``structure`` (a list of nested ``{\"title\", \"start_index\", \"end_index\", \"nodes\"}`` dicts; page indexes are 1-based) and ``has_abstract_or_references_section`` (True when a top-level entry is an abstract or references heading). With ``optimize`` an ``optimize`` key reports merge/expand counts and before/after search-cost metrics. \"\"\"\n    if optimize_expand is not None:\n        import warnings\n        warnings.warn(\n            \"optimize_expand is deprecated: pass optimize='full', 'merge', \"\n            \"or False. When optimize is not passed it maps onto it (False \"\n            \"-> 'merge', True -> 'full'), so the optimize pass now runs \"\n            \"where the old optimize=False default ran nothing.\",\n            DeprecationWarning, stacklevel=2)\n    if optimize is None or optimize is True:\n        # legacy spellings only — an explicit 'full'/'merge' wins\n        optimize = \"merge\" if optimize_expand is False else \"full\"\n    if not optimize:\n        optimize = False\n    elif optimize not in (\"full\", \"merge\"):\n        raise ValueError(\n            f\"optimize must be 'full', 'merge', or False, got {optimize!r}\")\n    result = extract_toc(_validate_pdf(pdf), use_embedded_toc=use_embedded_toc)\n    structure = result.get(\"structure\", [])\n    if optimize and structure:\n        # bookmark-only extractions carry no page_texts and scanned ones\n        # only empty strings; expand needs text","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/VectifyAI/PageIndex/blob/afb5e119766630af6014b04fe8b53357527bc05e/pageindex/flash/api.py#L87-L123","documentation":"Deprecation warning emitted by page_index_flash when the legacy optimize_expand keyword is passed. The option still works (False -> 'merge', True -> 'full') but only when the newer optimize argument is not passed, and the optimize pass now runs where the old optimize=False default did nothing.","triggerScenarios":"Calling page_index_flash(optimize_expand=True/False) — old scripts written before the optimize='full'|'merge'|False API was introduced.","commonSituations":"Upgrading the library and running existing pipelines that pass optimize_expand; seeing behavior change because optimize now defaults to 'full' and runs LLM expand where it previously did nothing.","solutions":["Replace optimize_expand=True with optimize='full' and optimize_expand=False with optimize='merge'","Pass optimize=False to fully disable the optimize pass (the old default behavior)","Silence during migration with warnings.filterwarnings('ignore', category=DeprecationWarning) — but migration is better"],"exampleFix":"# before\npage_index_flash(pdf, optimize_expand=True)\n# after\npage_index_flash(pdf, optimize='full')","handlingStrategy":"validation","validationCode":"import inspect\nkwargs = dict(model_kwargs)\nif 'optimize_expand' in kwargs:\n    kwargs['optimize'] = 'full' if kwargs.pop('optimize_expand') else 'merge'\nresult = page_index_flash(pdf, **kwargs)","typeGuard":"def uses_current_optimize_api(kwargs: dict) -> bool:\n    return 'optimize' in kwargs and 'optimize_expand' not in kwargs","tryCatchPattern":"import warnings\nwith warnings.catch_warnings():n    warnings.simplefilter('ignore', DeprecationWarning)\n    result = page_index_flash(pdf, optimize_expand=True)  # legacy call, silenced","preventionTips":["Grep codebase for optimize_expand after upgrading and migrate call sites","Pin behavior explicitly (optimize='full'|'merge'|False) instead of relying on defaults","Run tests with -W error::DeprecationWarning to catch these early"],"tags":["deprecation","optimize","api-migration","flash"],"backgroundTag":"deprecated-parameter","analyzedSha":"afb5e119766630af6014b04fe8b53357527bc05e","analyzedAt":"2026-08-27T11:20:48.519Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}