tests/testthat/test-model-defaults.R

local_restore_model_defaults <- function() {
  caller <- parent.frame()
  env <- get(".model_env", envir = asNamespace("aisdk"))
  old_default <- env$default %||% NULL
  old_options_env <- env$options %||% NULL
  old_default_option <- getOption("aisdk.default_model")
  old_options_option <- getOption("aisdk.default_model_options")

  withr::defer({
    env$default <- old_default
    env$options <- old_options_env
    options(
      aisdk.default_model = old_default_option,
      aisdk.default_model_options = old_options_option
    )
  }, envir = caller)
}

test_that("set_model and model manage the package default", {
  local_restore_model_defaults()
  old <- get_model()

  previous <- set_model("mock:test-model")
  expect_identical(previous, old)
  expect_identical(get_model(), "mock:test-model")
  expect_identical(model(), "mock:test-model")

  previous <- model("mock:next-model")
  expect_identical(previous, "mock:test-model")
  expect_identical(get_model(), "mock:next-model")
})

test_that("set_model can adjust runtime options without changing the model", {
  local_restore_model_defaults()
  old <- get_model()

  set_model("mock:runtime-target")
  previous <- set_model(context_window = 64000, thinking = "on")

  expect_identical(previous, "mock:runtime-target")
  expect_identical(get_model(), "mock:runtime-target")
  expect_equal(get_model_options()$context_window, 64000)
  expect_true(aisdk:::list_get_exact(get_model_options()$call_options, "thinking"))

  model(max_tokens = 512)
  expect_identical(get_model(), "mock:runtime-target")
  expect_equal(aisdk:::list_get_exact(get_model_options()$call_options, "max_tokens"), 512)
})

test_that("set_model stores runtime options for default model calls and sessions", {
  local_restore_model_defaults()

  captured <- NULL
  mock_model <- structure(
    list(
      provider = "mock",
      model_id = "runtime-default",
      do_generate = function(params) {
        captured <<- params
        list(text = "ok", tool_calls = NULL, finish_reason = "stop", usage = NULL)
      },
      get_history_format = function() "openai"
    ),
    class = "LanguageModelV1"
  )

  set_model(
    mock_model,
    context_window = 1000000,
    max_output_tokens = 384000,
    max_tokens = 700,
    thinking = TRUE,
    reasoning_effort = "high"
  )

  options <- get_model_options()
  expect_equal(options$context_window, 1000000)
  expect_equal(options$max_output_tokens, 384000)
  expect_equal(options$call_options$max_tokens, 700)
  expect_true(options$call_options$thinking)
  expect_equal(options$call_options$reasoning_effort, "high")

  result <- generate_text(prompt = "Hello")
  expect_equal(result$text, "ok")
  expect_equal(captured$max_tokens, 700)
  expect_true(captured$thinking)
  expect_equal(captured$reasoning_effort, "high")

  session <- create_chat_session()
  session_options <- session$get_model_options()
  expect_equal(session_options$context_window, 1000000)
  expect_equal(session_options$max_output_tokens, 384000)
  expect_equal(session_options$call_options$max_tokens, 700)
})

test_that("aisdk.yaml can define default model and runtime options", {
  local_restore_model_defaults()
  old_wd <- getwd()
  tmp <- tempfile("aisdk-config-")
  dir.create(tmp)
  on.exit({
    setwd(old_wd)
  }, add = TRUE)
  setwd(tmp)
  set_model(NULL, reset_options = TRUE)
  options(aisdk.default_model = NULL)

  writeLines(c(
    "default_model: yulab:gpt-5.5",
    "model_providers:",
    "  yulab:",
    "    type: custom",
    "    base_url: https://api.yulab.example/v1",
    "    wire_api: responses",
    "models:",
    "  yulab:gpt-5.5:",
    "    reasoning_effort: xhigh",
    "    context_window: 1000000",
    "    max_output_tokens: 384000",
    "    max_tokens: 700"
  ), "aisdk.yaml")

  expect_equal(get_model(), "yulab:gpt-5.5")
  opts <- get_model_options()
  expect_equal(opts$context_window, 1000000)
  expect_equal(opts$max_output_tokens, 384000)
  expect_equal(opts$call_options$reasoning_effort, "xhigh")
  expect_equal(opts$call_options$max_tokens, 700)

  session <- create_chat_session("yulab:gpt-5.5")
  expect_equal(session$get_model_options()$context_window, 1000000)
  expect_equal(session$get_model_options()$call_options$reasoning_effort, "xhigh")
})

test_that("aisdk.yaml supports top-level model_provider and model", {
  local_restore_model_defaults()
  old_wd <- getwd()
  tmp <- tempfile("aisdk-config-")
  dir.create(tmp)
  on.exit(setwd(old_wd), add = TRUE)
  setwd(tmp)
  set_model(NULL, reset_options = TRUE)
  options(aisdk.default_model = NULL)

  writeLines(c(
    "model_provider: yulab",
    "model: gpt-5.5",
    "model_context_window: 1000000",
    "model_reasoning_effort: xhigh",
    "model_providers:",
    "  yulab:",
    "    type: custom",
    "    base_url: https://api.yulab.example/v1",
    "    wire_api: responses"
  ), "aisdk.yaml")

  expect_equal(get_model(), "yulab:gpt-5.5")
  opts <- get_model_options()
  expect_equal(opts$context_window, 1000000)
  expect_equal(opts$call_options$reasoning_effort, "xhigh")
})

test_that("project aisdk.yaml overrides global config values", {
  project_cfg <- tempfile(fileext = ".yaml")
  global_cfg <- tempfile(fileext = ".yaml")

  writeLines(c(
    "default_model: global:model",
    "models:",
    "  shared:model:",
    "    reasoning_effort: low"
  ), global_cfg)
  writeLines(c(
    "default_model: project:model",
    "models:",
    "  shared:model:",
    "    reasoning_effort: high"
  ), project_cfg)

  cfg <- aisdk:::load_model_config(paths = c(global_cfg, project_cfg))
  expect_equal(aisdk:::model_config_default_model(cfg), "project:model")
  expect_equal(aisdk:::model_config_runtime_options("shared:model", cfg)$call_options$reasoning_effort, "high")
})

test_that("AISDK_CONFIG_FILE overrides default global aisdk config", {
  config_home <- tempfile("aisdk-config-home-")
  dir.create(file.path(config_home, "aisdk"), recursive = TRUE)
  explicit_cfg <- tempfile(fileext = ".yaml")
  project_dir <- tempfile("aisdk-config-project-")
  dir.create(project_dir)

  writeLines("default_model: default-global:model", file.path(config_home, "aisdk", "config.yaml"))
  writeLines("default_model: explicit-global:model", explicit_cfg)

  withr::with_envvar(c(
    XDG_CONFIG_HOME = config_home,
    AISDK_CONFIG_FILE = explicit_cfg
  ), {
    cfg <- aisdk:::load_model_config(project_dir = project_dir)
    expect_equal(aisdk:::default_global_model_config_path(), explicit_cfg)
    expect_equal(aisdk:::model_config_default_model(cfg), "explicit-global:model")
  })
})

test_that("generate_text uses the package default model when model is NULL", {
  local_restore_model_defaults()

  mock_model <- structure(
    list(
      provider = "mock",
      model_id = "default",
      do_generate = function(params) {
        list(
          text = "default-response",
          tool_calls = NULL,
          finish_reason = "stop",
          usage = NULL
        )
      },
      get_history_format = function() "openai"
    ),
    class = "LanguageModelV1"
  )

  set_model(mock_model)

  result <- generate_text(prompt = "Hello")

  expect_equal(result$text, "default-response")
})

test_that("ChatSession uses the package default model when no model is provided", {
  local_restore_model_defaults()

  registry <- ProviderRegistry$new()
  registry$register("mock", function(model_id) {
    structure(
      list(
        provider = "mock",
        model_id = model_id,
        do_generate = function(params) {
          list(
            text = paste("reply-from", model_id),
            tool_calls = NULL,
            finish_reason = "stop",
            usage = NULL
          )
        },
        get_history_format = function() "openai"
      ),
      class = "LanguageModelV1"
    )
  })

  set_model("mock:test-model")

  session <- ChatSession$new(registry = registry)
  expect_equal(session$get_model_id(), "mock:test-model")

  result <- session$send("Hello")
  expect_equal(result$text, "reply-from test-model")
})

test_that("ChatSession model options are applied to send calls", {
  captured <- NULL
  mock_model <- structure(
    list(
      provider = "mock",
      model_id = "session-options",
      do_generate = function(params) {
        captured <<- params
        list(text = "ok", tool_calls = NULL, finish_reason = "stop", usage = NULL)
      },
      get_history_format = function() "openai"
    ),
    class = "LanguageModelV1"
  )

  session <- create_chat_session(model = mock_model)
  session$set_model_options(
    max_tokens = 500,
    thinking = TRUE,
    thinking_budget = 2000,
    reasoning_effort = "medium"
  )

  session$send("Hello")

  expect_equal(captured$max_tokens, 500)
  expect_true(captured$thinking)
  expect_equal(captured$thinking_budget, 2000)
  expect_equal(captured$reasoning_effort, "medium")
})

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.