Map a page LLM response to ``(brief, content, obj)``. - JSON object (or a single-element ``[{...}]`` array): brief/content come from it and ``obj`` is the dict (entity callers read ``type`` from it). - Valid JSON of the wrong shape (multi/empty array, scalar): ``("", "", None)``
(raw: str)
| 548 | |
| 549 | |
| 550 | def _page_fields(raw: str) -> tuple[str, str, dict | None]: |
| 551 | """Map a page LLM response to ``(brief, content, obj)``. |
| 552 | |
| 553 | - JSON object (or a single-element ``[{...}]`` array): brief/content come |
| 554 | from it and ``obj`` is the dict (entity callers read ``type`` from it). |
| 555 | - Valid JSON of the wrong shape (multi/empty array, scalar): ``("", "", |
| 556 | None)`` — the empty content makes ``_require_nonempty_content`` skip the |
| 557 | page rather than persisting the raw JSON text as its body. |
| 558 | - Not JSON at all: ``("", raw, None)`` — ``raw`` is written as a |
| 559 | prose-markdown body (the legitimate fallback for models that emit |
| 560 | markdown instead of JSON). |
| 561 | |
| 562 | Shared by all four page-generation closures so a new edge case is handled |
| 563 | in one place instead of four near-identical blocks. |
| 564 | """ |
| 565 | try: |
| 566 | obj = _parse_page_json(raw) |
| 567 | except (json.JSONDecodeError, ValueError): |
| 568 | return "", raw, None |
| 569 | if obj is None: |
| 570 | return "", "", None |
| 571 | return obj.get("description", ""), (obj.get("content") or ""), obj |
| 572 | |
| 573 | |
| 574 | def _filter_concept_items(items: list, label: str) -> list[dict]: |