An Agent wraps an ellmer Chat and uses it to carry out tasks. The model can
call tools over several turns while the agent applies permissions, hooks and
usage limits and reports its progress as AgentEvent objects. Use
LeadAgent when the agent should delegate work to subagents.
An Agent also works as an ellmer Chat ($chat(), $stream_async(),
$get_turns() and so on), so you can pass it to code that expects one, such
as shinychat.
Settings given to $new(), such as permissions, usage_limits and
working_dir, are read-only afterwards.
File checkpoints
With enable_file_checkpointing = TRUE, the agent records the previous
contents of files changed by write_file, edit_file and multi_edit.
Changes made any other way, including by run_r_code or run_bash, are not
recorded. A checkpoint is created at the start of every run, and
$checkpoint() creates one on demand. $rewind_files() restores files to a
checkpoint without changing the conversation. A file tool call that would
exceed the checkpoint size limits is refused.
Active bindings
agent_idThe agent's ID. Read-only.
agent_nameThe agent's name, or
NULL. Read-only.run_contextThe
run_contextattached to every run. Read-only.trusted_resultsThe TrustedResults policy, or
NULL. Read-only.permissionsThe agent's Permissions. Read-only; use
$set_permission_mode()to narrow them.usage_limitsThe UsageLimits applied to each run. Read-only.
context_policyThe agent's ContextPolicy. Read-only; use
$set_context_policy()to replace it.working_dirThe directory file tools work in. Read-only.
hooksThe agent's HookRegistry. The field can't be replaced; add hooks with
$add_hook().
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,
delegation_scope = list(),
delegation_disclosure = DelegationDisclosure(),
delegation_observation = DelegationObservation(),
trusted_results = NULL
)Arguments
chatAn ellmer Chat, for example from
ellmer::chat().toolsA list of tools created with
ellmer::tool(). Seetools_preset(),tools_file()andtools_code()for built-in tools.system_promptOptional system prompt. Replaces the Chat's system prompt.
permissionsA Permissions policy. Defaults to
permissions_standard()forworking_dir.usage_limitsUsageLimits applied to each run separately. Defaults to 25 model requests per run.
UsageLimits()sets no limits.context_policyA ContextPolicy controlling automatic compaction and where large tool results are stored. The default compacts the conversation once it passes about 32,000 tokens.
enable_file_checkpointingIf
TRUE, record file changes so they can be undone with$rewind_files(). See the "File checkpoints" section.file_checkpoint_max_file_bytesLargest file, in bytes, whose previous contents a checkpoint can record. Defaults to 50 MiB.
file_checkpoint_max_journal_bytesMaximum total size, in bytes, of all checkpoint records. Defaults to 250 MiB.
working_dirDirectory that file tools work in. Must exist. Defaults to the current directory.
session_idOptional session ID. One is generated if not given.
run_contextNamed list of JSON-compatible values (strings, numbers, logicals and nested lists) attached to every event and result, for example user or conversation IDs. Keys that look like credentials, such as
passwordorapi_key, are rejected.agent_idOptional agent ID. One is generated if not given.
agent_nameOptional human-readable name.
fallback_chatsA list of ellmer Chats to try, in order, when a request fails with a transient error (a network failure or HTTP 408, 429, 500, 502, 503 or 504) before the run has received any response or called any tool. Each must have no turns or tools; the agent copies it and gives it the agent's system prompt, history and tools. Once used, a fallback stays in use for later runs. Compaction summaries don't use these; see
summary_fallback_chatsinContextPolicy().approval_dirA directory, which must already exist, where tool calls waiting for approval are saved, so you can decide them later with
$resume_approval(), even after restarting R. Tools that can wait for approval must be created withellmer::tool(convert = FALSE). When set, tools run one at a time. Seeapproval_read().delegation_scopeNamed list identifying what this agent belongs to, such as an owner or conversation ID. It is passed as
scopeto theauthorizefunction ofdelegation_disclosure.delegation_disclosureA DelegationDisclosure that decides who may inspect this agent's subagents. The default denies everyone.
delegation_observationA DelegationObservation setting how many subagent events are kept for
$observe_subagents().trusted_resultsOptional TrustedResults policy naming the one tool allowed to produce each type of trusted result. Registering a tool that could get around it is an error.
Agent$retain_agent()
Retain another agent so you can send it more tasks with
$continue_agent(). The retained agent keeps its conversation between
tasks.
Until you call $release_agent(), the retained agent can't be run
directly, and its conversation, prompt, model, tools, hooks and tool
observers can't be changed (observers it already has keep working). An
agent can retain up to 32 others at a time. See
vignette("retained-agents", package = "deputy").
Arguments
agentAnother
Agent(not aLeadAgent) with its own Chat and noapproval_dir,fallback_chatsor provider-native tools.usage_limitsUsageLimits for all of its tasks combined, also capped by the retained agent's own limits.
max_runsMaximum number of tasks. Defaults to 32.
Agent$retain_agent_graph()
Retain several agents at once and let them delegate to each other through
tools you define in routes. This agent is the root of the graph and
holds every conversation in it. The graph's usage limits add up across
all delegated runs until you call $release_agent_graph().
Routes may form a cycle, but delegating to an agent that is already
running fails. An agent waiting on its own delegate still counts toward
max_concurrency.
Each agent keeps its own permissions, and each of its tool calls is also checked against the current permissions of every agent above it, so an agent in read-only or plan mode can use its route tools and its delegates are held to that mode too.
Usage
Agent$retain_agent_graph(
agents,
routes,
usage_limits,
max_depth,
max_delegations,
max_concurrency,
max_runs = 32L
)Arguments
agentsNamed list of distinct agents, each meeting the conditions in
$retain_agent(). The namerootis reserved for this agent.routesNamed list keyed by
rootor an agent name. Each element is a named list of delegation tools to add to that agent, where each tool is a list withtarget(an agent name),descriptionandusage_limits.usage_limitsUsageLimits for the whole graph.
max_requestsis required.max_depthMaximum delegation depth. This agent's direct delegates are at depth 1.
max_delegationsMaximum number of delegations over the graph's lifetime.
max_concurrencyMaximum number of delegations running at once.
max_runsMaximum number of tasks for each agent in the graph.
Agent$delegation_graph_usage()
Get the total usage of all delegated runs in this agent's graph, including runs still in progress. Errors if this agent doesn't own a graph.
Returns
An AgentUsage object.
Agent$release_agent_graph()
Release the graph, removing its route tools and handles.
Errors if anything in it is still running. This also discards the
graph's delegation records, so save them first with $export_subagents()
if you need them. The agents' own tools and connections are left open.
Agent$continue_agent_async()
Send a retained agent its next task. It still has its earlier
conversation. This errors, before any request is made, if the agent is
busy, was changed or released, has used up max_runs, or the handle
belongs to another agent. After a failed or cancelled task, call this
again to carry on.
Arguments
handleA handle from this agent's
$retain_agent()or$retain_agent_graph().taskThe next task, as one string of at most 64 KiB.
usage_limitsUsageLimits for this task. It is also capped by what remains of the handle's total budget and by the retained agent's own limits.
Returns
A promise that resolves to an AgentResult. If the task is cancelled before it starts, the result has zero usage and no run ID.
Agent$cancel_agent()
Ask a retained agent to stop its current task. The run stops at the next safe point and keeps the conversation so far. Calling this more than once is harmless.
Agent$release_agent()
Stop retaining an agent so it can be used on its own again. This also
discards its delegation records, so save them first with
$export_subagents() if you need them. Its tools and connections stay
open. Errors while the agent is running: cancel it with $cancel_agent()
and wait for the task to end first. Agents in a graph are released with
$release_agent_graph(). Handles don't survive an R restart.
Agent$list_subagents()
List this agent's delegations, oldest first, including ones still running. The records are kept in memory only.
status is "queued", "running", "completed", "failed",
"stopped", "not_started" or "suspended" (waiting for a tool
approval). "completed" means the subagent finished normally, not that
it did the task well; stop_reason gives the exact reason. IDs and times
are NA until known, and completed_at is set when the run ends or is
suspended. input_error says why a task was rejected before it ran:
"invalid", "missing", "stale", "unauthorized" or "oversized".
hook_error records errors from hooks watching the subagent.
Agent$get_subagent_results()
Get the results of delegated runs.
Arguments
agent_nameOnly return results from subagents with this name.
delegation_idOnly return the result of this delegation.
Returns
A list of AgentResult objects, oldest first. It holds NULL
for runs that are still going, never started, or failed without a
result.
Agent$get_subagent_messages()
Get the conversation turns of each delegation. For a subagent that is
still running, you get the turns completed so far. Reading them doesn't
add anything to this agent's context. No disclosure checks are applied,
so use $inspect_subagents() before showing history to users.
Agent$get_subagent_contexts()
See what each subagent was given at the start, or what its model context holds now, oldest first. Nothing is sent to a model. No disclosure checks are applied.
Arguments
delegation_idOnly return this delegation.
view"initial"returns the DelegationManifest recording what the subagent started with."current"returns a list with itssystem_promptand theturnsin its model context.redactIf
TRUE(only withview = "initial"), leave out the task, instructions and source text. Other metadata is still included.
Agent$observe_subagents()
Follow subagent activity as it happens. The returned subscription lets you poll for new events without affecting the subagents' runs.
Arguments
requesterWhoever is asking, as identified by your app (for example a user ID). The
delegation_disclosurepolicy checks it on every read.delegation_idOnly follow this delegation.
afterA cursor from an earlier subscription on this agent, to resume from.
NULLstarts from now.
Returns
A DelegationSubscription. Closing it stops observing but doesn't stop any subagent.
Agent$interrupt_subagent()
Ask a running subagent to stop. It stops at the next safe point; in a
delegation graph, its own delegations stop too. This doesn't consult
delegation_disclosure, so check that the user may do this before
calling it. Models can't call this method.
Agent$inspect_subagents()
Get a snapshot of each delegation that requester may see: its task, its
outcome (what Deputy observed, kept apart from what the subagent
claimed), usage, the DelegationManifest it started from and any errors.
Retained agents also report their total usage across tasks; unknown usage
is NULL. Each view passes through the delegation_disclosure policy,
which may redact it. Errors if requester isn't allowed. Nothing is run.
Arguments
requesterWhoever is asking, as identified by your app. Never pass values that came from a model.
delegation_idOnly return this delegation. Unknown IDs give an empty list.
transcriptIf
TRUE, also include the conversation, astranscriptrecords and as ellmerturns. Hidden reasoning and raw provider data are left out.
Agent$export_subagents()
Export finished delegations, with their conversations, so you can store
them and view them later with delegation_history(). The export is a
record to read, not something you can resume.
Returns
A plain list for delegation_history(). Errors if a selected
delegation is still running. Reading it back checks a
DelegationDisclosure again.
Agent$read_subagent_result()
Read part of a large result that a subagent saved, using a reference
from its $inspect_subagents() view. No tool or model is run.
Agent$run()
Run a task and stream its progress.
Returns a generator that yields AgentEvent objects as the agent works.
The run continues until the model finishes, a usage limit is reached or
it is interrupted. The "stop" event gives the reason, and $last_run()
then returns the AgentResult.
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.
usage_limitsUsageLimits for this run.
NULLfields use the agent's limits.include_partial_messagesIf
TRUE(the default), yield a"text"event for each streamed chunk. IfFALSE, skip them; the full text still arrives in the"text_complete"event.run_contextNamed list merged into the agent's
run_contextfor this run. It can't change or remove ID fields (keys ending inid) that the agent already sets.typeOptional ellmer type, such as
ellmer::type_object(). After the task, the agent extracts data of this type from the conversation into the result'sstructured_output. This counts toward the run's limits.validateOptional function that checks the extracted value. Return
TRUEto accept it, orFALSEor a message to reject it; a message is sent to the model as feedback. An error or any other return value, such asNA, ends the run with an error.max_correctionsHow many times to ask the model to fix a rejected value. Defaults to 0. If the value is still rejected, the run errors. Every attempt counts toward the run's limits.
Returns
A generator yielding AgentEvent objects.
Agent$run_sync()
Run a task and wait for it to finish.
Runs $run() to the end and returns the AgentResult, which holds
every event.
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.
usage_limitsUsageLimits for this run.
NULLfields use the agent's limits.include_partial_messagesPassed to
$run(). It doesn't change the returned result, which always includes the"text"events.run_contextNamed list merged into the agent's
run_contextfor this run. It can't change or remove ID fields (keys ending inid) that the agent already sets.typeOptional ellmer type, such as
ellmer::type_object(). After the task, the agent extracts data of this type from the conversation intoresult$structured_output. This counts toward the run's limits.validateOptional function that checks the extracted value. Return
TRUEto accept it, orFALSEor a message to reject it; a message is sent to the model as feedback. An error or any other return value, such asNA, ends the run with an error.max_correctionsHow many times to ask the model to fix a rejected value. Defaults to 0. If the value is still rejected, the run errors. Every attempt counts toward the run's limits.
Returns
An AgentResult object.
Agent$chat()
Send a message and return the reply, like ellmer::Chat$chat(), with the
agent's tools, permissions, hooks and usage limits applied. $last_run()
then returns the full AgentResult.
Usage
Agent$chat(..., echo = NULL, run_context = list())Agent$chat_async()
Asynchronous version of $chat().
Agent$chat_structured()
Extract structured data, like
ellmer::Chat$chat_structured(), with the agent's permissions, hooks and
usage limits applied.
Usage
Agent$chat_structured(
...,
type,
echo = "none",
convert = TRUE,
run_context = list(),
validate = NULL,
max_corrections = 0L
)Arguments
...Message content, as for ellmer.
typeAn ellmer type describing the data, such as
ellmer::type_object().echoPassed to ellmer.
convertPassed to ellmer: whether to convert the result to R objects.
run_contextNamed list merged into the agent's
run_contextfor this run.validateOptional function that checks the extracted value. Return
TRUEto accept it, orFALSEor a message to reject it; a message is sent to the model as feedback. An error or any other return value, such asNA, ends the run with an error.max_correctionsHow many times to ask the model to fix a rejected value. Defaults to 0. If the value is still rejected, the run errors. Every attempt counts toward the usage limits.
Agent$chat_structured_async()
Asynchronous version of $chat_structured().
Usage
Agent$chat_structured_async(
...,
type,
echo = "none",
convert = TRUE,
run_context = list(),
validate = NULL,
max_corrections = 0L
)Arguments
...Message content, as for ellmer.
typeAn ellmer type describing the data, such as
ellmer::type_object().echoPassed to ellmer.
convertPassed to ellmer: whether to convert the result to R objects.
run_contextNamed list merged into the agent's
run_contextfor this run.validateOptional function that checks the extracted value. Return
TRUEto accept it, orFALSEor a message to reject it; a message is sent to the model as feedback. An error or any other return value, such asNA, ends the run with an error.max_correctionsHow many times to ask the model to fix a rejected value. Defaults to 0. If the value is still rejected, the run errors. Every attempt counts toward the usage limits.
Agent$stream()
Stream a reply, like ellmer::Chat$stream(), with the agent's
permissions, hooks and usage limits applied.
Arguments
...Message content, as for ellmer.
stream"text"yields text chunks;"content"yields ellmer content objects, including tool requests and results.controllerOptional ellmer stream controller. As in ellmer, a cancelled controller is reset when the new run starts.
run_contextNamed list merged into the agent's
run_contextfor this run.typeOptional ellmer type for structured streaming, passed to ellmer. If the provider can't stream structured output, use
$chat_structured()instead.
Agent$stream_async()
Asynchronous version of $stream(). This is the method shinychat uses:
the stream is the same as ellmer's, with the agent's permissions, hooks,
usage limits and compaction applied.
Arguments
...Message content, as for ellmer, including the attachment
Contentobjects that shinychat sends.tool_mode"concurrent"runs the tool calls from one response in parallel;"sequential"runs them one at a time.stream"text"yields text chunks;"content"yields ellmer content objects, including tool requests and results.controllerOptional ellmer stream controller. As in ellmer, a cancelled controller is reset when the new run starts.
run_contextNamed list merged into the agent's
run_contextfor this run.typeOptional ellmer type for structured streaming, passed to ellmer. If the provider can't stream structured output, use
$chat_structured()instead.
Returns
An asynchronous generator suitable for shinychat::chat_append().
Agent$last_run()
Get the result of the most recent run.
Returns
An AgentResult, or NULL before the first run finishes.
Agent$last_compaction()
Get the result of the most recent compaction.
Returns
A DeputyCompaction, or NULL if there hasn't been one.
Agent$resolve_tool_result()
Get the full value of a large tool result that was saved outside the model context.
Agent$add_turn()
Add a user turn and an assistant turn, as ellmer's
$add_turn() does.
Agent$get_turns()
Get the whole conversation, as ellmer's $get_turns()
does. Unlike $get_context_turns(), this includes turns that
compaction removed from the model context, and the original tool
results that $microcompact() cleared. Removed turns stay in memory
until $set_turns() replaces the conversation.
Agent$get_context_turns()
Get the turns the model currently sees. After compaction
this is shorter than $get_turns(), and tool results cleared by
$microcompact() show their marker.
Agent$set_turns()
Replace the conversation, as ellmer's $set_turns() does.
This also drops any compaction summary and the turns compaction
removed. During a run, usage counted so far still counts.
Agent$get_system_prompt()
Get the system prompt, as ellmer's $get_system_prompt()
does. After compaction it includes the conversation summary.
Agent$set_system_prompt()
Replace the system prompt, as ellmer's
$set_system_prompt() does. After compaction, this also drops the
conversation summary unless value still contains it.
Agent$set_tools()
Replace all registered tools. The new tools are checked and
wrapped as in $register_tools().
Agent$get_cost()
Get the estimated cost, as ellmer's $get_cost() does.
Usage
Agent$get_cost(include = c("all", "last"))Agent$token_count()
Count tokens, as ellmer's $token_count() does.
Usage
Agent$token_count(..., include = c("new", "complete"), type = NULL)Agent$set_chat()
Replace the Chat the agent sends requests to, for example to continue a conversation with a model from another provider. The conversation, system prompt and tools move to the new Chat, and the agent's permissions, hooks, tool observers and usage limits keep applying. Reasoning content (ellmer::ContentThinking) is dropped from the history, because each provider accepts only its own. Subagents created after the change use the new Chat.
To change the model within one provider, use $set_model(). The
replaced Chat is left with no tools or tool callbacks. Callbacks you
registered directly on it are not moved; register them with
$on_tool_request() and $on_tool_result() instead. An agent whose
Chat another agent also uses can't replace it.
Agent$set_context_policy()
Replace the ContextPolicy, for example to compact at a different size after switching to a model with a larger or smaller context window. The new policy applies from the next run.
Arguments
context_policyA ContextPolicy. It must use the same
offload_diras the current policy, because large tool results that were already saved are read back from there.
Agent$register_tool()
Add a tool. Calls to it go through the agent's permission checks and hooks.
Provider-native web search and fetch tools run on the provider's
servers, not in R, so they are checked once, when you register them. The
permissions must have web = TRUE, list the tool in tool_allowlist and
have no can_use_tool callback.
Arguments
toolA tool created with
ellmer::tool()or a supported provider-native web tool.replaceIf
TRUE, replace a registered tool with the same name. IfFALSE(the default), a name clash is an error.
Agent$register_tools()
Add several tools, as $register_tool() does. All of them are checked
before any is added, so if one fails, none are added. List names are
ignored: each tool keeps its own name.
Arguments
toolsA list of tools created with
ellmer::tool()or supported provider-native web tools.replaceIf
TRUE, replace registered tools with the same names. IfFALSE(the default), a name clash is an error. Two tools with the same name intoolsare always an error.
Agent$on_tool_request()
Add a callback that runs when the model requests a tool, as
ellmer's $on_tool_request() does.
Agent$on_tool_result()
Add a callback that runs when a tool returns a result, as
ellmer's $on_tool_result() does.
Agent$add_hook()
Add a hook. Hooks run at set points in a run (see HookEvent). They can observe the run and, at some points, change it, for example by denying a tool call.
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$turns()
Get the whole conversation, including turns removed by compaction. The
same as $get_turns().
Agent$last_turn()
Get the last turn in the conversation with a given role.
Usage
Agent$last_turn(role = c("assistant", "user", "system"))Agent$set_permission_mode()
Switch to a narrower permission mode for later tool calls. Permissions
can be narrowed but not widened: from "full" any mode is allowed, and
"standard" and "plan" can only switch to "readonly". Anything else
is an error, so create a new Agent instead. Setting the current mode
does nothing. The agent's other permission settings still apply within
the new mode. If the new mode doesn't allow web access,
provider-native web tools are removed, since Deputy can't check their
calls.
Arguments
modePermission mode, see PermissionMode.
Agent$cost()
Get token counts and estimated cost for the whole conversation,
including turns that compaction removed from the model's context. The
requests that wrote compaction summaries aren't conversation turns, so
they aren't included; see $last_compaction().
Agent$usage()
Get usage for the whole conversation, including turns that compaction
removed from the model's context. tool_calls counts the tool calls the
model asked for. Compaction summary requests aren't included; see
$last_compaction(). For one run's usage, use $usage on its
AgentResult or the "usage" event from $run().
Returns
An AgentUsage object.
Agent$interrupt()
Stop the current run, and any subagent runs it started.
The run stops as soon as ellmer allows, usually during the current model request or before the next tool call. An McpConnection call in progress is stopped by closing its connection, which loses the server's session state.
Agent$save_session()
Save the conversation to an .rds file that $load_session() can
restore.
Details
The file holds the conversation (including turns removed by compaction), the system prompt and any compaction summary, copies of large tool results, the run context, file checkpoint state (when enabled) and some metadata, such as the time, Deputy version and provider. It doesn't hold tools, permissions, hooks or the Chat itself.
Agent$load_session()
Load a conversation saved by $save_session().
Details
Tools, permissions, hooks and the working directory come from the agent
you load into, not from the file. The saved run_context is merged into
the agent's, and loading fails if they disagree on an ID field. Saved
tool results and compaction summaries are restored under this agent's
session ID. Files saved by early development versions of Deputy can't be
loaded. Loading errors while a run is active.
Agent$pending_approval()
Get the tool approval this agent is waiting on.
Returns
An ApprovalContinuation, or NULL if nothing is waiting. Its
source$path is the path to pass to $resume_approval().
Agent$resume_approval()
Approve or deny a tool call that is waiting for approval, then continue
the run. Both the saved permissions and the agent's current permissions
apply. After restarting R, first create an agent with the same
session_id, agent_id, working_dir and approval_dir, the same tool
definition (with convert = FALSE) and the permission callback. Tool
calls that already ran are not run again, and each approval can be
decided only once.
Usage
Agent$resume_approval(
path,
decision = c("approve", "deny"),
tool_input = NULL,
usage_limits = NULL
)Arguments
pathThe approval's directory, from the
"approval"event or$pending_approval().decision"approve"or"deny".tool_inputOptional named list of edited tool arguments to use instead of the original ones. Only allowed with
"approve".usage_limitsOptional UsageLimits for the resumed run. They can't exceed the agent's limits at the time of suspension or now, and usage from before the suspension still counts.
NULLkeeps the suspended run's limits.
Returns
An AgentResult. Its usage includes the work done before the suspension.
Agent$checkpoint()
Create a file checkpoint that $rewind_files() can restore. Needs
enable_file_checkpointing = TRUE.
Usage
Agent$checkpoint(name = NULL, metadata = list())Agent$rewind_files()
Restore files to how they were at a checkpoint. Later checkpoints are discarded. The conversation doesn't change. Errors during a run.
Agent$compact()
Replace older turns in the model context with a summary, so later
requests are smaller. The removed turns stay available from
$get_turns(). Errors during a run; runs compact automatically as set
by the ContextPolicy.
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 keep.
NULLkeeps as many recent turns as fit inmax_tokens * compact_toof the context policy, starting at a user turn, or the last 4 turns ifmax_tokensisNULL.summaryOptional summary to use. If
NULL, aPreCompacthook can supply one; otherwise the model writes one covering decisions, findings, files, errors and progress.fallback"error"or"text": what to do if the model can't write the summary. Defaults to the context policy'sfallback.automaticSet by the agent when a run compacts automatically. Leave it as
FALSE.estimated_tokensOptional token estimate before compaction, recorded in the result.
Details
Compaction:
Fires the
PreCompacthook, which can cancel compaction or supply a summary.Asks the model to summarise the older turns, unless a summary was supplied.
Appends the summary to the system prompt under "Previous Conversation Summary".
Keeps only the last
keep_lastturns in the model context.
If the model can't write a summary, $compact() errors, unless
fallback = "text", which builds a plain summary from the first 200
characters of each turn instead. The result's method shows which was
used.
Returns
A DeputyCompaction describing what happened.
Agent$microcompact()
Clear old tool results from the model's context, as Posit Assistant's
/microcompact does.
Every tool result before the last keep_last turns has its value
replaced by marker in the model's context, unless its tool is named in
keep_tools. Nothing is summarised and no model call is made. Any
earlier compaction summary is kept. Errors during a run.
Like compaction, this changes only what the model sees. $get_turns(),
$last_turn() and saved sessions keep the original results, so your
app's conversation history is unchanged. $get_context_turns() shows
the markers.
Usage
Agent$microcompact(
keep_last = 2L,
keep_tools = character(),
marker = "[Old tool result cleared to save context.]"
)Agent$load_skill()
Load a Skill: register its tools and append its prompt to the system prompt. Warns if packages the skill needs are missing or it expects a different provider.
Arguments
skillA Skill object or path to a skill directory.
allow_conflictsIf
TRUE, the skill's tools replace registered tools with the same names, with a warning. IfFALSE(the default), a name clash is an error.
Agent$load_mcp()
Load tools from the MCP (Model Context Protocol) servers in an mcptools configuration file.
Needs the mcptools package. If it isn't installed or the tools can't be
fetched, this warns and loads nothing; $mcp_status() records each
attempt. If a reload fails, tools whose connections were closed are
removed and the rest stay.
Arguments
configPath to the configuration file.
NULLuses the mcptools default,~/.config/mcptools/config.json.serversNames of the servers to load from.
NULLloads from all of them.replaceIf
TRUE, replace the tools loaded earlier from these servers, dropping any a server no longer offers, and replace any other tools with the same names. IfFALSE, a name clash is an error.
Agent$run_async()
Run a task asynchronously. Works like $run_sync() but returns a
promise, so you can use it from async code, such as a Shiny app or a
tool that runs another agent while its own chat is streaming.
Usage
Agent$run_async(
task,
usage_limits = NULL,
run_context = list(),
type = NULL,
validate = NULL,
max_corrections = 0L
)Arguments
taskThe task for the agent.
usage_limitsUsageLimits for this run.
NULLfields use the agent's limits.run_contextNamed list merged into the agent's
run_contextfor this run. It can't change or remove ID fields (keys ending inid) that the agent already sets.typeOptional ellmer type, such as
ellmer::type_object(). After the task, the agent extracts data of this type from the conversation intoresult$structured_output. This counts toward the run's limits.validateOptional function that checks the extracted value. Return
TRUEto accept it, orFALSEor a message to reject it; a message is sent to the model as feedback. An error or any other return value, such asNA, ends the run with an error.max_correctionsHow many times to ask the model to fix a rejected value. Defaults to 0. If the value is still rejected, the run errors. Every attempt counts toward the run's limits.
Returns
A promise that resolves to an AgentResult. It is rejected if
the provider request fails or a limit with on_exceed = "error" is
reached.
Examples
if (FALSE) { # \dontrun{
# Create an agent with file tools
agent <- Agent$new(
chat = ellmer::chat("openai/gpt-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")
}
))
} # }