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
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# btw (development version)

## Bug fixes

* `btw_tool_agent_subagent()` now correctly uses the options from your `btw.md` file when called directly rather than through `btw_client()` or `btw_app()` (#185).

# btw 1.2.1

## Bug fixes
Expand Down
19 changes: 17 additions & 2 deletions R/tool-agent-subagent.R
Original file line number Diff line number Diff line change
Expand Up @@ -410,20 +410,35 @@ subagent_client <- function(
))
}

# We may need to read btw.md directly to determine client settings
config <- NULL

subagent_client_resolved <-
client %||%
getOption("btw.subagent.client") %||%
getOption("btw.client")

if (is.null(subagent_client_resolved)) {
config <- read_btw_file()

subagent_client_resolved <-
config$options$btw.subagent.client %||%
btw_client_config(config = config, tools = FALSE)$client
}

tools_default <-
tools_default %||%
getOption("btw.subagent.tools_default") %||%
getOption("btw.tools")
getOption("btw.tools") %||%
config$options$btw.subagent.tools_default %||%
config$tools

tools_default <- subagent_disallow_recursion(tools_default)

tools_allowed <-
tools_allowed %||%
getOption("btw.subagent.tools_allowed")
getOption("btw.subagent.tools_allowed") %||%
config$options$btw.subagent.tools_allowed
# Note: Don't filter subagent from tools_allowed here.
# The allowed list should be used as-is for validation.
# The final subagent_disallow_recursion() at the end handles the actual filtering.
Expand Down
19 changes: 19 additions & 0 deletions tests/testthat/helpers.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
use_latest_pandoc <- function(.envir = parent.frame()) {
has_internet <- asNamespace("testthat")[["has_internet"]]

if (!is.null(has_internet) && !has_internet("captive.apple.com")) {
# No internet, skip
return()
}

if (!identical(Sys.getenv("NOT_CRAN"), "true")) {
# On CRAN, don't attempt to do anything with pandoc
return()
Expand Down Expand Up @@ -151,3 +158,15 @@ local_skip_pandoc_convert <- function(.env = caller_env()) {
.env = .env
)
}

local_btw_md <- function(project = NULL, user = NULL, .env = caller_env()) {
local_mocked_bindings(
find_btw_context_file = function(...) {
project
},
path_find_user = function(...) {
user
},
.env = .env
)
}
39 changes: 39 additions & 0 deletions tests/testthat/test-tool-agent-subagent.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,37 @@ test_that("subagent_client() clones clients from options", {
expect_false(identical(chat1, chat_obj))
})

test_that("subagent_client() consults btw.md if options are unset", {
# i.e. btw_tool_agent_subagent() uses btw.md settings when called directly
tmp_btw_md <- withr::local_tempfile(
lines = c(
"---",
"options:",
" subagent:",
" client: openrouter/super-cool-model",
" tools_allowed: docs",
" tools_default: docs_help_page",
"---"
)
)

local_btw_md(project = tmp_btw_md)

agent_client <- subagent_client()
expect_equal(agent_client$get_provider()@name, "OpenRouter")
expect_equal(agent_client$get_provider()@model, "super-cool-model")

expect_equal(
names(agent_client$get_tools()),
"btw_tool_docs_help_page"
)

expect_error(
subagent_client(tools = "btw_tool_skill"),
"disallowed tools"
)
})

# subagent_build_description() is internal - description content is tested
# through btw_tool_agent_subagent registration tests below

Expand Down Expand Up @@ -314,6 +345,8 @@ test_that("btw_tool_agent_subagent is filtered out from default tools", {
})

test_that("btw_tool_agent_subagent is silently filtered out from 'agent' tool group", {
local_btw_md()

# Request the 'agent' tool group which includes btw_tool_agent_subagent
# The subagent tool is silently filtered via can_register (no warning)
chat <- subagent_client(tools = c("agent"))
Expand Down Expand Up @@ -343,6 +376,8 @@ test_that("btw_tool_agent_subagent is silently filtered out even when in tools_a
})

test_that("btw_tool_agent_subagent never appears in chat$get_tools() for subagent", {
local_btw_md()

# Test multiple scenarios to ensure subagent tool never appears

# Scenario 1: Explicit request → throws error
Expand Down Expand Up @@ -377,6 +412,8 @@ test_that("btw_tool_agent_subagent never appears in chat$get_tools() for subagen
})

test_that("subagent tool errors even when in tools_allowed", {
local_btw_md()

withr::local_options(
btw.subagent.tools_allowed = c("btw_tool_agent_subagent", "docs")
)
Expand All @@ -401,6 +438,8 @@ test_that("subagent tool errors even when in tools_allowed", {
# ---- Chat Client Configuration ----------------------------------------------

test_that("subagent_client creates chat with filtered tools", {
local_btw_md()

chat <- subagent_client(tools = "files")

expect_true(inherits(chat, "Chat"))
Expand Down
3 changes: 3 additions & 0 deletions tests/testthat/test-tool-session-package-installed.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ test_that("btw_tool_sessioninfo_is_package_installed()", {
expect_equal(res_installed@extra$package, "dplyr")
expect_equal(res_installed@extra$version, "1.0.0")

# Listing available packages requires an internet connection
skip_if_offline()

expect_error(
btw_tool_sessioninfo_is_package_installed("skibidi")
)
Expand Down
Loading