Skip to content

Commit

Permalink
Merge commit '137216ecd9416cd77eb6007d11b22c987770f607'
Browse files Browse the repository at this point in the history
  • Loading branch information
hadley committed Dec 19, 2024
2 parents 6d982d3 + 137216e commit c9261b8
Show file tree
Hide file tree
Showing 62 changed files with 211 additions and 177 deletions.
2 changes: 1 addition & 1 deletion .Rbuildignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
^elmer\.Rproj$
^ellmer\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
^\.github$
Expand Down
8 changes: 4 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Package: elmer
Package: ellmer
Title: Call Large Language Model 'API's
Version: 0.0.0.9000
Authors@R: c(
Expand All @@ -11,8 +11,8 @@ Description: A consistent interface for calling 'LLM' (large language model)
'Azure' 'Bedrock' and 'Google' 'Gemini'. Supports streaming, 'async', tool
calling, and structured data extraction.
License: MIT + file LICENSE
URL: https://elmer.tidyverse.org, https://github.com/tidyverse/elmer
BugReports: https://github.com/tidyverse/elmer/issues
URL: https://ellmer.tidyverse.org, https://github.com/tidyverse/ellmer
BugReports: https://github.com/tidyverse/ellmer/issues
Imports:
cli,
coro (>= 1.1.0),
Expand Down Expand Up @@ -57,7 +57,7 @@ Collate:
'chat.R'
'content-image.R'
'content-tools.R'
'elmer-package.R'
'ellmer-package.R'
'httr2.R'
'import-standalone-obj-type.R'
'import-standalone-purrr.R'
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
YEAR: 2024
COPYRIGHT HOLDER: elmer authors
COPYRIGHT HOLDER: ellmer authors
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MIT License

Copyright (c) 2024 elmer authors
Copyright (c) 2024 ellmer authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# elmer (development version)
# ellmer (development version)

* New `chat_vllm()` to chat with models served by vLLM (#140).

Expand Down Expand Up @@ -28,7 +28,7 @@

* The `echo` can now be one of three values: "none", "text", or "all". If "all", you'll now see both user and assistant turns, and all content types will be printed, not just text. When running in the global environment, `echo` defaults to "text", and when running inside a function it defaults to "none".

* You can now log low-level JSON request/response info by setting `options(elmer_verbosity = 2)`.
* You can now log low-level JSON request/response info by setting `options(ellmer_verbosity = 2)`.

* `chat$register_tool()` now takes an object created by `Tool()`. This makes it a little easier to reuse tool definitions (#32).

Expand Down
8 changes: 4 additions & 4 deletions R/chat.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ NULL
#' but instead call [chat_openai()] or friends instead.
#'
#' @return A Chat object
#' @examplesIf elmer:::openai_key_exists()
#' @examplesIf ellmer:::openai_key_exists()
#' chat <- chat_openai(echo = TRUE)
#' chat$chat("Tell me a funny joke")
Chat <- R6::R6Class("Chat",
Expand Down Expand Up @@ -254,13 +254,13 @@ Chat <- R6::R6Class("Chat",
},

#' @description Register a tool (an R function) that the chatbot can use.
#' If the chatbot decides to use the function, elmer will automatically
#' If the chatbot decides to use the function, ellmer will automatically
#' call it and submit the results back.
#'
#'
#' The return value of the function. Generally, this should either be a
#' string, or a JSON-serializable value. If you must have more direct
#' control of the structure of the JSON that's returned, you can return a
#' JSON-serializable value wrapped in [base::I()], which elmer will leave
#' JSON-serializable value wrapped in [base::I()], which ellmer will leave
#' alone until the entire request is JSON-serialized.
#' @param tool_def Tool definition created by [tool()].
register_tool = function(tool_def) {
Expand Down
6 changes: 3 additions & 3 deletions R/content-image.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
#' the `chat()`, `stream()`, `chat_async()`, or `stream_async()` methods.
#'
#' @export
#' @examplesIf elmer:::openai_key_exists()
#' @examplesIf ellmer:::openai_key_exists()
#' chat <- chat_openai(echo = TRUE)
#' chat$chat(
#' "What do you see in these images?",
#' content_image_url("https://www.r-project.org/Rlogo.png"),
#' content_image_file(system.file("httr2.png", package = "elmer"))
#' content_image_file(system.file("httr2.png", package = "ellmer"))
#' )
#'
#' \dontshow{dev.control('enable')}
Expand Down Expand Up @@ -144,7 +144,7 @@ content_image_plot <- function(width = 768, height = 768) {

old <- grDevices::dev.cur()

path <- tempfile("elmer-plot-", fileext = ".png")
path <- tempfile("ellmer-plot-", fileext = ".png")
defer(unlink(path))

grDevices::png(path, width = width, height = height)
Expand Down
4 changes: 2 additions & 2 deletions R/content.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ contents_markdown <- new_generic("contents_markdown", "content")
#' Content types received from and sent to a chatbot
#'
#' @description
#' Use these functions if you're writing a package that extends elmer and need
#' Use these functions if you're writing a package that extends ellmer and need
#' to customise methods for various types of content. For normal use, see
#' [content_image_url()] and friends.
#'
#' elmer abstracts away differences in the way that different [Provider]s
#' ellmer abstracts away differences in the way that different [Provider]s
#' represent various types of content, allowing you to more easily write
#' code that works with any chatbot. This set of classes represents types of
#' content that can be either sent to and received from a provider:
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion R/httr2.R
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,5 @@ cat_with_prefix <- function(prefix, lines) {
}

log_http_traffic <- function() {
getOption("elmer_verbosity", 0L) >= 2L
getOption("ellmer_verbosity", 0L) >= 2L
}
4 changes: 2 additions & 2 deletions R/provider-bedrock.R
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ method(chat_resp_stream, ProviderBedrock) <- function(provider, resp) {
resp_stream_aws(resp)
}

# Bedrock -> elmer -------------------------------------------------------------
# Bedrock -> ellmer -------------------------------------------------------------

method(stream_parse, ProviderBedrock) <- function(provider, event) {
if (is.null(event)) {
Expand Down Expand Up @@ -221,7 +221,7 @@ method(value_turn, ProviderBedrock) <- function(provider, result, has_type = FAL
Turn(result$output$message$role, contents, json = result, tokens = tokens)
}

# elmer -> Bedrock -------------------------------------------------------------
# ellmer -> Bedrock -------------------------------------------------------------

# https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ContentBlock.html
method(as_json, list(ProviderBedrock, Turn)) <- function(provider, x) {
Expand Down
6 changes: 3 additions & 3 deletions R/provider-claude.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ NULL
#' @param max_tokens Maximum number of tokens to generate before stopping.
#' @family chatbots
#' @export
#' @examplesIf elmer:::anthropic_key_exists()
#' @examplesIf ellmer:::anthropic_key_exists()
#' chat <- chat_claude()
#' chat$chat("Tell me three jokes about statisticians")
chat_claude <- function(system_prompt = NULL,
Expand Down Expand Up @@ -139,7 +139,7 @@ method(chat_request, ProviderClaude) <- function(provider,
req
}

# Claude -> elmer --------------------------------------------------------------
# Claude -> ellmer --------------------------------------------------------------

method(stream_parse, ProviderClaude) <- function(provider, event) {
if (is.null(event)) {
Expand Down Expand Up @@ -224,7 +224,7 @@ method(value_turn, ProviderClaude) <- function(provider, result, has_type = FALS
Turn(result$role, contents, json = result, tokens = tokens)
}

# elmer -> Claude --------------------------------------------------------------
# ellmer -> Claude --------------------------------------------------------------

method(as_json, list(ProviderClaude, Turn)) <- function(provider, x) {
if (x@role == "system") {
Expand Down
10 changes: 5 additions & 5 deletions R/provider-cortex.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ NULL
#' @inheritParams chat_openai
#' @inherit chat_openai return
#' @family chatbots
#' @examplesIf elmer:::cortex_credentials_exist()
#' @examplesIf ellmer:::cortex_credentials_exist()
#' chat <- chat_cortex(
#' model_file = "@my_db.my_schema.my_stage/model.yaml"
#' )
Expand Down Expand Up @@ -137,11 +137,11 @@ method(chat_request, ProviderCortex) <- function(provider,
req <- req_error(req, body = function(resp) resp_body_json(resp)$message)

# Snowflake uses the User Agent header to identify "parter applications",
# so identify requests as coming from "r_elmer" (unless an explicit
# so identify requests as coming from "r_ellmer" (unless an explicit
# partner application is set via the ambient SF_PARTNER environment
# variable).
req <- req_user_agent(
req, paste0("r_elmer/", utils::packageVersion("elmer"))
req, paste0("r_ellmer/", utils::packageVersion("ellmer"))
)
if (nchar(Sys.getenv("SF_PARTNER")) != 0) {
req <- req_user_agent(req, Sys.getenv("SF_PARTNER"))
Expand All @@ -158,7 +158,7 @@ method(chat_request, ProviderCortex) <- function(provider,
req
}

# Cortex -> elmer --------------------------------------------------------------
# Cortex -> ellmer --------------------------------------------------------------

method(stream_parse, ProviderCortex) <- function(provider, event) {
# While undocumented, Cortex seems to mostly follow OpenAI API conventions for
Expand Down Expand Up @@ -281,7 +281,7 @@ method(value_turn, ProviderCortex) <- function(provider, result, has_type = FALS
}


# elmer -> Cortex --------------------------------------------------------------
# ellmer -> Cortex --------------------------------------------------------------

# Cortex supports not only "text" content, but also bespoke "suggestions" and
# "sql" types.
Expand Down
6 changes: 3 additions & 3 deletions R/provider-databricks.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#'
#' Databricks models do not support images, but they do support structured
#' outputs. Tool calling support is also very limited at present; too limited
#' for `elmer`'s tool calling features to work properly at all.
#' for `ellmer`'s tool calling features to work properly at all.
#'
#' ## Authentication
#'
Expand Down Expand Up @@ -193,7 +193,7 @@ databricks_token <- function(workspace = databricks_workspace(), token = NULL) {
paste0("https://", host, "/oidc/v1/token"),
secret = client_secret,
auth = "header",
name = "elmer-databricks-m2m"
name = "ellmer-databricks-m2m"
),
oauth_flow_client_credentials,
# The "all-apis" scope translates to "everything this service principal
Expand Down Expand Up @@ -244,7 +244,7 @@ databricks_token <- function(workspace = databricks_workspace(), token = NULL) {
"databricks-cli",
paste0("https://", host, "/oidc/v1/token"),
auth = "body",
name = "elmer-databricks-u2m"
name = "ellmer-databricks-u2m"
),
oauth_flow_auth_code,
flow_params = list(
Expand Down
4 changes: 2 additions & 2 deletions R/provider-gemini.R
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ method(chat_request, ProviderGemini) <- function(provider,
req
}

# Gemini -> elmer --------------------------------------------------------------
# Gemini -> ellmer --------------------------------------------------------------

method(stream_parse, ProviderGemini) <- function(provider, event) {
if (is.null(event)) {
Expand Down Expand Up @@ -174,7 +174,7 @@ method(value_turn, ProviderGemini) <- function(provider, result, has_type = FALS
Turn("assistant", contents, json = result, tokens = tokens)
}

# elmer -> Gemini --------------------------------------------------------------
# ellmer -> Gemini --------------------------------------------------------------

# https://ai.google.dev/api/caching#Content
method(as_json, list(ProviderGemini, Turn)) <- function(provider, x) {
Expand Down
6 changes: 3 additions & 3 deletions R/provider-openai.R
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ NULL
#' @family chatbots
#' @export
#' @returns A [Chat] object.
#' @examplesIf elmer:::openai_key_exists()
#' @examplesIf ellmer:::openai_key_exists()
#' chat <- chat_openai()
#' chat$chat("
#' What is the difference between a tibble and a data frame?
Expand Down Expand Up @@ -145,7 +145,7 @@ method(chat_request, ProviderOpenAI) <- function(provider,
req
}

# OpenAI -> elmer --------------------------------------------------------------
# OpenAI -> ellmer --------------------------------------------------------------

method(stream_parse, ProviderOpenAI) <- function(provider, event) {
if (is.null(event)) {
Expand Down Expand Up @@ -204,7 +204,7 @@ method(value_turn, ProviderOpenAI) <- function(provider, result, has_type = FALS
Turn(message$role, content, json = result, tokens = tokens)
}

# elmer -> OpenAI --------------------------------------------------------------
# ellmer -> OpenAI --------------------------------------------------------------

method(as_json, list(ProviderOpenAI, Turn)) <- function(provider, x) {
if (x@role == "system") {
Expand Down
7 changes: 5 additions & 2 deletions R/provider-vllm.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ NULL
#' `chat_vllm()` to connect to endpoints powered by vLLM.
#'
#' @inheritParams chat_openai
#' @param api_key The API key to use for authentication. You generally should
#' not supply this directly, but instead set the `VLLM_API_KEY` environment
#' variable.
#' @inherit chat_openai return
#' @export
#' @examples
Expand Down Expand Up @@ -59,7 +62,7 @@ chat_vllm_test <- function(...) {
ProviderVllm <- new_class(
"ProviderVllm",
parent = ProviderOpenAI,
package = "elmer",
package = "ellmer",
)

# Just like OpenAI but no strict
Expand All @@ -75,7 +78,7 @@ method(as_json, list(ProviderVllm, ToolDef)) <- function(provider, x) {
}

vllm_key <- function() {
key_get("VLLM_KEY")
key_get("VLLM_API_KEY")
}

vllm_models <- function(base_url, key = vllm_key()) {
Expand Down
2 changes: 1 addition & 1 deletion R/tools-def-auto.R
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ create_tool_def <- function(topic,

topic_str <- format(expr)

tool_prompt <- readLines(system.file("tool_prompt.md", package = "elmer"), warn = FALSE)
tool_prompt <- readLines(system.file("tool_prompt.md", package = "ellmer"), warn = FALSE)
tool_prompt <- paste(tool_prompt, collapse = "\n")

payload <- paste0(
Expand Down
2 changes: 1 addition & 1 deletion R/tools-def.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ NULL
#' function.
#' @export
#' @return An S7 `ToolDef` object.
#' @examplesIf elmer:::openai_key_exists()
#' @examplesIf ellmer:::openai_key_exists()
#'
#' # First define the metadata that the model uses to figure out when to
#' # call the tool
Expand Down
4 changes: 2 additions & 2 deletions R/turns.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ NULL
#'
#' Note that a call to `$chat()` and related functions may result in multiple
#' user-assistant turn cycles. For example, if you have registered tools,
#' elmer will automatically handle the tool calling loop, which may result in
#' ellmer will automatically handle the tool calling loop, which may result in
#' any number of additional cycles. Learn more about tool calling in
#' `vignette("tool-calling")`.
#'
Expand All @@ -21,7 +21,7 @@ NULL
#' @param json The serialized JSON corresponding to the underlying data of
#' the turns. Currently only provided for assistant.
#'
#' This is useful if there's information returned by the provider that elmer
#' This is useful if there's information returned by the provider that ellmer
#' doesn't otherwise expose.
#' @param tokens A numeric vector of length 2 representing the number of
#' input and output tokens (respectively) used in this turn. Currently
Expand Down
2 changes: 1 addition & 1 deletion R/types.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ NULL
#' Type definitions for function calling and structured data extraction.
#'
#' These S7 classes are provided for use by package devlopers who are
#' extending elmer. In every day use, use [type_boolean()] and friends.
#' extending ellmer. In every day use, use [type_boolean()] and friends.
#'
#' @name Type
#' @inheritParams type_boolean
Expand Down
2 changes: 1 addition & 1 deletion R/utils-coro.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async_method <- function(fn) {
# upon first call. This is necessary because the transformation needs to be done
# not at package build time, but after package load time.
#
# Elsewhere in elmer, we use rlang::on_load to defer the transformation of
# Elsewhere in ellmer, we use rlang::on_load to defer the transformation of
# generators until after package load time. We can't do that for R6 methods
# because nesting R6 class definitions inside of rlang::on_load causes roxygen2
# to get confused.
Expand Down
Loading

0 comments on commit c9261b8

Please sign in to comment.