The main class for creating AI agents that can use tools to accomplish tasks. Agent wraps an ellmer Chat object and adds agentic capabilities including multi-turn execution, permission enforcement, and streaming output.
Security Note: Core agent fields are read-only from the public API after construction. Internal lifecycle methods may update the underlying state through private storage when required.
Skill Methods
The following methods manage skills:
$load_skill(skill, allow_conflicts = FALSE)Load a Skill into the agent. The
skillparameter can be a Skill object or path to a skill directory. Ifallow_conflictsis FALSE (default), an error is thrown when skill tools conflict with existing tools. Set to TRUE to allow overwriting. Returns invisible self.$skills()Get a named list of loaded Skill objects.
MCP Methods
The following methods manage MCP (Model Context Protocol) server tools:
$load_mcp(config = NULL, servers = NULL)Load tools from MCP servers. The
configparameter specifies the path to the MCP config file (defaults to~/.config/mcptools/config.json). Theserversparameter optionally filters to specific server names. Requires the mcptools package. Returns invisible self.$mcp_tools()Get names of loaded MCP tools.
File checkpoint methods
When enable_file_checkpointing = TRUE, Deputy captures exact preimages for
writes made through its native file tools.
$checkpoint(name = NULL, metadata = list())Create a manual file checkpoint and return its checkpoint ID.
$list_checkpoints()List available file checkpoints.
$rewind_files(checkpoint_id)Restore files to a checkpoint and invalidate later file history. Conversation history is not changed.
Active bindings
agent_idStable Agent instance identifier. Read-only.
agent_nameOptional human-readable Agent name. Read-only.
run_contextDefault canonical product context. Read-only.
chatThe wrapped ellmer Chat object. Read-only after construction.
permissionsPermission policy for the agent. Read-only after construction.
usage_limitsDefault per-run UsageLimits. Read-only after construction.
working_dirWorking directory for file operations. Read-only after construction.
hooksHook registry for lifecycle events. Read-only after construction.
Methods
Agent$new()
Create a new Agent.
Usage
Agent$new(
chat,
tools = list(),
system_prompt = NULL,
permissions = NULL,
usage_limits = UsageLimits(max_requests = 25),
enable_file_checkpointing = FALSE,
file_checkpoint_max_file_bytes = 50 * 1024^2,
file_checkpoint_max_journal_bytes = 250 * 1024^2,
working_dir = getwd(),
session_id = NULL,
run_context = list(),
agent_id = NULL,
agent_name = NULL
)Arguments
chatAn ellmer Chat object created by
ellmer::chat()or provider-specific functions likeellmer::chat_openai().toolsA list of tools created with
ellmer::tool(). Seetools_file()andtools_code()for built-in tool bundles.system_promptOptional system prompt. If provided, overrides the chat object's existing system prompt.
permissionsA Permissions object controlling what the agent can do. Defaults to
permissions_standard().usage_limitsUsageLimits applied independently to each run. Defaults to 25 model requests. Use
UsageLimits()for no limits.enable_file_checkpointingWhether to journal exact file preimages for Deputy's mutating file tools. A checkpoint is created automatically at the beginning of every run.
file_checkpoint_max_file_bytesMaximum bytes captured for one file preimage. Defaults to 50 MiB.
file_checkpoint_max_journal_bytesMaximum aggregate serialized bytes for checkpoint records, markers, metadata, and pending captures. Defaults to 250 MiB.
working_dirWorking directory for file operations. Defaults to current directory.
session_idOptional stable session identifier used for correlation. A unique identifier is generated by default.
run_contextImmutable canonical JSON-compatible product context inherited by each run. Credential-like fields and runtime objects are rejected.
agent_idOptional stable identifier for this Agent instance. A unique identifier is generated by default.
agent_nameOptional human-readable Agent name.
Agent$run()
Run an agentic task with streaming output.
Returns a generator that yields AgentEvent objects as the agent works. The agent will continue until the task is complete, a run limit is reached, or it is interrupted.
Usage
Agent$run(
task,
usage_limits = NULL,
include_partial_messages = TRUE,
output_format = NULL,
run_context = list()
)Arguments
taskThe task for the agent to perform
usage_limitsOptional UsageLimits override for this run.
include_partial_messagesIf TRUE (default), yield partial text chunks as they stream. If FALSE, only yield
text_complete.output_formatOptional output format spec (e.g. JSON schema) to guide and validate structured responses.
run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
Returns
A generator yielding AgentEvent objects
Agent$run_sync()
Run an agentic task and block until completion.
Convenience wrapper around run() that collects all events and returns
an AgentResult.
Usage
Agent$run_sync(
task,
usage_limits = NULL,
include_partial_messages = TRUE,
output_format = NULL,
run_context = list()
)Arguments
taskThe task for the agent to perform
usage_limitsOptional UsageLimits override for this run.
include_partial_messagesIf TRUE (default), keep partial text events. If FALSE, suppress partials.
output_formatOptional output format spec (e.g. JSON schema) to guide and validate structured responses.
run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
Returns
An AgentResult object
Agent$register_tool()
Register a tool with the agent.
Arguments
toolA tool created with
ellmer::tool()
Agent$register_tools()
Register multiple tools with the agent.
Arguments
toolsA list of tools created with
ellmer::tool()
Agent$add_hook()
Add a hook to the agent.
Hooks are called at specific points during agent execution and can modify behavior (e.g., deny tool calls, log events).
Arguments
hookA HookMatcher object
Examples
# Add a hook to block dangerous bash commands
agent$add_hook(hook_block_dangerous_bash())
# Add a custom PreToolUse hook
agent$add_hook(HookMatcher$new(
event = "PreToolUse",
pattern = "^write_file$",
callback = function(tool_name, tool_input, context) {
cli::cli_alert_info("Writing to: {tool_input$path}")
HookResultPreToolUse(permission = "allow")
}
))Agent$set_permission_mode()
Preserve or narrow the active permission mode for subsequent tool calls.
Reapplying the current mode is a no-op. Widening or incomparable mode
changes require a newly configured Agent so custom restrictions remain
an immutable authority ceiling.
Arguments
modePermission mode, see PermissionMode
Agent$usage()
Get normalized usage for the complete in-memory conversation.
Per-run usage is available on AgentResult and in the final usage
event returned by $run().
Returns
An AgentUsage object
Agent$interrupt()
Request cancellation of the active stream.
Cancellation is cooperative and takes effect at the next provider or tool boundary supported by ellmer.
Agent$save_session()
Save the current session to an RDS file.
Agent$load_session()
Load a session from an RDS file.
Agent$checkpoint()
Create a reversible file checkpoint.
Usage
Agent$checkpoint(name = NULL, metadata = list())Agent$compact()
Compact the conversation history to reduce context size.
This method uses the LLM to generate a meaningful summary of older conversation turns, then replaces them with the summary appended to the system prompt. This preserves important context while reducing token usage.
Arguments
keep_lastNumber of recent turns to keep uncompacted (default: 4)
summaryOptional custom summary to use instead of auto-generating. If NULL, the LLM will generate a summary focusing on key decisions, findings, files discussed, and task progress.
Details
The compaction process:
Fires the PreCompact hook (can cancel or provide custom summary)
If no custom summary, uses LLM to summarize compacted turns
Appends summary to system prompt under "Previous Conversation Summary"
Keeps only the most recent
keep_lastturns
If LLM summarization fails (e.g., no API key), falls back to a simple text-based summary with truncated turn contents.
Agent$load_skill()
Load a Skill into the agent.
Arguments
skillA Skill object or path to a skill directory.
allow_conflictsIf FALSE (default), error on tool name conflicts. Set TRUE to allow overwriting existing tools.
Agent$load_mcp()
Load tools from MCP (Model Context Protocol) servers.
Requires the mcptools package. Issues a warning if not installed or if tool fetching fails.
Agent$run_shiny()
Run an agentic task for use in Shiny applications with shinychat.
Returns an async content stream suitable for passing to
shinychat::chat_append(). Unlike run() and run_sync(), the
multi-turn loop is driven by ellmer's stream_async() rather than
deputy's own generator. Deputy's permissions, hooks, and observable
UsageLimits are still enforced via callbacks and terminal accounting.
File tools must use absolute paths within working_dir; rejected calls
still count toward tool usage.
Usage
Agent$run_shiny(prompt, max_tool_calls = NULL, run_context = list())Arguments
promptThe user message to send
max_tool_callsMaximum number of tool calls before stopping. Overrides
usage_limits$max_tool_calls; otherwise falls back to that value or 25. This counts individual tool call requests, not LLM turns (one turn can have multiple parallel calls).run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
Returns
An async content stream suitable for
shinychat::chat_append().
Agent$run_async()
Run an agentic task asynchronously and resolve to an AgentResult.
Like run_shiny(), the multi-turn loop is driven by ellmer's
stream_async(), so the R process is never blocked while the model or
tools work: other Shiny sessions, later callbacks, and promise chains
keep running. Unlike run_shiny(), nothing is streamed to a UI. The
returned promise resolves once the run stops and carries the final
response, run-scoped usage, and stop reason. Permissions, hooks, and
UsageLimits are enforced as in run_shiny() (callbacks plus terminal
accounting). File tools may use relative paths resolved against
working_dir, as in run(); the absolute-path rule is specific to
run_shiny().
Use this when an Agent is a worker inside a larger async system, for
example a delegated sub-agent executed from the tool of a parent chat
that is itself streaming. output_format is not supported here;
structured output still requires run() or run_sync().
Usage
Agent$run_async(task, usage_limits = NULL, run_context = list())Arguments
taskThe task for the agent to perform
usage_limitsOptional UsageLimits override for this run. Unset fields fall back to the Agent's limits. With
on_exceed = "error", hitting a limit rejects the promise with the structured limit error instead of resolving with a typedstop_reason.run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
Returns
A promises::promise resolving to an AgentResult. It is
rejected if the provider stream fails or a limit configured with
on_exceed = "error" is reached.
Examples
if (FALSE) { # \dontrun{
# Create an agent with file tools
agent <- Agent$new(
chat = ellmer::chat("openai/gpt-4o"),
tools = tools_file()
)
# Run a task with streaming output
events <- agent$run("List files in the current directory")
repeat {
event <- events()
if (coro::is_exhausted(event)) break
if (event$type == "text") cat(event$text)
}
# Or use the blocking convenience method
result <- agent$run_sync("List files")
print(result$response)
} # }
## ------------------------------------------------
## Method `Agent$add_hook()`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Add a hook to block dangerous bash commands
agent$add_hook(hook_block_dangerous_bash())
# Add a custom PreToolUse hook
agent$add_hook(HookMatcher$new(
event = "PreToolUse",
pattern = "^write_file$",
callback = function(tool_name, tool_input, context) {
cli::cli_alert_info("Writing to: {tool_input$path}")
HookResultPreToolUse(permission = "allow")
}
))
} # }