Nothing
library(aisdk)
test_that("read_console_env_file parses quoted values", {
path <- tempfile(fileext = ".Renviron")
writeLines(c(
"OPENAI_API_KEY=\"sk-test\"",
"OPENAI_BASE_URL=https://api.openai.com/v1",
"OPENAI_MODEL='gpt-5-mini'",
"# comment"
), path)
parsed <- aisdk:::read_console_env_file(path)
expect_equal(parsed$values$OPENAI_API_KEY, "sk-test")
expect_equal(parsed$values$OPENAI_BASE_URL, "https://api.openai.com/v1")
expect_equal(parsed$values$OPENAI_MODEL, "gpt-5-mini")
})
test_that("discover_console_model_profiles finds project and global profiles", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
writeLines(c(
"OPENAI_API_KEY=sk-project",
"OPENAI_BASE_URL=https://api.openai.com/v1",
"OPENAI_MODEL=gpt-5-mini"
), project_path)
writeLines(c(
"ANTHROPIC_API_KEY=sk-global",
"ANTHROPIC_BASE_URL=https://api.anthropic.com/v1",
"ANTHROPIC_MODEL=claude-sonnet-4-20250514"
), global_path)
profiles <- aisdk:::discover_console_model_profiles(
project_path = project_path,
global_path = global_path
)
expect_length(profiles, 2)
expect_equal(profiles[[1]]$scope, "project")
expect_equal(profiles[[1]]$model_id, "openai:gpt-5-mini")
expect_equal(profiles[[2]]$scope, "global")
expect_equal(profiles[[2]]$model_id, "anthropic:claude-sonnet-4-20250514")
})
test_that("discover_console_model_profiles includes backup base URLs", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
writeLines(c(
"AISDK_CUSTOM_API_KEY=sk-project",
"AISDK_CUSTOM_BASE_URL=https://primary.example/v1",
"AISDK_CUSTOM_BASE_URLS=https://backup.example/v1",
"AISDK_CUSTOM_MODEL=proxy-model"
), project_path)
profiles <- aisdk:::discover_console_model_profiles(
project_path = project_path,
global_path = global_path
)
custom_idx <- which(vapply(profiles, function(p) identical(p$provider, "custom"), logical(1)))[[1]]
custom <- profiles[[custom_idx]]
expect_equal(custom$base_url, "https://primary.example/v1")
expect_equal(custom$backup_base_urls, "https://backup.example/v1")
expect_equal(custom$values$AISDK_CUSTOM_BASE_URLS, "https://backup.example/v1")
})
test_that("discover_console_model_profiles includes aisdk.yaml profiles", {
tmp <- tempfile("aisdk-config-")
dir.create(tmp)
old_wd <- getwd()
on.exit(setwd(old_wd), add = TRUE)
setwd(tmp)
writeLines(c(
"default_model: yulab:gpt-5.5",
"model_providers:",
" yulab:",
" type: custom",
" name: openai-yulab",
" base_url: http://186.244.210.51:8080/v1",
" wire_api: responses",
" api_key_env: YULAB_OPENAI_API_KEY",
"models:",
" yulab:gpt-5.5:",
" reasoning_effort: xhigh"
), "aisdk.yaml")
profiles <- aisdk:::discover_console_model_profiles(
project_path = file.path(tmp, ".Renviron"),
global_path = tempfile(fileext = ".Renviron")
)
yulab <- profiles[[which(vapply(profiles, function(p) identical(p$model_id, "yulab:gpt-5.5"), logical(1)))[[1]]]]
expect_equal(yulab$provider, "yulab")
expect_equal(yulab$storage, "yaml")
expect_equal(yulab$base_url, "http://186.244.210.51:8080/v1")
expect_equal(yulab$api_format, "responses")
})
test_that("apply_console_profile exports provider values into current env", {
profile <- list(
values = list(
OPENAI_API_KEY = "sk-temp",
OPENAI_BASE_URL = "https://api.openai.com/v1",
OPENAI_MODEL = "gpt-5-mini"
)
)
old_key <- Sys.getenv("OPENAI_API_KEY", unset = "")
old_base <- Sys.getenv("OPENAI_BASE_URL", unset = "")
old_model <- Sys.getenv("OPENAI_MODEL", unset = "")
on.exit({
Sys.setenv(
OPENAI_API_KEY = old_key,
OPENAI_BASE_URL = old_base,
OPENAI_MODEL = old_model
)
}, add = TRUE)
aisdk:::apply_console_profile(profile)
expect_equal(Sys.getenv("OPENAI_API_KEY"), "sk-temp")
expect_equal(Sys.getenv("OPENAI_BASE_URL"), "https://api.openai.com/v1")
expect_equal(Sys.getenv("OPENAI_MODEL"), "gpt-5-mini")
})
test_that("read_console_rprofile_default_model parses saved model option", {
path <- tempfile(fileext = ".Rprofile")
writeLines(c(
"options(stringsAsFactors = FALSE)",
"options(aisdk.console_default_model = \"openai:gpt-5-mini\")"
), path)
parsed <- aisdk:::read_console_rprofile_default_model(path)
expect_equal(parsed$model_id, "openai:gpt-5-mini")
})
test_that("update_console_rprofile_default_model writes and replaces saved model option", {
old_default <- getOption("aisdk.console_default_model")
on.exit(options(aisdk.console_default_model = old_default), add = TRUE)
path <- tempfile(fileext = ".Rprofile")
writeLines("options(aisdk.console_default_model = \"openai:gpt-4o\")", path)
aisdk:::update_console_rprofile_default_model("anthropic:claude-sonnet-4-20250514", path = path)
lines <- readLines(path, warn = FALSE)
expect_length(grep("aisdk\\.console_default_model", lines), 1)
expect_true(any(grepl("anthropic:claude-sonnet-4-20250514", lines, fixed = TRUE)))
})
test_that("resolve_console_startup_model uses saved default and matching profile", {
old_default <- getOption("aisdk.console_default_model")
on.exit(options(aisdk.console_default_model = old_default), add = TRUE)
options(aisdk.console_default_model = NULL)
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
project_rprofile_path <- tempfile(fileext = ".Rprofile")
writeLines(c(
"OPENAI_API_KEY=sk-project",
"OPENAI_BASE_URL=https://api.openai.com/v1",
"OPENAI_MODEL=gpt-5-mini"
), project_path)
writeLines(
"options(aisdk.console_default_model = \"openai:gpt-5-mini\")",
project_rprofile_path
)
applied <- NULL
resolved <- aisdk:::resolve_console_startup_model(
project_path = project_path,
global_path = global_path,
project_rprofile_path = project_rprofile_path,
global_rprofile_path = tempfile(fileext = ".Rprofile"),
apply_profile_fn = function(profile) {
applied <<- profile
profile
}
)
expect_equal(resolved$model_id, "openai:gpt-5-mini")
expect_equal(resolved$source, "rprofile")
expect_equal(applied$model_id, "openai:gpt-5-mini")
})
test_that("resolve_console_startup_model falls back when saved default is unusable", {
old_default <- getOption("aisdk.console_default_model")
on.exit(options(aisdk.console_default_model = old_default), add = TRUE)
options(aisdk.console_default_model = NULL)
old_key <- Sys.getenv("OPENAI_API_KEY", unset = "")
on.exit({
if (nzchar(old_key)) {
Sys.setenv(OPENAI_API_KEY = old_key)
} else {
Sys.unsetenv("OPENAI_API_KEY")
}
}, add = TRUE)
Sys.unsetenv("OPENAI_API_KEY")
resolved <- aisdk:::resolve_console_startup_model(
project_path = tempfile(fileext = ".Renviron"),
global_path = tempfile(fileext = ".Renviron"),
project_rprofile_path = tempfile(fileext = ".Rprofile"),
global_rprofile_path = tempfile(fileext = ".Rprofile"),
apply_profile_fn = function(profile) profile
)
expect_null(resolved$model_id)
expect_equal(resolved$source, "prompt")
path <- tempfile(fileext = ".Rprofile")
writeLines("options(aisdk.console_default_model = \"openai:gpt-5-mini\")", path)
resolved_invalid <- aisdk:::resolve_console_startup_model(
project_path = tempfile(fileext = ".Renviron"),
global_path = tempfile(fileext = ".Renviron"),
project_rprofile_path = path,
global_rprofile_path = tempfile(fileext = ".Rprofile"),
apply_profile_fn = function(profile) profile
)
expect_null(resolved_invalid$model_id)
expect_equal(resolved_invalid$source, "invalid_default")
})
test_that("console_model_id_is_usable allows custom profiles without API keys", {
profile <- list(
provider = "custom",
api_key = "",
base_url = "http://127.0.0.1:3000/v1"
)
expect_true(aisdk:::console_model_id_is_usable("custom:local-model", profile = profile))
})
test_that("console status line includes context metrics when available", {
session <- aisdk::create_chat_session(model = "openai:gpt-5-mini")
session$append_message("user", "hello world")
app_state <- aisdk:::create_console_app_state(session, view_mode = "clean")
line <- aisdk:::build_console_status_line(app_state)
expect_match(line, "Model: openai:gpt-5-mini")
expect_match(line, "Ctx: 400.0k")
expect_match(line, "Used:")
expect_match(line, "Left:")
expect_match(line, "Out: 128.0k")
})
test_that("console status line shows DeepSeek V4 million-token context", {
session <- aisdk::create_chat_session(model = "deepseek:deepseek-v4-flash")
session$append_message("user", "hello world")
app_state <- aisdk:::create_console_app_state(session, view_mode = "clean")
line <- aisdk:::build_console_status_line(app_state)
expect_match(line, "Model: deepseek:deepseek-v4-flash")
expect_match(line, "Ctx: 1.0M")
expect_match(line, "Out: 384.0k")
expect_no_match(line, "Ctx\\(est\\): 64.0k")
})
test_that("prompt_console_provider_profile can choose an existing profile", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
writeLines(c(
"OPENAI_API_KEY=sk-project",
"OPENAI_BASE_URL=https://api.openai.com/v1",
"OPENAI_MODEL=gpt-5-mini"
), project_path)
applied <- NULL
remembered <- list()
menu_answers <- c(1L)
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
apply_profile = function(profile) {
applied <<- profile
profile
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_rprofile_path = "project-test.Rprofile",
global_rprofile_path = "global-test.Rprofile",
prompt_hooks = hooks
)
expect_equal(model_id, "openai:gpt-5-mini")
expect_equal(applied$model_id, "openai:gpt-5-mini")
expect_equal(remembered$model_id, "openai:gpt-5-mini")
expect_equal(remembered$path, "project-test.Rprofile")
})
test_that("format_console_profile_choice uses compact labels", {
profile <- list(
scope = "project",
model_id = "openai:gpt-5-mini",
provider = "openai",
base_url = "https://api.openai.com/v1"
)
label <- aisdk:::format_console_profile_choice(profile)
expect_match(label, "^project · openai:gpt-5-mini · api\\.openai\\.com/v1$")
expect_false(grepl("\\[project\\]", label, fixed = TRUE))
expect_false(grepl("https://", label, fixed = TRUE))
})
test_that("prompt_console_provider_profile supports manual setup and persistence seam", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
menu_answers <- c(
1L, # provider: OpenAI
1L, # use default base url
1L, # select first fetched/static model
1L # save to project
)
input_answers <- c("sk-manual")
saved <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
c("gpt-5-mini", "gpt-4o")
},
save = function(updates, path) {
saved <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_rprofile_path = "project-default.Rprofile",
global_rprofile_path = "global-default.Rprofile",
prompt_hooks = hooks
)
expect_equal(model_id, "openai:gpt-5-mini")
expect_equal(saved$path, project_path)
expect_equal(saved$updates$OPENAI_API_KEY, "sk-manual")
expect_equal(saved$updates$OPENAI_BASE_URL, "https://api.openai.com/v1")
expect_equal(saved$updates$OPENAI_MODEL, "gpt-5-mini")
expect_equal(remembered$model_id, "openai:gpt-5-mini")
expect_equal(remembered$path, "project-default.Rprofile")
})
test_that("prompt_console_provider_profile can edit and overwrite an existing profile", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
writeLines(c(
"OPENAI_API_KEY=sk-old",
"OPENAI_BASE_URL=https://api.openai.com/v1",
"OPENAI_MODEL=gpt-4o"
), project_path)
menu_answers <- c(
2L, # choose "Edit saved profile"
1L, # edit the first saved profile
3L, # enter custom base url
2L, # enter new API key
2L, # choose second model option
1L # overwrite existing profile
)
input_answers <- c(
"https://proxy.example.com/v1",
"sk-new"
)
saved <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
c("gpt-4o", "gpt-5-mini")
},
save = function(updates, path) {
saved <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_rprofile_path = "project-edit.Rprofile",
global_rprofile_path = "global-edit.Rprofile",
prompt_hooks = hooks
)
expect_equal(model_id, "openai:gpt-5-mini")
expect_equal(saved$path, project_path)
expect_equal(saved$updates$OPENAI_API_KEY, "sk-new")
expect_equal(saved$updates$OPENAI_BASE_URL, "https://proxy.example.com/v1")
expect_equal(saved$updates$OPENAI_MODEL, "gpt-5-mini")
expect_equal(remembered$model_id, "openai:gpt-5-mini")
expect_equal(remembered$path, "project-edit.Rprofile")
})
test_that("prompt_console_provider_profile supports custom API setup", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
menu_answers <- c(
10L, # provider: Custom API
1L, # api format: OpenAI Chat Completions
1L, # compatibility: basic text fallback
1L, # select first fetched/static model
1L # save to project
)
input_answers <- c(
"https://proxy.example.com/v1",
"sk-custom"
)
saved <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
c("proxy-model", "backup-model")
},
save = function(updates, path) {
saved <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_rprofile_path = "project-custom.Rprofile",
global_rprofile_path = "global-custom.Rprofile",
prompt_hooks = hooks
)
expect_equal(model_id, "custom:proxy-model")
expect_equal(saved$path, project_path)
expect_equal(saved$updates$AISDK_CUSTOM_API_KEY, "sk-custom")
expect_equal(saved$updates$AISDK_CUSTOM_BASE_URL, "https://proxy.example.com/v1")
expect_equal(saved$updates$AISDK_CUSTOM_MODEL, "proxy-model")
expect_equal(saved$updates$AISDK_CUSTOM_API_FORMAT, "chat_completions")
expect_equal(saved$updates$AISDK_CUSTOM_ENABLE_STREAM_OPTIONS, "false")
expect_equal(saved$updates$AISDK_CUSTOM_SUPPORTS_NATIVE_TOOLS, "false")
expect_equal(remembered$model_id, "custom:proxy-model")
expect_equal(remembered$path, "project-custom.Rprofile")
})
test_that("prompt_console_provider_profile can save custom API setup to aisdk.yaml", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
project_config_path <- tempfile(fileext = ".yaml")
registry_env <- get(".registry_env", envir = asNamespace("aisdk"))
old_registry <- registry_env$default %||% NULL
registry_env$default <- ProviderRegistry$new()
on.exit({
registry_env$default <- old_registry
}, add = TRUE)
menu_answers <- c(
10L, # provider: Custom API
1L, # api format: OpenAI Chat Completions
2L, # compatibility: native tools, no stream_options
1L, # select first fetched/static model
3L # save project aisdk.yaml
)
input_answers <- c(
"https://proxy.example.com/v1",
"sk-custom",
"yulab"
)
saved_env <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
c("gpt-5.5")
},
save = function(updates, path) {
saved_env <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_config_path = project_config_path,
project_rprofile_path = "project-yaml.Rprofile",
global_rprofile_path = "global-yaml.Rprofile",
prompt_hooks = hooks
)
cfg <- yaml::read_yaml(project_config_path)
expect_equal(model_id, "yulab:gpt-5.5")
expect_equal(cfg$default_model, "yulab:gpt-5.5")
expect_equal(cfg$model_providers$yulab$base_url, "https://proxy.example.com/v1")
expect_equal(cfg$model_providers$yulab$api_key_env, "AISDK_YULAB_API_KEY")
expect_true(cfg$model_providers$yulab$supports_native_tools)
expect_true(cfg$model_providers$yulab$disable_stream_options)
expect_equal(saved_env$updates$AISDK_YULAB_API_KEY, "sk-custom")
expect_equal(saved_env$path, project_path)
expect_equal(remembered$model_id, "yulab:gpt-5.5")
expect_null(registry_env$default)
})
test_that("prompt_console_provider_profile can edit dynamic YAML custom providers", {
tmp <- tempfile("aisdk-config-")
dir.create(tmp)
project_path <- file.path(tmp, ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
project_config_path <- file.path(tmp, "aisdk.yaml")
writeLines(c(
"default_model: yulab:gpt-5.5",
"model_providers:",
" yulab:",
" type: custom",
" name: openai-yulab",
" base_url: https://proxy.example.com/v1",
" wire_api: responses",
" api_key_env: AISDK_YULAB_API_KEY",
"models:",
" yulab:gpt-5.5:",
" reasoning_effort: xhigh"
), project_config_path)
Sys.setenv(AISDK_YULAB_API_KEY = "sk-existing")
on.exit(Sys.unsetenv("AISDK_YULAB_API_KEY"), add = TRUE)
menu_answers <- c(
2L, # edit saved setup
1L, # edit first profile
1L, # keep API format
1L, # keep compatibility
1L, # keep base URL
1L, # keep API key
1L, # keep model
1L # overwrite saved YAML
)
input_answers <- list(NULL)
saved_env <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
c("gpt-5.5")
},
save = function(updates, path) {
saved_env <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_config_path = project_config_path,
global_config_path = tempfile(fileext = ".yaml"),
project_rprofile_path = "project-yaml.Rprofile",
global_rprofile_path = "global-yaml.Rprofile",
prompt_hooks = hooks
)
cfg <- yaml::read_yaml(project_config_path)
expect_equal(model_id, "yulab:gpt-5.5")
expect_equal(cfg$default_model, "yulab:gpt-5.5")
expect_equal(cfg$model_providers$yulab$base_url, "https://proxy.example.com/v1")
expect_equal(saved_env$updates$AISDK_YULAB_API_KEY, "sk-existing")
expect_equal(saved_env$path, project_path)
expect_equal(remembered$model_id, "yulab:gpt-5.5")
})
test_that("prompt_console_provider_profile supports custom API setup without API key", {
project_path <- tempfile(fileext = ".Renviron")
global_path <- tempfile(fileext = ".Renviron")
menu_answers <- c(
10L, # provider: Custom API
1L, # api format: OpenAI Chat Completions
1L, # compatibility: basic text fallback
1L, # select first fetched/static model
1L # save to project
)
input_answers <- list(
"http://172.16.153.230:8010/v1",
NULL
)
saved <- list()
remembered <- list()
hooks <- list(
menu = function(title, choices) {
answer <- menu_answers[[1]]
menu_answers <<- menu_answers[-1]
answer
},
input = function(prompt, default = NULL) {
answer <- input_answers[[1]]
input_answers <<- input_answers[-1]
answer %||% default
},
model_choices = function(provider, api_key = NULL, base_url = NULL) {
expect_equal(provider, "openai")
expect_equal(api_key, "")
expect_equal(base_url, "http://172.16.153.230:8010/v1")
c("qwen3-8b-dflash")
},
save = function(updates, path) {
saved <<- list(updates = updates, path = path)
TRUE
},
remember_model = function(model_id, path = NULL) {
remembered <<- list(model_id = model_id, path = path)
model_id
}
)
model_id <- aisdk:::prompt_console_provider_profile(
project_path = project_path,
global_path = global_path,
project_rprofile_path = "project-custom-no-key.Rprofile",
global_rprofile_path = "global-custom-no-key.Rprofile",
prompt_hooks = hooks
)
expect_equal(model_id, "custom:qwen3-8b-dflash")
expect_equal(saved$path, project_path)
expect_equal(saved$updates$AISDK_CUSTOM_API_KEY, "")
expect_equal(saved$updates$AISDK_CUSTOM_BASE_URL, "http://172.16.153.230:8010/v1")
expect_equal(saved$updates$AISDK_CUSTOM_MODEL, "qwen3-8b-dflash")
expect_equal(saved$updates$AISDK_CUSTOM_API_FORMAT, "chat_completions")
expect_equal(saved$updates$AISDK_CUSTOM_ENABLE_STREAM_OPTIONS, "false")
expect_equal(saved$updates$AISDK_CUSTOM_SUPPORTS_NATIVE_TOOLS, "false")
expect_equal(remembered$model_id, "custom:qwen3-8b-dflash")
expect_equal(remembered$path, "project-custom-no-key.Rprofile")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.