Version 0.3.0 is currently being prepared for CRAN. This release represents a major milestone for tidyllm
The largest changes compared to 0.2.0 are:
chat()
, embed()
,
send_batch()
, check_batch()
, and
fetch_batch()
to interact with APIs. These functions always
work with a combination of verbs and providers:
chat()
,
embed()
, send_batch()
) define the type of
action you want to perform.openai()
,
claude()
, ollama()
) are an arguement of verbs
and specify the API to handle the action with and take provider-specific
argumentsEach verb and provider combination routes the interaction to
provider-specific functions like openai_chat()
or
claude_chat()
that do the work in the background. These
functions can also be called directly as an alternative more verbose and
provider-specific interface.
llm_message("Hello World") |>
openai(.model = "gpt-4o")
# Recommended Verb-Based Approach
llm_message("Hello World") |>
chat(openai(.model = "gpt-4o"))
# Or even configuring a provider outside
<- ollama(.model = "llama3.2-vision:90B",
my_ollama .ollama_server = "https://ollama.example-server.de",
.temperature = 0)
llm_message("Hello World") |>
chat(my_ollama)
# Alternative Approach is to use more verbose specific functions:
llm_message("Hello World") |>
openai_chat(.model = "gpt-4o")
openai()
, claude()
,
etc.) still work if you directly supply an LLMMessage
as
arguement, but issue deprecation warnings when used directly for
chat.R6
-based saved LLMMessage
objects are no
longer compatible with the new version. Saved objects from earlier
versions need to be re-createdgemini()
and perplexity()
as new supported
API providers. gemini()
brings interesting Video and Audio
features as well as search grounding to tidyllm.
perplexity()
also offers well cited search grounded
assitant repliesmistral()
get_reply_metadata()
to get information on token usage, or on other relevant metadata (like
sources used for grounding)R6
to S7
for the main
LLMMessage
class, improving maintainability,
interoperability, and future-proofing..grounding_threshold
argument
added of the gemini_chat()
function allowing you to use
Google searches to ground model responses to a search result Gemini
models. For example, asking about the maintainer of an obscure R package
works with grounding but does only lead to a hallucination without:llm_message("What is tidyllm and who maintains this package?") |>
gemini_chat(.grounding_threshold = 0.3)
perplexity_chat()
. The neat feature of perplexity is the
up-to-date web search it does with detailed citations. Cited sources are
available in the api_specific
-list column of
get_metadata()
.json_schema
support for ollama()
available with Ollama 0.5.0get_metadata()
returns a list column with API-specific
metadataR6
to S7
for the main
LLMMessage
classdf_llm_message()
APIProvider
classesapi_openai.R
,api_gemini.R
,etc. filesas_tibble()
S3 Generic for
LLMMessage
track_rate_limit()
.onattach()
removedR6
-based LLMMessage
-objects are not
compatible with the new version anymore! This also applies to saved
objects, like lists of batch files.::here("local_wip","example.mp3") |> gemini_upload_file()
here::here("local_wip","legrille.mp4") |> gemini_upload_file()
here
<- gemini_list_files()
file_tibble
llm_message("What are these two files about?") |>
gemini_chat(.fileid=file_tibble$name)
Better embedding functions with improved output and error handling
and new documentation. New article on using embeddings with
tidyllm. Support for embedding models on azure with
azure_openai_embedding()
embed()
and the related
API-specific functions was changed from a matrix to a tibble with an
input column and a list column containing one embedding vector and one
input per row.One disadvantage of the first iteration of the new interface was that
all arguements that needed to be passed to provider-specific functions,
were going through the provider function. This feels, unintuitive,
because users expect common arguments (e.g., .model, .temperature) to be
set directly in main verbs like chat()
or
send_batch()
.Moreover, provider functions don’t expose
arguments for autocomplete, making it harder for users to explore
options. Therefore, the main API verbs now directly accept common
arguements, and check them against the available arguements for each
API.
tidyllm
has introduced a verb-based interface overhaul
to provide a more intuitive and flexible user experience. Previously,
provider-specific functions like claude()
,
openai()
, and others were directly used for chat-based
workflows. Now, these functions primarily serve as provider
configuration for some general verbs like chat()
.
chat()
, embed()
,
send_batch()
, check_batch()
, and
fetch_batch()
to interact with APIs. These functions always
work with a combination of verbs and providers:
chat()
,
embed()
, send_batch()
) define the type of
action you want to perform.openai()
,
claude()
, ollama()
) are an arguement of verbs
and specify the API to handle the action with and take provider-specific
argumentsEach verb and provider combination routes the interaction to
provider-specific functions like openai_chat()
or
claude_chat()
that do the work in the background. These
functions can also be called directly as an alternative more verbose and
provider-specific interface.
llm_message("Hello World") |>
openai(.model = "gpt-4o")
# Recommended Verb-Based Approach
llm_message("Hello World") |>
chat(openai(.model = "gpt-4o"))
# Or even configuring a provider outside
<- ollama(.model = "llama3.2-vision:90B",
my_ollama .ollama_server = "https://ollama.example-server.de",
.temperature = 0)
llm_message("Hello World") |>
chat(my_ollama)
# Alternative Approach is to use more verbose specific functions:
llm_message("Hello World") |>
openai_chat(.model = "gpt-4o")
openai()
, claude()
,
etc.) still work if you directly supply an LLMMessage
as
arguement, but issue deprecation warnings when used directly for
chat.gemini()
main API-function#Upload a file for use with gemini
<- gemini_upload_file("example.mp3")
upload_info
#Make the file available during a Gemini API call
llm_message("Summarize this speech") |>
gemini(.fileid = upload_info$name)
#Delte the file from the Google servers
gemini_delete_file(upload_info$name)
tidyllm_schema()
gemini()
-requests allow for a wide range of file types
that can be used for context in messagesgemini()
file workflows:
application/pdf
text/plain
text/html
text/css
text/md
text/csv
text/xml
text/rtf
gemini()
file workflows:
application/x-javascript
,
text/javascript
application/x-python
,
text/x-python
gemini()
file workflows:
image/png
image/jpeg
image/webp
image/heic
image/heif
gemini()
file workflows:
video/mp4
video/mpeg
video/mov
video/avi
video/x-flv
video/mpg
video/webm
video/wmv
video/3gpp
gemini()
file workflows:
audio/wav
audio/mp3
audio/aiff
audio/aac
audio/ogg
audio/flac
get_metadata()
function to retrieve and format
metadata from LLMMessage
objects.print
method for LLMMessage
to support printing metadata, controlled via the new
tidyllm_print_metadata
option or a new
.meta
-arguement for the print method.<- llm_message("Write a short poem about software development") |>
conversation claude()
#Get metdata on token usage and model as tibble
get_metadata(conversation)
#or print it with the message
print(conversation,.meta=TRUE)
#Or allways print it
options(tidyllm_print_metadata=TRUE)
send_openai_batch()
caused by a missing
.json
-arguement not being passed for messages without
schemaNew CRAN release. Largest changes compared to 0.1.0:
Major Features:
.json_schema
handling in openai()
,
enhancing support for well-defined JSON responses.azure_openai()
function for accessing the Azure OpenAI service, with full support for
rate-limiting and batch operations tailored to Azure’s API
structure.mistral()
function
provides full support for Mistral models hosted in the EU, including
rate-limiting and streaming capabilities.pdf_page_batch()
function, which processes PDFs page by page, allowing users to define
page-specific prompts for detailed analysis..compatible
argument (and flexible url and path) in
openai()
to allow compatibility with third-party
OpenAI-compatible APIs.Improvements:
to_api_format()
to reduce code duplication, simplify API
format generation, and improve maintainability.httr2::req_retry()
in addition to the rate-limit tracking
functions in tidyllm, using 429 headers to wait for rate limit
resets.httptest2
Breaking Changes:
get_reply()
was split into
get_reply()
for text outputs and
get_reply_data()
for structured outputs, improving type
stability compared to an earlier function that had different outputs
based on a .json
-arguement.chatgpt()
: The chatgpt()
function has been deprecated in favor of openai()
for
feature alignment and improved consistency.Minor Updates and Bug Fixes:
llm_message()
: Allows
extraction of specific page ranges from PDFs, improving flexibility in
document handling.ollama_download_model()
function to download models
from the Ollama API.compatible
-arguement in openai()
to
allow working with compatible third party APIsto_api_format()
:
API format generation now has much less code duplication and is more
maintainable.get_reply()
was split into two type-stable functions:
get_reply()
for text and get_reply_data()
for
structured outputs.httr2::req_retry()
: Rate limiting now uses the
right 429 headers where they come.Enhanced Input Validation: All API functions now have improved input validation, ensuring better alignment with API documentation
Improved error handling More human-readable error messages for failed requests from the API
Advanced JSON Mode in openai()
: The
openai()
function now supports advanced
.json_schemas
, allowing structured output in JSON mode for
more precise responses.
Reasoning Models Support: Support for O1
reasoning models has been added, with better handling of system prompts
in the openai()
function.
Streaming callback functions refactored: Given that the streaming callback format for Open AI, Mistral and Groq is nearly identical the three now rely on the same callback function.
chatgpt()
Deprecated: The
chatgpt()
function has been deprecated in favor of
openai()
. Users should migrate to openai()
to
take advantage of the new features and enhancements.openai()
,
ollama()
, and claude()
functions now return
more informative error messages when API calls fail, helping with
debugging and troubleshooting.ollama_embedding()
to generate embeddings using the
Ollama API.openai_embedding()
to generate embeddings using the
OpenAI API.mistral_embedding()
to generate embeddings using the
Mistral API.llm_message()
: The
llm_message()
function now supports specifying a range of
pages in a PDF by passing a list with filename
,
start_page
, and end_page
. This allows users to
extract and process specific pages of a PDF.pdf_page_batch()
function, which processes PDF files page
by page, extracting text and converting each page into an image,
allowing for a general prompt or page-specific prompts. The function
generates a list of LLMMessage
objects that can be sent to
an API and work with the batch-API functions in
tidyllm.mistral()
function to use Mistral Models on Le Platforme on
servers hosted in the EU, with rate-limiting and streaming support.last_user_message()
pulls the last message the user
sent.get_reply()
gets the assistant reply at a given index
of assistant messages.get_user_message()
gets the user message at a given
index of user messages..dry_run
argument, allowing users
to generate an httr2
-request for easier debugging and
inspection.httptest2
-based tests with mock responses for all API
functions, covering both basic functionality and rate-limiting.ollama_download_model()
function to download models from
the Ollama API. It supports a streaming mode that provides live progress
bar updates on the download progress.llm_message()
groq()
function now supports images.llm_message()
.JSON Mode: JSON mode is now more widely
supported across all API functions, allowing for structured outputs when
APIs support them. The .json
argument is now passed only to
API functions, specifying how the API should respond, and it is not
needed anymore in last_reply()
.
Improved last_reply()
Behavior: The
behavior of the last_reply()
function has changed. It now
automatically handles JSON replies by parsing them into structured data
and falling back to raw text in case of errors. You can still force raw
text replies even for JSON output using the .raw
argument.
last_reply()
: The .json
argument is no longer used, and JSON replies are automatically parsed.
Use .raw
to force raw text replies.