| Title: | OpenAI-Compatible SDK for the nRouter LLM Gateway |
|---|---|
| Description: | A client for the nRouter LLM gateway (<https://nrouter.ai>), an OpenAI-compatible API giving one key access to models across six provider clouds. No official OpenAI SDK exists for R, so this package calls the HTTP API directly via 'httr'. Gateway refusals are raised as classed conditions, and per-request cost and token metadata are returned alongside every response. |
| Authors: | nRouter [aut, cre] |
| Maintainer: | nRouter <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 3.0.0 |
| Built: | 2026-10-05 11:13:48 UTC |
| Source: | https://github.com/nRouterAI/nrouter-sdk |
POST /audio/speech — generated audio bytes plus response metadata
nrouter_audio_speech(client, body)nrouter_audio_speech(client, body)
client |
An |
body |
Named list forming the request body. |
A list with bytes, meta and status_code.
POST /audio/transcriptions - Whisper-style speech to text
nrouter_audio_transcriptions(client, file_path, fields = list())nrouter_audio_transcriptions(client, file_path, fields = list())
client |
An |
file_path |
Path to the file to upload. Its EXTENSION is load-bearing — the upstream providers pick their decoder from it. |
fields |
Named list of additional form fields, e.g. |
A list with body, meta and status_code.
POST /audio/translations - speech in any language to English text
nrouter_audio_translations(client, file_path, fields = list())nrouter_audio_translations(client, file_path, fields = list())
client |
An |
file_path |
Path to the file to upload. Its EXTENSION is load-bearing — the upstream providers pick their decoder from it. |
fields |
Named list of additional form fields, e.g. |
A list with body, meta and status_code.
/v1/audio/speech returns audio, /v1/videos/{id}/content
returns a video, and stream = TRUE returns SSE. The JSON helpers
refuse those rather than handing back an empty body for a request you were
billed for; this is the function that returns them.
nrouter_bytes(client, path, body = NULL)nrouter_bytes(client, path, body = NULL)
client |
An |
path |
Path under the gateway's |
body |
Named list to send as JSON, or |
A list with bytes, meta and status_code.
Kept as the package's original one-call entry point. Prefer
nrouter_chat_completions() when you need the response metadata.
nrouter_chat( messages, model = "gpt-5.4-mini", api_key = NULL, base_url = nrouter_default_base_url() )nrouter_chat( messages, model = "gpt-5.4-mini", api_key = NULL, base_url = nrouter_default_base_url() )
messages |
List of message objects, e.g.
|
model |
Model name. The default MUST be a model the gateway serves on
|
api_key |
nRouter API key. Defaults to |
base_url |
Gateway base URL. |
The parsed JSON response as an R list.
POST /chat/completions
nrouter_chat_completions(client, body)nrouter_chat_completions(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
Stream POST /chat/completions
nrouter_chat_completions_stream(client, body, on_chunk)nrouter_chat_completions_stream(client, body, on_chunk)
client |
An |
body |
Named list forming the request body. |
on_chunk |
Function called incrementally with |
The gateway speaks the OpenAI wire format, so request and response bodies are the shapes you already know. There is no official OpenAI SDK for R, so this package calls the HTTP API directly via httr.
nrouter_client( api_key = NULL, base_url = nrouter_default_base_url(), timeout_seconds = nrouter_default_timeout_seconds(), connect_timeout_seconds = nrouter_default_connect_timeout_seconds(), stream_idle_seconds = nrouter_default_stream_idle_seconds() )nrouter_client( api_key = NULL, base_url = nrouter_default_base_url(), timeout_seconds = nrouter_default_timeout_seconds(), connect_timeout_seconds = nrouter_default_connect_timeout_seconds(), stream_idle_seconds = nrouter_default_stream_idle_seconds() )
api_key |
nRouter API key. Defaults to |
base_url |
Gateway base URL. |
timeout_seconds |
Whole-request ceiling for buffered calls. See
|
connect_timeout_seconds |
Connect-phase ceiling. See
|
stream_idle_seconds |
Stall ceiling for streaming and binary transfers,
which carry no whole-request ceiling. See
|
An object of class nrouter_client.
## Not run: client <- nrouter_client() result <- nrouter_chat_completions(client, list( model = "gpt-5.4-mini", messages = list(list(role = "user", content = "Hello!")) )) # Unpriced is unknown, not free. Never render a NULL cost as 0. print(result$meta) ## End(Not run)## Not run: client <- nrouter_client() result <- nrouter_chat_completions(client, list( model = "gpt-5.4-mini", messages = list(list(role = "user", content = "Hello!")) )) # Unpriced is unknown, not free. Never render a NULL cost as 0. print(result$meta) ## End(Not run)
POST /completions — the legacy text-completions wire
nrouter_completions(client, body)nrouter_completions(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
Stream POST /completions
nrouter_completions_stream(client, body, on_chunk)nrouter_completions_stream(client, body, on_chunk)
client |
An |
body |
Named list forming the request body. |
on_chunk |
Function called incrementally with |
Build (but do not signal) an nRouter condition
nrouter_condition( message, code = NULL, status = NULL, request_id = NULL, limit_source = NULL, auth_reason = NULL )nrouter_condition( message, code = NULL, status = NULL, request_id = NULL, limit_source = NULL, auth_reason = NULL )
message |
Human-readable message. |
code |
The gateway's stable error code, or |
status |
HTTP status, or |
request_id |
Value of |
limit_source |
Value of |
auth_reason |
Value of |
A condition object.
Separate from nrouter_transport_condition on purpose. Both are raised
locally, but this one is PERMANENT — a caller retrying on
nrouter_is_retryable would spin forever without making a request.
nrouter_configuration_condition(message)nrouter_configuration_condition(message)
message |
Human-readable message. |
A condition object.
POST /messages/count_tokens — counts input without generating
nrouter_count_tokens(client, body)nrouter_count_tokens(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
POST /videos — starts a video generation job
nrouter_create_video(client, body)nrouter_create_video(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
A dynamic value: override it for stage.
nrouter_default_base_url()nrouter_default_base_url()
The default base URL.
Bounds DNS resolution plus the TCP handshake and nothing after it, so a black-holed gateway address is reported rather than waited on. Matches the gateway's own 10 s provider connect timeout.
nrouter_default_connect_timeout_seconds()nrouter_default_connect_timeout_seconds()
The default connect timeout in seconds.
nrouter_stream() and nrouter_bytes() deliberately set NO
whole-request timeout: a whole-request ceiling severs an SSE stream
mid-generation and truncates a long /v1/videos/{id}/content
download, both of them already billed. They bound the transfer with libcurl's
low-speed limit instead, so a transfer that STOPS producing bytes for this
long is abandoned while a working one runs as long as it needs. 180 s sits
above the gateway's own 120 s between-bytes read timeout, so the gateway's
honest error reaches the caller instead of a client-side abort racing it.
nrouter_default_stream_idle_seconds()nrouter_default_stream_idle_seconds()
The default stall timeout in seconds.
Applied to nrouter_request() and nrouter_multipart() as
httr::timeout(). 600 s is above the gateway's ~410 s worst honest case
with margin, and the same order as the OpenAI and Anthropic clients' own
600 s defaults.
nrouter_default_timeout_seconds()nrouter_default_timeout_seconds()
The default request timeout in seconds.
GET /videos/(id)/content — downloads generated video bytes
nrouter_download_video_content(client, video_id)nrouter_download_video_content(client, video_id)
client |
An |
video_id |
Video job identifier. It is encoded as one URL path segment. |
A list with bytes, meta and status_code.
POST /embeddings
nrouter_embeddings(client, body)nrouter_embeddings(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
The one environment variable this package reads
nrouter_env_key()nrouter_env_key()
The variable name.
The gateway nests them under error; a bare object is accepted too, so
a proxy that reshapes the envelope cannot downgrade a typed error into a
generic one.
nrouter_error_from_payload(status, payload, meta)nrouter_error_from_payload(status, payload, meta)
status |
HTTP status. |
payload |
Parsed response body. |
meta |
An |
A condition object.
Exactly the names in spec/nrouter-sdk-spec.json.
nrouter_header_names()nrouter_header_names()
A character vector of 15 header names.
POST /images/generations
nrouter_images_generations(client, body)nrouter_images_generations(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
Did the gateway price this request exactly?
nrouter_is_priced(meta)nrouter_is_priced(meta)
meta |
An |
TRUE only when the cost is both present and exact.
Is this nRouter condition worth retrying?
nrouter_is_retryable(cond)nrouter_is_retryable(cond)
cond |
A condition raised by this package. |
TRUE when retrying the identical request could succeed.
The prefix every nRouter customer key carries
nrouter_key_prefix()nrouter_key_prefix()
The key prefix.
POST /messages (the Anthropic wire format the gateway also serves)
nrouter_messages(client, body)nrouter_messages(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
Stream POST /messages
nrouter_messages_stream(client, body, on_chunk)nrouter_messages_stream(client, body, on_chunk)
client |
An |
body |
Named list forming the request body. |
on_chunk |
Function called incrementally with |
Every field is NULL when the gateway did not send it. The gateway
omits a header rather than sending a placeholder, and the two omissions that
matter most are x-nr-request-cost — ABSENT when the model is unpriced,
never 0 — and x-nr-limit-source, absent when nothing measured a
refusal.
nrouter_meta(headers = list())nrouter_meta(headers = list())
headers |
Named character vector or list of response headers, keyed by lowercase name. |
An object of class nrouter_meta.
GET /models/(model_id)
nrouter_model(client, model_id)nrouter_model(client, model_id)
client |
An |
model_id |
Model identifier. It is encoded as one URL path segment. |
A list with body, meta and status_code.
GET /models — what this key is allowed to route to
nrouter_models(client)nrouter_models(client)
client |
An |
A list with body, meta and status_code.
multipart/form-data, not JSON: /v1/audio/transcriptions and
/v1/audio/translations require a binary file part, so the JSON
helpers cannot reach those endpoints at all.
nrouter_multipart(client, path, file_path, fields = list())nrouter_multipart(client, path, file_path, fields = list())
client |
An |
path |
Path under the gateway's |
file_path |
Path to the file to upload. Its EXTENSION is load-bearing — the upstream providers pick their decoder from it. |
fields |
Named list of additional form fields, e.g. |
A list with body, meta and status_code.
Send a request to the nRouter gateway
nrouter_request( client, path, body = NULL, method = if (is.null(body)) "GET" else "POST" )nrouter_request( client, path, body = NULL, method = if (is.null(body)) "GET" else "POST" )
client |
An |
path |
Path under the gateway's |
body |
Named list to send as JSON, or |
method |
HTTP method; inferred from |
A list with body, meta and status_code.
Explicit argument first, then NROUTER_API_KEY. Validation happens
before any request so a malformed key fails here rather than as a 401 that
reads like a revoked credential.
nrouter_resolve_api_key(api_key = NULL)nrouter_resolve_api_key(api_key = NULL)
api_key |
Explicit key, or |
The validated key.
POST /responses
nrouter_responses(client, body)nrouter_responses(client, body)
client |
An |
body |
Named list forming the request body. |
A list with body, meta and status_code.
Stream POST /responses
nrouter_responses_stream(client, body, on_chunk)nrouter_responses_stream(client, body, on_chunk)
client |
An |
body |
Named list forming the request body. |
on_chunk |
Function called incrementally with |
GET /videos/(id) — polls a video generation job
nrouter_retrieve_video(client, video_id)nrouter_retrieve_video(client, video_id)
client |
An |
video_id |
Video job identifier. It is encoded as one URL path segment. |
A list with body, meta and status_code.
The parser is public for advanced transports and deterministic testing. Most callers should use one of the named streaming helpers.
nrouter_sse_parser(on_chunk)nrouter_sse_parser(on_chunk)
on_chunk |
Function called with each decoded event. Return |
A list with feed(raw) and finish() functions.
Stream a JSON request from the nRouter gateway
nrouter_stream(client, path, body, on_chunk)nrouter_stream(client, path, body, on_chunk)
client |
An |
path |
Path under the gateway's |
body |
Named list forming the request body. |
on_chunk |
Function called incrementally with |
A list with final meta, status_code, and
cancelled.
A transport failure: the request left this process and got no answer
nrouter_transport_condition(message)nrouter_transport_condition(message)
message |
Human-readable message. |
A condition object.
Every gateway refusal is raised as a classed R condition. The class vector
runs specific-to-general — e.g.
c("nrouter_rate_limit_error", "nrouter_error", "error", "condition") —
so tryCatch(nrouter_error = ...) catches everything while
tryCatch(nrouter_rate_limit_error = ...) catches only that.
The gateway's stable code decides the class, not the HTTP status:
status alone cannot separate invalid_request from
guardrail_blocked (both 400), nor rate_limit_exceeded from
tpm_limit_exceeded (both 429).
R's default list printer shows every element, so an interactive
client or a print(client) would display the full API key — a
credential that spends real credits, leaked by an ordinary session
transcript. Only the prefix and last four characters are shown.
## S3 method for class 'nrouter_client' print(x, ...)## S3 method for class 'nrouter_client' print(x, ...)
x |
An |
... |
Ignored. |
x, invisibly.