% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/answer_using_tools.R
\name{answer_using_tools}
\alias{answer_using_tools}
\title{Enable LLM to call R functions (and/or MCP server tools)}
\usage{
answer_using_tools(
  prompt,
  tools = list(),
  type = c("auto", "openai", "ollama", "ellmer", "text-based")
)
}
\arguments{
\item{prompt}{A single string or a \code{\link[=tidyprompt]{tidyprompt()}} object}

\item{tools}{An R function, an 'ellmer' tool definition (from \code{\link[ellmer:tool]{ellmer::tool()}}),
or a list of either, which the LLM will be able to call. If an R function is passed
which has been documented in a help file (e.g., because it is part of a package),
the documentation will be parsed from the help file. If it is a custom function,
documentation should be added with \code{\link[=tools_add_docs]{tools_add_docs()}} or with \code{\link[ellmer:tool]{ellmer::tool()}}.
Note that you can also provide Model Context Protocol (MCP) tools from MCP servers
as returned from \code{\link[mcptools:client]{mcptools::mcp_tools()}}.
Provider-specific 'ellmer' built-in tools are only supported with
'ellmer'-backed providers.}

\item{type}{(optional) The way that tool calling should be enabled.
"auto" will automatically determine the type based on \code{llm_provider$api_type}
or 'llm_provider$tool_type' (if set; 'tool_type' overrides 'api_type' determination)
(note that this may not consider model compatibility, and could lead to errors;
set 'type' manually if errors occur). "openai" and "ollama" will set the
relevant API parameters. "ellmer" will register the tool in the 'ellmer' chat
object of the LLM provider; note that this will only work for an \code{\link[=llm_provider_ellmer]{llm_provider_ellmer()}}
("auto" will always set the type to "ellmer" if you are using an 'ellmer' LLM provider).
"text-based" will provide function definitions in the prompt, extract function
calls from the LLM response, and call the
functions, providing the results back via \code{\link[=llm_feedback]{llm_feedback()}}. "text-based"
always works, but may be inefficient for APIs that support tool calling
natively. Note that when using "openai", "ollama", or "ellmer", tool calls are not counted
as interactions by \code{\link[=send_prompt]{send_prompt()}} and may continue indefinitely unless restricted
by other means}
}
\value{
A \code{\link[=tidyprompt]{tidyprompt()}} with an added \code{\link[=prompt_wrap]{prompt_wrap()}} which
will allow the LLM to call the given R functions when evaluating
the prompt with \code{\link[=send_prompt]{send_prompt()}}
}
\description{
This function adds the ability for the a LLM to call R functions.
Users can specify a list of functions that the LLM can call, and the
prompt will be modified to include information, as well as an
accompanying extraction function to call the functions (handled by
\code{\link[=send_prompt]{send_prompt()}}). Documentation for the functions is extracted from
the help file (if available), or from documentation added by
\code{\link[=tools_add_docs]{tools_add_docs()}}. Users can also provide an 'ellmer' tool definition
(see \code{\link[ellmer:tool]{ellmer::tool()}}; \href{https://ellmer.tidyverse.org/articles/tool-calling.html}{'ellmer' documentation}).
Model Context Protocol (MCP) tools from MCP servers, as returned from
\code{\link[mcptools:client]{mcptools::mcp_tools()}}, may also be used. Regular \code{\link[ellmer:tool]{ellmer::tool()}}
definitions are converted as needed and can work with both 'ellmer' and
regular LLM providers. Provider-specific 'ellmer' built-in tools
(i.e., 'ToolBuiltIn' objects) only work with 'ellmer'-backed providers.
}
\details{
Note that conversion between 'tidyprompt' and 'ellmer' tool definitions
is experimntal and might contain bugs.
Provider-specific 'ellmer' built-in tools are only supported when using an
\code{\link[=llm_provider_ellmer]{llm_provider_ellmer()}} object (or an 'ellmer' chat passed directly to
\code{\link[=send_prompt]{send_prompt()}}).
}
\examples{
# When using functions from base R or R packages,
#   documentation is automatically extracted from help files:
prompt_with_dir_function <- "What are the files in my current directory?" |>
  answer_using_tools(dir) # The 'dir' function is from base R
\dontrun{
  send_prompt(prompt_with_dir_function)
  # --- Sending request to LLM provider (llama3.1:8b): ---
  #   What are the files in my current directory?
  #   --- Receiving response from LLM provider: ---
  #   Calling function 'nm' with arguments:
  #   {
  #     "all.files": true,
  #     "full.names": false,
  #     "ignore.case": false,
  #     "include.dirs": false,
  #     "no..": false,
  #     "path": "./",
  #     "pattern": "*",
  #     "recursive": false
  #   }
  # Result:
  #   .git, .github, .gitignore, .Rbuildignore, .Rhistory, ...
  # The files in your current directory are:
  #   .git, .github, .gitignore, .Rbuildignore, .Rhistory, ...
  # [1] "The files in your current directory are:\n\n .git, .github, ..."
}

# Users may provide custom functions in two ways:
#   1) as a function object, optionally documented with `tools_get_docs()`, or
#   2) as an 'ellmer' tool definition, using `ellmer::tool()`

# Take this fake weather function as an example:
temperature_in_location <- function(
  location = c("Amsterdam", "Utrecht", "Enschede"),
  unit = c("Celcius", "Fahrenheit")
) {
  location <- match.arg(location)
  unit <- match.arg(unit)

  temperature_celcius <- switch(
    location,
    "Amsterdam" = 32.5,
    "Utrecht" = 19.8,
    "Enschede" = 22.7
  )

  if (unit == "Celcius") {
    return(temperature_celcius)
  } else {
    return(temperature_celcius * 9/5 + 32)
  }
}


# 1: `tools_add_docs()` --------------------------------------------------------

# Generate documentation for a function, based on formals & help file
docs <- tools_get_docs(temperature_in_location)

# The types get inferred from the function's formals
# However, descriptions are still missing as the function is not from a package
# We can modify the documentation object to add descriptions:
docs$description <- "Get the temperature in a location"
docs$arguments$unit$description <- "Unit in which to return the temperature"
docs$arguments$location$description <- "Location for which to return the temperature"
docs$return$description <- "The temperature in the specified location and unit"
# (See `?tools_add_docs` for more details on the structure of the documentation)

# When we are satisfied with the documentation, we can add it to the function:
temperature_in_location <- tools_add_docs(temperature_in_location, docs)

prompt_with_weather_function <-
  "What is the weather in Enschede? Give me Celcius degrees" |>
  answer_using_tools(temperature_in_location)
\dontrun{
  send_prompt(prompt_with_weather_function)
  # --- Sending request to LLM provider (llama3.1:8b): ---
  #   What is the weather in Enschede? Give me Celcius degrees
  #   --- Receiving response from LLM provider: ---
  #   Calling function 'temperature_in_location' with arguments:
  #   {
  #     "location": "Enschede",
  #     "unit": "Celcius"
  #   }
  # Result:
  #   22.7
  # The temperature in Enschede is 22.7 Celcius degrees.
  # [1] "The temperature in Enschede is 22.7 Celcius degrees."
}

# 2: `ellmer::tool()` -----------------------------------------------

# Alternatively, we can define the function as an 'ellmer' tool

temperature_in_location_ellmer <- ellmer::tool(
  temperature_in_location,
  name = "get_temperature",
  description = "Get the temperature in a location",
  arguments = list(
    location = ellmer::type_string(
      "Location for which to return the temperature", required = TRUE
    ),
    unit = ellmer::type_string(
      "Unit in which to return the temperature", required = TRUE
    )
  )
)

prompt_with_weather_function_ellmer <-
  "What is the weather in Utrecht? Give me Fahrenheit degrees" |>
  answer_using_tools(temperature_in_location_ellmer)
\dontrun{
  send_prompt(prompt_with_weather_function_ellmer)
  # ...
}

# Because `mcptools::mcp_tools()` returns a list of `ellmer:tool()` tools,
#   you can also use Model Context Protocol (MCP) server tools with
#   `answer_using_tools()`:
\dontrun{
  prompt_using_mcp_tools <- mcptools::mcp_tools()
  "Push my latest commit to GitHub" |>
    answer_using_tools(mcp_tools)
  send_prompt(prompt_using_mcp_tools)
}

# `answer_using_tools()` will automatically attempt to use the most appropriate
#   way of sending the tool to the LLM

# If you use a LLM provider of type 'ollama' or 'openai',
#   it will automatically convert the tool definition to parameters
#   appropriate for those APIs
# If you use a LLM provider of type 'ellmer', it will call the appropriate
#   ellmer function directly which will handle the tool call for various
#   providers
# Note that both tool definitions from `tools_add_docs()` and `ellmer::tool()`
#   will work with any LLM provider; `answer_using_tools()` can convert
#   the two types of tool definitions to each other when needed
\dontrun{
  ollama <- llm_provider_ollama()
  # Ollama LLM provider:
  "What is the weather in Amsterdam? Give me Fahrenheit degrees" |>
    answer_using_tools(temperature_in_location) |>
    send_prompt(ollama)

  # Ollama LLM provider also works with `ellmer::tool()` definitions:
  "What is the weather in Amsterdam? Give me Celcius degrees" |>
    answer_using_tools(temperature_in_location_ellmer) |>
    send_prompt(ollama)

  # Similar for OpenAI API:
  openai <- llm_provider_openai()
  "What is the weather in Amsterdam? Give me Celcius degrees" |>
    answer_using_tools(temperature_in_location) |>
    send_prompt(openai)
  # ...

  # Ellmer LLM provider:
  ellmer <- llm_provider_ellmer(ellmer::chat_openai())
  "What is the weather in Amsterdam? Give me Celcius degrees" |>
    answer_using_tools(temperature_in_location_ellmer) |>
    send_prompt(ellmer)

  # Also works with `tools_add_docs()` definition:
  "What is the weather in Amsterdam? Give me Celcius degrees" |>
    answer_using_tools(temperature_in_location) |>
    send_prompt(ellmer)
}
}
\seealso{
\code{\link[=answer_using_r]{answer_using_r()}} \code{\link[=tools_get_docs]{tools_get_docs()}}

Other pre_built_prompt_wraps: 
\code{\link{add_image}()},
\code{\link{add_text}()},
\code{\link{answer_as_boolean}()},
\code{\link{answer_as_category}()},
\code{\link{answer_as_dataframe}()},
\code{\link{answer_as_integer}()},
\code{\link{answer_as_json}()},
\code{\link{answer_as_list}()},
\code{\link{answer_as_multi_category}()},
\code{\link{answer_as_named_list}()},
\code{\link{answer_as_numeric}()},
\code{\link{answer_as_regex_match}()},
\code{\link{answer_as_text}()},
\code{\link{answer_by_chain_of_thought}()},
\code{\link{answer_by_react}()},
\code{\link{answer_using_r}()},
\code{\link{answer_using_sql}()},
\code{\link{prompt_wrap}()},
\code{\link{quit_if}()},
\code{\link{set_system_prompt}()}

Other answer_using_prompt_wraps: 
\code{\link{answer_using_r}()},
\code{\link{answer_using_sql}()}

Other tools: 
\code{\link{tools_add_docs}()},
\code{\link{tools_get_docs}()}
}
\concept{answer_using_prompt_wraps}
\concept{pre_built_prompt_wraps}
\concept{tools}
