"""从 LLM 文本输出里稳健地取出 JSON。各 integration / stage 共用，避免重复。"""
from __future__ import annotations

import json
from typing import Any

from core.text_limits import JSON_ERROR_SNIPPET_MAX_CHARS, clip_text


def extract_json_object(text: str) -> dict:
    """取第一个 { 到最后一个 } 的切片解析为 dict。

    天然容忍 ```json fences、前后多余说明文字（它们都在大括号之外）。
    """
    start, end = text.find("{"), text.rfind("}")
    if start == -1 or end == -1 or end < start:
        raise ValueError(f"no json object in output: {clip_text(text, JSON_ERROR_SNIPPET_MAX_CHARS)!r}")
    return json.loads(text[start : end + 1])


def to_bool(value: Any) -> bool:
    if isinstance(value, bool):
        return value
    return str(value).strip().lower() in ("1", "true", "yes", "是")
