defmodule AgentSea.Provider do
@moduledoc """
A chat-completion backend (Anthropic, OpenAI, a local model, …).
Every LLM integration implements this behaviour. Streaming is optional and,
where supported, returns a lazy `Stream` of normalized chunks built from an
SSE body — there is no async-generator plumbing.
"""
@typedoc "A single conversation message. `role` is required; extra keys (e.g. `tool_calls`, `tool_call_id`) are allowed."
@type message :: %{
required(:role) => :system | :user | :assistant | :tool,
required(:content) => term(),
optional(atom()) => term()
}
@typedoc "Provider options (model, api_key, system_prompt, tools, …)."
@type opts :: keyword()
@typedoc "A streamed event from `c:stream/2`."
@type stream_event ::
{:content, String.t()}
| {:thinking, String.t()}
| {:tool_call, map()}
| :done
@doc "Run a single (non-streaming) completion."
@callback complete([message()], opts()) ::
{:ok, AgentSea.Response.t()} | {:error, term()}
@doc "Run a streaming completion, returning a lazy stream of `t:stream_event/0`."
@callback stream([message()], opts()) :: Enumerable.t()
@doc "Static capabilities for a model id; `nil` for unknown models."
@callback model_info(model :: String.t()) :: AgentSea.ModelInfo.t() | nil
@optional_callbacks stream: 2
end