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.
permissionsPermission policy for the agent. Read-only after construction.
usage_limitsDefault per-run UsageLimits. Read-only after construction.
context_policyAutomatic context-management policy. Read-only.
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),
context_policy = ContextPolicy(),
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,
fallback_chats = list(),
approval_dir = 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.context_policyA ContextPolicy controlling automatic compaction and durable offloading of large tool results.
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.
fallback_chatsOrdered configured ellmer Chats, explicitly allowed to receive this conversation after a transient failure before any response. Templates are cloned; their connection/model settings are preserved and their history, system prompt, and tools are replaced by the Agent's. The selected Chat remains active for subsequent runs. Applies to governed task and structured requests. Pre-run automatic compaction retains the separate ContextPolicy summary-failure policy.
approval_dirOptional existing host-owned directory for durable tool approvals. Enables sequential tool execution and an execution journal. See
approval_read()and$resume_approval().
Agent$run()
Run an agentic task with semantic streaming events.
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,
run_context = list(),
type = NULL,
validate = NULL,
max_corrections = 0L
)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.run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
typeOptional ellmer type. Complete the task with tools, then extract from the conversation within the same run budget.
validateOptional synchronous function receiving ellmer's value. Return TRUE, FALSE, or non-empty correction feedback. Errors and NA are terminal.
max_correctionsMaximum additional structured requests after invalid output. Defaults to zero; all attempts share the run budget.
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,
run_context = list(),
type = NULL,
validate = NULL,
max_corrections = 0L
)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.
run_contextCanonical JSON-compatible context to add to or narrow for this run. Protected constructor identity fields cannot change.
typeOptional ellmer type. Complete the task with tools, then extract from the conversation within the same run budget.
validateOptional synchronous function receiving ellmer's value. Return TRUE, FALSE, or non-empty correction feedback. Errors and NA are terminal.
max_correctionsMaximum additional structured requests after invalid output. Defaults to zero; all attempts share the run budget.
Returns
An AgentResult object
Agent$chat()
Send messages synchronously using the ellmer Chat interface.
All requests pass through Deputy's run kernel. The return value matches
ellmer::Chat$chat(); inspect AgentResult metadata with $last_run().
Usage
Agent$chat(..., echo = NULL, run_context = list())Agent$chat_async()
Send messages asynchronously using the ellmer Chat interface.
Agent$chat_structured()
Send a structured request through the governed run kernel.
Usage
Agent$chat_structured(
...,
type,
echo = "none",
convert = TRUE,
run_context = list(),
validate = NULL,
max_corrections = 0L
)Arguments
...User content accepted by ellmer.
typeAn ellmer structured-output type.
echoEcho mode forwarded to ellmer.
convertWhether ellmer converts the structured response.
run_contextCanonical JSON-compatible context to add to or narrow for this run.
validateOptional synchronous function receiving ellmer's value. Return TRUE, FALSE, or non-empty correction feedback. Errors and NA are terminal.
max_correctionsMaximum additional structured requests after invalid output. Defaults to zero; all attempts share the run budget.
Agent$chat_structured_async()
Send an asynchronous structured request through Deputy.
Usage
Agent$chat_structured_async(
...,
type,
echo = "none",
convert = TRUE,
run_context = list(),
validate = NULL,
max_corrections = 0L
)Arguments
...User content accepted by ellmer.
typeAn ellmer structured-output type.
echoEcho mode forwarded to ellmer.
convertWhether ellmer converts the structured response.
run_contextCanonical JSON-compatible context to add to or narrow for this run.
validateOptional synchronous function receiving ellmer's value. Return TRUE, FALSE, or non-empty correction feedback. Errors and NA are terminal.
max_correctionsMaximum additional structured requests after invalid output. Defaults to zero; all attempts share the run budget.
Agent$stream()
Stream synchronously using the ellmer Chat interface.
Arguments
...User content accepted by ellmer.
streamYield text or semantic ellmer content.
controllerOptional ellmer stream controller.
run_contextCanonical JSON-compatible context to add to or narrow for this run.
typeOptional ellmer type for native structured streaming. Providers requiring schema-tool fallback must use
chat_structured().
Agent$stream_async()
Stream asynchronously using the ellmer Chat interface.
This is the primary interface for shinychat. It returns the same content stream as ellmer while enforcing Deputy permissions, hooks, limits, workspace resolution, context management, and run accounting.
Arguments
...User content accepted by ellmer, including shinychat's list of attachment-enabled
Contentobjects.tool_modeWhether ellmer executes tool calls concurrently or sequentially.
streamYield text or semantic ellmer content.
controllerOptional ellmer stream controller.
run_contextCanonical JSON-compatible context to add to or narrow for this run.
typeOptional ellmer type for native structured streaming. Providers requiring schema-tool fallback must use
chat_structured().
Returns
An asynchronous generator suitable for shinychat::chat_append().
Agent$last_run()
Return the most recently completed governed run.
Returns
An AgentResult, or NULL before the first run completes.
Agent$last_compaction()
Return the most recent compaction outcome.
Returns
A read-only DeputyCompaction S7 value, or NULL before
compaction occurs.
Agent$add_turn()
Add a user/assistant turn pair, as in ellmer Chat.
Agent$get_turns()
Return the complete selected conversation, as in ellmer Chat. Compaction removes turns from model context, not from this transcript. Hosts can persist this view through their normal history API. Retained turns remain in memory until the conversation is replaced.
Agent$get_context_turns()
Return only the current model context. Unlike get_turns()
and turns(), this view shrinks when compaction succeeds. Use it when
inspecting or transferring the bounded input for a model request.
Agent$set_turns()
Replace the selected conversation and its model context, as in ellmer Chat. Clears the retained compacted prefix and summary, so host branch restoration cannot carry another branch's history. During a run, already accrued usage remains charged after replacement.
Agent$get_cost()
Return provider cost records, as in ellmer Chat.
Usage
Agent$get_cost(include = c("all", "last"))Agent$token_count()
Estimate tokens, as in ellmer Chat.
Usage
Agent$token_count(..., include = c("new", "complete"), type = NULL)Agent$register_tool()
Register a tool with the agent.
Function tools are wrapped with Deputy's runtime enforcement. Known
provider-native web tools are authorized once, before registration,
because their execution occurs inside the provider rather than R. Native
tools therefore require static permissions and cannot be registered with
a custom can_use_tool callback.
Existing names require explicit replacement. Every tool in a batch is
validated and adapted before the registry changes. List element names
do not rename tools; each tool's own name is authoritative.
Arguments
toolA tool created with
ellmer::tool()or a supported provider-native web tool.replaceReplace tools already registered under the same name? Defaults to FALSE. Duplicate names within a batch always fail.
Agent$register_tools()
Register multiple tools with the agent.
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(
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$last_turn()
Get the last turn in the conversation.
Usage
Agent$last_turn(role = c("assistant", "user", "system"))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. When narrowing removes web access,
registered provider-native web tools are removed before the new policy
becomes active because Deputy cannot interpose on provider-side calls.
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. Active McpConnection calls terminate their owned connections and discard server session state.
Agent$save_session()
Save the current session to an RDS file.
Details
The session file contains:
Conversation turns
System prompt
The cumulative compaction summary
Retained compacted turns for the complete selected conversation
Portable copies of offloaded tool results
Effective run context
File checkpoint state, when enabled
Metadata (timestamp, version, provider info)
Agent$load_session()
Load a session from an RDS file.
Details
Tools, permissions, hooks, and the working directory are runtime policy and are never restored from a session file. Saved run context is validated before conversation state changes and merged with constructor context; protected identity conflicts fail the load. Compaction summaries and integrity-checked tool-result envelopes are restored as conversational state under the receiving Agent's session identity. Schema 3 preserves both the selected conversation and model context. Earlier development schemas are rejected; native host history remains independently readable through that host's restore API.
Agent$pending_approval()
Inspect the approval that suspended this Agent, or NULL.
Returns
An ApprovalContinuation or NULL. Its source includes the path.
Agent$resume_approval()
Resume a persisted pending tool approval under current and saved policy. Reattach a Chat, the same raw-argument tool definition, permission callback, session_id, agent_id, working_dir, and approval_dir after process restart. Existing completed effects are never replayed; duplicate decisions fail.
Usage
Agent$resume_approval(
path,
decision = c("approve", "deny"),
tool_input = NULL,
usage_limits = NULL
)Arguments
pathApproval directory supplied by the approval event or snapshot.
decisionEither "approve" or "deny".
tool_inputOptional edited raw JSON argument list for approval.
usage_limitsOptional explicit UsageLimits for the continuation. Escalation is bounded by the saved and current Agent limits. Previously observed usage is retained. NULL keeps the suspended run's limits.
Returns
An AgentResult, including usage observed before suspension.
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.
Usage
Agent$compact(
keep_last = NULL,
summary = NULL,
fallback = self$context_policy$fallback,
automatic = FALSE,
estimated_tokens = NULL
)Arguments
keep_lastNumber of recent turns to retain.
NULLchooses a complete conversational boundary using the context policy's token target.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.
fallbackWhat to do when LLM summary generation fails.
automaticWhether the run kernel triggered this compaction.
estimated_tokensOptional pre-compaction token estimate.
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
LLM summary-generation failures are errors by default. A deterministic
truncated-text summary is used only when fallback = "text" is
explicitly configured. The returned object records that degraded method.
Returns
A read-only DeputyCompaction S7 value describing the method and usage.
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.
Arguments
configPath to MCP configuration file. If NULL (default), uses the mcptools default location (
~/.config/mcptools/config.json).serversOptional character vector of server names to load from. If NULL, loads from all configured servers.
replaceRefresh the selected servers' complete tool sets, removing obsolete tools, and explicitly replace other matching names. On failure, tools whose connections were invalidated are removed; working tools remain.
Agent$run_async()
Run an agentic task asynchronously and resolve to an AgentResult.
Uses the same run kernel as $stream_async(), $stream(), $chat(),
and $run_sync(). It collects the final response and run metadata rather
than returning the content stream.
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. Supply type to extract structured output
after the tool-using task within the same run budget.
Usage
Agent$run_async(
task,
usage_limits = NULL,
run_context = list(),
type = NULL,
validate = NULL,
max_corrections = 0L
)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.
typeOptional ellmer type. Complete the task with tools, then extract from the conversation within the same run budget.
validateOptional synchronous function receiving ellmer's value. Return TRUE, FALSE, or non-empty correction feedback. Errors and NA are terminal.
max_correctionsMaximum additional structured requests after invalid output. Defaults to zero; all attempts share the run budget.
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-5.6-luna"),
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(
event = "PreToolUse",
pattern = "^write_file$",
callback = function(tool_name, tool_input, context) {
cli::cli_alert_info("Writing to: {tool_input$path}")
HookResultPreToolUse(permission = "allow")
}
))
} # }