Subagents, Skills, and Memory
Source:vignettes/subagents-skills-memory.Rmd
subagents-skills-memory.RmdLonger tasks benefit from isolating work. deepagentsr
supports three related mechanisms:
- subagents for focused delegated work;
- skills for on-demand procedural instructions;
- memory files for always-loaded project or user context.
Subagents
Subagents are configured with subagent() and called
through the supervisor’s built-in task tool. Each subagent
receives an isolated agent runtime with its own system prompt, tool
list, and model.
reviewer <- subagent(
name = "reviewer",
description = "Reviews short R package changes.",
system_prompt = "You review R package changes and return concise findings.",
model = fake_chat(list(assistant_message("No blocking issues found.")))
)
supervisor <- create_deep_agent(
model = fake_chat(list(
assistant_tool_call(
"task",
list(description = "Review the latest package changes.", subagent = "reviewer")
),
assistant_message("The reviewer found no blocking issues.")
)),
subagents = list(reviewer)
)
run <- supervisor$invoke("Review this package update.")
run$text
#> [1] "The reviewer found no blocking issues."
vapply(run$events, function(event) event$type, character(1))
#> [1] "agent_start" "tool_request" "subagent_start" "subagent_event"
#> [5] "subagent_event" "subagent_event" "subagent_end" "tool_result"
#> [9] "model_message" "agent_end"A default general-purpose subagent is registered
automatically. Add named subagents when you want different prompts,
tools, models, or step limits for specific work.
Skills
Skills are directories containing a SKILL.md file. The
agent reads only the inventory into the supervisor prompt; the full
instructions are loaded by the built-in read_skill tool
when relevant.
skill_root <- tempfile("skills-")
skill_dir <- file.path(skill_root, "r-package-review")
dir.create(skill_dir, recursive = TRUE)
writeLines(
c(
"---",
"name: r-package-review",
"description: Review R package changes for tests, docs, and API consistency.",
"---",
"",
"Check exported APIs, examples, tests, and package check output."
),
file.path(skill_dir, "SKILL.md")
)
skills <- discover_skills(skill_root)
names(skills)
#> [1] "r-package-review"
skills[["r-package-review"]]$description
#> [1] "Review R package changes for tests, docs, and API consistency."
skill_agent <- create_deep_agent(
model = fake_chat(list(
assistant_tool_call("read_skill", list(name = "r-package-review")),
assistant_message("Loaded the review skill.")
)),
skills = skill_root
)
skill_run <- skill_agent$invoke("Use the package review skill.")
skill_run$text
#> [1] "Loaded the review skill."Memory
Memory files are always loaded into the assembled supervisor prompt. They can come from the host filesystem or from the configured virtual backend.
mem_backend <- memory_backend(list(
"/AGENTS.md" = "Always prefer concise, testable examples in documentation."
))
memory_agent <- create_deep_agent(
model = fake_chat(list(assistant_message("I will keep examples concise."))),
backend = mem_backend,
memory = "/AGENTS.md"
)
memory_run <- memory_agent$invoke("How should examples be written?")
memory_run$text
#> [1] "I will keep examples concise."Use the virtual filesystem for writable or task-specific memory, and regular files for project-wide instructions that should be version controlled.
aisdk interop
aisdk_tool() wraps an aisdk-style Agent
as a tool. The wrapper only requires an object with a
$run() method, so it is easy to test without making
aisdk a hard dependency.
AgentLike <- R6::R6Class(
"AgentLikeForVignette",
public = list(
name = "worker",
description = "Does delegated work.",
run = function(task, context = NULL, model = NULL, max_steps = 10, ...) {
topic <- if (is.null(context) || is.null(context$topic)) "" else context$topic
paste("ran", task, topic)
}
)
)
worker_tool <- aisdk_tool(AgentLike$new())
worker_tool$name
#> [1] "worker_agent"
worker_tool$fun("summarise", list(topic = "documentation"))
#> [1] "ran summarise documentation"aisdk_subagent() exposes the same style of object as a
direct subagent. This is useful when you already use
aisdk for specialized agents and want the
deepagentsr supervisor to delegate to them through the
standard task tool.
worker_agent <- create_deep_agent(
model = fake_chat(list(
assistant_tool_call("task", list(description = "summarise docs", subagent = "worker")),
assistant_message("delegation complete")
)),
subagents = list(aisdk_subagent(AgentLike$new()))
)
worker_run <- worker_agent$invoke("Delegate this.")
worker_run$status
#> [1] "completed"