Behaviour for LLM provider adapters and dispatch entry point.
Implementing a Provider
A provider adapter implements this behaviour and returns a stream of
SkillKit.Event.* structs. The adapter is responsible for:
- Calling the provider's API (e.g.,
Anthropic.stream/3) - Converting provider-specific events to SkillKit events via the
SkillKit.Event.Streamableprotocol - Returning
{:ok, event_stream}or{:error, reason}
Example adapter
defmodule SkillKit.LLM.MyProvider do
@behaviour SkillKit.LLM
alias SkillKit.Event.Streamable
@impl true
def stream(messages, opts) do
encoded = encode_messages(messages)
case MyProvider.stream(encoded, opts) do
{:ok, raw_stream} ->
{:ok, Stream.transform(raw_stream, %{}, &Streamable.stream/2)}
{:error, reason} ->
{:error, reason}
end
end
endThe stream must yield these SkillKit.Event structs:
%Delta{text: text}— text fragment from the LLM%ToolCallStart{id: id, name: name}— a tool call has begun%ToolCallComplete{id: id, name: name, input: map}— tool call fully parsed%Usage{input_tokens: n, output_tokens: n}— token counts%Done{stop_reason: reason}— turn complete (:end_turnor:tool_use)
See SkillKit.Event.Streamable for how to implement the protocol for
your provider's event types. See SkillKit.LLM.Anthropic for a
complete reference implementation.
Streamable Protocol
Each provider defines its own typed event structs (e.g., Anthropic.Event.*).
SkillKit defines SkillKit.Event.Streamable implementations for those types,
converting them to universal SkillKit events. The provider knows nothing about
SkillKit — the protocol implementations live in the SkillKit codebase.
The protocol function stream/2 takes a provider event and an accumulator,
returning {[SkillKit.Event.*], updated_acc}. The accumulator carries state
across events (e.g., partial JSON fragments for tool call inputs).
Model URI Resolution
Providers are resolved from model URI strings:
"anthropic://claude-sonnet-4-20250514?max_tokens=8096"— full URI"claude-sonnet-4-20250514"— bare string, uses default provider"claude-sonnet-4-20250514?max_tokens=4096"— bare with query params
Configuration
config :skill_kit, SkillKit.LLM,
providers: [anthropic: SkillKit.LLM.Anthropic],
default_provider: :anthropic
config :skill_kit, SkillKit.LLM.Anthropic,
api_key: System.get_env("ANTHROPIC_API_KEY")
Summary
Functions
Looks up a provider module by scheme name.
Resolves a model URI to {:ok, provider, opts} or {:error, reason}.
Streams a response from the resolved LLM provider.
Types
@type message() :: SkillKit.Types.UserMessage.t() | SkillKit.Types.AssistantMessage.t() | SkillKit.Types.SystemMessage.t() | SkillKit.Types.ToolResult.t()
Callbacks
@callback stream(messages :: [message()], opts :: keyword()) :: {:ok, Enumerable.t()} | {:error, term()}
Functions
Looks up a provider module by scheme name.
Resolves a model URI to {:ok, provider, opts} or {:error, reason}.
@spec stream( [message()], keyword() ) :: {:ok, Enumerable.t()} | {:error, term()}
Streams a response from the resolved LLM provider.