% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/LLMR.R
\name{call_llm}
\alias{call_llm}
\alias{call_llm.ollama}
\title{Call an LLM (chat/completions or embeddings) with optional multimodal input}
\usage{
call_llm(config, messages, verbose = FALSE)

\method{call_llm}{ollama}(config, messages, verbose = FALSE)
}
\arguments{
\item{config}{An \code{\link{llm_config}} object.}

\item{messages}{One of:
\itemize{
\item Plain character vector — each element becomes a \code{"user"} message.
\item Named character vector — names are roles (\code{"system"}, \code{"user"},
\code{"assistant"}). \strong{Multimodal shortcut:} include one or more
elements named \code{"file"} whose values are local paths; consecutive
\code{{user | file}} entries are combined into one user turn and files
are inlined (base64) for capable providers.
\item List of message objects: \code{list(role=..., content=...)}. For
multimodal content, set \code{content} to a list of parts like
\code{list(list(type="text", text="..."), list(type="file", path="..."))}.
}}

\item{verbose}{Logical. If \code{TRUE}, prints the full parsed API response.}
}
\value{
\itemize{
\item Generative mode: an \code{llmr_response} object. Use \code{as.character(x)} to get just the text; \code{print(x)} shows text plus a status line; use helpers \code{finish_reason(x)} and \code{tokens(x)}.
\item Embedding mode: provider-native list with an element \code{data}; convert with \code{\link[=parse_embeddings]{parse_embeddings()}}.
}
}
\description{
\code{call_llm()} dispatches to the correct provider implementation based on
\code{config$provider}. It supports both generative chat/completions and
embeddings, plus a simple multimodal shortcut for local files.
}
\section{Provider notes}{

\itemize{
\item \strong{OpenAI-compatible:} On a server 400 that identifies the bad
parameter as \code{max_tokens}, LLMR will, unless \code{no_change=TRUE},
retry once replacing \code{max_tokens} with \code{max_completion_tokens}
(and inform via a \code{cli_alert_info}). The former experimental
"uncapped retry on empty content" is \emph{disabled} by default to
avoid unexpected costs.
\item \strong{Anthropic:} \code{max_tokens} is required; if omitted LLMR uses
\code{2048} and warns. Multimodal images are inlined as base64. Extended
thinking is supported: provide \code{thinking_budget} and
\code{include_thoughts = TRUE} to include a \code{content} block of type
\code{"thinking"} in the response; LLMR sets the beta header automatically.
\item \strong{Gemini (REST):} \code{systemInstruction} is supported; user
parts use \code{text}/\code{inlineData(mimeType,data)}; responses are set to
\code{responseMimeType = "text/plain"}. For Vertex AI, use
\verb{provider = "gemini", vertex = TRUE, project = ...}.
\item \strong{Ollama (local):} OpenAI-compatible endpoints on \verb{http://localhost:11434/v1/*};
no Authorization header is required. Override with \code{api_url} as needed.
\item \strong{Error handling:} HTTP errors raise structured conditions with
classes like \code{llmr_api_param_error}, \code{llmr_api_rate_limit_error},
\code{llmr_api_server_error}; see the condition fields for status, code,
request id, and (where supplied) the offending parameter.
}
}

\section{Message normalization}{

See the \emph{"multimodal shortcut"} described under \code{messages}. Internally,
LLMR expands these into the provider's native request shape and tilde-expands
local file paths.
}

\section{Using a local Ollama server}{

Ollama provides an OpenAI-compatible HTTP API on localhost by default. Start the
daemon and pull a model first (terminal): \verb{ollama serve} (in background) and
\verb{ollama pull llama3}. Then configure LLMR with
\code{llm_config("ollama", "llama3", embedding = FALSE)} for chat or
\code{llm_config("ollama", "nomic-embed-text", embedding = TRUE)} for embeddings.
Override the endpoint with \code{api_url} if not using the default
\verb{http://localhost:11434/v1/*}.
}

\examples{
\dontrun{
## 1) Basic generative call
cfg <- llm_config("openai", "gpt-5-nano")
call_llm(cfg, "Say hello in Greek.")

## 2) Generative with rich return
r <- call_llm(cfg, "Say hello in Greek.")
r
as.character(r)
finish_reason(r); tokens(r)

## 3) Anthropic extended thinking (single example)
a_cfg <- llm_config("anthropic", "claude-sonnet-4-6",
                    max_tokens = 5000,
                    thinking_budget = 16000,
                    include_thoughts = TRUE)
r2 <- call_llm(a_cfg, "Compute 87*93 in your head. Give only the final number.")
# thinking (if present): r2$raw$content[[1]]$thinking
# final text:            r2$raw$content[[2]]$text

## 4) Multimodal (named-vector shortcut)
msg <- c(
  system = "Answer briefly.",
  user   = "Describe this image in one sentence.",
  file   = "~/Pictures/example.png"
)
call_llm(cfg, msg)

## 5) Embeddings
e_cfg <- llm_config("voyage", "voyage-3.5-lite",
                    embedding = TRUE)
emb_raw <- call_llm(e_cfg, c("first", "second"))
emb_mat <- parse_embeddings(emb_raw)

## 6) With a chat session
ch <- chat_session(cfg)
ch$send("Say hello in Greek.")   # prints the same status line as `print.llmr_response`
ch$history()
}

}
\seealso{
\code{\link{llm_config}},
\code{\link{call_llm_robust}},
\code{\link{llm_chat_session}},
\code{\link{parse_embeddings}},
\code{\link{finish_reason}},
\code{\link{tokens}}
}
