from __future__ import annotations

from collections.abc import Mapping
from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

from ..models.agents_config_agent_api_type import AgentsConfigAgentApiType
from ..types import UNSET, Unset
from typing import cast

if TYPE_CHECKING:
  from ..models.web_search_config import WebSearchConfig





T = TypeVar("T", bound="AgentsConfig")



@_attrs_define
class AgentsConfig:
    r""" Configuration for agent workflow.

        Attributes:
            enabled (bool | Unset): Whether to use agents mode for queries. Default: True.
            human_in_the_loop (bool | Unset): Enable the ask_user tool, allowing the agent to pause and ask the user a
                question with options. Default: True.
            web_search (WebSearchConfig | Unset): Configuration for web search tools.
            mcp_tools (list[str] | Unset): MCP tool names to enable from LiteLLM (e.g. ['read_wiki_contents',
                'ask_question']).
            planning_enabled (bool | Unset): Include the create_plan tool so the agent can generate a research plan when it
                deems a task complex enough. Plan approval is configured on PlanningLLM. Default: False.
            suggested_queries (bool | Unset): Generate a single suggested follow-up query after each response. Default:
                False.
            artifacts_enabled (bool | Unset): Enable the create_artifact tool for generating standalone documents
                (summaries, reports, drafts) displayed in a side panel. Default: False.
            vision_enabled (bool | Unset): Enable the view_document_pages tool for visual inspection of document pages
                (figures, charts, scanned pages) using a vision-capable model. Default: False.
            personal_agent (bool | Unset): Enable the personal_agent tool for delegating tasks to an external agent via
                OpenClaw. Default: False.
            review_enabled (bool | Unset): Enable ReviewLLM to review agent draft answers against source material before
                sending to the user. Uses the reasoning model for higher quality. Default: False.
            persona (str | Unset): Agent persona prepended to the system prompt. Customise to change the agent's identity
                and tone. Default: 'You are ARBI, an AI assistant created by ARBI CITY.\n\nYou maintain formal, objective tone
                appropriate for professional/legal contexts. If any part of the answer is based on general knowledge instead of
                the supplied sources, you must state so clearly and recognise that it may not be accurate.'.
            agent_model_name (str | Unset): The name of the model to be used for the agent decision-making. Default:
                'dummy'.
            agent_api_type (AgentsConfigAgentApiType | Unset): The inference type for the agent LLM (local or remote).
                Default: AgentsConfigAgentApiType.REMOTE.
            llm_agent_temperature (float | Unset): Temperature value for agent LLM. Default: 0.7.
            agent_max_tokens (int | Unset): Maximum tokens for the agent LLM response. Default: 20000.
            agent_max_iterations (int | Unset): Maximum number of tool call iterations before forcing an answer. Default:
                10.
            max_passage_pages (int | Unset): Maximum number of pages allowed per get_document_passages call. Calls
                requesting a wider range are rejected, forcing the agent to use get_table_of_contents and target specific
                sections. Default: 10.
            agent_history_char_threshold (int | Unset): Char threshold for conversation history injected into the agent
                context. Below: verbatim user/assistant pairs. Above: summarized by SummariseLLM. Default: 8000.
            agent_system_prompt (str | Unset): System prompt for the agent. Dynamic context is appended automatically.
                Default: "YOU ARE:\nARBI — an AI assistant made by Arbitration City Ltd (https://arbicity.com), capable of
                helping with a wide variety of tasks using workspace documents, web search, and general knowledge.\nAlways
                respond in first person. Be helpful and natural, not overly formal.\n\nYOUR TASK:\nAnswer the user's query. Use
                workspace documents when relevant. If appropriate, you may use available tools to perform external
                research.\n\nANSWERING GUIDELINES:\n- If the answer comes from workspace documents, cite them normally.\n- If
                the answer comes from external research, say so.\n- If the answer is based on general knowledge (no tool
                results), state that\n  it is based on general knowledge and may not be fully accurate.\n- You are allowed to
                answer questions that are not about the documents.\n\nEFFICIENCY GUIDELINES:\n1. PARALLEL CALLS: When a query
                has multiple aspects, call multiple tools in parallel (e.g., search different keywords simultaneously)\n2. AVOID
                DUPLICATION: Before searching, review learnings from previous results. Do not repeat searches for information
                you already have\n3. TARGETED SEARCHES: Use specific, focused queries rather than broad ones\n4. NARROW
                RETRIEVALS: When retrieving document passages, use sub-page references (e.g. 5.3-8.1) where available from
                search results or table of contents. Request narrow ranges per call and fetch additional ranges in subsequent
                iterations if needed — avoid fetching entire documents at once\n5. STOP WHEN READY: Provide your answer when you
                have sufficient evidence. Signs you have enough:\n   - Multiple sources confirm the same facts\n   - Key
                questions from the query are addressed\n   - Additional searches return redundant information\n\nWORKFLOW:\n1.
                For complex multi-document queries, plan your approach before executing searches\n2. Choose the right tool for
                each need — documents for uploaded content, web for external/current info\n3. Execute parallel searches for
                different aspects when appropriate\n4. Evaluate results - extract learnings, note gaps\n5. Only search again if
                specific gaps remain unfilled\n6. Answer when confident (no tool call) - do not over-research\n\nIMPORTANT:\n-
                The document index contains metadata only - you must retrieve actual content\n- Do not add inline citation
                markers - the system handles citations automatically".
     """

    enabled: bool | Unset = True
    human_in_the_loop: bool | Unset = True
    web_search: WebSearchConfig | Unset = UNSET
    mcp_tools: list[str] | Unset = UNSET
    planning_enabled: bool | Unset = False
    suggested_queries: bool | Unset = False
    artifacts_enabled: bool | Unset = False
    vision_enabled: bool | Unset = False
    personal_agent: bool | Unset = False
    review_enabled: bool | Unset = False
    persona: str | Unset = 'You are ARBI, an AI assistant created by ARBI CITY.\n\nYou maintain formal, objective tone appropriate for professional/legal contexts. If any part of the answer is based on general knowledge instead of the supplied sources, you must state so clearly and recognise that it may not be accurate.'
    agent_model_name: str | Unset = 'dummy'
    agent_api_type: AgentsConfigAgentApiType | Unset = AgentsConfigAgentApiType.REMOTE
    llm_agent_temperature: float | Unset = 0.7
    agent_max_tokens: int | Unset = 20000
    agent_max_iterations: int | Unset = 10
    max_passage_pages: int | Unset = 10
    agent_history_char_threshold: int | Unset = 8000
    agent_system_prompt: str | Unset = "YOU ARE:\nARBI — an AI assistant made by Arbitration City Ltd (https://arbicity.com), capable of helping with a wide variety of tasks using workspace documents, web search, and general knowledge.\nAlways respond in first person. Be helpful and natural, not overly formal.\n\nYOUR TASK:\nAnswer the user's query. Use workspace documents when relevant. If appropriate, you may use available tools to perform external research.\n\nANSWERING GUIDELINES:\n- If the answer comes from workspace documents, cite them normally.\n- If the answer comes from external research, say so.\n- If the answer is based on general knowledge (no tool results), state that\n  it is based on general knowledge and may not be fully accurate.\n- You are allowed to answer questions that are not about the documents.\n\nEFFICIENCY GUIDELINES:\n1. PARALLEL CALLS: When a query has multiple aspects, call multiple tools in parallel (e.g., search different keywords simultaneously)\n2. AVOID DUPLICATION: Before searching, review learnings from previous results. Do not repeat searches for information you already have\n3. TARGETED SEARCHES: Use specific, focused queries rather than broad ones\n4. NARROW RETRIEVALS: When retrieving document passages, use sub-page references (e.g. 5.3-8.1) where available from search results or table of contents. Request narrow ranges per call and fetch additional ranges in subsequent iterations if needed — avoid fetching entire documents at once\n5. STOP WHEN READY: Provide your answer when you have sufficient evidence. Signs you have enough:\n   - Multiple sources confirm the same facts\n   - Key questions from the query are addressed\n   - Additional searches return redundant information\n\nWORKFLOW:\n1. For complex multi-document queries, plan your approach before executing searches\n2. Choose the right tool for each need — documents for uploaded content, web for external/current info\n3. Execute parallel searches for different aspects when appropriate\n4. Evaluate results - extract learnings, note gaps\n5. Only search again if specific gaps remain unfilled\n6. Answer when confident (no tool call) - do not over-research\n\nIMPORTANT:\n- The document index contains metadata only - you must retrieve actual content\n- Do not add inline citation markers - the system handles citations automatically"
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)





    def to_dict(self) -> dict[str, Any]:
        from ..models.web_search_config import WebSearchConfig
        enabled = self.enabled

        human_in_the_loop = self.human_in_the_loop

        web_search: dict[str, Any] | Unset = UNSET
        if not isinstance(self.web_search, Unset):
            web_search = self.web_search.to_dict()

        mcp_tools: list[str] | Unset = UNSET
        if not isinstance(self.mcp_tools, Unset):
            mcp_tools = self.mcp_tools



        planning_enabled = self.planning_enabled

        suggested_queries = self.suggested_queries

        artifacts_enabled = self.artifacts_enabled

        vision_enabled = self.vision_enabled

        personal_agent = self.personal_agent

        review_enabled = self.review_enabled

        persona = self.persona

        agent_model_name = self.agent_model_name

        agent_api_type: str | Unset = UNSET
        if not isinstance(self.agent_api_type, Unset):
            agent_api_type = self.agent_api_type.value


        llm_agent_temperature = self.llm_agent_temperature

        agent_max_tokens = self.agent_max_tokens

        agent_max_iterations = self.agent_max_iterations

        max_passage_pages = self.max_passage_pages

        agent_history_char_threshold = self.agent_history_char_threshold

        agent_system_prompt = self.agent_system_prompt


        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({
        })
        if enabled is not UNSET:
            field_dict["ENABLED"] = enabled
        if human_in_the_loop is not UNSET:
            field_dict["HUMAN_IN_THE_LOOP"] = human_in_the_loop
        if web_search is not UNSET:
            field_dict["WEB_SEARCH"] = web_search
        if mcp_tools is not UNSET:
            field_dict["MCP_TOOLS"] = mcp_tools
        if planning_enabled is not UNSET:
            field_dict["PLANNING_ENABLED"] = planning_enabled
        if suggested_queries is not UNSET:
            field_dict["SUGGESTED_QUERIES"] = suggested_queries
        if artifacts_enabled is not UNSET:
            field_dict["ARTIFACTS_ENABLED"] = artifacts_enabled
        if vision_enabled is not UNSET:
            field_dict["VISION_ENABLED"] = vision_enabled
        if personal_agent is not UNSET:
            field_dict["PERSONAL_AGENT"] = personal_agent
        if review_enabled is not UNSET:
            field_dict["REVIEW_ENABLED"] = review_enabled
        if persona is not UNSET:
            field_dict["PERSONA"] = persona
        if agent_model_name is not UNSET:
            field_dict["AGENT_MODEL_NAME"] = agent_model_name
        if agent_api_type is not UNSET:
            field_dict["AGENT_API_TYPE"] = agent_api_type
        if llm_agent_temperature is not UNSET:
            field_dict["LLM_AGENT_TEMPERATURE"] = llm_agent_temperature
        if agent_max_tokens is not UNSET:
            field_dict["AGENT_MAX_TOKENS"] = agent_max_tokens
        if agent_max_iterations is not UNSET:
            field_dict["AGENT_MAX_ITERATIONS"] = agent_max_iterations
        if max_passage_pages is not UNSET:
            field_dict["MAX_PASSAGE_PAGES"] = max_passage_pages
        if agent_history_char_threshold is not UNSET:
            field_dict["AGENT_HISTORY_CHAR_THRESHOLD"] = agent_history_char_threshold
        if agent_system_prompt is not UNSET:
            field_dict["AGENT_SYSTEM_PROMPT"] = agent_system_prompt

        return field_dict



    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        from ..models.web_search_config import WebSearchConfig
        d = dict(src_dict)
        enabled = d.pop("ENABLED", UNSET)

        human_in_the_loop = d.pop("HUMAN_IN_THE_LOOP", UNSET)

        _web_search = d.pop("WEB_SEARCH", UNSET)
        web_search: WebSearchConfig | Unset
        if isinstance(_web_search,  Unset):
            web_search = UNSET
        else:
            web_search = WebSearchConfig.from_dict(_web_search)




        mcp_tools = cast(list[str], d.pop("MCP_TOOLS", UNSET))


        planning_enabled = d.pop("PLANNING_ENABLED", UNSET)

        suggested_queries = d.pop("SUGGESTED_QUERIES", UNSET)

        artifacts_enabled = d.pop("ARTIFACTS_ENABLED", UNSET)

        vision_enabled = d.pop("VISION_ENABLED", UNSET)

        personal_agent = d.pop("PERSONAL_AGENT", UNSET)

        review_enabled = d.pop("REVIEW_ENABLED", UNSET)

        persona = d.pop("PERSONA", UNSET)

        agent_model_name = d.pop("AGENT_MODEL_NAME", UNSET)

        _agent_api_type = d.pop("AGENT_API_TYPE", UNSET)
        agent_api_type: AgentsConfigAgentApiType | Unset
        if isinstance(_agent_api_type,  Unset):
            agent_api_type = UNSET
        else:
            agent_api_type = AgentsConfigAgentApiType(_agent_api_type)




        llm_agent_temperature = d.pop("LLM_AGENT_TEMPERATURE", UNSET)

        agent_max_tokens = d.pop("AGENT_MAX_TOKENS", UNSET)

        agent_max_iterations = d.pop("AGENT_MAX_ITERATIONS", UNSET)

        max_passage_pages = d.pop("MAX_PASSAGE_PAGES", UNSET)

        agent_history_char_threshold = d.pop("AGENT_HISTORY_CHAR_THRESHOLD", UNSET)

        agent_system_prompt = d.pop("AGENT_SYSTEM_PROMPT", UNSET)

        agents_config = cls(
            enabled=enabled,
            human_in_the_loop=human_in_the_loop,
            web_search=web_search,
            mcp_tools=mcp_tools,
            planning_enabled=planning_enabled,
            suggested_queries=suggested_queries,
            artifacts_enabled=artifacts_enabled,
            vision_enabled=vision_enabled,
            personal_agent=personal_agent,
            review_enabled=review_enabled,
            persona=persona,
            agent_model_name=agent_model_name,
            agent_api_type=agent_api_type,
            llm_agent_temperature=llm_agent_temperature,
            agent_max_tokens=agent_max_tokens,
            agent_max_iterations=agent_max_iterations,
            max_passage_pages=max_passage_pages,
            agent_history_char_threshold=agent_history_char_threshold,
            agent_system_prompt=agent_system_prompt,
        )


        agents_config.additional_properties = d
        return agents_config

    @property
    def additional_keys(self) -> list[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
