diff --git a/DESCRIPTION b/DESCRIPTION index a3f0f34..98365ca 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,13 +1,15 @@ Package: foundryR Title: Tibble Workflows for 'Azure AI Foundry' -Version: 0.0.0.9000 +Version: 0.1.0 Authors@R: person("Alex", "Farach", , "alexfarach@microsoft.com", role = c("aut", "cre", "cph")) -Description: Work with 'Microsoft Azure AI Foundry' from dataframe-oriented - 'R' workflows. Returns tibbles for Content Safety, Responses API calls, - strict structured extraction, embeddings, files, batch jobs, audio, media, - and chat completions. Supports research annotation, safety gates, - semantic search, and 'tidymodels' recipes for teams committed to Azure. +Description: Work with 'Microsoft Azure AI Foundry' from data-frame-oriented + 'R' workflows. Provides tibble-returning helpers for 'Azure AI Content + Safety', 'Azure OpenAI' Responses API calls, strict structured extraction, + embeddings, files, batch jobs, audio, media, and chat completions. Supports + research annotation, safety gates, semantic search, and 'tidymodels' + recipes. Helps teams keep model workflows inside their 'Azure' environment + while preserving analyzable outputs. License: MIT + file LICENSE Depends: R (>= 4.1.0) diff --git a/LICENSE b/LICENSE index 540d2f0..c16f312 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -YEAR: 2025 +YEAR: 2026 COPYRIGHT HOLDER: Alex Farach diff --git a/NEWS.md b/NEWS.md index 5da6853..844a7d1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,6 @@ -# foundryR 0.0.0.9000 +# foundryR 0.1.0 -Initial development release of foundryR, a tidy interface to Microsoft Azure AI Foundry. +Initial CRAN release of foundryR, a tidy interface to Microsoft Azure AI Foundry. ## New features diff --git a/R/batches.R b/R/batches.R index 2e8fcde..59a4fc5 100644 --- a/R/batches.R +++ b/R/batches.R @@ -376,6 +376,18 @@ foundry_extract_batch <- function(data, #' #' @return A one-row tibble with token totals and optional `cost`. #' @export +#' +#' @examples +#' responses <- data.frame( +#' input_tokens = c(10, 20), +#' cached_input_tokens = c(0, 5), +#' output_tokens = c(3, 7) +#' ) +#' foundry_usage(responses) +#' foundry_usage( +#' responses, +#' rates = c(input = 0.000001, cached_input = 0.0000001, output = 0.000004) +#' ) foundry_usage <- function(x, rates = NULL) { if (!is.data.frame(x)) { cli::cli_abort("{.arg x} must be a data frame.") diff --git a/R/codebook.R b/R/codebook.R index e8d266f..505463f 100644 --- a/R/codebook.R +++ b/R/codebook.R @@ -21,7 +21,6 @@ #' @export #' #' @examples -#' \dontrun{ #' codebook <- foundry_codebook( #' name = "ai-applicability", #' version = "1.0.0", @@ -34,7 +33,6 @@ #' list(text = "Lift a heavy box", ai_applicable = FALSE) #' ) #' ) -#' } foundry_codebook <- function(name, version, instructions, @@ -76,6 +74,12 @@ foundry_codebook <- function(name, #' #' @return A JSON Schema fragment represented as an R list. #' @name codebook_schema_helpers +#' +#' @examples +#' type_boolean("Whether AI could materially assist the task") +#' type_enum("Priority label", values = c("low", "medium", "high")) +#' type_number("Confidence score") +#' type_string("Short rationale") NULL @@ -119,9 +123,22 @@ type_string <- function(desc = NULL) { #' @export #' #' @examples -#' \dontrun{ -#' codebook_diff(old_codebook, new_codebook) -#' } +#' old <- foundry_codebook( +#' name = "support-sentiment", +#' version = "1.0.0", +#' instructions = "Label the sentiment of support tickets.", +#' schema = foundry_schema(sentiment = type_enum(values = c("pos", "neg"))) +#' ) +#' new <- foundry_codebook( +#' name = "support-sentiment", +#' version = "1.1.0", +#' instructions = "Label the sentiment and urgency of support tickets.", +#' schema = foundry_schema( +#' sentiment = type_enum(values = c("pos", "neg")), +#' urgent = type_boolean() +#' ) +#' ) +#' codebook_diff(old, new) codebook_diff <- function(old, new) { foundry_check_codebook(old, "old") foundry_check_codebook(new, "new") diff --git a/R/content-safety-extra.R b/R/content-safety-extra.R index 778f005..1370c22 100644 --- a/R/content-safety-extra.R +++ b/R/content-safety-extra.R @@ -78,6 +78,13 @@ foundry_moderate_image <- function(image, #' #' @return A tibble with one row per input text. #' @export +#' +#' @examples +#' if (interactive() && +#' nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_ENDPOINT")) && +#' nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_KEY"))) { +#' foundry_protected_material("A short text sample.") +#' } foundry_protected_material <- function(text, endpoint = NULL, api_key = NULL, @@ -126,6 +133,21 @@ foundry_protected_material <- function(text, #' #' @return A tibble with blocklist or blocklist-item metadata. #' @name foundry_blocklists +#' +#' @examples +#' if (interactive() && +#' nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_ENDPOINT")) && +#' nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_KEY"))) { +#' foundry_blocklists() +#' foundry_blocklist_create("example-blocklist", description = "Example") +#' foundry_blocklist_get("example-blocklist") +#' items <- foundry_blocklist_add_items("example-blocklist", "blocked phrase") +#' foundry_blocklist_items("example-blocklist") +#' if (nrow(items) > 0 && !is.na(items$item_id[[1]])) { +#' foundry_blocklist_remove_items("example-blocklist", items$item_id) +#' } +#' foundry_blocklist_delete("example-blocklist") +#' } NULL diff --git a/R/conversations.R b/R/conversations.R index 6b05ccd..c3e5dba 100644 --- a/R/conversations.R +++ b/R/conversations.R @@ -13,6 +13,21 @@ #' #' @return A tibble with conversation metadata or conversation items. #' @name foundry_conversations +#' +#' @examples +#' if (interactive() && +#' nzchar(Sys.getenv("AZURE_FOUNDRY_ENDPOINT")) && +#' nzchar(Sys.getenv("AZURE_FOUNDRY_KEY"))) { +#' conversation <- foundry_conversation_create( +#' metadata = list(example = "cran") +#' ) +#' id <- conversation$conversation_id[[1]] +#' foundry_conversations(limit = 10) +#' foundry_conversation_get(id) +#' foundry_conversation_update(id, metadata = list(example = "updated")) +#' foundry_conversation_items(id) +#' foundry_conversation_delete(id) +#' } NULL diff --git a/R/schema.R b/R/schema.R index 9181416..6666313 100644 --- a/R/schema.R +++ b/R/schema.R @@ -50,6 +50,14 @@ foundry_schema <- function(..., #' #' @return A JSON Schema fragment represented as an R list. #' @name schema_constructors +#' +#' @examples +#' schema_string("Free-text label") +#' schema_enum(c("positive", "negative", "neutral")) +#' schema_object( +#' sentiment = schema_enum(c("positive", "negative", "neutral")), +#' confidence = schema_number() +#' ) NULL @@ -168,6 +176,10 @@ schema_object <- function(..., #' #' @return A JSON Schema represented as an R list. #' @export +#' +#' @examples +#' schema <- foundry_schema(label = schema_string()) +#' as_foundry_schema(schema) as_foundry_schema <- function(x) { if (inherits(x, "ellmer::Type")) { return(foundry_preserve_schema_arrays(ellmer_type_to_schema(x))) diff --git a/R/utils-pipe.R b/R/utils-pipe.R index fd0b1d1..b9e64da 100644 --- a/R/utils-pipe.R +++ b/R/utils-pipe.R @@ -11,4 +11,6 @@ #' @param lhs A value or the magrittr placeholder. #' @param rhs A function call using the magrittr semantics. #' @return The result of calling `rhs(lhs)`. +#' @examples +#' 1:3 %>% sum() NULL diff --git a/R/validation.R b/R/validation.R index e093c32..329d04f 100644 --- a/R/validation.R +++ b/R/validation.R @@ -121,6 +121,14 @@ foundry_consistency <- function(text, schema, n = 3L, ...) { #' #' @return A one-row tibble. #' @export +#' +#' @examples +#' schema <- foundry_schema(label = schema_string()) +#' foundry_provenance( +#' model = "gpt-5-nano", +#' schema = schema, +#' metadata = list(run = "pilot") +#' ) foundry_provenance <- function(model, schema, metadata = NULL) { foundry_check_character_scalar(model, "model") schema <- as_foundry_schema(schema) diff --git a/R/vector-stores.R b/R/vector-stores.R index d319cc3..3f7c9cc 100644 --- a/R/vector-stores.R +++ b/R/vector-stores.R @@ -20,6 +20,26 @@ #' #' @return A tibble with vector store, file, or search-result metadata. #' @name foundry_vector_stores +#' +#' @examples +#' if (interactive() && +#' nzchar(Sys.getenv("AZURE_FOUNDRY_ENDPOINT")) && +#' nzchar(Sys.getenv("AZURE_FOUNDRY_KEY"))) { +#' store <- foundry_vector_store_create("example-store") +#' id <- store$vector_store_id[[1]] +#' foundry_vector_stores(limit = 10) +#' foundry_vector_store_get(id) +#' foundry_vector_store_modify(id, name = "renamed-example-store") +#' foundry_vector_store_files(id) +#' file_id <- Sys.getenv("AZURE_FOUNDRY_FILE_ID") +#' if (nzchar(file_id)) { +#' foundry_vector_store_file_add(id, file_id) +#' foundry_vector_store_file_remove(id, file_id) +#' foundry_vector_store_file_batch(id, file_id) +#' foundry_vector_search(id, "example query") +#' } +#' foundry_vector_store_delete(id) +#' } NULL @@ -260,6 +280,9 @@ foundry_vector_search <- function(vector_store_id, #' #' @return A Responses API tool definition list. #' @export +#' +#' @examples +#' foundry_tool_file_search("vs_abc123", max_num_results = 3) foundry_tool_file_search <- function(vector_store_ids, max_num_results = NULL) { if (!is.character(vector_store_ids) || length(vector_store_ids) == 0L || any(is.na(vector_store_ids))) { diff --git a/README.Rmd b/README.Rmd index 45241b6..141897a 100644 --- a/README.Rmd +++ b/README.Rmd @@ -38,7 +38,7 @@ if (run_api) { } ``` -# foundryR foundryR website +# foundryR foundryR website [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) @@ -57,6 +57,12 @@ Its strongest path is dataframe in, dataframe out. ## Installation +Install the released version from CRAN: + +```r +install.packages("foundryR") +``` + Install the development version from GitHub: ```r diff --git a/README.md b/README.md index 775ec50..adebbb6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ -# foundryR foundryR website +# foundryR foundryR website @@ -34,6 +34,12 @@ Its strongest path is dataframe in, dataframe out. ## Installation +Install the released version from CRAN: + +``` r +install.packages("foundryR") +``` + Install the development version from GitHub: ``` r diff --git a/cran-comments.md b/cran-comments.md index 8a07810..1870ab2 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,3 +1,11 @@ +## Submission + +This is the first CRAN submission for foundryR. + +## Test environments + +- Local Windows 11 x64, R 4.5.2 + ## R CMD check results 0 errors | 0 warnings | 0 notes diff --git a/inst/extdata/samples/README b/inst/extdata/samples/README new file mode 100644 index 0000000..446960a --- /dev/null +++ b/inst/extdata/samples/README @@ -0,0 +1,11 @@ +jfk.wav +======= + +jfk.wav is a short excerpt from John F. Kennedy's January 20, 1961 +inaugural address, included as a small speech-recognition example. The +address is a U.S. federal government work and is in the public domain in +the United States under 17 U.S.C. 105. + +Source recording: John F. Kennedy Presidential Library and Museum, +"The Inaugural Address": +https://www.jfklibrary.org/learn/about-jfk/historic-speeches/the-inaugural-address diff --git a/man/as_foundry_schema.Rd b/man/as_foundry_schema.Rd index 311c2c2..67c021f 100644 --- a/man/as_foundry_schema.Rd +++ b/man/as_foundry_schema.Rd @@ -21,3 +21,7 @@ package is installed, \code{ellmer::type_object()} specifications are converted the equivalent strict JSON Schema, so ellmer users can pass their existing type definitions to \code{\link[=foundry_extract]{foundry_extract()}} and \code{\link[=foundry_response]{foundry_response()}}. } +\examples{ +schema <- foundry_schema(label = schema_string()) +as_foundry_schema(schema) +} diff --git a/man/codebook_diff.Rd b/man/codebook_diff.Rd index 3180ac7..9975809 100644 --- a/man/codebook_diff.Rd +++ b/man/codebook_diff.Rd @@ -18,7 +18,20 @@ hashes, a unified diff of instructions, and field-level changes for schema properties and examples. } \examples{ -\dontrun{ -codebook_diff(old_codebook, new_codebook) -} +old <- foundry_codebook( + name = "support-sentiment", + version = "1.0.0", + instructions = "Label the sentiment of support tickets.", + schema = foundry_schema(sentiment = type_enum(values = c("pos", "neg"))) +) +new <- foundry_codebook( + name = "support-sentiment", + version = "1.1.0", + instructions = "Label the sentiment and urgency of support tickets.", + schema = foundry_schema( + sentiment = type_enum(values = c("pos", "neg")), + urgent = type_boolean() + ) +) +codebook_diff(old, new) } diff --git a/man/codebook_schema_helpers.Rd b/man/codebook_schema_helpers.Rd index 28ed925..b3d8d5a 100644 --- a/man/codebook_schema_helpers.Rd +++ b/man/codebook_schema_helpers.Rd @@ -28,3 +28,9 @@ A JSON Schema fragment represented as an R list. These light wrappers reuse foundryR's existing strict JSON Schema constructors while following the measurement-layer codebook vocabulary. } +\examples{ +type_boolean("Whether AI could materially assist the task") +type_enum("Priority label", values = c("low", "medium", "high")) +type_number("Confidence score") +type_string("Short rationale") +} diff --git a/man/foundryR-package.Rd b/man/foundryR-package.Rd index bb03a12..4a149e5 100644 --- a/man/foundryR-package.Rd +++ b/man/foundryR-package.Rd @@ -6,7 +6,7 @@ \alias{foundryR-package} \title{foundryR: Tibble Workflows for 'Azure AI Foundry'} \description{ -Work with 'Microsoft Azure AI Foundry' from dataframe-oriented 'R' workflows. Returns tibbles for Content Safety, Responses API calls, strict structured extraction, embeddings, files, batch jobs, audio, media, and chat completions. Supports research annotation, safety gates, semantic search, and 'tidymodels' recipes for teams committed to Azure. +Work with 'Microsoft Azure AI Foundry' from data-frame-oriented 'R' workflows. Provides tibble-returning helpers for 'Azure AI Content Safety', 'Azure OpenAI' Responses API calls, strict structured extraction, embeddings, files, batch jobs, audio, media, and chat completions. Supports research annotation, safety gates, semantic search, and 'tidymodels' recipes. Helps teams keep model workflows inside their 'Azure' environment while preserving analyzable outputs. } \seealso{ Useful links: diff --git a/man/foundry_blocklists.Rd b/man/foundry_blocklists.Rd index 05f009e..9ff1df3 100644 --- a/man/foundry_blocklists.Rd +++ b/man/foundry_blocklists.Rd @@ -81,3 +81,18 @@ A tibble with blocklist or blocklist-item metadata. \description{ Create, list, retrieve, delete, and edit Azure AI Content Safety blocklists. } +\examples{ +if (interactive() && + nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_ENDPOINT")) && + nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_KEY"))) { + foundry_blocklists() + foundry_blocklist_create("example-blocklist", description = "Example") + foundry_blocklist_get("example-blocklist") + items <- foundry_blocklist_add_items("example-blocklist", "blocked phrase") + foundry_blocklist_items("example-blocklist") + if (nrow(items) > 0 && !is.na(items$item_id[[1]])) { + foundry_blocklist_remove_items("example-blocklist", items$item_id) + } + foundry_blocklist_delete("example-blocklist") +} +} diff --git a/man/foundry_codebook.Rd b/man/foundry_codebook.Rd index 9deb02d..20ec8a6 100644 --- a/man/foundry_codebook.Rd +++ b/man/foundry_codebook.Rd @@ -33,7 +33,6 @@ collapse to scalars. The payload is serialized with normalized with \code{enc2utf8()}, and hashed with SHA-256. } \examples{ -\dontrun{ codebook <- foundry_codebook( name = "ai-applicability", version = "1.0.0", @@ -47,4 +46,3 @@ codebook <- foundry_codebook( ) ) } -} diff --git a/man/foundry_conversations.Rd b/man/foundry_conversations.Rd index 2a95c9f..54b4f38 100644 --- a/man/foundry_conversations.Rd +++ b/man/foundry_conversations.Rd @@ -67,3 +67,18 @@ A tibble with conversation metadata or conversation items. Create, list, retrieve, update, and delete server-side conversations used by the Responses API. } +\examples{ +if (interactive() && + nzchar(Sys.getenv("AZURE_FOUNDRY_ENDPOINT")) && + nzchar(Sys.getenv("AZURE_FOUNDRY_KEY"))) { + conversation <- foundry_conversation_create( + metadata = list(example = "cran") + ) + id <- conversation$conversation_id[[1]] + foundry_conversations(limit = 10) + foundry_conversation_get(id) + foundry_conversation_update(id, metadata = list(example = "updated")) + foundry_conversation_items(id) + foundry_conversation_delete(id) +} +} diff --git a/man/foundry_protected_material.Rd b/man/foundry_protected_material.Rd index e4a1217..bbb6265 100644 --- a/man/foundry_protected_material.Rd +++ b/man/foundry_protected_material.Rd @@ -26,3 +26,10 @@ A tibble with one row per input text. \description{ Call the Azure AI Content Safety protected-material detector. } +\examples{ +if (interactive() && + nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_ENDPOINT")) && + nzchar(Sys.getenv("AZURE_CONTENT_SAFETY_KEY"))) { + foundry_protected_material("A short text sample.") +} +} diff --git a/man/foundry_provenance.Rd b/man/foundry_provenance.Rd index cd57122..48b4c52 100644 --- a/man/foundry_provenance.Rd +++ b/man/foundry_provenance.Rd @@ -20,3 +20,11 @@ A one-row tibble. Create a one-row tibble that records the model, schema hash, package version, and timestamp for a reproducible annotation run. } +\examples{ +schema <- foundry_schema(label = schema_string()) +foundry_provenance( + model = "gpt-5-nano", + schema = schema, + metadata = list(run = "pilot") +) +} diff --git a/man/foundry_tool_file_search.Rd b/man/foundry_tool_file_search.Rd index 9b7f37d..3235353 100644 --- a/man/foundry_tool_file_search.Rd +++ b/man/foundry_tool_file_search.Rd @@ -17,3 +17,6 @@ A Responses API tool definition list. \description{ Create a file-search tool definition } +\examples{ +foundry_tool_file_search("vs_abc123", max_num_results = 3) +} diff --git a/man/foundry_usage.Rd b/man/foundry_usage.Rd index 4afffd9..50c9458 100644 --- a/man/foundry_usage.Rd +++ b/man/foundry_usage.Rd @@ -20,3 +20,15 @@ Sum token columns returned by foundryR chat, Responses, extraction, and batch helpers. Pass your own \code{rates} to compute spend; foundryR does not hardcode Azure prices because they change over time. } +\examples{ +responses <- data.frame( + input_tokens = c(10, 20), + cached_input_tokens = c(0, 5), + output_tokens = c(3, 7) +) +foundry_usage(responses) +foundry_usage( + responses, + rates = c(input = 0.000001, cached_input = 0.0000001, output = 0.000004) +) +} diff --git a/man/foundry_vector_stores.Rd b/man/foundry_vector_stores.Rd index 3247d75..7916c85 100644 --- a/man/foundry_vector_stores.Rd +++ b/man/foundry_vector_stores.Rd @@ -117,3 +117,23 @@ A tibble with vector store, file, or search-result metadata. \description{ Create, list, retrieve, update, delete, and search hosted vector stores. } +\examples{ +if (interactive() && + nzchar(Sys.getenv("AZURE_FOUNDRY_ENDPOINT")) && + nzchar(Sys.getenv("AZURE_FOUNDRY_KEY"))) { + store <- foundry_vector_store_create("example-store") + id <- store$vector_store_id[[1]] + foundry_vector_stores(limit = 10) + foundry_vector_store_get(id) + foundry_vector_store_modify(id, name = "renamed-example-store") + foundry_vector_store_files(id) + file_id <- Sys.getenv("AZURE_FOUNDRY_FILE_ID") + if (nzchar(file_id)) { + foundry_vector_store_file_add(id, file_id) + foundry_vector_store_file_remove(id, file_id) + foundry_vector_store_file_batch(id, file_id) + foundry_vector_search(id, "example query") + } + foundry_vector_store_delete(id) +} +} diff --git a/man/pipe.Rd b/man/pipe.Rd index a648c29..a827738 100644 --- a/man/pipe.Rd +++ b/man/pipe.Rd @@ -17,4 +17,7 @@ The result of calling \code{rhs(lhs)}. \description{ See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. } +\examples{ +1:3 \%>\% sum() +} \keyword{internal} diff --git a/man/schema_constructors.Rd b/man/schema_constructors.Rd index 5b55179..e274fff 100644 --- a/man/schema_constructors.Rd +++ b/man/schema_constructors.Rd @@ -56,3 +56,11 @@ A JSON Schema fragment represented as an R list. Build JSON Schema field definitions for use with \code{foundry_schema()} or raw schema lists passed to \code{foundry_extract()} and \code{foundry_response()}. } +\examples{ +schema_string("Free-text label") +schema_enum(c("positive", "negative", "neutral")) +schema_object( + sentiment = schema_enum(c("positive", "negative", "neutral")), + confidence = schema_number() +) +} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index d5e644a..c0335a7 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -21,6 +21,15 @@ skip_if_no_model <- function(env_var = "AZURE_FOUNDRY_MODEL") { ) } +#' Skip tests that make live API calls unless explicitly enabled +skip_if_no_live_api <- function() { + enabled <- tolower(Sys.getenv("FOUNDRYR_RUN_LIVE_TESTS")) + skip_if( + !enabled %in% c("true", "1", "yes"), + "FOUNDRYR_RUN_LIVE_TESTS not enabled" + ) +} + #' Set up test environment with mock credentials #' #' Use within withr::local_ or test_that blocks diff --git a/tests/testthat/test-chat.R b/tests/testthat/test-chat.R index 97a0bf1..44c80d1 100644 --- a/tests/testthat/test-chat.R +++ b/tests/testthat/test-chat.R @@ -185,6 +185,7 @@ test_that("foundry_chat uses v1 endpoint by default and keeps deployment escape test_that("foundry_chat returns tibble with real API", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model() diff --git a/tests/testthat/test-embed-batch.R b/tests/testthat/test-embed-batch.R index dd103b2..625db21 100644 --- a/tests/testthat/test-embed-batch.R +++ b/tests/testthat/test-embed-batch.R @@ -358,6 +358,7 @@ test_that("foundry_embed_batch returns n_dims for successful embeddings", { test_that("foundry_embed_batch works with real API", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model("AZURE_FOUNDRY_EMBED_MODEL") @@ -389,6 +390,7 @@ test_that("foundry_embed_batch works with real API", { test_that("foundry_embed_batch processes many texts efficiently", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model("AZURE_FOUNDRY_EMBED_MODEL") diff --git a/tests/testthat/test-embed.R b/tests/testthat/test-embed.R index 2614a45..59396c2 100644 --- a/tests/testthat/test-embed.R +++ b/tests/testthat/test-embed.R @@ -200,6 +200,7 @@ test_that("foundry_similarity can limit rows or return a matrix", { test_that("foundry_embed returns tibble with real API", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model("AZURE_FOUNDRY_EMBED_MODEL") diff --git a/tests/testthat/test-groundedness.R b/tests/testthat/test-groundedness.R index b09a40a..bb94a5a 100644 --- a/tests/testthat/test-groundedness.R +++ b/tests/testthat/test-groundedness.R @@ -368,6 +368,7 @@ test_that("foundry_groundedness validates the correction flag", { test_that("foundry_groundedness returns tibble with real API", { skip_on_cran() + skip_if_no_live_api() skip_if( Sys.getenv("AZURE_CONTENT_SAFETY_KEY") == "", "AZURE_CONTENT_SAFETY_KEY not set" diff --git a/tests/testthat/test-image.R b/tests/testthat/test-image.R index 88f1a45..514f8b8 100644 --- a/tests/testthat/test-image.R +++ b/tests/testthat/test-image.R @@ -668,7 +668,8 @@ test_that("foundry_get_image_key errors when required and not set", { # ============================================================================ test_that("foundry_image generates image with real API", { - skip_on_cran() + skip_on_cran() + skip_if_no_live_api() skip_if( Sys.getenv("AZURE_FOUNDRY_IMAGE_ENDPOINT") == "" && Sys.getenv("AZURE_FOUNDRY_ENDPOINT") == "", @@ -681,8 +682,7 @@ test_that("foundry_image generates image with real API", { result <- foundry_image( "A simple red square on a white background, minimalist", - model = Sys.getenv("AZURE_FOUNDRY_IMAGE_MODEL"), - quality = "standard" + model = Sys.getenv("AZURE_FOUNDRY_IMAGE_MODEL") ) expect_s3_class(result, "tbl_df") diff --git a/tests/testthat/test-moderate.R b/tests/testthat/test-moderate.R index bb2c35c..270adb8 100644 --- a/tests/testthat/test-moderate.R +++ b/tests/testthat/test-moderate.R @@ -164,6 +164,7 @@ test_that("foundry_moderate works with custom categories", { test_that("foundry_moderate returns tibble with real API", { skip_on_cran() + skip_if_no_live_api() skip_if( Sys.getenv("AZURE_CONTENT_SAFETY_KEY") == "", "AZURE_CONTENT_SAFETY_KEY not set" diff --git a/tests/testthat/test-recipe.R b/tests/testthat/test-recipe.R index 5dc625f..a7b988b 100644 --- a/tests/testthat/test-recipe.R +++ b/tests/testthat/test-recipe.R @@ -615,6 +615,7 @@ test_that("foundry_cache_clear removes cached embedding files", { test_that("step_foundry_embed works with real API", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model("AZURE_FOUNDRY_EMBED_MODEL") @@ -651,6 +652,7 @@ test_that("step_foundry_embed works with real API", { test_that("step_foundry_embed works with new_data in bake", { skip_on_cran() + skip_if_no_live_api() skip_if_no_auth() skip_if_no_model("AZURE_FOUNDRY_EMBED_MODEL") diff --git a/tests/testthat/test-shield.R b/tests/testthat/test-shield.R index 8ebad14..4f81046 100644 --- a/tests/testthat/test-shield.R +++ b/tests/testthat/test-shield.R @@ -234,6 +234,7 @@ test_that("mock_shield_response handles document attacks", { test_that("foundry_shield returns tibble with real API", { skip_on_cran() + skip_if_no_live_api() skip_if( Sys.getenv("AZURE_CONTENT_SAFETY_KEY") == "", "AZURE_CONTENT_SAFETY_KEY not set"