Skip to contents

Pals are persistent, ergonomic LLM assistants designed to help you complete repetitive, hard-to-automate tasks quickly.

The pal package ships with a number of pre-engineered “roles.” A pal role is a descriptor that succinctly describes what the pal is intended to do and serves as an identifier to match the pal with its prompt and interface. A pal’s prompt is just a markdown file with enough context and examples to teach a model to carry out a given task well. A pal’s interface determines whether it replaces, prefixes, or suffixes the selected code. For example:

  • The "testthat" pal helps you transition your R package’s unit tests to the third edition of testthat. Its prompt shows the model how to convert to snapshot tests, disentangle nested expectations, and transition from deprecated functions. It replaces the selected code.
  • The "roxygen" pal helps you quickly template out royxgen documentation for a function. Its prompt shows the model how to write high-quality stub @param and @returns entries that can be later extended by the developer. It prefixes the selected code.

Choosing a model

Under the hood, pals are driven by Large Language Models (LLMs). To use pals, you will need an API key for a commercial model or a connection to a locally hosted model.

Pals use the elmer package to interface with LLMs. Any model supported by elmer is supported by pal.

As of October 2024, we highly recommend Anthropic’s Claude Sonnet 3.5 as the model to power your pals. Compared to other models we’ve tried, Claude is most likely to generate syntactically valid code that aligns with the pal’s prompt well. As such, Claude is the default model used by pal. If you want to use Claude with pal, the only additional setup step you need is to set an ANTHROPIC_API_KEY in your .Renviron—you might use usethis::edit_r_environ() to open the file, and then set:

ANTHROPIC_API_KEY=your.key.here

To use another model to power your pals, use the .pal_fn and .pal_args options. .pal_fn is the name of a chat_*() function from elmer, and .pal_args is a list of any non-default arguments you’d like to supply to that function. For example, to use models from OpenAI, you might write:

options(
  .pal_fn = "chat_openai"
)

Or, to use GPT 4o mini specifically, you might write:

options(
  .pal_fn = "chat_openai",
  .pal_args = list(model = "gpt-4o-mini")
)

You’ll probably want pal to always use whichever model you’re configuring with this option. To make this selection persist across sessions, add that options() code to your .Rprofile. You might use usethis::edit_r_profile() to open the file. After making those changes and restarting R, your pal will use the new model.

The pal addin

Rather than through package functions directly, pals are interfaced with via the pal addin. Once you have a default model set up, you’re ready to use the package in any RStudio session (even if you haven’t loaded the package yet).

Just:

  • Select some code.
  • Trigger the pal addin.
  • Type in a pal “role.” Once it’s autocompleted, press Enter.
  • Watch your code be rewritten.

Pals are interfaced with the via the pal addin. For easiest access, we recommend registering the pal addin to a keyboard shortcut.

In RStudio, navigate to Tools > Modify Keyboard Shortcuts > Search "Pal"—we suggest Ctrl+Alt+P (or Ctrl+Cmd+P on macOS).

In Positron, you’ll need to open the command palette, run “Open Keyboard Shortcuts (JSON)”, and paste the following into your keybindings.json():

    {
        "key": "Ctrl+Cmd+P",
        "command": "workbench.action.executeCode.console",
        "when": "editorTextFocus",
        "args": {
            "langId": "r",
            "code": "pal::.init_addin()",
            "focus": true
        }
    }

The analogous keybinding on non-macOS is Ctrl+Alt+P. That said, change the "key" entry to any keybinding you wish!

Once those steps are completed, you’re ready to use pals with a keyboard shortcut.

Adding custom pals

While the pal package comes with three pals for package development, one can use pals for all sorts of coding tasks in R, from interactive data analysis to authoring with Quarto, or even for pieces of code in languages other than R! All you need to set up your own pal is a markdown file.

The pal package looks for custom prompts in the “prompt directory”, which can be located with directory_path() and defaults to ~/.config/pal. Prompts are markdown files (likely created with prompt_new()) that live in the prompt directory with a name like role-interface.md. A prompt directory might look like:

/
├── .config/
│   └── pal/
│       ├── proofread-replace.md
│       └── summarize-prefix.md

In that case, pal will register two custom pals when you call library(pal) (or directory_load(). One of them has the role "proofread" and will replace the selected text with a proofread version (according to the instructions contained in the markdown file itself). The other has the role "summarize" and will prefix the selected text with a summarized version (again, according to the markdown file’s instructions). Note:

  • Files without a .md extension are ignored.
  • Files with a .md extension must contain only one hyphen in their filename, and the text following the hyphen must be one of replace, prefix, or suffix.

Custom pals can also be situated in R package. See palpable for an example pal extension package.

For more in-depth documentation on adding custom pals, see the documentation for prompt_new() and friends as well as directory_load() and friends.