diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 4bbce750..32000de7 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -21,6 +21,8 @@ jobs: group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} permissions: contents: write steps: diff --git a/R/provider-claude.R b/R/provider-claude.R index 70701a6a..52d62b9b 100644 --- a/R/provider-claude.R +++ b/R/provider-claude.R @@ -68,11 +68,11 @@ anthropic_key_exists <- function() { } method(chat_request, ProviderClaude) <- function(provider, - stream = TRUE, - turns = list(), - tools = list(), - type = NULL, - extra_args = list()) { + stream = TRUE, + turns = list(), + tools = list(), + type = NULL, + extra_args = list()) { req <- request(provider@base_url) # https://docs.anthropic.com/en/api/messages @@ -87,17 +87,14 @@ method(chat_request, ProviderClaude) <- function(provider, ) # - # 529 is not documented, but we see it fairly frequently in tests - req <- req_retry( - req, - max_tries = 2, - is_transient = function(resp) resp_status(resp) %in% c(429, 503, 529) - ) + req <- req_retry(req, max_tries = 2) # req <- req_error(req, body = function(resp) { - json <- resp_body_json(resp) - paste0(json$error$message, " [", json$error$type, "]") + if (resp_content_type(resp) == "application/json") { + json <- resp_body_json(resp) + paste0(json$error$message, " [", json$error$type, "]") + } }) if (length(turns) >= 1 && is_system_prompt(turns[[1]])) { @@ -180,7 +177,14 @@ method(stream_merge_chunks, ProviderClaude) <- function(provider, result, chunk) result$stop_sequence <- chunk$delta$stop_sequence result$usage$output_tokens <- chunk$usage$output_tokens } else if (chunk$type == "error") { - cli::cli_abort("{chunk$error$message}") + if (chunk$error$type == "overloaded_error") { + # https://docs.anthropic.com/en/api/messages-streaming#error-events + # TODO: track number of retries + wait <- backoff_default(1) + Sys.sleep(wait) + } else { + cli::cli_abort("{chunk$error$message}") + } } else { cli::cli_inform(c("!" = "Unknown chunk type {.str {chunk$type}}.")) } @@ -273,3 +277,12 @@ method(as_json, list(ProviderClaude, ToolDef)) <- function(provider, x) { input_schema = compact(as_json(provider, x@arguments)) ) } + + + +# Helpers ---------------------------------------------------------------- + +# From httr2 +backoff_default <- function(i) { + round(min(stats::runif(1, min = 1, max = 2^i), 60), 1) +}