tests/testthat/test-tabscreen_ollama.r

skip <- TRUE
skip_github_action <- FALSE

test_that(".ollama_engine return errors correctly", {
  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  tools_choice_name <- list(
    type = "function",
    "function" = list(
      name = "inclusion_decision_simple"
    )
  )

  # Specifying unknown model
  body <- list(
    model = "llama-7",
    messages = list(list(
      role = "user",
      content = question
    )),
    tools = tools_simple,
    tool_choice = tools_choice_name,
    top_p = 1
  )

  expect_error(
    .ollama_engine(
      body = body,
      RPM = 10000,
      time_inf = TRUE,
      max_t = 4,
      max_s = 10,
      back = NULL,
      aft = NULL,
      endpoint_url = "http://127.0.0.1:11434/api/chat"
    ),
    regexp = "404|Not Found|Error"
  )

  # Specifying ineligible role
  body <- list(
    model = "llama3-8b-8192",
    messages = list(list(
      role = "use",
      content = question
    )),
    tools = tools_simple,
    tool_choice = tools_choice_name,
    top_p = 1
  )

  expect_error(
    .ollama_engine(
      body = body,
      RPM = 10000,
      time_inf = TRUE,
      max_t = 4,
      max_s = 10,
      back = NULL,
      aft = NULL,
      endpoint_url = "http://127.0.0.1:11434/api/chat"
    ),
    regexp = "HTTP 404 Not Found"
  )

})


test_that(".rep_ollama_engine controls errors correctly", {
  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()
  
  iterations <- 3

  # Ineligible role
  res <- .rep_ollama_engine(
    question = question,
    model_gpt = "llama3-8b-8192",
    topp = 1,
    role_gpt = "use",
    tool = tools_simple,
    t_choice = "inclusion_decision_simple",
    iterations = iterations,
    req_per_min = 10000,
    seeds = NULL,
    time_inf = T,
    max_t = 4,
    max_s = 10,
    ba = NULL,
    af = NULL,
    endpoint_url = "http://127.0.0.1:11434/api/chat"
  )

  expect_equal(ncol(res), 4)
  expect_equal(nrow(res), iterations)
  expect_equal(max(res$n), iterations)
  expect_true(all(stringr::str_detect(res$decision_gpt, "400|Error")))

  # Ineligible api key
  res <- .rep_ollama_engine(
    question = question,
    model_gpt = "llama3-8b-8192",
    topp = 1,
    role_gpt = "user",
    tool = tools_simple,
    t_choice = "inclusion_decision_simple",
    iterations = iterations,
    req_per_min = 10000,
    seeds = NULL,
    time_inf = T,
    max_t = 4,
    max_s = 10,
    ba = NULL,
    af = NULL,
    endpoint_url = "http://127.0.0.1:11434/api/chat"
  )

  expect_equal(ncol(res), 4)
  expect_equal(nrow(res), iterations)
  expect_equal(max(res$n), iterations)
  expect_true(all(stringr::str_detect(res$decision_gpt, "401|Error")))

  # Ineligible model
  res <- .rep_ollama_engine(
    question = question,
    model_gpt = "llama-min",
    topp = 1,
    role_gpt = "user",
    tool = tools_simple,
    t_choice = "inclusion_decision_simple",
    iterations = iterations,
    req_per_min = 10000,
    seeds = NULL,
    time_inf = T,
    max_t = 4,
    max_s = 10,
    ba = NULL,
    af = NULL,
    endpoint_url = "http://127.0.0.1:11434/api/chat"
  )

  expect_equal(ncol(res), 4)
  expect_equal(nrow(res), iterations)
  expect_equal(max(res$n), iterations)
  expect_true(any(stringr::str_detect(res$decision_gpt, "404|400|Error")))

})


paths <- system.file("extdata", "test_prompts.rds", package = "AIscreenR")
prompts <- readRDS(file = paths)


prompt <- prompts[1]
prompt2 <- prompts[2]


models <- c("llama-3.1-8b-instant", "openai/gpt-oss-20b")
reps <- c(2, 1)
rpm <- c(30, 30)

test_that("tabscreen_ollama() overinclusive chooses default tools", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  # Use closed local port to avoid dependency on a running Ollama server.
  test_api <- "http://127.0.0.1:1/api/chat"

  # Binary default tools when overinclusive = FALSE
  res_bin <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api,
    model = "llama3-8b-8192",
    overinclusive = FALSE,
    decision_description = FALSE,
    messages = FALSE,
    progress = FALSE
  )

  args_bin <- attr(res_bin, "arg_list")
  expect_identical(args_bin$tool_choice, "inclusion_decision_simple_binary")
  expect_identical(args_bin$tools[[1]]$`function`$name, "inclusion_decision_simple_binary")

  res_bin_det <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api,
    model = "llama3-8b-8192",
    overinclusive = FALSE,
    decision_description = TRUE,
    messages = FALSE,
    progress = FALSE
  )

  args_bin_det <- attr(res_bin_det, "arg_list")
  expect_identical(args_bin_det$tool_choice, "inclusion_decision_binary")
  expect_identical(args_bin_det$tools[[1]]$`function`$name, "inclusion_decision_binary")

  # Over-inclusive tools (supports 1.1) when overinclusive = TRUE
  res_over <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api,
    model = "llama3-8b-8192",
    overinclusive = TRUE,
    decision_description = FALSE,
    messages = FALSE,
    progress = FALSE
  )

  args_over <- attr(res_over, "arg_list")
  expect_identical(args_over$tool_choice, "inclusion_decision_simple")
  expect_identical(args_over$tools[[1]]$`function`$name, "inclusion_decision_simple")

  res_over_det <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api,
    model = "llama3-8b-8192",
    overinclusive = TRUE,
    decision_description = TRUE,
    messages = FALSE,
    progress = FALSE
  )

  args_over_det <- attr(res_over_det, "arg_list")
  expect_identical(args_over_det$tool_choice, "inclusion_decision")
  expect_identical(args_over_det$tools[[1]]$`function`$name, "inclusion_decision")

})

test_that("tabscreen_ollama() validates missing or empty model", {

  test_api <- "http://127.0.0.1:1/api/chat"

  expect_error(
    tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      title = title,
      abstract = abstract,
      api_url = test_api,
      messages = FALSE,
      progress = FALSE
    ),
    "You must provide a model\\."
  )

  expect_error(
    tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      title = title,
      abstract = abstract,
      api_url = test_api,
      model = "",
      messages = FALSE,
      progress = FALSE
    ),
    "You must provide a model\\."
  )

  expect_error(
    tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      title = title,
      abstract = abstract,
      api_url = test_api,
      model = NA_character_,
      messages = FALSE,
      progress = FALSE
    ),
    "You must provide a model\\."
  )

  expect_error(
    tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      title = title,
      abstract = abstract,
      api_url = test_api,
      model = character(0),
      messages = FALSE,
      progress = FALSE
    ),
    "You must provide a model\\."
  )

})

test_that("tabscreen_ollama() normalizes common Ollama base URLs", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  # Use closed local port to avoid dependency on a running Ollama server.
  test_api_base <- "http://127.0.0.1:1"
  test_api_root <- "http://127.0.0.1:1/api"

  res_base <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api_base,
    model = "llama3-8b-8192",
    messages = FALSE,
    progress = FALSE
  )

  res_root <- tabscreen_ollama(
    data = filges2015_dat[1,],
    prompt = prompt,
    studyid = studyid,
    title = title,
    abstract = abstract,
    api_url = test_api_root,
    model = "llama3-8b-8192",
    messages = FALSE,
    progress = FALSE
  )

  expect_identical(attr(res_base, "arg_list")$api_url, "http://127.0.0.1:1/api/chat")
  expect_identical(attr(res_root, "arg_list")$api_url, "http://127.0.0.1:1/api/chat")

})

future::plan(future::multisession)

test_that("tabscreen_ollama() works with single parameter values.",{

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      max_tries = 2
    )

  )

  expect_true(is.numeric(test_obj$answer_data$decision_binary))

  expect_equal(nrow(test_obj$answer_data), 1L)
  expect_null(test_obj$answer_data_aggregated)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)


  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192", "gemma-7b-it"),
      reps = 1
    )

  )

  expect_equal(nrow(test_obj$answer_data), 2L)
  expect_null(test_obj$answer_data_aggregated)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = c(prompt, prompt2),
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192"),
      reps = 1
    )

  )

  expect_equal(nrow(test_obj$answer_data), 2L)
  expect_null(test_obj$answer_data_aggregated)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)



})

test_that("tabscreen_ollama() works with multiple parameter values.",{

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192", "gemma-7b-it"),
      reps = c(2, 1)
    )

  )

  expect_equal(nrow(test_obj$answer_data), 3L)
  expect_equal(nrow(test_obj$answer_data_aggregated), 2L)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)

  expect_gt(nrow(test_obj$answer_data), nrow(test_obj$answer_data_aggregated))

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1:2,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192", "gemma-7b-it"),
      reps = c(2, 1)
    )

  )

  expect_equal(nrow(test_obj$answer_data), 6L)
  expect_equal(nrow(test_obj$answer_data_aggregated), 4L)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)


  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1:2,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192", "gemma-7b-it"),
      reps = c(2, 1),
      top_p = c(0.2, 1)
    )

  )

  expect_equal(nrow(test_obj$answer_data), 12L)
  expect_equal(nrow(test_obj$answer_data_aggregated), 2*2*2)
  expect_null(test_obj$price_data)
  expect_null(test_obj$price_dollar)

})

test_that("tabscreen_ollama() works with detailed functions and ... .", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1:2,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      decision_description = TRUE
    )

  ) |>
    suppressMessages()


  expect_true(is.character(test_obj$answer_data$detailed_description))
  expect_null(test_obj$answer_data_aggregated)

  # Working with temperature, i.e. ... calls

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 3,
      decision_description = TRUE,
      progress = FALSE,
      temperature = 0.001
    )

  ) |>
    suppressMessages()

  n_distinct_detailed_answers <- test_obj$answer_data$detailed_description |> dplyr::n_distinct()

  expect_lt(n_distinct_detailed_answers, 3)

})

test_that("Message behavior.", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_no_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      messages = FALSE,
      progress = FALSE
    )

  )

  expect_no_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      messages = FALSE,
      progress = FALSE
    )

  )
  expect_no_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "gemma-7b-it",
      reps = 2
    )
  )
  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      decision_description = TRUE
    )
  ) |>
    suppressMessages()
  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "gemma-7b-it",
      reps = 1,
      decision_description = TRUE
    ),

    paste0(
          "* Be aware that getting detailed reponses ",
          "will substantially increase the time of the screening."
    )

  ) |>
    suppressMessages()

  expect_message(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[148,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3.2:latest",
    ),

    paste0(
      "* Consider removing references without abstracts ",
      "since these can distort the accuracy of the screening."
    )

  ) |>
    suppressMessages()

})

test_that("tabscreen_ollama() expected errors.", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = models,
      reps = c(10, 1, 1)
    )

  )

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = models,
      reps = c(10, 1),
      rpm = c(30, 30, 30)
    )

  )

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192-x", "gemma-7b-it"),
      reps = reps,
      rpm = rpm
    )

  )

  # With detailed description functions

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = models,
      reps = c(10, 1, 1),
      decision_description = TRUE
    )

  )

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = models,
      reps = c(10, 1),
      rpm = c(30, 30, 30),
      decision_description = TRUE
    )

  )

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = c("llama3-8b-8192-x", "gemma-7b-it"),
      reps = reps,
      rpm = rpm,
      decision_description = TRUE
    )

  )

  expect_error(

    test_obj <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      incl_cutoff_upper = 0.4,
      incl_cutoff_lower = 0.5
    )

  )

})

future::plan(future::sequential)

# Test parallel

test_that("That parallel processing works.", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  future::plan(future::multisession, workers = future::availableCores())

  expect_message(

    tm_par <- system.time(
      test_obj <- tabscreen_ollama(
        data = filges2015_dat[1:2,],
        prompt = prompt,
        title = title,
        abstract = abstract,
        model = "llama3-8b-8192",
        reps = 10
      )
    )
  )

  future::plan(future::sequential)

  expect_lt(tm_par[["elapsed"]], sum(test_obj$answer_data$run_time))

  ollama_answers <-
    test_obj$answer_data |>
    filter(!is.na(decision_gpt)) |>
    pull(decision_gpt)

  # Testing function call work
  ollama_answers |>
    stringr::str_detect("1|0|rror") |>
    unique() |>
    expect_true()



})

test_that("Print and class expectation for ollama object.", {

  if(skip) skip()
  if(skip_github_action) skip_on_ci()
  skip_on_cran()

  expect_message(

    random_name <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
      max_tries = 2
    )

  )

  # class check
  expect_s3_class(random_name, "gpt")
  expect_s3_class(random_name, "list")

  expect_output(print(random_name), "result_object\\$answer_data")
  expect_output(print.gpt(random_name), "result_object\\$answer_data")
  expect_false("answer_data_aggregated" %in% names(random_name))
  expect_false("price_dollar" %in% names(random_name))

  print_out1 <- paste0(
    "Find the final result dataset via result_object$answer_data"
  )
  expect_output(print(random_name), print_out1)

  expect_message(

    random_name <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = c(prompt),
      studyid = studyid, # indicate the variable with the studyid in the data
      title = title, # indicate the variable with the titles in the data
      abstract = abstract,
    )
  ) |>
    suppressMessages()

  expect_identical(names(random_name$answer_data), names(random_name$error_data))

  expect_output(print(random_name), "result_object\\$answer_data")

  print_out2 <- paste0(
    "Find the final result dataset via result_object$answer_data"
  )

  expect_output(print(random_name), print_out2)

  #############
  expect_message(

    random_name <- tabscreen_ollama(
      data = filges2015_dat[1,],
      prompt = prompt,
      studyid = studyid,
      title = title,
      abstract = abstract,
      model = "llama3-8b-8192",
      reps = 1,
    )

  )

  # class check
  expect_s3_class(random_name, "gpt")
  expect_s3_class(random_name, "list")

  expect_output(print(random_name), "result_object\\$answer_data")
  expect_output(print.gpt(random_name), "result_object\\$answer_data")

  expect_false("price_dollar" %in% names(random_name))

  expect_message(

    random_name <- tabscreen_ollama(
      data = filges2015_dat[c(1:2),],
      prompt = c(prompt),
      studyid = studyid, # indicate the variable with the studyid in the data
      title = title, # indicate the variable with the titles in the data
      abstract = abstract
    )
  ) |>
    suppressMessages()


  expect_output(print(random_name), "result_object\\$answer_data")

  expect_false("price_dollar" %in% names(random_name))


})

Try the AIscreenR package in your browser

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

AIscreenR documentation built on April 14, 2026, 1:08 a.m.