Skip to contents

This function adds documentation to a custom function. This documentation is used to extract information about the function's name, description, arguments, and return value. This information is used to provide an LLM with information about the functions, so that the LLM can call R functions. The intended use of this function is to add documentation to custom functions that do not have help files; add_tools_get_documentation() will extract the documentation from help files when available.

Usage

add_tools_add_documentation(
  func,
  description,
  arguments = list(),
  return_value,
  name = NULL
)

Arguments

func

A function object

description

A description of the function

arguments

A named list of arguments (arguments) with descriptions

return_value

A description of the return value

name

The name of the function (optional). If not provided, the function name will be extracted from the function object

Value

The function object with the documentation added as an attribute

Details

If the function already has documentation, it will be overwritten by the documentation provided in this function (in terms of extraction by add_tools_get_documentation()). Thus, it is possible to override the help file documentation by adding custom documentation

Examples

# Example fake weather function to add to the prompt:
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)
  }
}

# Add documentation to a function:
temperature_in_location <- add_tools_add_documentation(
  temperature_in_location,
  description = "Get the temperature in a location",
  arguments = list(
    location = "Location, must be one of: 'Amsterdam', 'Utrecht', 'Enschede'",
    unit = "Unit, must be one of: 'Celcius', 'Fahrenheit'"
  ),
  return_value = "The temperature in the specified location and unit"
)

# Attempt to extract documentation as it is extracted by add_tools():
add_tools_get_documentation(temperature_in_location)
#> $name
#> [1] "temperature_in_location"
#> 
#> $description
#> [1] "Get the temperature in a location"
#> 
#> $arguments
#> $arguments$location
#> [1] "Location, must be one of: 'Amsterdam', 'Utrecht', 'Enschede'"
#> 
#> $arguments$unit
#> [1] "Unit, must be one of: 'Celcius', 'Fahrenheit'"
#> 
#> 
#> $return_value
#> [1] "The temperature in the specified location and unit"
#> 

# You can also pass functions which are included in packages;
#   documentation is then extracted from help files
#   (so you don't need to manually add documentation):
add_tools_get_documentation(list.files)
#> $name
#> [1] "list.files"
#> 
#> $description
#> [1] "List the Files in a Directory/Folder: These functions produce a character vector of the names of files\nor directories in the named directory."
#> 
#> $arguments
#> $arguments$path
#> [1] "a character vector of full path names; the default corresponds to the working directory, ‘getwd()’.  Tilde expansion (see ‘path.expand’) is performed.  Missing values will be ignored.  Elements with a marked encoding will be converted to the native encoding (and if that fails, considered non-existent)."
#> 
#> $arguments$pattern
#> [1] "an optional regular expression.  Only file names which match the regular expression will be returned."
#> 
#> $arguments$all.files
#> [1] "a logical value.  If ‘FALSE’, only the names of visible files are returned (following Unix-style visibility, that is files whose name does not start with a dot).  If ‘TRUE’, all file names will be returned."
#> 
#> $arguments$full.names
#> [1] "a logical value.  If ‘TRUE’, the directory path is prepended to the file names to give a relative file path.  If ‘FALSE’, the file names (rather than paths) are returned."
#> 
#> $arguments$recursive
#> [1] "logical.  Should the listing recurse into directories?"
#> 
#> $arguments$ignore.case
#> [1] "logical.  Should pattern-matching be case-insensitive?"
#> 
#> $arguments$include.dirs
#> [1] "logical.  Should subdirectory names be included in recursive listings?  (They always are in non-recursive ones)."
#> 
#> $arguments$no..
#> [1] "logical.  Should both ‘\".\"’ and ‘\"..\"’ be excluded also from non-recursive listings?"
#> 
#> 
#> $return_value
#> [1] "A character vector containing the names of the files in the\nspecified directories (empty if there were no files).  If a path\ndoes not exist or is not a directory or is unreadable it is\nskipped.\nThe files are sorted in alphabetical order, on the full path if\n‘full.names = TRUE’.\n‘list.dirs’ implicitly has ‘all.files = TRUE’, and if ‘recursive =\nTRUE’, the answer includes ‘path’ itself (provided it is a\nreadable directory).\n‘dir’ is an alias for ‘list.files’."
#> 

# Example usage:
prompt1 <- "Hi, what is the weather in Enschede? Give me Celcius degrees" |>
  add_tools(temperature_in_location)

prompt2 <- "What are the files in my current directory?" |>
  add_tools(list.files)

if (FALSE) { # \dontrun{
  prompt1 |>
    send_prompt(llm_provider_ollama())
  #   --- Sending request to LLM provider (llama3.1:8b): ---
  #     Hi, what is the weather in Enschede? Give me Celcius degrees
  #
  #     If you need more information, you can call functions to help you.
  #     To call a function, output a JSON object with the following format:
  #
  #       {
  #         "function": "<function name>",
  #         "arguments": {
  #           "<argument_name>": <argument_value>,
  #           ...
  #         }
  #       }
  #
  #     (Note: you cannot call other functions within arguments.)
  #
  #     The following functions are available:
  #
  #       function name: temperature_in_location
  #     description: Get the temperature in a location
  #     arguments:
  #       - location: Location, must be one of: 'Amsterdam', 'Utrecht', 'Enschede'
  #     - unit: Unit, must be one of: 'Celcius', 'Fahrenheit'
  #     return value: The temperature in the specified location and unit
  #
  #     After you call a function, wait until you receive more information.
  #     Use the information to decide your next steps or provide a final response.
  #   --- Receiving response from LLM provider: ---
  #     To get the weather in Enschede, I'll need to call the
  #     `temperature_in_location` function.
  #
  #   Here's my JSON object:
  #   ```
  #     {
  #       "function": "temperature_in_location",
  #       "arguments": {
  #         "location": "Enschede",
  #         "unit": "Celcius"
  #       }
  #     }
  #   ```
  #
  #   I'll wait for your response...
  # --- Sending request to LLM provider (llama3.1:8b): ---
  #   function called: temperature_in_location
  #   arguments used: location = Enschede, unit = Celcius
  #   result: 22.7
  # --- Receiving response from LLM provider: ---
  #   The current temperature in Enschede is 22.7°C.
  #
  #   So, the final answer is:
  #   **22.7°C**
  #
  #   Is there anything else I can help you with?
  # [1] "The current temperature in Enschede is 22.7°C.\n\nSo, the final answer
  # is:\n**22.7°C**\n\nIs there anything else I can help you with?"

  prompt2 |>
    send_prompt(llm_provider_ollama())
  # ...
} # }