Provider-neutral LLM adapter boundary used by trusted Kernel provider builders.
prepare/2 seals a model selector into an immutable prepared target under a
closed requirements map. callback/2 binds that target to a credential and
cache flag and returns an arity-two requester. Kernel policy, retries, prompt
construction, and protocol recovery live in shipped Lisp libraries rather than
this transport adapter.
Summary
Types
Provider-reported token usage. :total_cost is absent when pricing is
unavailable; a present zero-microunit object is a measured zero-cost response.
Adapter responses may use a non-negative USD number or bounded decimal string;
the Kernel immediately replaces it with this fixed-point object.
Callbacks
Make an LLM call.
Preload adapter-owned model metadata into a shared, process-independent store
(e.g. a :persistent_term/ETS catalog) so the first per-request provider
worker does not pay a large one-time load inside its bounded heap.
Prepares an adapter-owned request target and attests the sealed requirements.
Names the OTP application this adapter needs running to serve model.
Attests that the exact adapter target is safe to publish in canonical traces.
Functions
Returns the configured LLM adapter module.
Creates a normalized requester for a prepared model.
Returns the closed public warning fact for an uncataloged prepared model.
Resolves a configured selector into an immutable adapter-owned request target.
Types
@type catalog_status() :: :cataloged | :uncataloged | :unavailable
@type message() :: %{role: :system | :user | :assistant | :tool, content: String.t()}
@type output_limit() :: %{ name: :max_tokens, value: pos_integer(), bindings: [output_limit_binding()] }
@type output_limit_binding() ::
:application_limit
| :installation_param
| :configured
| :adapter_default
| :model_output_limit
| :remaining_context
@type requester_context() :: %{llm_request_deadline_ms: integer() | nil}
@type tokens() :: %{ optional(:input) => non_neg_integer(), optional(:output) => non_neg_integer(), optional(:cache_creation) => non_neg_integer(), optional(:cache_read) => non_neg_integer(), optional(:total_cost) => usd_cost() | non_neg_integer() | float() | String.t() }
@type tool_call_response() :: %{ :tool_calls => [map()], :content => String.t() | nil, :tokens => tokens(), optional(:finish_reason) => atom(), optional(:output_limit) => output_limit() }
@type usd_cost() :: %{currency: String.t(), microunits: non_neg_integer()}
Provider-reported token usage. :total_cost is absent when pricing is
unavailable; a present zero-microunit object is a measured zero-cost response.
Adapter responses may use a non-negative USD number or bounded decimal string;
the Kernel immediately replaces it with this fixed-point object.
Callbacks
@callback call(model :: term(), invocation :: PtcRunner.LLM.Invocation.t()) :: {:ok, map()} | {:error, PtcRunner.Kernel.ProviderError.t()}
Make an LLM call.
The request map contains:
:system- System prompt string:messages- List of message maps:schema- JSON Schema map (triggers structured output when the sealed installation mode isjson_schemaorjson_object):tools- Tool definitions (triggers tool calling):cache- Boolean for prompt caching
Returns {:ok, response} or {:error, reason}.
@callback ensure_ready() :: :ok
Preload adapter-owned model metadata into a shared, process-independent store
(e.g. a :persistent_term/ETS catalog) so the first per-request provider
worker does not pay a large one-time load inside its bounded heap.
Optional. The Kernel invokes it during selected provider-application admission and capability-build time for direct embedding paths. An adapter may also invoke its own callback during audited local contract attestation; that path runs before provider activity inside a bounded worker, so it must use only process-independent local metadata. Implementations must be idempotent.
@callback prepare_model( model :: String.t(), requirements :: PtcRunner.LLM.Requirements.t() ) :: {:ok, target :: term(), catalog_status(), PtcRunner.LLM.Requirements.t()} | {:error, term()}
Prepares an adapter-owned request target and attests the sealed requirements.
The returned attestation must be exactly the canonical requirements map. An
adapter that cannot preserve the requested options, mode, reporting
guarantees, or reservation authority returns {:error, :unsupported_model_option}.
An adapter that has positively established an uncataloged target and cannot
supply the USD rates required by a requested cost reservation returns the
payload-free sentinel
{:error, :uncataloged_cost_reservation_pricing_unavailable}. The Kernel
maps only that exact sentinel to the pricing-specific
model_contract_unsupported diagnostic and model_uncataloged warning;
payload-bearing variants fail closed.
@callback provider_application(model :: String.t()) :: :req_llm | nil
Names the OTP application this adapter needs running to serve model.
Optional. An adapter backed by a dependency the core does not start returns
that application's name so a host can report an unstarted provider
application as a host misconfiguration rather than as a retryable transport
failure. The answer is per model, because one adapter may route some models
through a dependency and others straight over HTTP. Adapters with no such
dependency omit the callback or return nil.
Constrained to :req_llm because that is the only backing application the
installation catalog validates and the CLI's ownership selection understands.
Admitting arbitrary applications means widening those two consumers as well,
which is a deliberate change rather than a side effect of this callback.
Attests that the exact adapter target is safe to publish in canonical traces.
Optional. Return {:ok, model} only when the complete value is public model
identity. Return :private for local, endpoint-bearing, deployment-private,
or otherwise sensitive targets. PtcRunner rejects altered, malformed, or
oversized values and treats a missing or raising callback as private.
@callback reservation_bound( prepared_target :: term(), normalized_request :: map(), reservation_tariff :: PtcRunner.LLM.Requirements.cost_tariff() | nil ) :: map()
Functions
@spec adapter!() :: module()
Returns the configured LLM adapter module.
Resolution order:
config :ptc_runner, :llm_adapter, MyAdapterPtcRunner.LLM.ReqLLMAdapterifreq_llmis available- Raises if no adapter found
@spec callback(PtcRunner.LLM.PreparedModel.t(), runtime_binding()) :: {:ok, (map(), requester_context() -> {:ok, map()} | {:error, PtcRunner.Kernel.ProviderError.t()})} | {:error, :invalid_prepared_model | :invalid_llm_binding}
Creates a normalized requester for a prepared model.
The binding is a closed map of credential and cache. The returned
requester is arity two: a provider-neutral request plus
%{llm_request_deadline_ms: integer() | nil}. An uncataloged selector emits
one concise warning while the requester is built.
@spec catalog_warning(PtcRunner.LLM.PreparedModel.t()) :: {:model_uncataloged, binary() | nil} | nil
Returns the closed public warning fact for an uncataloged prepared model.
The adapter remains the authority on whether its selector is public. Direct HTTP selectors therefore stay private even when catalog facts are absent.
@spec prepare(String.t(), PtcRunner.LLM.Requirements.t(), module()) :: {:ok, PtcRunner.LLM.PreparedModel.t()} | {:error, term()}
Resolves a configured selector into an immutable adapter-owned request target.
Generated prepare/2 means (model, requirements). Explicit prepare/3
means (model, requirements, adapter). Preparation runs adapter warmup and
model resolution once, validates exact requirements/attestation equality, and
returns a typed error immediately when either operation cannot produce a valid
prepared value.