"""Raycast agent definition. Field set is the union of ``raycast_api.ChatAPI.stream`` parameters that make sense as **per-agent defaults**. Per-request values (currently: ``temperature``) win when both are set; the rest fall back to whatever the agent declared, then to Raycast's own defaults. ``BaseAgent.system_prompt`` maps onto Raycast's wire field ``additional_system_instructions`` (the slot the real client uses for *content*); the wire field ``system_instructions`` stays at the Raycast source default — ``"markdown"`` for ``AI_CHAT``, ``"plain"`` otherwise. We don't expose that wire dichotomy to the user — they get one conceptual "system prompt". Excluded on purpose: * ``buffer_id``/``message_id``/``current_date`` — per-call ephemeral * ``provider`` override — escape hatch for non-catalog models, no clear use case yet (revisit in PRD §14 when discovery lands) * ``locale`` — process-wide via ``Settings.raycast_locale`` because we only spin up one ``raycast_api.Client`` per gateway * ``system_instructions`` (wire) — that's a format marker, not content; the SDK fills it from the source default and we let it """ from __future__ import annotations from raycast_api import ( # noqa: F401 — UserPreferences re-exported for user configs RemoteTool, Source, UserPreferences, UserPreferencesArg, ) from beaver_gateway.agents.base import BaseAgent class RaycastAgent(BaseAgent): """Agent backed by ``raycast-api``. ``available_native_tools`` is the closed set of Raycast's server-side "remote tools" (``web_search``, ``search_images``, ``read_page``) — typed as ``RemoteTool`` so config-time IDE completion lists exactly the three valid values. Pydantic also coerces string literals, so ``("web_search", "read_page")`` keeps working unchanged. ``user_preferences`` toggles the auto-generated ```` block Raycast prepends to ``additional_system_instructions``: * ``True`` (default) → auto from host locale/timezone/today, rebuilt every request so the date stays fresh; * ``False`` → omit the block entirely; * ``UserPreferences(...)`` instance → used verbatim (frozen at the time the agent was loaded, so the date won't auto-update); * ``Callable[[], UserPreferencesArg]`` → re-invoked on every request. Use this for the common case "fresh date but custom locale/timezone": ``user_preferences=lambda: UserPreferences(locale="ru-RU", timezone="Europe/Berlin", current_date=date.today().isoformat())``. Callables may nest (a lambda returning a lambda…) but there's no real reason to. The library uses this block for date/locale-aware formatting, not for personalisation/memory — those are out of scope upstream. ``reasoning_effort`` values vary by model: GPT-5 takes ``"minimal"|"low"|"medium"|"high"``; Anthropic exposes nothing here (Claude reasoning lives in a separate ``…-reasoning`` model variant in the catalog). Unknown effort for the chosen model is ignored server-side, so we stay loose as ``str | None``. """ streaming: bool = True available_native_tools: tuple[RemoteTool, ...] = () source: Source = Source.AI_CHAT temperature: float | None = None reasoning_effort: str | None = None tool_choice: str | None = None user_preferences: UserPreferencesArg = True