"""Auto-generated by adk-fluent generator. Manual edits will be overwritten."""

from __future__ import annotations

from collections import defaultdict
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, Self

from google.adk.agents.base_agent import BaseAgent as _ADK_BaseAgent
from google.adk.agents.llm_agent import LlmAgent

from adk_fluent._base import BuilderBase

if not TYPE_CHECKING:
    try:
        from google.adk.agents.remote_a2a_agent import RemoteA2aAgent as _ADK_RemoteA2aAgent
    except (ImportError, ModuleNotFoundError):
        _ADK_RemoteA2aAgent = None  # type: ignore[assignment,misc]

if TYPE_CHECKING:
    from collections.abc import AsyncIterator, Awaitable
    from typing import Literal

    from google.adk.agents.readonly_context import ReadonlyContext
    from google.adk.agents.remote_a2a_agent import RemoteA2aAgent as _ADK_RemoteA2aAgent
    from google.adk.code_executors.base_code_executor import BaseCodeExecutor
    from google.adk.models.base_llm import BaseLlm
    from google.adk.planners.base_planner import BasePlanner
    from google.genai.types import Content, File, GenerateContentConfig, Part
    from pydantic import BaseModel


class BaseAgent(BuilderBase):
    """Base class for all agents in Agent Development Kit."""

    _ALIASES: dict[str, str] = {"describe": "description"}
    _CALLBACK_ALIASES: dict[str, str] = {"after_agent": "after_agent_callback", "before_agent": "before_agent_callback"}
    _ADDITIVE_FIELDS: set[str] = {"after_agent_callback", "before_agent_callback"}
    _ADK_TARGET_CLASS = _ADK_BaseAgent

    def __init__(self, name: str) -> None:
        self._config: dict[str, Any] = {"name": name}
        self._callbacks: dict[str, list[Callable]] = defaultdict(list)
        self._lists: dict[str, list] = defaultdict(list)
        self._frozen = False

    def describe(self, value: str) -> Self:
        """Set agent description (metadata for transfer routing and topology display — NOT sent to the LLM as instruction). Always set this on sub-agents so the coordinator LLM can pick the right specialist."""
        self = self._maybe_fork_for_mutation()
        self._config["description"] = value
        return self

    def after_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `after_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def after_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `after_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def before_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `before_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def before_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `before_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def sub_agents(self, value: list[BaseAgent]) -> Self:
        """Set the ``sub_agents`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["sub_agents"] = value
        return self

    def sub_agent(self, value: BaseAgent) -> Self:
        """Append to ``sub_agents`` (lazy — built at .build() time)."""
        self = self._maybe_fork_for_mutation()
        self._lists["sub_agents"].append(value)
        return self

    def build(self) -> _ADK_BaseAgent:
        """Base class for all agents in Agent Development Kit. Resolve into a native ADK _ADK_BaseAgent."""
        config = self._prepare_build_config()
        result = self._safe_build(_ADK_BaseAgent, config)
        return self._apply_native_hooks(result)


class Agent(BuilderBase):
    """LLM-based Agent."""

    _ALIASES: dict[str, str] = {
        "describe": "description",
        "global_instruct": "global_instruction",
        "instruct": "instruction",
        "static": "static_instruction",
    }
    _CALLBACK_ALIASES: dict[str, str] = {
        "after_agent": "after_agent_callback",
        "after_model": "after_model_callback",
        "after_tool": "after_tool_callback",
        "before_agent": "before_agent_callback",
        "before_model": "before_model_callback",
        "before_tool": "before_tool_callback",
        "on_model_error": "on_model_error_callback",
        "on_tool_error": "on_tool_error_callback",
    }
    _ADDITIVE_FIELDS: set[str] = {
        "after_agent_callback",
        "after_model_callback",
        "after_tool_callback",
        "before_agent_callback",
        "before_model_callback",
        "before_tool_callback",
        "on_model_error_callback",
        "on_tool_error_callback",
    }
    _ADK_TARGET_CLASS = LlmAgent

    def __init__(self, name: str, model: str | None = None) -> None:
        self._config: dict[str, Any] = {"name": name}
        self._callbacks: dict[str, list[Callable]] = defaultdict(list)
        self._lists: dict[str, list] = defaultdict(list)
        self._frozen = False
        if model is not None:
            self._config["model"] = model

    def describe(self, value: str) -> Self:
        """Set agent description (metadata for transfer routing and topology display — NOT sent to the LLM as instruction). Always set this on sub-agents so the coordinator LLM can pick the right specialist."""
        self = self._maybe_fork_for_mutation()
        self._config["description"] = value
        return self

    def global_instruct(self, value: str | Callable[[ReadonlyContext], str | Awaitable[str]]) -> Self:
        """Set instruction shared by ALL agents in a workflow. Only meaningful on the root agent. Prepended to every agent's system prompt."""
        self = self._maybe_fork_for_mutation()
        self._config["global_instruction"] = value
        return self

    def static(self, value: Content | str | File | Part | list[str | File | Part] | None) -> Self:
        """Set cached instruction. When set, ``.instruct()`` text moves from system to user content, enabling context caching. Use for large, stable prompt sections that rarely change."""
        self = self._maybe_fork_for_mutation()
        self._config["static_instruction"] = value
        return self

    def delegate(self, value: Any) -> Self:
        """Deprecated: use ``.agent_tool()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".delegate() is deprecated, use .agent_tool() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["_delegate"] = value
        return self

    def guardrail(self, value: Any) -> Self:
        """Deprecated: use ``.guard()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".guardrail() is deprecated, use .guard() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["_guardrail"] = value
        return self

    def history(self, value: Literal["default", "none"]) -> Self:
        """Deprecated: use ``.context()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".history() is deprecated, use .context() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["include_contents"] = value
        return self

    def include_history(self, value: Literal["default", "none"]) -> Self:
        """Deprecated: use ``.context()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".include_history() is deprecated, use .context() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["include_contents"] = value
        return self

    def inject_context(self, value: Any) -> Self:
        """Deprecated: use ``.prepend()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".inject_context() is deprecated, use .prepend() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["_inject_context"] = value
        return self

    def input_schema(self, value: type[BaseModel] | None) -> Self:
        """Deprecated: use ``.accepts()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".input_schema() is deprecated, use .accepts() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["input_schema"] = value
        return self

    def output_key(self, value: str | None) -> Self:
        """Deprecated: use ``.writes()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".output_key() is deprecated, use .writes() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["output_key"] = value
        return self

    def output_schema(self, value: type[BaseModel] | None) -> Self:
        """Deprecated: use ``.returns()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".output_schema() is deprecated, use .returns() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["output_schema"] = value
        return self

    def outputs(self, value: str | None) -> Self:
        """Deprecated: use ``.writes()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".outputs() is deprecated, use .writes() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["output_key"] = value
        return self

    def retry_if(self, value: Any) -> Self:
        """Deprecated: use ``.loop_while()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".retry_if() is deprecated, use .loop_while() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["_retry_if"] = value
        return self

    def save_as(self, value: str | None) -> Self:
        """Deprecated: use ``.writes()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".save_as() is deprecated, use .writes() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["output_key"] = value
        return self

    def static_instruct(self, value: Content | str | File | Part | list[str | File | Part] | None) -> Self:
        """Deprecated: use ``.static()`` instead."""
        self = self._maybe_fork_for_mutation()
        import warnings

        warnings.warn(
            ".static_instruct() is deprecated, use .static() instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self._config["static_instruction"] = value
        return self

    def after_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `after_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def after_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `after_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def after_model(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `after_model_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["after_model_callback"].append(fn)
        return self

    def after_model_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `after_model_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["after_model_callback"].append(fn)
        return self

    def after_tool(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `after_tool_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["after_tool_callback"].append(fn)
        return self

    def after_tool_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `after_tool_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["after_tool_callback"].append(fn)
        return self

    def before_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `before_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def before_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `before_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def before_model(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `before_model_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["before_model_callback"].append(fn)
        return self

    def before_model_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `before_model_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["before_model_callback"].append(fn)
        return self

    def before_tool(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `before_tool_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["before_tool_callback"].append(fn)
        return self

    def before_tool_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `before_tool_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["before_tool_callback"].append(fn)
        return self

    def on_model_error(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `on_model_error_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["on_model_error_callback"].append(fn)
        return self

    def on_model_error_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `on_model_error_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["on_model_error_callback"].append(fn)
        return self

    def on_tool_error(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `on_tool_error_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["on_tool_error_callback"].append(fn)
        return self

    def on_tool_error_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `on_tool_error_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["on_tool_error_callback"].append(fn)
        return self

    def sub_agents(self, value: list[BaseAgent]) -> Self:
        """Set the ``sub_agents`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["sub_agents"] = value
        return self

    def model(self, value: str | BaseLlm) -> Self:
        """Set the ``model`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["model"] = value
        return self

    def generate_content_config(self, value: GenerateContentConfig | None) -> Self:
        """Set the ``generate_content_config`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["generate_content_config"] = value
        return self

    def disallow_transfer_to_parent(self, value: bool) -> Self:
        """Prevent this agent from transferring control back to its parent. Also forces an auto-handoff back to parent on the next turn. Equivalent to ``.stay()``. See also ``.isolate()``."""
        self = self._maybe_fork_for_mutation()
        self._config["disallow_transfer_to_parent"] = value
        return self

    def disallow_transfer_to_peers(self, value: bool) -> Self:
        """Prevent this agent from transferring control to sibling agents. Equivalent to ``.no_peers()``. See also ``.isolate()``."""
        self = self._maybe_fork_for_mutation()
        self._config["disallow_transfer_to_peers"] = value
        return self

    def planner(self, value: BasePlanner | None) -> Self:
        """Set the ``planner`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["planner"] = value
        return self

    def code_executor(self, value: BaseCodeExecutor | None) -> Self:
        """Set the ``code_executor`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["code_executor"] = value
        return self

    def sub_agent(self, value: BaseAgent) -> Self:
        """Append to ``sub_agents`` (lazy — built at .build() time)."""
        self = self._maybe_fork_for_mutation()
        self._lists["sub_agents"].append(value)
        return self

    def tool(self, fn_or_tool: Any, *, require_confirmation: bool = False) -> Self:
        """Add a single tool (appends). Wraps plain callables in FunctionTool when require_confirmation=True."""
        from adk_fluent._helpers import _add_tool

        return _add_tool(self, fn_or_tool, require_confirmation=require_confirmation)

    def tools(self, value: Any) -> Self:
        """Set tools. Accepts a list, a TComposite chain (T.fn(x) | T.fn(y)), or a single tool/toolset."""
        from adk_fluent._helpers import _add_tools

        return _add_tools(self, value)

    def ui(self, spec: Any) -> Self:
        """Attach A2UI surface for rich UI output. Declarative: .ui(UI.form(...)). LLM-guided: .ui(UI.auto()). Component tree: .ui(UI.column(UI.text('Hi'), UI.button('Go', action='go')))."""
        from adk_fluent._helpers import _add_ui_spec

        return _add_ui_spec(self, spec)

    def guard(self, value: Any) -> Self:
        """Add an output validation guard. Accepts a G composite (G.pii() | G.length(max=500)) or a plain callable. Guards run as after_model callbacks and validate/transform the LLM response before it is returned."""
        from adk_fluent._helpers import _guard_dispatch

        return _guard_dispatch(self, value)

    def ask(self, prompt: str) -> str:
        """One-shot SYNC execution (blocking). Builds agent, sends prompt, returns response text. Raises RuntimeError inside async event loops (Jupyter, FastAPI) — use .ask_async() instead."""
        from adk_fluent._helpers import run_one_shot

        return run_one_shot(self, prompt)

    async def ask_async(self, prompt: str) -> str:
        """One-shot ASYNC execution (non-blocking, use with await). Safe in Jupyter, FastAPI, and other async contexts."""
        from adk_fluent._helpers import run_one_shot_async

        return await run_one_shot_async(self, prompt)

    async def stream(self, prompt: str) -> AsyncIterator[str]:
        """ASYNC streaming execution. Yields response text chunks as they arrive. Use with ``async for chunk in agent.stream(prompt):``."""
        from adk_fluent._helpers import run_stream

        async for chunk in run_stream(self, prompt):
            yield chunk

    def test(
        self, prompt: str, *, contains: str | None = None, matches: str | None = None, equals: str | None = None
    ) -> Self:
        """Run a smoke test. Calls .ask() internally, asserts output matches condition."""
        from adk_fluent._helpers import run_inline_test

        return run_inline_test(self, prompt, contains=contains, matches=matches, equals=equals)

    def session(self) -> Any:
        """Create an interactive multi-turn chat session. Returns an async context manager — use with ``async with agent.session() as chat:``. The agent is auto-built."""
        from adk_fluent._helpers import create_session

        return create_session(self)

    def map(self, prompts: list[str], *, concurrency: int = 5) -> list[str]:
        """Batch SYNC execution (blocking). Run agent against multiple prompts with bounded concurrency. Raises RuntimeError inside async event loops — use .map_async() instead."""
        from adk_fluent._helpers import run_map

        return run_map(self, prompts, concurrency=concurrency)

    async def map_async(self, prompts: list[str], *, concurrency: int = 5) -> list[str]:
        """Batch ASYNC execution (non-blocking, use with await). Safe in Jupyter, FastAPI, and other async contexts."""
        from adk_fluent._helpers import run_map_async

        return await run_map_async(self, prompts, concurrency=concurrency)

    async def events(self, prompt: str) -> AsyncIterator[Any]:
        """Stream raw ADK Event objects. Yields every event including state deltas and function calls."""
        from adk_fluent._helpers import run_events

        async for chunk in run_events(self, prompt):
            yield chunk

    def instruct(self, value: str | Callable[[ReadonlyContext], str | Awaitable[str]]) -> Self:
        """Set the main instruction / system prompt — what the LLM is told to do. Accepts plain text, a callable, or a P module composition (P.role() + P.task()). Raises TypeError if passed a CTransform (use .context() instead)."""
        from adk_fluent._helpers import _instruct_with_guard

        return _instruct_with_guard(self, value)

    def context(self, spec: Any) -> Self:
        """Declare what conversation context this agent should see. Accepts a C module transform (C.none(), C.user_only(), C.from_state(), etc.)."""
        from adk_fluent._helpers import _context_with_guard

        return _context_with_guard(self, spec)

    def show(self) -> Self:
        """Force this agent's events to be user-facing (override topology inference)."""
        from adk_fluent._helpers import _show_agent

        return _show_agent(self)

    def hide(self) -> Self:
        """Force this agent's events to be internal (override topology inference)."""
        from adk_fluent._helpers import _hide_agent

        return _hide_agent(self)

    def memory(self, mode: str = "preload") -> Self:
        """Add memory tools to this agent. Modes: 'preload', 'on_demand', 'both'."""
        from adk_fluent._helpers import _add_memory

        return _add_memory(self, mode)

    def memory_auto_save(self) -> Self:
        """Auto-save session to memory after each agent run."""
        from adk_fluent._helpers import _add_memory_auto_save

        return _add_memory_auto_save(self)

    def agent_tool(self, agent: Any) -> Self:
        """Wrap another agent as a callable AgentTool and add it to this agent's tools. The parent LLM invokes the child like any other tool, stays in control, and receives the response. Compare with .sub_agent() which fully transfers control to the child."""
        from adk_fluent._helpers import add_agent_tool

        return add_agent_tool(self, agent)

    def isolate(self) -> Self:
        """Prevent this agent from transferring to parent or peers. Sets both disallow_transfer_to_parent and disallow_transfer_to_peers to True. Use for specialist agents that should complete their task and return."""
        from adk_fluent._helpers import _isolate_agent

        return _isolate_agent(
            self,
        )

    def stay(self) -> Self:
        """Prevent transfer to parent only (can still transfer to sibling peers). Equivalent to .disallow_transfer_to_parent(True). Use for agents in peer-to-peer handoff chains where the coordinator should not regain control mid-sequence."""
        from adk_fluent._helpers import _stay_agent

        return _stay_agent(
            self,
        )

    def no_peers(self) -> Self:
        """Prevent this agent from transferring to sibling agents. The agent can still return to its parent."""
        from adk_fluent._helpers import _no_peers_agent

        return _no_peers_agent(
            self,
        )

    def artifacts(self, *transforms: Any) -> Self:
        """Attach artifact operations (A.publish, A.snapshot, etc.) that fire after this agent completes."""
        from adk_fluent._helpers import _add_artifacts

        return _add_artifacts(self, transforms)

    def tool_schema(self, schema: type) -> Self:
        """Attach a ToolSchema declaring tool state dependencies."""
        self = self._maybe_fork_for_mutation()
        self._config["_tool_schema"] = schema
        return self

    def callback_schema(self, schema: type) -> Self:
        """Attach a CallbackSchema declaring callback state dependencies."""
        self = self._maybe_fork_for_mutation()
        self._config["_callback_schema"] = schema
        return self

    def prompt_schema(self, schema: type) -> Self:
        """Attach a PromptSchema declaring prompt state dependencies."""
        self = self._maybe_fork_for_mutation()
        self._config["_prompt_schema"] = schema
        return self

    def artifact_schema(self, schema: type) -> Self:
        """Attach an ArtifactSchema declaring artifact dependencies."""
        self = self._maybe_fork_for_mutation()
        self._config["_artifact_schema"] = schema
        return self

    def eval(self, prompt: str, *, expect: str | None = None, criteria: Any | None = None) -> Any:
        """Inline evaluation. Run a single eval case against this agent. Returns an EvalSuite ready to .run()."""
        from adk_fluent._helpers import _eval_inline

        return _eval_inline(self, prompt, expect=expect, criteria=criteria)

    def eval_suite(self) -> Any:
        """Create an evaluation suite builder for this agent. Returns an EvalSuite bound to this agent."""
        from adk_fluent._helpers import _eval_suite

        return _eval_suite(self)

    def to_ir(self) -> Any:
        """Convert this Agent builder to an AgentNode IR node."""
        from adk_fluent._helpers import _agent_to_ir

        return _agent_to_ir(self)

    def skill(
        self,
        skill_id: str,
        name: str,
        *,
        description: str = "",
        tags: list[str] | None = None,
        examples: list[str] | None = None,
        input_modes: list[str] | None = None,
        output_modes: list[str] | None = None,
    ) -> Self:
        """Declare an A2A skill for this agent's AgentCard. Skills are metadata consumed by ``A2AServer`` during card generation. They have no effect on local agent execution. If no skills are declared, ``A2AServer`` auto-infers them from the agent's tools and sub-agents."""
        from adk_fluent._helpers import _add_skill

        return _add_skill(
            self,
            skill_id,
            name,
            description=description,
            tags=tags,
            examples=examples,
            input_modes=input_modes,
            output_modes=output_modes,
        )

    def publish(self, *, port: int = 8000, host: str = "0.0.0.0") -> Any:
        """Publish this agent as an A2A server (returns Starlette app). Shorthand for ``A2AServer(self).port(port).host(host).build()``."""
        from adk_fluent._helpers import _publish_agent

        return _publish_agent(self, port=port, host=host)

    def build(self) -> LlmAgent:
        """LLM-based Agent. Resolve into a native ADK LlmAgent."""
        config = self._prepare_build_config()
        result = self._safe_build(LlmAgent, config)
        return self._apply_native_hooks(result)


class RemoteA2aAgent(BuilderBase):
    """Agent that communicates with a remote A2A agent via A2A client."""

    _ALIASES: dict[str, str] = {"describe": "description"}
    _CALLBACK_ALIASES: dict[str, str] = {"after_agent": "after_agent_callback", "before_agent": "before_agent_callback"}
    _ADDITIVE_FIELDS: set[str] = {"after_agent_callback", "before_agent_callback"}
    _ADK_TARGET_CLASS = _ADK_RemoteA2aAgent

    def __init__(self, name: str) -> None:
        self._config: dict[str, Any] = {"name": name}
        self._callbacks: dict[str, list[Callable]] = defaultdict(list)
        self._lists: dict[str, list] = defaultdict(list)
        self._frozen = False

    def describe(self, value: str) -> Self:
        """Set agent description (metadata for transfer routing and topology display — NOT sent to the LLM as instruction). Always set this on sub-agents so the coordinator LLM can pick the right specialist."""
        self = self._maybe_fork_for_mutation()
        self._config["description"] = value
        return self

    def after_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `after_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def after_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `after_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["after_agent_callback"].append(fn)
        return self

    def before_agent(self, *fns: Callable[..., Any]) -> Self:
        """Append callback(s) to `before_agent_callback`. Multiple calls accumulate."""
        self = self._maybe_fork_for_mutation()
        for fn in fns:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def before_agent_if(self, condition: bool, fn: Callable[..., Any]) -> Self:
        """Append callback to `before_agent_callback` only if condition is True."""
        self = self._maybe_fork_for_mutation()
        if condition:
            self._callbacks["before_agent_callback"].append(fn)
        return self

    def sub_agents(self, value: list[BaseAgent]) -> Self:
        """Set the ``sub_agents`` field."""
        self = self._maybe_fork_for_mutation()
        self._config["sub_agents"] = value
        return self

    def sub_agent(self, value: BaseAgent) -> Self:
        """Append to ``sub_agents`` (lazy — built at .build() time)."""
        self = self._maybe_fork_for_mutation()
        self._lists["sub_agents"].append(value)
        return self

    def build(self) -> _ADK_RemoteA2aAgent:
        """Agent that communicates with a remote A2A agent via A2A client. Resolve into a native ADK _ADK_RemoteA2aAgent."""
        if _ADK_RemoteA2aAgent is None:
            raise ImportError("A2A support requires the a2a SDK. Install with: pip install 'google-adk[a2a]'")
        config = self._prepare_build_config()
        result = self._safe_build(_ADK_RemoteA2aAgent, config)
        return self._apply_native_hooks(result)
