Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: btw
Title: A Toolkit for Connecting R and Large Language Models
Version: 1.4.0.9000
Version: 1.5.0
Authors@R: c(
person("Garrick", "Aden-Buie", , "garrick@adenbuie.com", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-7111-0077")),
Expand Down Expand Up @@ -78,7 +78,7 @@ Suggests:
roxygen2,
RSQLite (>= 2.2.2),
shiny,
shinychat (>= 0.5.0),
shinychat (>= 0.4.0),
testthat (>= 3.0.0),
tibble,
usethis
Expand Down Expand Up @@ -151,5 +151,3 @@ Collate:
'utils-shinychat.R'
'utils.R'
'zzz.R'
Remotes:
posit-dev/shinychat@rc-v0.5.0
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# btw (development version)
# btw 1.5.0

## New features

Expand Down Expand Up @@ -34,6 +34,8 @@

* btw now requires ellmer (>= 0.4.2). The `set_model()` compatibility shim was removed, and `client_get_models()` now delegates to ellmer's `models_list()` generic, replacing a bespoke per-provider dispatch table (#214).

* btw no longer reads the legacy user skills directory used by btw <= 1.2.0 (`skills/` under `tools::R_user_dir("btw", "config")`) (#204).

# btw 1.4.0

## New features
Expand Down
51 changes: 3 additions & 48 deletions R/tool-skills.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ NULL
#' 2. Skills from currently **attached** R packages — any package with an
#' `inst/skills/` directory that is loaded via [library()] or [require()]
#' 3. User-level skills (`~/.btw/skills`, `~/.config/btw/skills`,
#' `tools::R_user_dir("btw")/skills`). For backwards compatibility, the
#' legacy `tools::R_user_dir("btw", "config")/skills` path used by briefly
#' by btw 1.2.0 is also included at lower priority.
#' `tools::R_user_dir("btw")/skills`)
#' 4. Project-level skills (`.btw/skills/` or `.agents/skills/`)
#'
#' The default user-level and project-level directories can be replaced by
Expand Down Expand Up @@ -294,55 +292,12 @@ skill_dirs_from_option_or_envvar <- function(option_name, envvar_name) {
}

default_user_skill_dirs <- function() {
# Legacy: btw <= 1.2.0 install target — kept for backwards compatibility only,
# never written to by newer versions. Listed first (lowest priority).
legacy_skills_dir <- file.path(tools::R_user_dir("btw", "config"), "skills")
warn_legacy_skill_dir(legacy_skills_dir)

# Current user-level skill dirs in increasing priority order
current_dirs <- rev(vapply(
# User-level skill dirs in increasing priority order.
rev(vapply(
btw_user_dirs(),
function(d) file.path(d, "skills"),
character(1)
))

# Combine: legacy first, then current dirs in increasing priority order.
# The `%in%` guard in the calling loop prevents re-adding dirs already
# present from earlier sources (e.g. attached packages). `unique()` removes
# any duplicates within this vector itself before the loop sees them.
unique(c(legacy_skills_dir, current_dirs))
}

warn_legacy_skill_dir <- function(dir) {
# Skip in tests, consistent with path_find_user() / find_user_agent_files().
# A maintainer's real legacy dir must not inject warnings into the suite.
if (identical(Sys.getenv("TESTTHAT"), "true")) {
return(invisible())
}
if (!fs::dir_exists(dir)) {
return(invisible())
}
# Warn on use: only when the legacy dir actually contains a skill.
has_skill <- length(fs::dir_ls(
dir,
recurse = 1,
regexp = "/SKILL\\.md$",
fail = FALSE
)) >
0
if (!has_skill) {
return(invisible())
}

cli::cli_warn(
c(
"!" = "Skills found in a deprecated location: {.path {dir}}",
"i" = "Move them to {.path {fs::path(btw_user_dir_preferred(), 'skills')}}.",
"i" = "This location (btw <= 1.2.0) is deprecated and will stop being read in btw 1.5.0."
),
.frequency = "once",
.frequency_id = "btw_legacy_skills_dir"
)
}

default_project_skill_dirs <- function(project_dir) {
Expand Down
4 changes: 1 addition & 3 deletions man/btw_tool_skill.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tests/testthat/test-tool-pkg-src.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Test btw_tool_pkg_src_list_impl ----------------------------------------------

skip_on_cran()

test_that("btw_tool_pkg_src_list_impl returns exported objects by default", {
result <- btw_tool_pkg_src_list_impl("tools")

Expand Down
51 changes: 2 additions & 49 deletions tests/testthat/test-tool_skills.R
Original file line number Diff line number Diff line change
Expand Up @@ -617,55 +617,9 @@ test_that("find_skill() returns the highest-priority version when skill exists i
expect_equal(fm$data$description, "High priority version")
})

# warn_legacy_skill_dir() ---------------------------------------------------

test_that("warn_legacy_skill_dir() warns when legacy dir contains a skill", {
withr::local_envvar(TESTTHAT = NA)
withr::local_options(rlib_warning_verbosity = "verbose")

dir <- withr::local_tempdir()
skill_dir <- fs::path(dir, "my-skill")
fs::dir_create(skill_dir)
fs::file_create(fs::path(skill_dir, "SKILL.md"))

w <- expect_warning(warn_legacy_skill_dir(dir))
expect_match(conditionMessage(w), "deprecated location")
expect_match(conditionMessage(w), "1.5.0")
})

test_that("warn_legacy_skill_dir() does not warn when legacy dir is empty", {
withr::local_envvar(TESTTHAT = NA)
withr::local_options(rlib_warning_verbosity = "verbose")

dir <- withr::local_tempdir()

expect_no_warning(warn_legacy_skill_dir(dir))
})

test_that("warn_legacy_skill_dir() does not warn when legacy dir does not exist", {
withr::local_envvar(TESTTHAT = NA)
withr::local_options(rlib_warning_verbosity = "verbose")

dir <- file.path(withr::local_tempdir(), "does-not-exist")

expect_no_warning(warn_legacy_skill_dir(dir))
})

test_that("warn_legacy_skill_dir() is guarded off during the test suite", {
withr::local_envvar(TESTTHAT = "true")
withr::local_options(rlib_warning_verbosity = "verbose")

dir <- withr::local_tempdir()
skill_dir <- fs::path(dir, "my-skill")
fs::dir_create(skill_dir)
fs::file_create(fs::path(skill_dir, "SKILL.md"))

expect_no_warning(warn_legacy_skill_dir(dir))
})

# default_user_skill_dirs() / resolve_user_skill_dir() with distinct home roots

test_that("default_user_skill_dirs() includes R-home skills dirs when home roots differ", {
test_that("default_user_skill_dirs() preserves current user-dir precedence", {
profile_dir <- withr::local_tempdir()
docs_dir <- withr::local_tempdir()
withr::local_envvar(R_USER_DATA_DIR = withr::local_tempdir())
Expand All @@ -678,8 +632,7 @@ test_that("default_user_skill_dirs() includes R-home skills dirs when home roots

dirs <- default_user_skill_dirs()

expect_true(fs::path(profile_dir, ".btw", "skills") %in% dirs)
expect_true(fs::path(docs_dir, ".btw", "skills") %in% dirs)
expect_equal(unname(dirs), rev(file.path(btw_user_dirs(), "skills")))
})

test_that("resolve_user_skill_dir() returns ~/.btw/skills as the default install target", {
Expand Down