This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ellmer is an R package that provides a unified interface to multiple Large Language Model (LLM) providers. It supports features like streaming outputs, tool/function calling, structured data extraction, and asynchronous processing.
General advice:
- When running R from the console, always run it with
--quiet --vanilla - Always run
air format .after generating code
-
Tests for
R/{name}.Rgo intests/testthat/test-{name}.R. -
Use
devtools::test(reporter = "check")to run all tests -
Use
devtools::test(filter = "name", reporter = "check")to run tests forR/{name}.R -
DO NOT USE
devtools::test_active_file() -
All testing functions automatically load code; you don't need to.
-
All new code should have an accompanying test.
-
If there are existing tests, place new tests next to similar existing tests.
- Run
devtools::document()after changing any roxygen2 docs. - Every user facing function should be exported and have roxygen2 documentation.
- Whenever you add a new documentation file, make sure to also add the topic name to
_pkgdown.yml. - Run
pkgdown::check_pkgdown()to check that all topics are included in the reference index. - Use sentence case for all headings
- Any user facing changes should be briefly described in a bullet point at the top of NEWS.md, following the tidyverse style guide (https://style.tidyverse.org/news.html).
- Use newspaper style/high-level first function organisation. Main logic at the top and helper functions should come below.
- Don't define functions inside of functions unless they are very brief.
- Error messages should use
cli::cli_abort()and follow the tidyverse style guide (https://style.tidyverse.org/errors.html)
Chat Objects: Central abstraction using R6 classes that maintain conversation state
Chat- Main chat interface with provider-agnostic methodsProvider- Abstract base class for different LLM providersTurn- Represents conversation turns with user/assistant messagesContent- Handles different content types (text, images, PDFs, tool calls)
Provider System: Modular architecture supporting 15+ LLM providers
- Each provider in separate R file (
provider-*.R) - Common interface abstracts provider differences
- Authentication handled per-provider (API keys, OAuth, IAM)
Tool System: Function calling capabilities
tools-def.R- Tool definition frameworktools-def-auto.R- Automatic tool definition generationchat-tools.R- Tool execution and management
Content Types: Rich content support
content-image.R- Image handling (files, URLs, plots)content-pdf.R- PDF document processingcontent-replay.R- Conversation replay functionality
Parallel Processing: Asynchronous and batch operations
parallel-chat.R- Parallel chat executionbatch-chat.R- Batch processing capabilities- Uses
coropackage for async operations
S7 Type System: Uses S7 for structured data types in types.R
- Type definitions for tool parameters and structured outputs
- Runtime type checking and validation
Standalone Imports: Self-contained utility functions
import-standalone-*.Rfiles reduce dependencies- Imported from other tidyverse packages
Provider Plugin Architecture: Each provider implements common interface
provider.Rdefines base Provider class- Provider-specific files extend base functionality
- Authentication and request handling per provider
R/chat.R- Main Chat class implementationR/provider.R- Base Provider class and interfaceR/types.R- S7 type definitions for structured dataR/content.R- Content handling framework
R/provider-openai.R- OpenAI/GPT integrationR/provider-anthropic.R- Anthropic/Claude integrationR/provider-google.R- Google Gemini integration- Additional providers for AWS, Azure, Ollama, etc.
R/chat-structured.R- Structured data extractionR/chat-tools.R- Tool/function callingR/live.R- Interactive chat interfacesR/interpolate.R- Template/prompt interpolation
tests/testthat/- Test suite with VCR cassettesvignettes/- Documentation and examples.github/workflows/- CI/CD with R CMD check
ellmer uses the S7 OOP system.
Key concepts:
- Classes: Define classes with
new_class(), specifying a name and properties (typed data fields). Properties are accessed using@syntax - Generics and methods: Create generic functions with
new_generic()and register class-specific implementations usingmethod(generic, class) <- implementation - Inheritance: Classes can inherit from parent classes using the
parentargument, enabling code reuse through method dispatch up the class hierarchy - Validation: Properties are automatically type-checked based on their definitions
Basic example:
# Define a class
Dog <- new_class("Dog", properties = list(
name = class_character,
age = class_numeric
))
# Create an instance
lola <- Dog(name = "Lola", age = 11)
# Access properties
lola@age # 11
# Define generic and method
speak <- new_generic("speak", "x")
method(speak, Dog) <- function(x) "Woof"
speak(lola) # "Woof"- Uses VCR for HTTP request mocking to avoid live API calls
- Parallel test execution configured in DESCRIPTION
- Snapshot testing for output validation
- Separate test files for each major component
- Collate field in DESCRIPTION defines file loading order
- Provider files follow consistent naming pattern
- Utility functions grouped by purpose (
utils-*.R) - Standalone imports minimize external dependencies
- Roxygen2 comments for all exported functions
- Vignettes demonstrate key use cases
- pkgdown site provides comprehensive documentation
- Examples use realistic but safe API interactions