tests/testthat/test-agent-skills-integration.R

test_that("Agent initializes with skills='auto'", {
  # Mock dir.exists to satisfy "auto" logic
  # Since we can't easily mock base R functions in this script without mockery or testthat::local_mock,
  # we will use a temporary directory structure.
  
  temp_root <- tempdir()
  skill_dir <- file.path(temp_root, "inst", "skills")
  dir.create(skill_dir, recursive = TRUE, showWarnings = FALSE)
  
  # Create a dummy skill
  dummy_skill_path <- file.path(skill_dir, "dummy_skill")
  dir.create(dummy_skill_path, recursive = TRUE)
  writeLines(c(
    "---",
    "name: dummy_skill",
    "description: A dummy skill",
    "---",
    "Instructions for dummy skill"
  ), file.path(dummy_skill_path, "SKILL.md"))
  
  # Temporarily change WD to temp_root so "auto" finds it
  withr::with_dir(temp_root, {
      # Source agent again to use the new definition? No, function is already defined.
      # But create_agent uses getwd().
      
      agent <- create_agent(
          name = "TestAgent",
          description = "Test Description",
          skills = "auto"
      )
      
      # Check if tools are added (load_skill, execute_skill_script, list_skill_scripts)
      tool_names <- sapply(agent$tools, function(t) t$name)
      expect_true("load_skill" %in% tool_names)
      expect_true("execute_skill_script" %in% tool_names)
      expect_true("list_skill_scripts" %in% tool_names)
      expect_true("reload_skills" %in% tool_names)

      # Check if system prompt contains skill info
      expect_true(grepl("Available Skills", agent$system_prompt))
      expect_true(grepl("dummy_skill", agent$system_prompt))
  })
})

test_that("Agent initializes with explicit skill path", {
  temp_root <- tempdir()
  skill_dir <- file.path(temp_root, "my_custom_skills")
  dir.create(skill_dir, recursive = TRUE, showWarnings = FALSE)
  
  dummy_skill_path <- file.path(skill_dir, "custom_skill")
  dir.create(dummy_skill_path, recursive = TRUE)
  writeLines(c(
    "---",
    "name: custom_skill",
    "description: A custom skill",
    "---",
    "Instructions"
  ), file.path(dummy_skill_path, "SKILL.md"))
  
  agent <- create_agent(
      name = "CustomAgent",
      description = "Desc",
      skills = skill_dir # Pass path directly
  )

  expect_true(grepl("custom_skill", agent$system_prompt))
  expect_gte(length(agent$tools), 7)
})

test_that("skill tools can reload updated skills from disk", {
  temp_root <- tempfile()
  skill_dir <- file.path(temp_root, "skills")
  dir.create(file.path(skill_dir, "live_skill"), recursive = TRUE)
  on.exit(unlink(temp_root, recursive = TRUE), add = TRUE)

  writeLines(c(
    "---",
    "name: live_skill",
    "description: Live skill",
    "---",
    "Version one"
  ), file.path(skill_dir, "live_skill", "SKILL.md"))

  registry <- create_skill_registry(skill_dir, recursive = TRUE)
  tools <- create_skill_tools(registry)
  reload_tool <- tools[[which(sapply(tools, function(t) t$name) == "reload_skills")]]
  load_tool <- tools[[which(sapply(tools, function(t) t$name) == "load_skill")]]

  expect_true(grepl("Version one", load_tool$run(list(skill_name = "live_skill"))))

  writeLines(c(
    "---",
    "name: live_skill",
    "description: Live skill",
    "---",
    "Version two"
  ), file.path(skill_dir, "live_skill", "SKILL.md"))

  reload_result <- reload_tool$run(list())

  expect_true(grepl("Reloaded skills", reload_result, fixed = TRUE))
  expect_true(grepl("Version two", load_tool$run(list(skill_name = "live_skill"))))
})

test_that("Agent keeps reload tools for initially empty skill roots", {
  temp_root <- tempfile()
  skill_dir <- file.path(temp_root, "skills")
  dir.create(skill_dir, recursive = TRUE)
  on.exit(unlink(temp_root, recursive = TRUE), add = TRUE)

  agent <- create_agent(
    name = "EmptySkillAgent",
    description = "Starts with an empty skill root",
    skills = skill_dir
  )

  expect_null(agent$system_prompt)
  expect_s3_class(agent$skill_registry, "SkillRegistry")
  tool_names <- sapply(agent$tools, function(t) t$name)
  expect_true("reload_skills" %in% tool_names)

  dir.create(file.path(skill_dir, "late_skill"))
  writeLines(c(
    "---",
    "name: late_skill",
    "description: Added after startup",
    "---",
    "Late body"
  ), file.path(skill_dir, "late_skill", "SKILL.md"))

  reload_tool <- agent$tools[[which(tool_names == "reload_skills")]]
  reload_tool$run(list())

  expect_true(agent$skill_registry$has_skill("late_skill"))
})

# The channel_resolve_agent test moved to aisdk.channels
# (test-channel-resolve-agent.R), where it accesses the channels-internal
# function without a cross-package ::: call.

Try the aisdk package in your browser

Any scripts or data that you put into this service are public.

aisdk documentation built on May 29, 2026, 9:07 a.m.