gleamunison/llm
LLM ability host surface (gap analysis concept A).
The LLM call is an effect; providers, retries, fallbacks, and mocks are composable handlers over the effects.run stack — no client registry, no codegen. Op contract at the handler boundary: args[0] = messages JSON BitArray ([{“role”:“user”,“content”:“…”}]) result passed to continuation = {ok, CompletionJsonBin} | {error, ReasonBin}
Types
pub type Completion {
Completion(
content: String,
model: String,
input_tokens: Int,
output_tokens: Int,
)
}
Constructors
-
Completion( content: String, model: String, input_tokens: Int, output_tokens: Int, )
pub type LlmError {
TransportError(reason: String)
HttpError(status: Int, body: String)
DecodeError(reason: String)
}
Constructors
-
TransportError(reason: String) -
HttpError(status: Int, body: String) -
DecodeError(reason: String)
Values
pub fn ability_ref() -> identity.DefinitionRef
pub fn build_request(
cfg: ProviderConfig,
messages: List(Message),
) -> #(String, List(#(String, String)), String)
pub fn complete_env(prompt: String) -> Result(String, String)
One-shot completion from environment config: the default live handler body. Reads OPENAI_API_KEY/OPENAI_BASE_URL/OPENAI_MODEL (or ANTHROPIC_* when its key is set). Kept dependency-free so the Erlang runtime can call it directly as the ambient handler.
pub fn completion_json(c: Completion) -> BitArray
pub fn error_string(e: LlmError) -> String
pub fn frame(
handler: fn(
List(dynamic.Dynamic),
fn(dynamic.Dynamic) -> dynamic.Dynamic,
) -> dynamic.Dynamic,
) -> effects.HandlerFrame
Wrap any LLM OpHandler as a HandlerFrame for effects.run.
pub fn messages_json(msgs: List(Message)) -> String
pub fn mock_handler(
response: Completion,
) -> fn(
List(dynamic.Dynamic),
fn(dynamic.Dynamic) -> dynamic.Dynamic,
) -> dynamic.Dynamic
Deterministic mock: always answers the same completion. The live call and the test double are the same handler swap — that is the whole point.
pub fn parse_response(
provider: Provider,
status: Int,
body: String,
) -> Result(Completion, LlmError)
pub fn provider_handler(
cfg: ProviderConfig,
) -> fn(
List(dynamic.Dynamic),
fn(dynamic.Dynamic) -> dynamic.Dynamic,
) -> dynamic.Dynamic
Live provider handler: performs the HTTP call via http_client.